fix:android
Android / build-android (push) Successful in 2m46s

This commit is contained in:
intelligence committed 2026-08-29 15:16:21 +02:00
1 parent 15ab99c740
commit 2b89bbd959
6 files changed
+76 -150

No files matched your search

@@ -1,36 +1,23 @@
package io.github.transui.android;
final class AppConfig {
final String remoteEndpoint;
final String remoteModel;
final String remoteKey;
final String localEndpoint;
final String localModel;
final String localKey;
final String endpoint;
final String model;
final String apiKey;
final String prompt;
final boolean remoteFirst;
AppConfig(
String remoteEndpoint,
String remoteModel,
String remoteKey,
String localEndpoint,
String localModel,
String localKey,
String prompt,
boolean remoteFirst) {
this.remoteEndpoint = remoteEndpoint;
this.remoteModel = remoteModel;
this.remoteKey = remoteKey;
this.localEndpoint = localEndpoint;
this.localModel = localModel;
this.localKey = localKey;
String endpoint,
String model,
String apiKey,
String prompt) {
this.endpoint = endpoint;
this.model = model;
this.apiKey = apiKey;
this.prompt = prompt;
this.remoteFirst = remoteFirst;
}
boolean hasUsableEndpoint() {
if (remoteFirst && !remoteEndpoint.isEmpty()) return true;
return !localEndpoint.isEmpty();
return !endpoint.isEmpty();
}
}
@@ -12,34 +12,38 @@ final class ConfigRepository {
ConfigRepository(Context context) {
preferences = context.getApplicationContext().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
removeObsoleteLocalSettings();
}
AppConfig load() {
String remoteKey = decryptOrEmpty(preferences.getString("remote_key", ""));
String localKey = decryptOrEmpty(preferences.getString("local_key", ""));
return new AppConfig(
preferences.getString("remote_endpoint", ""),
preferences.getString("remote_model", ""),
remoteKey,
preferences.getString("local_endpoint", "http://localhost:8080"),
preferences.getString("local_model", ""),
localKey,
preferences.getString("prompt", ""),
preferences.getBoolean("remote_first", true));
decryptOrEmpty(preferences.getString("remote_key", "")),
preferences.getString("prompt", ""));
}
void save(AppConfig config) throws GeneralSecurityException, IOException {
String remoteKey = SecretStore.encrypt(config.remoteKey);
String localKey = SecretStore.encrypt(config.localKey);
preferences.edit()
.putString("remote_endpoint", config.remoteEndpoint)
.putString("remote_model", config.remoteModel)
.putString("remote_key", remoteKey)
.putString("local_endpoint", config.localEndpoint)
.putString("local_model", config.localModel)
.putString("local_key", localKey)
.putString("remote_endpoint", config.endpoint)
.putString("remote_model", config.model)
.putString("remote_key", SecretStore.encrypt(config.apiKey))
.putString("prompt", config.prompt)
.putBoolean("remote_first", config.remoteFirst)
.apply();
}
private void removeObsoleteLocalSettings() {
if (!preferences.contains("local_endpoint")
&& !preferences.contains("local_model")
&& !preferences.contains("local_key")
&& !preferences.contains("remote_first")) {
return;
}
preferences.edit()
.remove("local_endpoint")
.remove("local_model")
.remove("local_key")
.remove("remote_first")
.apply();
}
@@ -10,7 +10,6 @@ import android.os.Bundle;
import android.provider.Settings;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
@@ -20,14 +19,12 @@ import java.security.GeneralSecurityException;
public final class MainActivity extends Activity {
private static final int MICROPHONE_REQUEST = 1;
private EditText remoteEndpoint;
private EditText remoteModel;
private EditText remoteKey;
private EditText localEndpoint;
private EditText localModel;
private EditText localKey;
private static final String ACTION_LANGUAGE_SETTINGS = "android.settings.LANGUAGE_SETTINGS";
private EditText endpoint;
private EditText model;
private EditText apiKey;
private EditText prompt;
private Switch remoteFirst;
private TextView providerStatus;
private Button microphone;
private ConfigRepository repository;
@@ -42,9 +39,7 @@ public final class MainActivity extends Activity {
findViewById(R.id.save).setOnClickListener(view -> saveConfig());
microphone.setOnClickListener(view -> requestMicrophone());
findViewById(R.id.choose_provider).setOnClickListener(view -> {
if (saveConfig()) openVoiceInputSettings();
});
findViewById(R.id.language_settings).setOnClickListener(view -> openLanguageSettings());
}
@Override
@@ -60,39 +55,27 @@ public final class MainActivity extends Activity {
}
private void bindViews() {
remoteEndpoint = findViewById(R.id.remote_endpoint);
remoteModel = findViewById(R.id.remote_model);
remoteKey = findViewById(R.id.remote_key);
localEndpoint = findViewById(R.id.local_endpoint);
localModel = findViewById(R.id.local_model);
localKey = findViewById(R.id.local_key);
endpoint = findViewById(R.id.endpoint);
model = findViewById(R.id.model);
apiKey = findViewById(R.id.api_key);
prompt = findViewById(R.id.prompt);
remoteFirst = findViewById(R.id.remote_first);
providerStatus = findViewById(R.id.provider_status);
microphone = findViewById(R.id.microphone);
}
private void showConfig(AppConfig config) {
remoteEndpoint.setText(config.remoteEndpoint);
remoteModel.setText(config.remoteModel);
remoteKey.setText(config.remoteKey);
localEndpoint.setText(config.localEndpoint);
localModel.setText(config.localModel);
localKey.setText(config.localKey);
endpoint.setText(config.endpoint);
model.setText(config.model);
apiKey.setText(config.apiKey);
prompt.setText(config.prompt);
remoteFirst.setChecked(config.remoteFirst);
}
private boolean saveConfig() {
AppConfig config = new AppConfig(
value(remoteEndpoint).trim(),
value(remoteModel).trim(),
value(remoteKey).trim(),
value(localEndpoint).trim(),
value(localModel).trim(),
value(localKey).trim(),
value(prompt),
remoteFirst.isChecked());
value(endpoint).trim(),
value(model).trim(),
value(apiKey).trim(),
value(prompt));
try {
repository.save(config);
Toast.makeText(this, R.string.settings_saved, Toast.LENGTH_SHORT).show();
@@ -109,11 +92,17 @@ public final class MainActivity extends Activity {
}
}
private void openVoiceInputSettings() {
private void openLanguageSettings() {
try {
startActivity(new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS));
} catch (ActivityNotFoundException error) {
Toast.makeText(this, R.string.voice_settings_unavailable, Toast.LENGTH_LONG).show();
startActivity(new Intent(ACTION_LANGUAGE_SETTINGS));
return;
} catch (ActivityNotFoundException ignored) {
// Older Android builds expose the combined Languages and input page here.
}
try {
startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
} catch (ActivityNotFoundException ignored) {
Toast.makeText(this, R.string.language_settings_unavailable, Toast.LENGTH_LONG).show();
}
}
@@ -20,25 +20,10 @@ final class TranscriptionClient {
private volatile HttpURLConnection activeConnection;
Result transcribe(AppConfig config, byte[] wav) {
Result remoteResult = null;
if (config.remoteFirst && !config.remoteEndpoint.isEmpty()) {
remoteResult = request(
config.remoteEndpoint, config.remoteModel, config.remoteKey, config.prompt, wav);
if (remoteResult.text != null) return remoteResult;
if (config.endpoint.isEmpty()) {
return Result.error("No transcription endpoint is configured", SpeechRecognizer.ERROR_CLIENT);
}
if (!config.localEndpoint.isEmpty()) {
Result localResult = request(
config.localEndpoint, config.localModel, config.localKey, config.prompt, wav);
if (localResult.text != null || remoteResult == null) return localResult;
return Result.error(
remoteResult.error + "; local: " + localResult.error,
localResult.errorCode);
}
return remoteResult != null
? remoteResult
: Result.error("No transcription endpoint is configured", SpeechRecognizer.ERROR_CLIENT);
return request(config.endpoint, config.model, config.apiKey, config.prompt, wav);
}
void cancel() {
@@ -48,51 +48,26 @@
<TextView
style="@style/SectionLabel"
android:text="@string/remote" />
android:text="@string/server" />
<EditText
android:id="@+id/remote_endpoint"
android:id="@+id/endpoint"
style="@style/Field"
android:hint="@string/remote_endpoint"
android:hint="@string/endpoint"
android:importantForAutofill="no"
android:inputType="textUri" />
<EditText
android:id="@+id/remote_model"
android:id="@+id/model"
style="@style/Field"
android:hint="@string/remote_model"
android:hint="@string/model"
android:importantForAutofill="no"
android:inputType="text" />
<EditText
android:id="@+id/remote_key"
android:id="@+id/api_key"
style="@style/Field"
android:hint="@string/remote_api_key"
android:importantForAutofill="no"
android:inputType="textPassword" />
<TextView
style="@style/SectionLabel"
android:text="@string/local" />
<EditText
android:id="@+id/local_endpoint"
style="@style/Field"
android:hint="@string/local_endpoint"
android:importantForAutofill="no"
android:inputType="textUri" />
<EditText
android:id="@+id/local_model"
style="@style/Field"
android:hint="@string/local_model"
android:importantForAutofill="no"
android:inputType="text" />
<EditText
android:id="@+id/local_key"
style="@style/Field"
android:hint="@string/local_api_key"
android:hint="@string/api_key"
android:importantForAutofill="no"
android:inputType="textPassword" />
@@ -109,15 +84,6 @@
android:maxLines="3"
android:singleLine="false" />
<Switch
android:id="@+id/remote_first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:checked="true"
android:text="@string/remote_first"
android:textColor="@color/ink" />
<Button
android:id="@+id/save"
android:layout_width="match_parent"
@@ -133,10 +99,10 @@
android:text="@string/allow_microphone" />
<Button
android:id="@+id/choose_provider"
android:id="@+id/language_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/choose_provider" />
android:text="@string/open_language_settings" />
</LinearLayout>
</ScrollView>
+6 -11
View File
@@ -5,22 +5,17 @@
<string name="title">Transui voice input</string>
<string name="status_selected">Selected as voice input</string>
<string name="status_not_selected">Select Transui as voice input</string>
<string name="remote">REMOTE</string>
<string name="local">LOCAL</string>
<string name="server">SERVER</string>
<string name="request">REQUEST</string>
<string name="remote_endpoint">Remote endpoint</string>
<string name="remote_model">Remote model</string>
<string name="remote_api_key">Remote API key</string>
<string name="local_endpoint">Local endpoint</string>
<string name="local_model">Local model</string>
<string name="local_api_key">Local API key</string>
<string name="endpoint">Transcription endpoint</string>
<string name="model">Model</string>
<string name="api_key">API key</string>
<string name="prompt">Prompt</string>
<string name="remote_first">Remote first, local fallback</string>
<string name="save">Save settings</string>
<string name="choose_provider">Choose voice input</string>
<string name="open_language_settings">Open language settings</string>
<string name="allow_microphone">Allow microphone</string>
<string name="microphone_allowed">Microphone allowed</string>
<string name="settings_saved">Settings saved</string>
<string name="settings_save_failed">Could not save API keys</string>
<string name="voice_settings_unavailable">Voice input settings are unavailable</string>
<string name="language_settings_unavailable">Language settings are unavailable</string>
</resources>