Merge "Update code for Rust 1.82.0" into main
diff --git a/android/TerminalApp/Android.bp b/android/TerminalApp/Android.bp
index 4bb9703..59f18df 100644
--- a/android/TerminalApp/Android.bp
+++ b/android/TerminalApp/Android.bp
@@ -18,6 +18,7 @@
"debian-service-grpclib-lite",
"gson",
"VmTerminalApp.aidl-java",
+ "MicrodroidTestHelper", // for DeviceProperties class
],
jni_libs: [
"libforwarder_host_jni",
diff --git a/android/TerminalApp/AndroidManifest.xml b/android/TerminalApp/AndroidManifest.xml
index 726004c..53fdafc 100644
--- a/android/TerminalApp/AndroidManifest.xml
+++ b/android/TerminalApp/AndroidManifest.xml
@@ -35,7 +35,8 @@
android:theme="@style/VmTerminalAppTheme"
android:usesCleartextTraffic="true"
android:supportsRtl="true"
- android:enabled="false">
+ android:enabled="false"
+ android:name=".Application">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden|navigation|uiMode|screenLayout|smallestScreenSize"
android:exported="true">
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
new file mode 100644
index 0000000..efe651e
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Application as AndroidApplication
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Context
+
+public class Application : AndroidApplication() {
+ override fun onCreate() {
+ super.onCreate()
+ setupNotificationChannels()
+ }
+
+ private fun setupNotificationChannels() {
+ val nm = getSystemService<NotificationManager>(NotificationManager::class.java)
+
+ nm.createNotificationChannel(
+ NotificationChannel(
+ CHANNEL_LONG_RUNNING_ID,
+ getString(R.string.notification_channel_long_running_name),
+ NotificationManager.IMPORTANCE_DEFAULT,
+ )
+ )
+
+ nm.createNotificationChannel(
+ NotificationChannel(
+ CHANNEL_SYSTEM_EVENTS_ID,
+ getString(R.string.notification_channel_system_events_name),
+ NotificationManager.IMPORTANCE_HIGH,
+ )
+ )
+ }
+
+ companion object {
+ const val CHANNEL_LONG_RUNNING_ID = "long_running"
+ const val CHANNEL_SYSTEM_EVENTS_ID = "system_events"
+
+ fun getInstance(c: Context): Application = c.getApplicationContext() as Application
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.java
deleted file mode 100644
index d6ca1e6..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import android.Manifest;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-public abstract class BaseActivity extends AppCompatActivity {
- private static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- NotificationManager notificationManager = getSystemService(NotificationManager.class);
- if (notificationManager.getNotificationChannel(this.getPackageName()) == null) {
- NotificationChannel channel =
- new NotificationChannel(
- this.getPackageName(),
- getString(R.string.app_name),
- NotificationManager.IMPORTANCE_DEFAULT);
- notificationManager.createNotificationChannel(channel);
- }
-
- if (!(this instanceof ErrorActivity)) {
- Thread currentThread = Thread.currentThread();
- if (!(currentThread.getUncaughtExceptionHandler()
- instanceof TerminalExceptionHandler)) {
- currentThread.setUncaughtExceptionHandler(
- new TerminalExceptionHandler(getApplicationContext()));
- }
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (getApplicationContext().checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)
- != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(
- new String[] {Manifest.permission.POST_NOTIFICATIONS},
- POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE);
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt
new file mode 100644
index 0000000..70bc5e4
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.Manifest
+import android.content.pm.PackageManager
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+
+abstract class BaseActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (this !is ErrorActivity) {
+ val currentThread = Thread.currentThread()
+ if (currentThread.uncaughtExceptionHandler !is TerminalExceptionHandler) {
+ currentThread.uncaughtExceptionHandler =
+ TerminalExceptionHandler(applicationContext)
+ }
+ }
+ }
+
+ public override fun onResume() {
+ super.onResume()
+
+ if (
+ applicationContext.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) !=
+ PackageManager.PERMISSION_GRANTED
+ ) {
+ requestPermissions(
+ arrayOf<String>(Manifest.permission.POST_NOTIFICATIONS),
+ POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE,
+ )
+ }
+ }
+
+ companion object {
+ private const val POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.java b/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.java
deleted file mode 100644
index e3d1a67..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.content.Context;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-import android.util.Base64;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.X509Certificate;
-
-public class CertificateUtils {
- private static final String ALIAS = "ttyd";
-
- public static KeyStore.PrivateKeyEntry createOrGetKey() {
- try {
- KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
- ks.load(null);
-
- if (!ks.containsAlias(ALIAS)) {
- Log.d(TAG, "there is no keypair, will generate it");
- createKey();
- } else if (!(ks.getCertificate(ALIAS) instanceof X509Certificate)) {
- Log.d(TAG, "certificate isn't X509Certificate or it is invalid");
- createKey();
- } else {
- try {
- ((X509Certificate) ks.getCertificate(ALIAS)).checkValidity();
- } catch (CertificateExpiredException | CertificateNotYetValidException e) {
- Log.d(TAG, "certificate is invalid", e);
- createKey();
- }
- }
- return ((KeyStore.PrivateKeyEntry) ks.getEntry(ALIAS, null));
- } catch (Exception e) {
- throw new RuntimeException("cannot generate or get key", e);
- }
- }
-
- private static void createKey()
- throws NoSuchAlgorithmException,
- NoSuchProviderException,
- InvalidAlgorithmParameterException {
- KeyPairGenerator kpg =
- KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
- kpg.initialize(
- new KeyGenParameterSpec.Builder(
- ALIAS, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
- .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
- .build());
-
- kpg.generateKeyPair();
- }
-
- public static void writeCertificateToFile(Context context, Certificate cert) {
- String certFileName = "ca.crt";
- File certFile = new File(context.getFilesDir(), certFileName);
- try (FileOutputStream writer = new FileOutputStream(certFile)) {
- String cert_begin = "-----BEGIN CERTIFICATE-----\n";
- String end_cert = "-----END CERTIFICATE-----\n";
- String output =
- cert_begin
- + Base64.encodeToString(cert.getEncoded(), Base64.DEFAULT)
- .replaceAll("(.{64})", "$1\n")
- + end_cert;
- writer.write(output.getBytes());
- } catch (IOException | CertificateEncodingException e) {
- throw new RuntimeException("cannot write certs", e);
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.kt b/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.kt
new file mode 100644
index 0000000..ee8a8f8
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.security.keystore.KeyGenParameterSpec
+import android.security.keystore.KeyProperties
+import android.util.Base64
+import android.util.Log
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.lang.Exception
+import java.lang.RuntimeException
+import java.security.InvalidAlgorithmParameterException
+import java.security.KeyPairGenerator
+import java.security.KeyStore
+import java.security.NoSuchAlgorithmException
+import java.security.NoSuchProviderException
+import java.security.cert.Certificate
+import java.security.cert.CertificateEncodingException
+import java.security.cert.CertificateExpiredException
+import java.security.cert.CertificateNotYetValidException
+import java.security.cert.X509Certificate
+
+object CertificateUtils {
+ private const val ALIAS = "ttyd"
+
+ fun createOrGetKey(): KeyStore.PrivateKeyEntry {
+ try {
+ val ks = KeyStore.getInstance("AndroidKeyStore")
+ ks.load(null)
+
+ if (!ks.containsAlias(ALIAS)) {
+ Log.d(MainActivity.TAG, "there is no keypair, will generate it")
+ createKey()
+ } else if (ks.getCertificate(ALIAS) !is X509Certificate) {
+ Log.d(MainActivity.TAG, "certificate isn't X509Certificate or it is invalid")
+ createKey()
+ } else {
+ try {
+ (ks.getCertificate(ALIAS) as X509Certificate).checkValidity()
+ } catch (e: CertificateExpiredException) {
+ Log.d(MainActivity.TAG, "certificate is invalid", e)
+ createKey()
+ } catch (e: CertificateNotYetValidException) {
+ Log.d(MainActivity.TAG, "certificate is invalid", e)
+ createKey()
+ }
+ }
+ return ks.getEntry(ALIAS, null) as KeyStore.PrivateKeyEntry
+ } catch (e: Exception) {
+ throw RuntimeException("cannot generate or get key", e)
+ }
+ }
+
+ @Throws(
+ NoSuchAlgorithmException::class,
+ NoSuchProviderException::class,
+ InvalidAlgorithmParameterException::class,
+ )
+ private fun createKey() {
+ val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore")
+ kpg.initialize(
+ KeyGenParameterSpec.Builder(
+ ALIAS,
+ KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY,
+ )
+ .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
+ .build()
+ )
+
+ kpg.generateKeyPair()
+ }
+
+ fun writeCertificateToFile(context: Context, cert: Certificate) {
+ val certFile = File(context.getFilesDir(), "ca.crt")
+ try {
+ FileOutputStream(certFile).use { writer ->
+ val certBegin = "-----BEGIN CERTIFICATE-----\n"
+ val certEnd = "-----END CERTIFICATE-----\n"
+ val output =
+ (certBegin +
+ Base64.encodeToString(cert.encoded, Base64.DEFAULT)
+ .replace("(.{64})".toRegex(), "$1\n") +
+ certEnd)
+ writer.write(output.toByteArray())
+ }
+ } catch (e: IOException) {
+ throw RuntimeException("cannot write certs", e)
+ } catch (e: CertificateEncodingException) {
+ throw RuntimeException("cannot write certs", e)
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
deleted file mode 100644
index a0fca82..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Rect;
-import android.os.Environment;
-import android.system.virtualmachine.VirtualMachineConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.AudioConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.Disk;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.DisplayConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.GpuConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.Partition;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.SharedPath;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-import android.view.WindowMetrics;
-
-import com.google.gson.Gson;
-import com.google.gson.annotations.SerializedName;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-/** This class and its inner classes model vm_config.json. */
-class ConfigJson {
- private static final boolean DEBUG = true;
-
- private ConfigJson() {}
-
- @SerializedName("protected")
- private boolean isProtected;
-
- private String name;
- private String cpu_topology;
- private String platform_version;
- private int memory_mib = 1024;
- private String console_input_device;
- private String bootloader;
- private String kernel;
- private String initrd;
- private String params;
- private boolean debuggable;
- private boolean console_out;
- private boolean connect_console;
- private boolean network;
- private InputJson input;
- private AudioJson audio;
- private DiskJson[] disks;
- private SharedPathJson[] sharedPath;
- private DisplayJson display;
- private GpuJson gpu;
- private boolean auto_memory_balloon;
-
- /** Parses JSON file at jsonPath */
- static ConfigJson from(Context context, Path jsonPath) {
- try (FileReader fileReader = new FileReader(jsonPath.toFile())) {
- String content = replaceKeywords(fileReader, context);
- return new Gson().fromJson(content, ConfigJson.class);
- } catch (Exception e) {
- throw new RuntimeException("Failed to parse " + jsonPath, e);
- }
- }
-
- private static String replaceKeywords(Reader r, Context context) throws IOException {
- Map<String, String> rules = new HashMap<>();
- rules.put("\\$PAYLOAD_DIR", InstalledImage.getDefault(context).getInstallDir().toString());
- rules.put("\\$USER_ID", String.valueOf(context.getUserId()));
- rules.put("\\$PACKAGE_NAME", context.getPackageName());
- rules.put("\\$APP_DATA_DIR", context.getDataDir().toString());
-
- try (BufferedReader br = new BufferedReader(r)) {
- return br.lines()
- .map(
- line -> {
- for (Map.Entry<String, String> rule : rules.entrySet()) {
- line = line.replaceAll(rule.getKey(), rule.getValue());
- }
- return line;
- })
- .collect(Collectors.joining("\n"));
- }
- }
-
- private int getCpuTopology() {
- switch (cpu_topology) {
- case "one_cpu":
- return VirtualMachineConfig.CPU_TOPOLOGY_ONE_CPU;
- case "match_host":
- return VirtualMachineConfig.CPU_TOPOLOGY_MATCH_HOST;
- default:
- throw new RuntimeException("invalid cpu topology: " + cpu_topology);
- }
- }
-
- private int getDebugLevel() {
- return debuggable
- ? VirtualMachineConfig.DEBUG_LEVEL_FULL
- : VirtualMachineConfig.DEBUG_LEVEL_NONE;
- }
-
- /** Converts this parsed JSON into VirtualMachieConfig Builder */
- VirtualMachineConfig.Builder toConfigBuilder(Context context) {
- return new VirtualMachineConfig.Builder(context)
- .setProtectedVm(isProtected)
- .setMemoryBytes((long) memory_mib * 1024 * 1024)
- .setConsoleInputDevice(console_input_device)
- .setCpuTopology(getCpuTopology())
- .setCustomImageConfig(toCustomImageConfigBuilder(context).build())
- .setDebugLevel(getDebugLevel())
- .setVmOutputCaptured(console_out)
- .setConnectVmConsole(connect_console);
- }
-
- VirtualMachineCustomImageConfig.Builder toCustomImageConfigBuilder(Context context) {
- VirtualMachineCustomImageConfig.Builder builder =
- new VirtualMachineCustomImageConfig.Builder();
-
- builder.setName(name)
- .setBootloaderPath(bootloader)
- .setKernelPath(kernel)
- .setInitrdPath(initrd)
- .useNetwork(network)
- .useAutoMemoryBalloon(auto_memory_balloon);
-
- if (input != null) {
- builder.useTouch(input.touchscreen)
- .useKeyboard(input.keyboard)
- .useMouse(input.mouse)
- .useTrackpad(input.trackpad)
- .useSwitches(input.switches);
- }
-
- if (audio != null) {
- builder.setAudioConfig(audio.toConfig());
- }
-
- if (display != null) {
- builder.setDisplayConfig(display.toConfig(context));
- }
-
- if (gpu != null) {
- builder.setGpuConfig(gpu.toConfig());
- }
-
- if (params != null) {
- Arrays.stream(params.split(" ")).forEach(builder::addParam);
- }
-
- if (disks != null) {
- Arrays.stream(disks).map(d -> d.toConfig()).forEach(builder::addDisk);
- }
-
- if (sharedPath != null) {
- Arrays.stream(sharedPath)
- .map(d -> d.toConfig(context))
- .filter(Objects::nonNull)
- .forEach(builder::addSharedPath);
- }
- return builder;
- }
-
- private static class SharedPathJson {
- private SharedPathJson() {}
-
- private String sharedPath;
- private static final int GUEST_UID = 1000;
- private static final int GUEST_GID = 100;
-
- private SharedPath toConfig(Context context) {
- try {
- int terminalUid = getTerminalUid(context);
- if (sharedPath.contains("emulated")) {
- if (Environment.isExternalStorageManager()) {
- int currentUserId = context.getUserId();
- String path = sharedPath + "/" + currentUserId + "/Download";
- return new SharedPath(
- path,
- terminalUid,
- terminalUid,
- GUEST_UID,
- GUEST_GID,
- 0007,
- "android",
- "android",
- false, /* app domain is set to false so that crosvm is spin up as child of virtmgr */
- "");
- }
- return null;
- }
- Path socketPath = context.getFilesDir().toPath().resolve("internal.virtiofs");
- Files.deleteIfExists(socketPath);
- return new SharedPath(
- sharedPath,
- terminalUid,
- terminalUid,
- 0,
- 0,
- 0007,
- "internal",
- "internal",
- true, /* app domain is set to true so that crosvm is spin up from app context */
- socketPath.toString());
- } catch (NameNotFoundException | IOException e) {
- return null;
- }
- }
-
- private int getTerminalUid(Context context) throws NameNotFoundException {
- return context.getPackageManager()
- .getPackageUidAsUser(context.getPackageName(), context.getUserId());
- }
- }
-
- private static class InputJson {
- private InputJson() {}
-
- private boolean touchscreen;
- private boolean keyboard;
- private boolean mouse;
- private boolean switches;
- private boolean trackpad;
- }
-
- private static class AudioJson {
- private AudioJson() {}
-
- private boolean microphone;
- private boolean speaker;
-
- private AudioConfig toConfig() {
- return new AudioConfig.Builder()
- .setUseMicrophone(microphone)
- .setUseSpeaker(speaker)
- .build();
- }
- }
-
- private static class DiskJson {
- private DiskJson() {}
-
- private boolean writable;
- private String image;
- private PartitionJson[] partitions;
-
- private Disk toConfig() {
- Disk d = writable ? Disk.RWDisk(image) : Disk.RODisk(image);
- for (PartitionJson pj : partitions) {
- boolean writable = this.writable && pj.writable;
- d.addPartition(new Partition(pj.label, pj.path, writable, pj.guid));
- }
- return d;
- }
- }
-
- private static class PartitionJson {
- private PartitionJson() {}
-
- private boolean writable;
- private String label;
- private String path;
- private String guid;
- }
-
- private static class DisplayJson {
- private DisplayJson() {}
-
- private float scale;
- private int refresh_rate;
- private int width_pixels;
- private int height_pixels;
-
- private DisplayConfig toConfig(Context context) {
- WindowManager wm = context.getSystemService(WindowManager.class);
- WindowMetrics metrics = wm.getCurrentWindowMetrics();
- Rect dispBounds = metrics.getBounds();
-
- int width = width_pixels > 0 ? width_pixels : dispBounds.right;
- int height = height_pixels > 0 ? height_pixels : dispBounds.bottom;
-
- int dpi = (int) (DisplayMetrics.DENSITY_DEFAULT * metrics.getDensity());
- if (scale > 0.0f) {
- dpi = (int) (dpi * scale);
- }
-
- int refreshRate = (int) context.getDisplay().getRefreshRate();
- if (this.refresh_rate != 0) {
- refreshRate = this.refresh_rate;
- }
-
- return new DisplayConfig.Builder()
- .setWidth(width)
- .setHeight(height)
- .setHorizontalDpi(dpi)
- .setVerticalDpi(dpi)
- .setRefreshRate(refreshRate)
- .build();
- }
- }
-
- private static class GpuJson {
- private GpuJson() {}
-
- private String backend;
- private String pci_address;
- private String renderer_features;
- private boolean renderer_use_egl = true;
- private boolean renderer_use_gles = true;
- private boolean renderer_use_glx = false;
- private boolean renderer_use_surfaceless = true;
- private boolean renderer_use_vulkan = false;
- private String[] context_types;
-
- private GpuConfig toConfig() {
- return new GpuConfig.Builder()
- .setBackend(backend)
- .setPciAddress(pci_address)
- .setRendererFeatures(renderer_features)
- .setRendererUseEgl(renderer_use_egl)
- .setRendererUseGles(renderer_use_gles)
- .setRendererUseGlx(renderer_use_glx)
- .setRendererUseSurfaceless(renderer_use_surfaceless)
- .setRendererUseVulkan(renderer_use_vulkan)
- .setContextTypes(context_types)
- .build();
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.kt
new file mode 100644
index 0000000..1fd58cd
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.kt
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Environment
+import android.system.virtualmachine.VirtualMachineConfig
+import android.system.virtualmachine.VirtualMachineCustomImageConfig
+import android.util.DisplayMetrics
+import android.view.WindowManager
+import com.android.virtualization.terminal.ConfigJson.AudioJson
+import com.android.virtualization.terminal.ConfigJson.DiskJson
+import com.android.virtualization.terminal.ConfigJson.DisplayJson
+import com.android.virtualization.terminal.ConfigJson.GpuJson
+import com.android.virtualization.terminal.ConfigJson.InputJson
+import com.android.virtualization.terminal.ConfigJson.PartitionJson
+import com.android.virtualization.terminal.ConfigJson.SharedPathJson
+import com.android.virtualization.terminal.InstalledImage.Companion.getDefault
+import com.google.gson.Gson
+import com.google.gson.annotations.SerializedName
+import java.io.BufferedReader
+import java.io.FileReader
+import java.io.IOException
+import java.io.Reader
+import java.lang.Exception
+import java.lang.RuntimeException
+import java.nio.file.Files
+import java.nio.file.Path
+
+/** This class and its inner classes model vm_config.json. */
+internal data class ConfigJson(
+ @SerializedName("protected") private val isProtected: Boolean,
+ private val name: String?,
+ private val cpu_topology: String?,
+ private val platform_version: String?,
+ private val memory_mib: Int = 1024,
+ private val console_input_device: String?,
+ private val bootloader: String?,
+ private val kernel: String?,
+ private val initrd: String?,
+ private val params: String?,
+ private val debuggable: Boolean,
+ private val console_out: Boolean,
+ private val connect_console: Boolean,
+ private val network: Boolean,
+ private val input: InputJson?,
+ private val audio: AudioJson?,
+ private val disks: Array<DiskJson>?,
+ private val sharedPath: Array<SharedPathJson>?,
+ private val display: DisplayJson?,
+ private val gpu: GpuJson?,
+ private val auto_memory_balloon: Boolean,
+) {
+ private fun getCpuTopology(): Int {
+ return when (cpu_topology) {
+ "one_cpu" -> VirtualMachineConfig.CPU_TOPOLOGY_ONE_CPU
+ "match_host" -> VirtualMachineConfig.CPU_TOPOLOGY_MATCH_HOST
+ else -> throw RuntimeException("invalid cpu topology: $cpu_topology")
+ }
+ }
+
+ private fun getDebugLevel(): Int {
+ return if (debuggable) VirtualMachineConfig.DEBUG_LEVEL_FULL
+ else VirtualMachineConfig.DEBUG_LEVEL_NONE
+ }
+
+ /** Converts this parsed JSON into VirtualMachineConfig Builder */
+ fun toConfigBuilder(context: Context): VirtualMachineConfig.Builder {
+ return VirtualMachineConfig.Builder(context)
+ .setProtectedVm(isProtected)
+ .setMemoryBytes(memory_mib.toLong() * 1024 * 1024)
+ .setConsoleInputDevice(console_input_device)
+ .setCpuTopology(getCpuTopology())
+ .setCustomImageConfig(toCustomImageConfigBuilder(context).build())
+ .setDebugLevel(getDebugLevel())
+ .setVmOutputCaptured(console_out)
+ .setConnectVmConsole(connect_console)
+ }
+
+ fun toCustomImageConfigBuilder(context: Context): VirtualMachineCustomImageConfig.Builder {
+ val builder = VirtualMachineCustomImageConfig.Builder()
+
+ builder
+ .setName(name)
+ .setBootloaderPath(bootloader)
+ .setKernelPath(kernel)
+ .setInitrdPath(initrd)
+ .useNetwork(network)
+ .useAutoMemoryBalloon(auto_memory_balloon)
+
+ if (input != null) {
+ builder
+ .useTouch(input.touchscreen)
+ .useKeyboard(input.keyboard)
+ .useMouse(input.mouse)
+ .useTrackpad(input.trackpad)
+ .useSwitches(input.switches)
+ }
+
+ if (audio != null) {
+ builder.setAudioConfig(audio.toConfig())
+ }
+
+ if (display != null) {
+ builder.setDisplayConfig(display.toConfig(context))
+ }
+
+ if (gpu != null) {
+ builder.setGpuConfig(gpu.toConfig())
+ }
+
+ params?.split(" ".toRegex())?.filter { it.isNotEmpty() }?.forEach { builder.addParam(it) }
+
+ disks?.forEach { builder.addDisk(it.toConfig()) }
+
+ sharedPath?.mapNotNull { it.toConfig(context) }?.forEach { builder.addSharedPath(it) }
+
+ return builder
+ }
+
+ internal data class SharedPathJson(private val sharedPath: String?) {
+ fun toConfig(context: Context): VirtualMachineCustomImageConfig.SharedPath? {
+ try {
+ val terminalUid = getTerminalUid(context)
+ if (sharedPath?.contains("emulated") == true) {
+ if (Environment.isExternalStorageManager()) {
+ val currentUserId = context.userId
+ val path = "$sharedPath/$currentUserId/Download"
+ return VirtualMachineCustomImageConfig.SharedPath(
+ path,
+ terminalUid,
+ terminalUid,
+ GUEST_UID,
+ GUEST_GID,
+ 7,
+ "android",
+ "android",
+ false, /* app domain is set to false so that crosvm is spin up as child of virtmgr */
+ "",
+ )
+ }
+ return null
+ }
+ val socketPath = context.getFilesDir().toPath().resolve("internal.virtiofs")
+ Files.deleteIfExists(socketPath)
+ return VirtualMachineCustomImageConfig.SharedPath(
+ sharedPath,
+ terminalUid,
+ terminalUid,
+ 0,
+ 0,
+ 7,
+ "internal",
+ "internal",
+ true, /* app domain is set to true so that crosvm is spin up from app context */
+ socketPath.toString(),
+ )
+ } catch (e: PackageManager.NameNotFoundException) {
+ return null
+ } catch (e: IOException) {
+ return null
+ }
+ }
+
+ @Throws(PackageManager.NameNotFoundException::class)
+ fun getTerminalUid(context: Context): Int {
+ return context
+ .getPackageManager()
+ .getPackageUidAsUser(context.getPackageName(), context.userId)
+ }
+
+ companion object {
+ private const val GUEST_UID = 1000
+ private const val GUEST_GID = 100
+ }
+ }
+
+ internal data class InputJson(
+ val touchscreen: Boolean,
+ val keyboard: Boolean,
+ val mouse: Boolean,
+ val switches: Boolean,
+ val trackpad: Boolean,
+ )
+
+ internal data class AudioJson(private val microphone: Boolean, private val speaker: Boolean) {
+
+ fun toConfig(): VirtualMachineCustomImageConfig.AudioConfig {
+ return VirtualMachineCustomImageConfig.AudioConfig.Builder()
+ .setUseMicrophone(microphone)
+ .setUseSpeaker(speaker)
+ .build()
+ }
+ }
+
+ internal data class DiskJson(
+ private val writable: Boolean,
+ private val image: String?,
+ private val partitions: Array<PartitionJson>?,
+ ) {
+ fun toConfig(): VirtualMachineCustomImageConfig.Disk {
+ val d =
+ if (writable) VirtualMachineCustomImageConfig.Disk.RWDisk(image)
+ else VirtualMachineCustomImageConfig.Disk.RODisk(image)
+ partitions?.forEach {
+ val writable = this.writable && it.writable
+ d.addPartition(
+ VirtualMachineCustomImageConfig.Partition(it.label, it.path, writable, it.guid)
+ )
+ }
+ return d
+ }
+ }
+
+ internal data class PartitionJson(
+ val writable: Boolean,
+ val label: String?,
+ val path: String?,
+ val guid: String?,
+ )
+
+ internal data class DisplayJson(
+ private val scale: Float = 0f,
+ private val refresh_rate: Int = 0,
+ private val width_pixels: Int = 0,
+ private val height_pixels: Int = 0,
+ ) {
+ fun toConfig(context: Context): VirtualMachineCustomImageConfig.DisplayConfig {
+ val wm = context.getSystemService<WindowManager>(WindowManager::class.java)
+ val metrics = wm.currentWindowMetrics
+ val dispBounds = metrics.bounds
+
+ val width = if (width_pixels > 0) width_pixels else dispBounds.right
+ val height = if (height_pixels > 0) height_pixels else dispBounds.bottom
+
+ var dpi = (DisplayMetrics.DENSITY_DEFAULT * metrics.density).toInt()
+ if (scale > 0.0f) {
+ dpi = (dpi * scale).toInt()
+ }
+
+ var refreshRate = context.display.refreshRate.toInt()
+ if (this.refresh_rate != 0) {
+ refreshRate = this.refresh_rate
+ }
+
+ return VirtualMachineCustomImageConfig.DisplayConfig.Builder()
+ .setWidth(width)
+ .setHeight(height)
+ .setHorizontalDpi(dpi)
+ .setVerticalDpi(dpi)
+ .setRefreshRate(refreshRate)
+ .build()
+ }
+ }
+
+ internal data class GpuJson(
+ private val backend: String?,
+ private val pci_address: String?,
+ private val renderer_features: String?,
+ // TODO: GSON actaully ignores the default values
+ private val renderer_use_egl: Boolean = true,
+ private val renderer_use_gles: Boolean = true,
+ private val renderer_use_glx: Boolean = false,
+ private val renderer_use_surfaceless: Boolean = true,
+ private val renderer_use_vulkan: Boolean = false,
+ private val context_types: Array<String>?,
+ ) {
+ fun toConfig(): VirtualMachineCustomImageConfig.GpuConfig {
+ return VirtualMachineCustomImageConfig.GpuConfig.Builder()
+ .setBackend(backend)
+ .setPciAddress(pci_address)
+ .setRendererFeatures(renderer_features)
+ .setRendererUseEgl(renderer_use_egl)
+ .setRendererUseGles(renderer_use_gles)
+ .setRendererUseGlx(renderer_use_glx)
+ .setRendererUseSurfaceless(renderer_use_surfaceless)
+ .setRendererUseVulkan(renderer_use_vulkan)
+ .setContextTypes(context_types)
+ .build()
+ }
+ }
+
+ companion object {
+ private const val DEBUG = true
+
+ /** Parses JSON file at jsonPath */
+ fun from(context: Context, jsonPath: Path): ConfigJson {
+ try {
+ FileReader(jsonPath.toFile()).use { fileReader ->
+ val content = replaceKeywords(fileReader, context)
+ return Gson().fromJson<ConfigJson?>(content, ConfigJson::class.java)
+ }
+ } catch (e: Exception) {
+ throw RuntimeException("Failed to parse $jsonPath", e)
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun replaceKeywords(r: Reader, context: Context): String {
+ val rules: Map<String, String> =
+ mapOf(
+ "\\\$PAYLOAD_DIR" to getDefault(context).installDir.toString(),
+ "\\\$USER_ID" to context.userId.toString(),
+ "\\\$PACKAGE_NAME" to context.getPackageName(),
+ "\\\$APP_DATA_DIR" to context.getDataDir().toString(),
+ )
+
+ return BufferedReader(r).useLines { lines ->
+ lines
+ .map { line ->
+ rules.entries.fold(line) { acc, rule ->
+ acc.replace(rule.key.toRegex(), rule.value)
+ }
+ }
+ .joinToString("\n")
+ }
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java
deleted file mode 100644
index 9cf6093..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.Keep;
-
-import com.android.virtualization.terminal.proto.DebianServiceGrpc;
-import com.android.virtualization.terminal.proto.ForwardingRequestItem;
-import com.android.virtualization.terminal.proto.IpAddr;
-import com.android.virtualization.terminal.proto.QueueOpeningRequest;
-import com.android.virtualization.terminal.proto.ReportVmActivePortsRequest;
-import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse;
-import com.android.virtualization.terminal.proto.ReportVmIpAddrResponse;
-import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest;
-import com.android.virtualization.terminal.proto.ShutdownRequestItem;
-
-import io.grpc.stub.StreamObserver;
-
-import java.util.HashSet;
-import java.util.Set;
-
-final class DebianServiceImpl extends DebianServiceGrpc.DebianServiceImplBase {
- private final Context mContext;
- private final PortsStateManager mPortsStateManager;
- private PortsStateManager.Listener mPortsStateListener;
- private final DebianServiceCallback mCallback;
- private Runnable mShutdownRunnable;
-
- static {
- System.loadLibrary("forwarder_host_jni");
- }
-
- DebianServiceImpl(Context context, DebianServiceCallback callback) {
- super();
- mCallback = callback;
- mContext = context;
- mPortsStateManager = PortsStateManager.getInstance(mContext);
- }
-
- @Override
- public void reportVmActivePorts(
- ReportVmActivePortsRequest request,
- StreamObserver<ReportVmActivePortsResponse> responseObserver) {
- Log.d(TAG, "reportVmActivePorts: " + request.toString());
- mPortsStateManager.updateActivePorts(new HashSet<>(request.getPortsList()));
- ReportVmActivePortsResponse reply =
- ReportVmActivePortsResponse.newBuilder().setSuccess(true).build();
- responseObserver.onNext(reply);
- responseObserver.onCompleted();
- }
-
- @Override
- public void reportVmIpAddr(
- IpAddr request, StreamObserver<ReportVmIpAddrResponse> responseObserver) {
- Log.d(TAG, "reportVmIpAddr: " + request.toString());
- mCallback.onIpAddressAvailable(request.getAddr());
- ReportVmIpAddrResponse reply = ReportVmIpAddrResponse.newBuilder().setSuccess(true).build();
- responseObserver.onNext(reply);
- responseObserver.onCompleted();
- }
-
- @Override
- public void openForwardingRequestQueue(
- QueueOpeningRequest request, StreamObserver<ForwardingRequestItem> responseObserver) {
- Log.d(TAG, "OpenForwardingRequestQueue");
- mPortsStateListener =
- new PortsStateManager.Listener() {
- @Override
- public void onPortsStateUpdated(
- Set<Integer> oldActivePorts, Set<Integer> newActivePorts) {
- updateListeningPorts();
- }
- };
- mPortsStateManager.registerListener(mPortsStateListener);
- updateListeningPorts();
- runForwarderHost(request.getCid(), new ForwarderHostCallback(responseObserver));
- responseObserver.onCompleted();
- }
-
- public boolean shutdownDebian() {
- if (mShutdownRunnable == null) {
- Log.d(TAG, "mShutdownRunnable is not ready.");
- return false;
- }
- mShutdownRunnable.run();
- return true;
- }
-
- @Override
- public void openShutdownRequestQueue(
- ShutdownQueueOpeningRequest request,
- StreamObserver<ShutdownRequestItem> responseObserver) {
- Log.d(TAG, "openShutdownRequestQueue");
- mShutdownRunnable =
- () -> {
- responseObserver.onNext(ShutdownRequestItem.newBuilder().build());
- responseObserver.onCompleted();
- mShutdownRunnable = null;
- };
- }
-
- @Keep
- private static class ForwarderHostCallback {
- private StreamObserver<ForwardingRequestItem> mResponseObserver;
-
- ForwarderHostCallback(StreamObserver<ForwardingRequestItem> responseObserver) {
- mResponseObserver = responseObserver;
- }
-
- private void onForwardingRequestReceived(int guestTcpPort, int vsockPort) {
- ForwardingRequestItem item =
- ForwardingRequestItem.newBuilder()
- .setGuestTcpPort(guestTcpPort)
- .setVsockPort(vsockPort)
- .build();
- mResponseObserver.onNext(item);
- }
- }
-
- private static native void runForwarderHost(int cid, ForwarderHostCallback callback);
-
- private static native void terminateForwarderHost();
-
- void killForwarderHost() {
- Log.d(TAG, "Stopping port forwarding");
- if (mPortsStateListener != null) {
- mPortsStateManager.unregisterListener(mPortsStateListener);
- mPortsStateListener = null;
- }
- terminateForwarderHost();
- }
-
- private static native void updateListeningPorts(int[] ports);
-
- private void updateListeningPorts() {
- Set<Integer> activePorts = mPortsStateManager.getActivePorts();
- Set<Integer> enabledPorts = mPortsStateManager.getEnabledPorts();
- updateListeningPorts(
- activePorts.stream()
- .filter(port -> enabledPorts.contains(port))
- .mapToInt(Integer::intValue)
- .toArray());
- }
-
- protected interface DebianServiceCallback {
- void onIpAddressAvailable(String ipAddr);
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
new file mode 100644
index 0000000..887ae02
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.util.Log
+import androidx.annotation.Keep
+import com.android.virtualization.terminal.DebianServiceImpl.ForwarderHostCallback
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import com.android.virtualization.terminal.PortsStateManager.Companion.getInstance
+import com.android.virtualization.terminal.proto.DebianServiceGrpc.DebianServiceImplBase
+import com.android.virtualization.terminal.proto.ForwardingRequestItem
+import com.android.virtualization.terminal.proto.QueueOpeningRequest
+import com.android.virtualization.terminal.proto.ReportVmActivePortsRequest
+import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse
+import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest
+import com.android.virtualization.terminal.proto.ShutdownRequestItem
+import io.grpc.stub.StreamObserver
+
+internal class DebianServiceImpl(context: Context) : DebianServiceImplBase() {
+ private val portsStateManager: PortsStateManager = getInstance(context)
+ private var portsStateListener: PortsStateManager.Listener? = null
+ private var shutdownRunnable: Runnable? = null
+
+ override fun reportVmActivePorts(
+ request: ReportVmActivePortsRequest,
+ responseObserver: StreamObserver<ReportVmActivePortsResponse?>,
+ ) {
+ portsStateManager.updateActivePorts(request.portsList)
+ Log.d(TAG, "reportVmActivePorts: " + portsStateManager.getActivePorts())
+ val reply = ReportVmActivePortsResponse.newBuilder().setSuccess(true).build()
+ responseObserver.onNext(reply)
+ responseObserver.onCompleted()
+ }
+
+ override fun openForwardingRequestQueue(
+ request: QueueOpeningRequest,
+ responseObserver: StreamObserver<ForwardingRequestItem?>,
+ ) {
+ Log.d(TAG, "OpenForwardingRequestQueue")
+ portsStateListener =
+ object : PortsStateManager.Listener {
+ override fun onPortsStateUpdated(
+ oldActivePorts: Set<Int>,
+ newActivePorts: Set<Int>,
+ ) {
+ updateListeningPorts()
+ }
+ }
+ portsStateManager.registerListener(portsStateListener!!)
+ updateListeningPorts()
+ runForwarderHost(request.cid, ForwarderHostCallback(responseObserver))
+ responseObserver.onCompleted()
+ }
+
+ fun shutdownDebian(): Boolean {
+ if (shutdownRunnable == null) {
+ Log.d(TAG, "mShutdownRunnable is not ready.")
+ return false
+ }
+ shutdownRunnable!!.run()
+ return true
+ }
+
+ override fun openShutdownRequestQueue(
+ request: ShutdownQueueOpeningRequest?,
+ responseObserver: StreamObserver<ShutdownRequestItem?>,
+ ) {
+ Log.d(TAG, "openShutdownRequestQueue")
+ shutdownRunnable = Runnable {
+ responseObserver.onNext(ShutdownRequestItem.newBuilder().build())
+ responseObserver.onCompleted()
+ shutdownRunnable = null
+ }
+ }
+
+ @Keep
+ private class ForwarderHostCallback(
+ private val responseObserver: StreamObserver<ForwardingRequestItem?>
+ ) {
+
+ fun onForwardingRequestReceived(guestTcpPort: Int, vsockPort: Int) {
+ val item =
+ ForwardingRequestItem.newBuilder()
+ .setGuestTcpPort(guestTcpPort)
+ .setVsockPort(vsockPort)
+ .build()
+ responseObserver.onNext(item)
+ }
+ }
+
+ fun killForwarderHost() {
+ Log.d(TAG, "Stopping port forwarding")
+ if (portsStateListener != null) {
+ portsStateManager.unregisterListener(portsStateListener!!)
+ portsStateListener = null
+ }
+ terminateForwarderHost()
+ }
+
+ private fun updateListeningPorts() {
+ val activePorts: Set<Int> = portsStateManager.getActivePorts()
+ val enabledPorts: Set<Int> = portsStateManager.getEnabledPorts()
+ updateListeningPorts(activePorts.filter { enabledPorts.contains(it) }.toIntArray())
+ }
+
+ companion object {
+ init {
+ System.loadLibrary("forwarder_host_jni")
+ }
+
+ @JvmStatic private external fun runForwarderHost(cid: Int, callback: ForwarderHostCallback?)
+
+ @JvmStatic private external fun terminateForwarderHost()
+
+ @JvmStatic private external fun updateListeningPorts(ports: IntArray?)
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.java
deleted file mode 100644
index 44dcce5..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-public class ErrorActivity extends BaseActivity {
- private static final String EXTRA_CAUSE = "cause";
-
- public static void start(Context context, Exception e) {
- Intent intent = new Intent(context, ErrorActivity.class);
- intent.putExtra(EXTRA_CAUSE, e);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
- }
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_error);
-
- View button = findViewById(R.id.recovery);
- button.setOnClickListener((event) -> launchRecoveryActivity());
- }
-
- @Override
- protected void onNewIntent(@NonNull Intent intent) {
- super.onNewIntent(intent);
- setIntent(intent);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- Intent intent = getIntent();
- Exception e = intent.getParcelableExtra(EXTRA_CAUSE, Exception.class);
- TextView cause = findViewById(R.id.cause);
- if (e != null) {
- cause.setText(getString(R.string.error_code, e.toString()));
- } else {
- cause.setText(null);
- }
- }
-
- private void launchRecoveryActivity() {
- Intent intent = new Intent(this, SettingsRecoveryActivity.class);
- startActivity(intent);
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
new file mode 100644
index 0000000..0a1090d
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import android.widget.TextView
+import java.io.IOException
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.lang.Exception
+import java.lang.RuntimeException
+
+class ErrorActivity : BaseActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.activity_error)
+
+ val button = findViewById<View>(R.id.recovery)
+ button.setOnClickListener(View.OnClickListener { _ -> launchRecoveryActivity() })
+ }
+
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
+ setIntent(intent)
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ val intent = getIntent()
+ val e = intent.getParcelableExtra<Exception?>(EXTRA_CAUSE, Exception::class.java)
+ val cause = findViewById<TextView>(R.id.cause)
+ cause.text = e?.let { getString(R.string.error_code, getStackTrace(it)) }
+ }
+
+ private fun launchRecoveryActivity() {
+ val intent = Intent(this, SettingsRecoveryActivity::class.java)
+ startActivity(intent)
+ }
+
+ companion object {
+ private const val EXTRA_CAUSE = "cause"
+
+ fun start(context: Context, e: Exception) {
+ val intent = Intent(context, ErrorActivity::class.java)
+ intent.putExtra(EXTRA_CAUSE, e)
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
+ context.startActivity(intent)
+ }
+
+ private fun getStackTrace(e: Exception): String? {
+ try {
+ StringWriter().use { sWriter ->
+ PrintWriter(sWriter).use { pWriter ->
+ e.printStackTrace(pWriter)
+ return sWriter.toString()
+ }
+ }
+ } catch (ex: IOException) {
+ // This shall never happen
+ throw RuntimeException(ex)
+ }
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.java b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.java
deleted file mode 100644
index 7f14179..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.os.Build;
-import android.os.Environment;
-import android.util.Log;
-
-import org.apache.commons.compress.archivers.ArchiveEntry;
-import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
-import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
-
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.Arrays;
-import java.util.function.Function;
-
-/**
- * ImageArchive models the archive file (images.tar.gz) where VM payload files are in. This class
- * provides methods for handling the archive file, most importantly installing it.
- */
-class ImageArchive {
- private static final String DIR_IN_SDCARD = "linux";
- private static final String ARCHIVE_NAME = "images.tar.gz";
- private static final String BUILD_TAG = "latest"; // TODO: use actual tag name
- private static final String HOST_URL = "https://dl.google.com/android/ferrochrome/" + BUILD_TAG;
-
- // Only one can be non-null
- private final URL mUrl;
- private final Path mPath;
-
- private ImageArchive(URL url) {
- mUrl = url;
- mPath = null;
- }
-
- private ImageArchive(Path path) {
- mUrl = null;
- mPath = path;
- }
-
- public static Path getSdcardPathForTesting() {
- return Environment.getExternalStoragePublicDirectory(DIR_IN_SDCARD).toPath();
- }
-
- /** Creates ImageArchive which is located in the sdcard. This archive is for testing only. */
- public static ImageArchive fromSdCard() {
- Path file = getSdcardPathForTesting().resolve(ARCHIVE_NAME);
- return new ImageArchive(file);
- }
-
- /** Creates ImageArchive which is hosted in the Google server. This is the official archive. */
- public static ImageArchive fromInternet() {
- String arch = Arrays.asList(Build.SUPPORTED_ABIS).contains("x86_64") ? "x86_64" : "aarch64";
- try {
- URL url = new URL(HOST_URL + "/" + arch + "/" + ARCHIVE_NAME);
- return new ImageArchive(url);
- } catch (MalformedURLException e) {
- // cannot happen
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Creates ImageArchive from either SdCard or Internet. SdCard is used only when the build is
- * debuggable and the file actually exists.
- */
- public static ImageArchive getDefault() {
- ImageArchive archive = fromSdCard();
- if (Build.isDebuggable() && archive.exists()) {
- return archive;
- } else {
- return fromInternet();
- }
- }
-
- /** Tests if ImageArchive exists on the medium. */
- public boolean exists() {
- if (mPath != null) {
- return Files.exists(mPath);
- } else {
- // TODO
- return true;
- }
- }
-
- /** Returns size of the archive in bytes */
- public long getSize() throws IOException {
- if (!exists()) {
- throw new IllegalStateException("Cannot get size of non existing archive");
- }
- if (mPath != null) {
- return Files.size(mPath);
- } else {
- HttpURLConnection conn = null;
- try {
- conn = (HttpURLConnection) mUrl.openConnection();
- conn.setRequestMethod("HEAD");
- conn.getInputStream();
- return conn.getContentLength();
- } finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- }
- }
-
- private InputStream getInputStream(Function<InputStream, InputStream> filter)
- throws IOException {
- InputStream is = mPath != null ? new FileInputStream(mPath.toFile()) : mUrl.openStream();
- BufferedInputStream bufStream = new BufferedInputStream(is);
- return filter == null ? bufStream : filter.apply(bufStream);
- }
-
- /**
- * Installs this ImageArchive to a directory pointed by path. filter can be supplied to provide
- * an additional input stream which will be used during the installation.
- */
- public void installTo(Path dir, Function<InputStream, InputStream> filter) throws IOException {
- String source = mPath != null ? mPath.toString() : mUrl.toString();
- Log.d(TAG, "Installing. source: " + source + ", destination: " + dir.toString());
- try (InputStream stream = getInputStream(filter);
- GzipCompressorInputStream gzStream = new GzipCompressorInputStream(stream);
- TarArchiveInputStream tarStream = new TarArchiveInputStream(gzStream)) {
-
- Files.createDirectories(dir);
- ArchiveEntry entry;
- while ((entry = tarStream.getNextEntry()) != null) {
- Path to = dir.resolve(entry.getName());
- if (Files.isDirectory(to)) {
- Files.createDirectories(to);
- continue;
- }
- Files.copy(tarStream, to, StandardCopyOption.REPLACE_EXISTING);
- }
- }
- commitInstallationAt(dir);
- }
-
- private void commitInstallationAt(Path dir) throws IOException {
- // To save storage, delete the source archive on the disk.
- if (mPath != null) {
- Files.deleteIfExists(mPath);
- }
-
- // Mark the completion
- Path marker = dir.resolve(InstalledImage.MARKER_FILENAME);
- Files.createFile(marker);
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
new file mode 100644
index 0000000..017ff89
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.os.Build
+import android.os.Environment
+import android.util.Log
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.io.BufferedInputStream
+import java.io.FileInputStream
+import java.io.IOException
+import java.io.InputStream
+import java.lang.RuntimeException
+import java.net.HttpURLConnection
+import java.net.MalformedURLException
+import java.net.URL
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardCopyOption
+import java.util.function.Function
+import org.apache.commons.compress.archivers.ArchiveEntry
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream
+
+/**
+ * ImageArchive models the archive file (images.tar.gz) where VM payload files are in. This class
+ * provides methods for handling the archive file, most importantly installing it.
+ */
+internal class ImageArchive {
+ // Only one can be non-null
+ private sealed class Source<out A, out B>
+
+ private data class UrlSource<out Url>(val value: Url) : Source<Url, Nothing>()
+
+ private data class PathSource<out Path>(val value: Path) : Source<Nothing, Path>()
+
+ private val source: Source<URL, Path>
+
+ private constructor(url: URL) {
+ source = UrlSource(url)
+ }
+
+ private constructor(path: Path) {
+ source = PathSource(path)
+ }
+
+ /** Tests if ImageArchive exists on the medium. */
+ fun exists(): Boolean {
+ return when (source) {
+ is UrlSource -> true
+ is PathSource -> Files.exists(source.value)
+ }
+ }
+
+ /** Returns size of the archive in bytes */
+ @Throws(IOException::class)
+ fun getSize(): Long {
+ check(exists()) { "Cannot get size of non existing archive" }
+ return when (source) {
+ is UrlSource -> {
+ val conn = source.value.openConnection() as HttpURLConnection
+ try {
+ conn.requestMethod = "HEAD"
+ conn.getInputStream()
+ return conn.contentLength.toLong()
+ } finally {
+ conn.disconnect()
+ }
+ }
+ is PathSource -> Files.size(source.value)
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun getInputStream(filter: Function<InputStream, InputStream>?): InputStream? {
+ val bufStream =
+ BufferedInputStream(
+ when (source) {
+ is UrlSource -> source.value.openStream()
+ is PathSource -> FileInputStream(source.value.toFile())
+ }
+ )
+ return filter?.apply(bufStream) ?: bufStream
+ }
+
+ /**
+ * Installs this ImageArchive to a directory pointed by path. filter can be supplied to provide
+ * an additional input stream which will be used during the installation.
+ */
+ @Throws(IOException::class)
+ fun installTo(dir: Path, filter: Function<InputStream, InputStream>?) {
+ val source =
+ when (source) {
+ is PathSource -> source.value.toString()
+ is UrlSource -> source.value.toString()
+ }
+ Log.d(TAG, "Installing. source: $source, destination: $dir")
+ TarArchiveInputStream(GzipCompressorInputStream(getInputStream(filter))).use { tarStream ->
+ Files.createDirectories(dir)
+ var entry: ArchiveEntry?
+ while ((tarStream.nextEntry.also { entry = it }) != null) {
+ val to = dir.resolve(entry!!.getName())
+ if (Files.isDirectory(to)) {
+ Files.createDirectories(to)
+ continue
+ }
+ Files.copy(tarStream, to, StandardCopyOption.REPLACE_EXISTING)
+ }
+ }
+ commitInstallationAt(dir)
+ }
+
+ @Throws(IOException::class)
+ private fun commitInstallationAt(dir: Path) {
+ // To save storage, delete the source archive on the disk.
+ if (source is PathSource) {
+ Files.deleteIfExists(source.value)
+ }
+
+ // Mark the completion
+ val marker = dir.resolve(InstalledImage.MARKER_FILENAME)
+ Files.createFile(marker)
+ }
+
+ companion object {
+ private const val DIR_IN_SDCARD = "linux"
+ private const val ARCHIVE_NAME = "images.tar.gz"
+ private const val BUILD_TAG = "latest" // TODO: use actual tag name
+ private const val HOST_URL = "https://dl.google.com/android/ferrochrome/$BUILD_TAG"
+
+ fun getSdcardPathForTesting(): Path {
+ return Environment.getExternalStoragePublicDirectory(DIR_IN_SDCARD).toPath()
+ }
+
+ /**
+ * Creates ImageArchive which is located in the sdcard. This archive is for testing only.
+ */
+ fun fromSdCard(): ImageArchive {
+ return ImageArchive(getSdcardPathForTesting().resolve(ARCHIVE_NAME))
+ }
+
+ /**
+ * Creates ImageArchive which is hosted in the Google server. This is the official archive.
+ */
+ fun fromInternet(): ImageArchive {
+ val arch =
+ if (listOf<String?>(*Build.SUPPORTED_ABIS).contains("x86_64")) "x86_64"
+ else "aarch64"
+ try {
+ return ImageArchive(URL("$HOST_URL/$arch/$ARCHIVE_NAME"))
+ } catch (e: MalformedURLException) {
+ // cannot happen
+ throw RuntimeException(e)
+ }
+ }
+
+ /**
+ * Creates ImageArchive from either SdCard or Internet. SdCard is used only when the build
+ * is debuggable and the file actually exists.
+ */
+ fun getDefault(): ImageArchive {
+ val archive = fromSdCard()
+ return if (Build.isDebuggable() && archive.exists()) {
+ archive
+ } else {
+ fromInternet()
+ }
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.java
deleted file mode 100644
index 318f49a..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.content.Context;
-import android.os.FileUtils;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.FileDescriptor;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-
-/** Collection of files that consist of a VM image. */
-class InstalledImage {
- private static final String INSTALL_DIRNAME = "linux";
- private static final String ROOTFS_FILENAME = "root_part";
- private static final String BACKUP_FILENAME = "root_part_backup";
- private static final String CONFIG_FILENAME = "vm_config.json";
- private static final String BUILD_ID_FILENAME = "build_id";
- static final String MARKER_FILENAME = "completed";
-
- public static final long RESIZE_STEP_BYTES = 4 << 20; // 4 MiB
-
- private final Path mDir;
- private final Path mRootPartition;
- private final Path mBackup;
- private final Path mConfig;
- private final Path mMarker;
- private String mBuildId;
-
- /** Returns InstalledImage for a given app context */
- public static InstalledImage getDefault(Context context) {
- Path installDir = context.getFilesDir().toPath().resolve(INSTALL_DIRNAME);
- return new InstalledImage(installDir);
- }
-
- private InstalledImage(Path dir) {
- mDir = dir;
- mRootPartition = dir.resolve(ROOTFS_FILENAME);
- mBackup = dir.resolve(BACKUP_FILENAME);
- mConfig = dir.resolve(CONFIG_FILENAME);
- mMarker = dir.resolve(MARKER_FILENAME);
- }
-
- public Path getInstallDir() {
- return mDir;
- }
-
- /** Tests if this InstalledImage is actually installed. */
- public boolean isInstalled() {
- return Files.exists(mMarker);
- }
-
- /** Fully understalls this InstalledImage by deleting everything. */
- public void uninstallFully() throws IOException {
- FileUtils.deleteContentsAndDir(mDir.toFile());
- }
-
- /** Returns the path to the VM config file. */
- public Path getConfigPath() {
- return mConfig;
- }
-
- /** Returns the build ID of the installed image */
- public String getBuildId() {
- if (mBuildId == null) {
- mBuildId = readBuildId();
- }
- return mBuildId;
- }
-
- private String readBuildId() {
- Path file = mDir.resolve(BUILD_ID_FILENAME);
- if (!Files.exists(file)) {
- return "<no build id>";
- }
- try (BufferedReader r = new BufferedReader(new FileReader(file.toFile()))) {
- return r.readLine();
- } catch (IOException e) {
- throw new RuntimeException("Failed to read build ID", e);
- }
- }
-
- public Path uninstallAndBackup() throws IOException {
- Files.delete(mMarker);
- Files.move(mRootPartition, mBackup, StandardCopyOption.REPLACE_EXISTING);
- return mBackup;
- }
-
- public Path getBackupFile() {
- return mBackup;
- }
-
- public boolean hasBackup() {
- return Files.exists(mBackup);
- }
-
- public void deleteBackup() throws IOException {
- Files.deleteIfExists(mBackup);
- }
-
- public long getSize() throws IOException {
- return Files.size(mRootPartition);
- }
-
- public long getSmallestSizePossible() throws IOException {
- runE2fsck(mRootPartition);
- String p = mRootPartition.toAbsolutePath().toString();
- String result = runCommand("/system/bin/resize2fs", "-P", p);
- // The return value is the number of 4k block
- try {
- long minSize =
- Long.parseLong(result.lines().toArray(String[]::new)[1].substring(42))
- * 4
- * 1024;
- return roundUp(minSize);
- } catch (NumberFormatException e) {
- Log.e(TAG, "Failed to parse min size, p=" + p + ", result=" + result);
- throw new IOException(e);
- }
- }
-
- public long resize(long desiredSize) throws IOException {
- desiredSize = roundUp(desiredSize);
- final long curSize = getSize();
-
- if (desiredSize == curSize) {
- return desiredSize;
- }
-
- runE2fsck(mRootPartition);
- if (desiredSize > curSize) {
- allocateSpace(mRootPartition, desiredSize);
- }
- resizeFilesystem(mRootPartition, desiredSize);
- return getSize();
- }
-
- private static void allocateSpace(Path path, long sizeInBytes) throws IOException {
- try {
- RandomAccessFile raf = new RandomAccessFile(path.toFile(), "rw");
- FileDescriptor fd = raf.getFD();
- Os.posix_fallocate(fd, 0, sizeInBytes);
- raf.close();
- Log.d(TAG, "Allocated space to: " + sizeInBytes + " bytes");
- } catch (ErrnoException e) {
- Log.e(TAG, "Failed to allocate space", e);
- throw new IOException("Failed to allocate space", e);
- }
- }
-
- private static void runE2fsck(Path path) throws IOException {
- String p = path.toAbsolutePath().toString();
- runCommand("/system/bin/e2fsck", "-y", "-f", p);
- Log.d(TAG, "e2fsck completed: " + path);
- }
-
- private static void resizeFilesystem(Path path, long sizeInBytes) throws IOException {
- long sizeInMB = sizeInBytes / (1024 * 1024);
- if (sizeInMB == 0) {
- Log.e(TAG, "Invalid size: " + sizeInBytes + " bytes");
- throw new IllegalArgumentException("Size cannot be zero MB");
- }
- String sizeArg = sizeInMB + "M";
- String p = path.toAbsolutePath().toString();
- runCommand("/system/bin/resize2fs", p, sizeArg);
- Log.d(TAG, "resize2fs completed: " + path + ", size: " + sizeArg);
- }
-
- private static String runCommand(String... command) throws IOException {
- try {
- Process process = new ProcessBuilder(command).redirectErrorStream(true).start();
- process.waitFor();
- String result = new String(process.getInputStream().readAllBytes());
- if (process.exitValue() != 0) {
- Log.w(TAG, "Process returned with error, command=" + String.join(" ", command)
- + ", exitValue=" + process.exitValue() + ", result=" + result);
- }
- return result;
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IOException("Command interrupted", e);
- }
- }
-
- private static long roundUp(long bytes) {
- // Round up every diskSizeStep MB
- return (long) Math.ceil(((double) bytes) / RESIZE_STEP_BYTES) * RESIZE_STEP_BYTES;
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.kt
new file mode 100644
index 0000000..7acc5f3
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.os.FileUtils
+import android.system.ErrnoException
+import android.system.Os
+import android.util.Log
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.io.BufferedReader
+import java.io.FileReader
+import java.io.IOException
+import java.io.RandomAccessFile
+import java.lang.IllegalArgumentException
+import java.lang.NumberFormatException
+import java.lang.RuntimeException
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardCopyOption
+import kotlin.math.ceil
+
+/** Collection of files that consist of a VM image. */
+public class InstalledImage private constructor(val installDir: Path) {
+ private val rootPartition: Path = installDir.resolve(ROOTFS_FILENAME)
+ val backupFile: Path = installDir.resolve(BACKUP_FILENAME)
+
+ /** The path to the VM config file. */
+ val configPath: Path = installDir.resolve(CONFIG_FILENAME)
+ private val marker: Path = installDir.resolve(MARKER_FILENAME)
+ /** The build ID of the installed image */
+ val buildId: String by lazy { readBuildId() }
+
+ /** Tests if this InstalledImage is actually installed. */
+ fun isInstalled(): Boolean {
+ return Files.exists(marker)
+ }
+
+ /** Fully uninstall this InstalledImage by deleting everything. */
+ @Throws(IOException::class)
+ fun uninstallFully() {
+ FileUtils.deleteContentsAndDir(installDir.toFile())
+ }
+
+ private fun readBuildId(): String {
+ val file = installDir.resolve(BUILD_ID_FILENAME)
+ if (!Files.exists(file)) {
+ return "<no build id>"
+ }
+ try {
+ BufferedReader(FileReader(file.toFile())).use { r ->
+ return r.readLine()
+ }
+ } catch (e: IOException) {
+ throw RuntimeException("Failed to read build ID", e)
+ }
+ }
+
+ @Throws(IOException::class)
+ fun uninstallAndBackup(): Path {
+ Files.delete(marker)
+ Files.move(rootPartition, backupFile, StandardCopyOption.REPLACE_EXISTING)
+ return backupFile
+ }
+
+ fun hasBackup(): Boolean {
+ return Files.exists(backupFile)
+ }
+
+ @Throws(IOException::class)
+ fun deleteBackup() {
+ Files.deleteIfExists(backupFile)
+ }
+
+ @Throws(IOException::class)
+ fun getSize(): Long {
+ return Files.size(rootPartition)
+ }
+
+ @Throws(IOException::class)
+ fun getSmallestSizePossible(): Long {
+ runE2fsck(rootPartition)
+ val p: String = rootPartition.toAbsolutePath().toString()
+ val result = runCommand("/system/bin/resize2fs", "-P", p)
+ val regex = "Estimated minimum size of the filesystem: ([0-9]+)".toRegex()
+ val matchResult = result.lines().firstNotNullOfOrNull { regex.find(it) }
+ if (matchResult != null) {
+ try {
+ val size = matchResult.groupValues[1].toLong()
+ // The return value is the number of 4k block
+ return roundUp(size * 4 * 1024)
+ } catch (e: NumberFormatException) {
+ // cannot happen
+ }
+ }
+ val msg = "Failed to get min size, p=$p, result=$result"
+ Log.e(TAG, msg)
+ throw RuntimeException(msg)
+ }
+
+ @Throws(IOException::class)
+ fun resize(desiredSize: Long): Long {
+ val roundedUpDesiredSize = roundUp(desiredSize)
+ val curSize = getSize()
+
+ if (roundedUpDesiredSize == curSize) {
+ return roundedUpDesiredSize
+ }
+
+ runE2fsck(rootPartition)
+ if (roundedUpDesiredSize > curSize) {
+ allocateSpace(rootPartition, roundedUpDesiredSize)
+ }
+ resizeFilesystem(rootPartition, roundedUpDesiredSize)
+ return getSize()
+ }
+
+ companion object {
+ private const val INSTALL_DIRNAME = "linux"
+ private const val ROOTFS_FILENAME = "root_part"
+ private const val BACKUP_FILENAME = "root_part_backup"
+ private const val CONFIG_FILENAME = "vm_config.json"
+ private const val BUILD_ID_FILENAME = "build_id"
+ const val MARKER_FILENAME: String = "completed"
+
+ const val RESIZE_STEP_BYTES: Long = 4 shl 20 // 4 MiB
+
+ /** Returns InstalledImage for a given app context */
+ fun getDefault(context: Context): InstalledImage {
+ val installDir = context.getFilesDir().toPath().resolve(INSTALL_DIRNAME)
+ return InstalledImage(installDir)
+ }
+
+ @Throws(IOException::class)
+ private fun allocateSpace(path: Path, sizeInBytes: Long) {
+ try {
+ val raf = RandomAccessFile(path.toFile(), "rw")
+ val fd = raf.fd
+ Os.posix_fallocate(fd, 0, sizeInBytes)
+ raf.close()
+ Log.d(TAG, "Allocated space to: $sizeInBytes bytes")
+ } catch (e: ErrnoException) {
+ Log.e(TAG, "Failed to allocate space", e)
+ throw IOException("Failed to allocate space", e)
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun runE2fsck(path: Path) {
+ val p: String = path.toAbsolutePath().toString()
+ runCommand("/system/bin/e2fsck", "-y", "-f", p)
+ Log.d(TAG, "e2fsck completed: $path")
+ }
+
+ @Throws(IOException::class)
+ private fun resizeFilesystem(path: Path, sizeInBytes: Long) {
+ val sizeInMB = sizeInBytes / (1024 * 1024)
+ if (sizeInMB == 0L) {
+ Log.e(TAG, "Invalid size: $sizeInBytes bytes")
+ throw IllegalArgumentException("Size cannot be zero MB")
+ }
+ val sizeArg = sizeInMB.toString() + "M"
+ val p: String = path.toAbsolutePath().toString()
+ runCommand("/system/bin/resize2fs", p, sizeArg)
+ Log.d(TAG, "resize2fs completed: $path, size: $sizeArg")
+ }
+
+ @Throws(IOException::class)
+ private fun runCommand(vararg command: String): String {
+ try {
+ val process = ProcessBuilder(*command).redirectErrorStream(true).start()
+ process.waitFor()
+ val result = String(process.inputStream.readAllBytes())
+ if (process.exitValue() != 0) {
+ Log.w(
+ TAG,
+ "Process returned with error, command=${listOf(*command).joinToString(" ")}," +
+ "exitValue=${process.exitValue()}, result=$result",
+ )
+ }
+ return result
+ } catch (e: InterruptedException) {
+ Thread.currentThread().interrupt()
+ throw IOException("Command interrupted", e)
+ }
+ }
+
+ private fun roundUp(bytes: Long): Long {
+ // Round up every diskSizeStep MB
+ return ceil((bytes.toDouble()) / RESIZE_STEP_BYTES).toLong() * RESIZE_STEP_BYTES
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
deleted file mode 100644
index 1c62572..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.annotation.MainThread;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.FileUtils;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.text.format.Formatter;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.material.progressindicator.LinearProgressIndicator;
-import com.google.android.material.snackbar.Snackbar;
-
-import java.io.IOException;
-import java.lang.ref.WeakReference;
-
-public class InstallerActivity extends BaseActivity {
- private static final long ESTIMATED_IMG_SIZE_BYTES = FileUtils.parseSize("550MB");
-
- private CheckBox mWaitForWifiCheckbox;
- private TextView mInstallButton;
-
- private IInstallerService mService;
- private ServiceConnection mInstallerServiceConnection;
- private InstallProgressListener mInstallProgressListener;
- private boolean mInstallRequested;
- private ConditionVariable mInstallCompleted = new ConditionVariable();
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setResult(RESULT_CANCELED);
-
- mInstallProgressListener = new InstallProgressListener(this);
-
- setContentView(R.layout.activity_installer);
- updateSizeEstimation(ESTIMATED_IMG_SIZE_BYTES);
- measureImageSizeAndUpdateDescription();
-
- mWaitForWifiCheckbox = (CheckBox) findViewById(R.id.installer_wait_for_wifi_checkbox);
- mInstallButton = (TextView) findViewById(R.id.installer_install_button);
-
- mInstallButton.setOnClickListener(
- (event) -> {
- requestInstall();
- });
-
- Intent intent = new Intent(this, InstallerService.class);
- mInstallerServiceConnection = new InstallerServiceConnection(this);
- if (!bindService(intent, mInstallerServiceConnection, Context.BIND_AUTO_CREATE)) {
- handleInternalError(new Exception("Failed to connect to installer service"));
- }
- }
-
- private void updateSizeEstimation(long est) {
- String desc =
- getString(
- R.string.installer_desc_text_format,
- Formatter.formatShortFileSize(this, est));
- runOnUiThread(
- () -> {
- TextView view = (TextView) findViewById(R.id.installer_desc);
- view.setText(desc);
- });
- }
-
- private void measureImageSizeAndUpdateDescription() {
- new Thread(
- () -> {
- long est;
- try {
- est = ImageArchive.getDefault().getSize();
- } catch (IOException e) {
- Log.w(TAG, "Failed to measure image size.", e);
- return;
- }
- updateSizeEstimation(est);
- })
- .start();
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (Build.isDebuggable() && ImageArchive.fromSdCard().exists()) {
- showSnackbar("Auto installing", Snackbar.LENGTH_LONG);
- requestInstall();
- }
- }
-
- @Override
- public void onDestroy() {
- if (mInstallerServiceConnection != null) {
- unbindService(mInstallerServiceConnection);
- mInstallerServiceConnection = null;
- }
-
- super.onDestroy();
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BUTTON_START) {
- requestInstall();
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
-
- @VisibleForTesting
- public boolean waitForInstallCompleted(long timeoutMillis) {
- return mInstallCompleted.block(timeoutMillis);
- }
-
- private void showSnackbar(String message, int length) {
- Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), message, length);
- snackbar.setAnchorView(mWaitForWifiCheckbox);
- snackbar.show();
- }
-
- public void handleInternalError(Exception e) {
- if (Build.isDebuggable()) {
- showSnackbar(
- e.getMessage() + ". File a bugreport to go/ferrochrome-bug",
- Snackbar.LENGTH_INDEFINITE);
- }
- Log.e(TAG, "Internal error", e);
- finishWithResult(RESULT_CANCELED);
- }
-
- private void finishWithResult(int resultCode) {
- if (resultCode == RESULT_OK) {
- mInstallCompleted.open();
- }
- setResult(resultCode);
- finish();
- }
-
- private void setInstallEnabled(boolean enable) {
- mInstallButton.setEnabled(enable);
- mWaitForWifiCheckbox.setEnabled(enable);
- LinearProgressIndicator progressBar = findViewById(R.id.installer_progress);
- if (enable) {
- progressBar.setVisibility(View.INVISIBLE);
- } else {
- progressBar.setVisibility(View.VISIBLE);
- }
-
- int resId =
- enable
- ? R.string.installer_install_button_enabled_text
- : R.string.installer_install_button_disabled_text;
- mInstallButton.setText(getString(resId));
- }
-
- @MainThread
- private void requestInstall() {
- setInstallEnabled(/* enable= */ false);
-
- if (mService != null) {
- try {
- mService.requestInstall(mWaitForWifiCheckbox.isChecked());
- } catch (RemoteException e) {
- handleInternalError(e);
- }
- } else {
- Log.d(TAG, "requestInstall() is called, but not yet connected");
- mInstallRequested = true;
- }
- }
-
- @MainThread
- public void handleInstallerServiceConnected() {
- try {
- mService.setProgressListener(mInstallProgressListener);
- if (mService.isInstalled()) {
- // Finishing this activity will trigger MainActivity::onResume(),
- // and VM will be started from there.
- finishWithResult(RESULT_OK);
- return;
- }
-
- if (mInstallRequested) {
- requestInstall();
- } else if (mService.isInstalling()) {
- setInstallEnabled(false);
- }
- } catch (RemoteException e) {
- handleInternalError(e);
- }
- }
-
- @MainThread
- public void handleInstallerServiceDisconnected() {
- handleInternalError(new Exception("InstallerService is destroyed while in use"));
- }
-
- @MainThread
- private void handleInstallError(String displayText) {
- showSnackbar(displayText, Snackbar.LENGTH_LONG);
- setInstallEnabled(true);
- }
-
- private static class InstallProgressListener extends IInstallProgressListener.Stub {
- private final WeakReference<InstallerActivity> mActivity;
-
- InstallProgressListener(InstallerActivity activity) {
- mActivity = new WeakReference<>(activity);
- }
-
- @Override
- public void onCompleted() {
- InstallerActivity activity = mActivity.get();
- if (activity == null) {
- // Ignore incoming connection or disconnection after activity is destroyed.
- return;
- }
-
- // MainActivity will be resume and handle rest of progress.
- activity.finishWithResult(RESULT_OK);
- }
-
- @Override
- public void onError(String displayText) {
- InstallerActivity context = mActivity.get();
- if (context == null) {
- // Ignore incoming connection or disconnection after activity is destroyed.
- return;
- }
-
- context.runOnUiThread(
- () -> {
- InstallerActivity activity = mActivity.get();
- if (activity == null) {
- // Ignore incoming connection or disconnection after activity is
- // destroyed.
- return;
- }
-
- activity.handleInstallError(displayText);
- });
- }
- }
-
- @MainThread
- public static final class InstallerServiceConnection implements ServiceConnection {
- private final WeakReference<InstallerActivity> mActivity;
-
- InstallerServiceConnection(InstallerActivity activity) {
- mActivity = new WeakReference<>(activity);
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- InstallerActivity activity = mActivity.get();
- if (activity == null || activity.mInstallerServiceConnection == null) {
- // Ignore incoming connection or disconnection after activity is destroyed.
- return;
- }
- if (service == null) {
- activity.handleInternalError(new Exception("service shouldn't be null"));
- }
-
- activity.mService = IInstallerService.Stub.asInterface(service);
- activity.handleInstallerServiceConnected();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- InstallerActivity activity = mActivity.get();
- if (activity == null || activity.mInstallerServiceConnection == null) {
- // Ignore incoming connection or disconnection after activity is destroyed.
- return;
- }
-
- if (activity.mInstallerServiceConnection != null) {
- activity.unbindService(activity.mInstallerServiceConnection);
- activity.mInstallerServiceConnection = null;
- }
- activity.handleInstallerServiceDisconnected();
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.kt
new file mode 100644
index 0000000..ec4a8c4
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.kt
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.annotation.MainThread
+import android.content.ComponentName
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.Build
+import android.os.Bundle
+import android.os.ConditionVariable
+import android.os.FileUtils
+import android.os.IBinder
+import android.os.RemoteException
+import android.text.format.Formatter
+import android.util.Log
+import android.view.KeyEvent
+import android.view.View
+import android.widget.CheckBox
+import android.widget.TextView
+import com.android.internal.annotations.VisibleForTesting
+import com.android.virtualization.terminal.ImageArchive.Companion.fromSdCard
+import com.android.virtualization.terminal.ImageArchive.Companion.getDefault
+import com.android.virtualization.terminal.InstallerActivity.InstallProgressListener
+import com.android.virtualization.terminal.InstallerActivity.InstallerServiceConnection
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import com.google.android.material.progressindicator.LinearProgressIndicator
+import com.google.android.material.snackbar.Snackbar
+import java.io.IOException
+import java.lang.Exception
+import java.lang.ref.WeakReference
+
+public class InstallerActivity : BaseActivity() {
+ private lateinit var waitForWifiCheckbox: CheckBox
+ private lateinit var installButton: TextView
+
+ private var service: IInstallerService? = null
+ private var installerServiceConnection: ServiceConnection? = null
+ private lateinit var installProgressListener: InstallProgressListener
+ private var installRequested = false
+ private val installCompleted = ConditionVariable()
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setResult(RESULT_CANCELED)
+
+ installProgressListener = InstallProgressListener(this)
+
+ setContentView(R.layout.activity_installer)
+ updateSizeEstimation(ESTIMATED_IMG_SIZE_BYTES)
+ measureImageSizeAndUpdateDescription()
+
+ waitForWifiCheckbox = findViewById<CheckBox>(R.id.installer_wait_for_wifi_checkbox)
+ installButton = findViewById<TextView>(R.id.installer_install_button)
+
+ installButton.setOnClickListener(View.OnClickListener { requestInstall() })
+
+ val intent = Intent(this, InstallerService::class.java)
+ installerServiceConnection = InstallerServiceConnection(this)
+ if (!bindService(intent, installerServiceConnection!!, BIND_AUTO_CREATE)) {
+ handleInternalError(Exception("Failed to connect to installer service"))
+ }
+ }
+
+ private fun updateSizeEstimation(est: Long) {
+ val desc =
+ getString(R.string.installer_desc_text_format, Formatter.formatShortFileSize(this, est))
+ runOnUiThread {
+ val view = findViewById<TextView>(R.id.installer_desc)
+ view.text = desc
+ }
+ }
+
+ private fun measureImageSizeAndUpdateDescription() {
+ Thread {
+ val est: Long =
+ try {
+ getDefault().getSize()
+ } catch (e: IOException) {
+ Log.w(TAG, "Failed to measure image size.", e)
+ return@Thread
+ }
+ updateSizeEstimation(est)
+ }
+ .start()
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ if (Build.isDebuggable() && fromSdCard().exists()) {
+ showSnackBar("Auto installing", Snackbar.LENGTH_LONG)
+ requestInstall()
+ }
+ }
+
+ public override fun onDestroy() {
+ if (installerServiceConnection != null) {
+ unbindService(installerServiceConnection!!)
+ installerServiceConnection = null
+ }
+
+ super.onDestroy()
+ }
+
+ override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
+ if (keyCode == KeyEvent.KEYCODE_BUTTON_START) {
+ requestInstall()
+ return true
+ }
+ return super.onKeyUp(keyCode, event)
+ }
+
+ @VisibleForTesting
+ public fun waitForInstallCompleted(timeoutMillis: Long): Boolean {
+ return installCompleted.block(timeoutMillis)
+ }
+
+ private fun showSnackBar(message: String, length: Int) {
+ val snackBar = Snackbar.make(findViewById<View>(android.R.id.content), message, length)
+ snackBar.anchorView = waitForWifiCheckbox
+ snackBar.show()
+ }
+
+ fun handleInternalError(e: Exception) {
+ if (Build.isDebuggable()) {
+ showSnackBar(
+ e.message + ". File a bugreport to go/ferrochrome-bug",
+ Snackbar.LENGTH_INDEFINITE,
+ )
+ }
+ Log.e(TAG, "Internal error", e)
+ finishWithResult(RESULT_CANCELED)
+ }
+
+ private fun finishWithResult(resultCode: Int) {
+ if (resultCode == RESULT_OK) {
+ installCompleted.open()
+ }
+ setResult(resultCode)
+ finish()
+ }
+
+ private fun setInstallEnabled(enabled: Boolean) {
+ installButton.setEnabled(enabled)
+ waitForWifiCheckbox.setEnabled(enabled)
+ val progressBar = findViewById<LinearProgressIndicator>(R.id.installer_progress)
+ progressBar.visibility = if (enabled) View.INVISIBLE else View.VISIBLE
+
+ val resId =
+ if (enabled) R.string.installer_install_button_enabled_text
+ else R.string.installer_install_button_disabled_text
+ installButton.text = getString(resId)
+ }
+
+ @MainThread
+ private fun requestInstall() {
+ setInstallEnabled(/* enabled= */ false)
+
+ if (service != null) {
+ try {
+ service!!.requestInstall(waitForWifiCheckbox.isChecked)
+ } catch (e: RemoteException) {
+ handleInternalError(e)
+ }
+ } else {
+ Log.d(TAG, "requestInstall() is called, but not yet connected")
+ installRequested = true
+ }
+ }
+
+ @MainThread
+ fun handleInstallerServiceConnected() {
+ try {
+ service!!.setProgressListener(installProgressListener)
+ if (service!!.isInstalled()) {
+ // Finishing this activity will trigger MainActivity::onResume(),
+ // and VM will be started from there.
+ finishWithResult(RESULT_OK)
+ return
+ }
+
+ if (installRequested) {
+ requestInstall()
+ } else if (service!!.isInstalling()) {
+ setInstallEnabled(false)
+ }
+ } catch (e: RemoteException) {
+ handleInternalError(e)
+ }
+ }
+
+ @MainThread
+ fun handleInstallerServiceDisconnected() {
+ handleInternalError(Exception("InstallerService is destroyed while in use"))
+ }
+
+ @MainThread
+ private fun handleInstallError(displayText: String) {
+ showSnackBar(displayText, Snackbar.LENGTH_LONG)
+ setInstallEnabled(true)
+ }
+
+ private class InstallProgressListener(activity: InstallerActivity) :
+ IInstallProgressListener.Stub() {
+ private val activity: WeakReference<InstallerActivity> =
+ WeakReference<InstallerActivity>(activity)
+
+ override fun onCompleted() {
+ val activity = activity.get()
+ if (activity == null) {
+ // Ignore incoming connection or disconnection after activity is destroyed.
+ return
+ }
+
+ // MainActivity will be resume and handle rest of progress.
+ activity.finishWithResult(RESULT_OK)
+ }
+
+ override fun onError(displayText: String) {
+ val context = activity.get()
+ if (context == null) {
+ // Ignore incoming connection or disconnection after activity is destroyed.
+ return
+ }
+
+ context.runOnUiThread {
+ val activity = activity.get()
+ if (activity == null) {
+ // Ignore incoming connection or disconnection after activity is
+ // destroyed.
+ return@runOnUiThread
+ }
+ activity.handleInstallError(displayText)
+ }
+ }
+ }
+
+ @MainThread
+ class InstallerServiceConnection internal constructor(activity: InstallerActivity) :
+ ServiceConnection {
+ private val activity: WeakReference<InstallerActivity> =
+ WeakReference<InstallerActivity>(activity)
+
+ override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
+ val activity = activity.get()
+ if (activity == null || activity.installerServiceConnection == null) {
+ // Ignore incoming connection or disconnection after activity is destroyed.
+ return
+ }
+ if (service == null) {
+ activity.handleInternalError(Exception("service shouldn't be null"))
+ }
+
+ activity.service = IInstallerService.Stub.asInterface(service)
+ activity.handleInstallerServiceConnected()
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) {
+ val activity = activity.get()
+ if (activity == null || activity.installerServiceConnection == null) {
+ // Ignore incoming connection or disconnection after activity is destroyed.
+ return
+ }
+
+ activity.unbindService(activity.installerServiceConnection!!)
+ activity.installerServiceConnection = null
+ activity.handleInstallerServiceDisconnected()
+ }
+ }
+
+ companion object {
+ private val ESTIMATED_IMG_SIZE_BYTES = FileUtils.parseSize("550MB")
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
deleted file mode 100644
index 66ab414..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.ServiceInfo;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.os.Build;
-import android.os.IBinder;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.ref.WeakReference;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.file.Path;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class InstallerService extends Service {
- private static final int NOTIFICATION_ID = 1313; // any unique number among notifications
-
- private final Object mLock = new Object();
-
- private Notification mNotification;
-
- @GuardedBy("mLock")
- private boolean mIsInstalling;
-
- @GuardedBy("mLock")
- private boolean mHasWifi;
-
- @GuardedBy("mLock")
- private IInstallProgressListener mListener;
-
- private ExecutorService mExecutorService;
- private ConnectivityManager mConnectivityManager;
- private MyNetworkCallback mNetworkCallback;
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- Intent intent = new Intent(this, MainActivity.class);
- PendingIntent pendingIntent =
- PendingIntent.getActivity(
- this, /* requestCode= */ 0, intent, PendingIntent.FLAG_IMMUTABLE);
- mNotification =
- new Notification.Builder(this, this.getPackageName())
- .setSilent(true)
- .setSmallIcon(R.drawable.ic_launcher_foreground)
- .setContentTitle(getString(R.string.installer_notif_title_text))
- .setContentText(getString(R.string.installer_notif_desc_text))
- .setOngoing(true)
- .setContentIntent(pendingIntent)
- .build();
-
- mExecutorService =
- Executors.newSingleThreadExecutor(
- new TerminalThreadFactory(getApplicationContext()));
-
- mConnectivityManager = getSystemService(ConnectivityManager.class);
- Network defaultNetwork = mConnectivityManager.getBoundNetworkForProcess();
- if (defaultNetwork != null) {
- NetworkCapabilities capability =
- mConnectivityManager.getNetworkCapabilities(defaultNetwork);
- if (capability != null) {
- mHasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- }
- }
- mNetworkCallback = new MyNetworkCallback();
- mConnectivityManager.registerDefaultNetworkCallback(mNetworkCallback);
- }
-
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return new InstallerServiceImpl(this);
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- super.onStartCommand(intent, flags, startId);
-
- Log.d(TAG, "Starting service ...");
-
- return START_STICKY;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- Log.d(TAG, "Service is destroyed");
- if (mExecutorService != null) {
- mExecutorService.shutdown();
- }
- mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
- }
-
- private void requestInstall(boolean isWifiOnly) {
- synchronized (mLock) {
- if (mIsInstalling) {
- Log.i(TAG, "already installing..");
- return;
- } else {
- Log.i(TAG, "installing..");
- mIsInstalling = true;
- }
- }
-
- // Make service to be long running, even after unbind() when InstallerActivity is destroyed
- // The service will still be destroyed if task is remove.
- startService(new Intent(this, InstallerService.class));
- startForeground(
- NOTIFICATION_ID, mNotification, ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
-
- mExecutorService.execute(
- () -> {
- boolean success = downloadFromSdcard() || downloadFromUrl(isWifiOnly);
- stopForeground(STOP_FOREGROUND_REMOVE);
-
- synchronized (mLock) {
- mIsInstalling = false;
- }
- if (success) {
- notifyCompleted();
- }
- });
- }
-
- private boolean downloadFromSdcard() {
- ImageArchive archive = ImageArchive.fromSdCard();
-
- // Installing from sdcard is preferred, but only supported only in debuggable build.
- if (Build.isDebuggable() && archive.exists()) {
- Log.i(TAG, "trying to install /sdcard/linux/images.tar.gz");
-
- Path dest = InstalledImage.getDefault(this).getInstallDir();
- try {
- archive.installTo(dest, null);
- Log.i(TAG, "image is installed from /sdcard/linux/images.tar.gz");
- return true;
- } catch (IOException e) {
- Log.i(TAG, "Failed to install /sdcard/linux/images.tar.gz", e);
- }
- } else {
- Log.i(TAG, "Non-debuggable build doesn't support installation from /sdcard/linux");
- }
- return false;
- }
-
- private boolean checkForWifiOnly(boolean isWifiOnly) {
- if (!isWifiOnly) {
- return true;
- }
- synchronized (mLock) {
- return mHasWifi;
- }
- }
-
- // TODO(b/374015561): Support pause/resume download
- private boolean downloadFromUrl(boolean isWifiOnly) {
- if (!checkForWifiOnly(isWifiOnly)) {
- Log.e(TAG, "Install isn't started because Wifi isn't available");
- notifyError(getString(R.string.installer_error_no_wifi));
- return false;
- }
-
- Path dest = InstalledImage.getDefault(this).getInstallDir();
- try {
- ImageArchive.fromInternet()
- .installTo(
- dest,
- is -> {
- WifiCheckInputStream filter = new WifiCheckInputStream(is);
- filter.setWifiOnly(isWifiOnly);
- return filter;
- });
- } catch (WifiCheckInputStream.NoWifiException e) {
- Log.e(TAG, "Install failed because of Wi-Fi is gone");
- notifyError(getString(R.string.installer_error_no_wifi));
- return false;
- } catch (UnknownHostException | SocketException e) {
- // Log.e() doesn't print stack trace for UnknownHostException
- Log.e(TAG, "Install failed: " + e.getMessage(), e);
- notifyError(getString(R.string.installer_error_network));
- return false;
- } catch (IOException e) {
- Log.e(TAG, "Installation failed", e);
- notifyError(getString(R.string.installer_error_unknown));
- return false;
- }
- return true;
- }
-
- private void notifyError(String displayText) {
- IInstallProgressListener listener;
- synchronized (mLock) {
- listener = mListener;
- }
-
- try {
- listener.onError(displayText);
- } catch (Exception e) {
- // ignore. Activity may not exist.
- }
- }
-
- private void notifyCompleted() {
- IInstallProgressListener listener;
- synchronized (mLock) {
- listener = mListener;
- }
-
- try {
- listener.onCompleted();
- } catch (Exception e) {
- // ignore. Activity may not exist.
- }
- }
-
- private static final class InstallerServiceImpl extends IInstallerService.Stub {
- // Holds weak reference to avoid Context leak
- private final WeakReference<InstallerService> mService;
-
- public InstallerServiceImpl(InstallerService service) {
- mService = new WeakReference<>(service);
- }
-
- private InstallerService ensureServiceConnected() throws RuntimeException {
- InstallerService service = mService.get();
- if (service == null) {
- throw new RuntimeException(
- "Internal error: Installer service is being accessed after destroyed");
- }
- return service;
- }
-
- @Override
- public void requestInstall(boolean isWifiOnly) {
- InstallerService service = ensureServiceConnected();
- synchronized (service.mLock) {
- service.requestInstall(isWifiOnly);
- }
- }
-
- @Override
- public void setProgressListener(IInstallProgressListener listener) {
- InstallerService service = ensureServiceConnected();
- synchronized (service.mLock) {
- service.mListener = listener;
- }
- }
-
- @Override
- public boolean isInstalling() {
- InstallerService service = ensureServiceConnected();
- synchronized (service.mLock) {
- return service.mIsInstalling;
- }
- }
-
- @Override
- public boolean isInstalled() {
- InstallerService service = ensureServiceConnected();
- synchronized (service.mLock) {
- return !service.mIsInstalling && InstalledImage.getDefault(service).isInstalled();
- }
- }
- }
-
- private final class WifiCheckInputStream extends InputStream {
- private static final int READ_BYTES = 1024;
-
- private final InputStream mInputStream;
- private boolean mIsWifiOnly;
-
- public WifiCheckInputStream(InputStream is) {
- super();
- mInputStream = is;
- }
-
- public void setWifiOnly(boolean isWifiOnly) {
- mIsWifiOnly = isWifiOnly;
- }
-
- @Override
- public int read(byte[] buf, int offset, int numToRead) throws IOException {
- int totalRead = 0;
- while (numToRead > 0) {
- if (!checkForWifiOnly(mIsWifiOnly)) {
- throw new NoWifiException();
- }
- int read =
- mInputStream.read(buf, offset + totalRead, Math.min(READ_BYTES, numToRead));
- if (read <= 0) {
- break;
- }
- totalRead += read;
- numToRead -= read;
- }
- return totalRead;
- }
-
- @Override
- public int read() throws IOException {
- if (!checkForWifiOnly(mIsWifiOnly)) {
- throw new NoWifiException();
- }
- return mInputStream.read();
- }
-
- private static final class NoWifiException extends SocketException {
- // empty
- }
- }
-
- private final class MyNetworkCallback extends ConnectivityManager.NetworkCallback {
- @Override
- public void onCapabilitiesChanged(
- @NonNull Network network, @NonNull NetworkCapabilities capability) {
- synchronized (mLock) {
- mHasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- }
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
new file mode 100644
index 0000000..7180e87
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Intent
+import android.content.pm.ServiceInfo
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.os.Build
+import android.os.IBinder
+import android.util.Log
+import com.android.internal.annotations.GuardedBy
+import com.android.virtualization.terminal.ImageArchive.Companion.fromInternet
+import com.android.virtualization.terminal.ImageArchive.Companion.fromSdCard
+import com.android.virtualization.terminal.InstalledImage.Companion.getDefault
+import com.android.virtualization.terminal.InstallerService.InstallerServiceImpl
+import com.android.virtualization.terminal.InstallerService.WifiCheckInputStream.NoWifiException
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.io.IOException
+import java.io.InputStream
+import java.lang.Exception
+import java.lang.RuntimeException
+import java.lang.ref.WeakReference
+import java.net.SocketException
+import java.net.UnknownHostException
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import kotlin.math.min
+
+class InstallerService : Service() {
+ private val lock = Any()
+
+ private lateinit var notification: Notification
+
+ @GuardedBy("lock") private var isInstalling = false
+
+ @GuardedBy("lock") private var hasWifi = false
+
+ @GuardedBy("lock") private var listener: IInstallProgressListener? = null
+
+ private lateinit var executorService: ExecutorService
+ private lateinit var connectivityManager: ConnectivityManager
+ private lateinit var networkCallback: MyNetworkCallback
+
+ override fun onCreate() {
+ super.onCreate()
+
+ val intent = Intent(this, MainActivity::class.java)
+ val pendingIntent =
+ PendingIntent.getActivity(
+ this,
+ /* requestCode= */ 0,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE,
+ )
+ notification =
+ Notification.Builder(this, Application.CHANNEL_LONG_RUNNING_ID)
+ .setSilent(true)
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setContentTitle(getString(R.string.installer_notif_title_text))
+ .setContentText(getString(R.string.installer_notif_desc_text))
+ .setOngoing(true)
+ .setContentIntent(pendingIntent)
+ .build()
+
+ executorService =
+ Executors.newSingleThreadExecutor(TerminalThreadFactory(applicationContext))
+
+ connectivityManager = getSystemService<ConnectivityManager>(ConnectivityManager::class.java)
+ val defaultNetwork = connectivityManager.boundNetworkForProcess
+ if (defaultNetwork != null) {
+ val capability = connectivityManager.getNetworkCapabilities(defaultNetwork)
+ if (capability != null) {
+ hasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+ }
+ }
+ networkCallback = MyNetworkCallback()
+ connectivityManager.registerDefaultNetworkCallback(networkCallback)
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return InstallerServiceImpl(this)
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ super.onStartCommand(intent, flags, startId)
+
+ Log.d(TAG, "Starting service ...")
+
+ return START_STICKY
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+
+ Log.d(TAG, "Service is destroyed")
+ executorService.shutdown()
+ connectivityManager.unregisterNetworkCallback(networkCallback)
+ }
+
+ private fun requestInstall(isWifiOnly: Boolean) {
+ synchronized(lock) {
+ if (isInstalling) {
+ Log.i(TAG, "already installing..")
+ return
+ } else {
+ Log.i(TAG, "installing..")
+ isInstalling = true
+ }
+ }
+
+ // Make service to be long running, even after unbind() when InstallerActivity is destroyed
+ // The service will still be destroyed if task is remove.
+ startService(Intent(this, InstallerService::class.java))
+ startForeground(
+ NOTIFICATION_ID,
+ notification,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE,
+ )
+
+ executorService.execute(
+ Runnable {
+ val success = downloadFromSdcard() || downloadFromUrl(isWifiOnly)
+ stopForeground(STOP_FOREGROUND_REMOVE)
+
+ synchronized(lock) { isInstalling = false }
+ if (success) {
+ notifyCompleted()
+ }
+ }
+ )
+ }
+
+ private fun downloadFromSdcard(): Boolean {
+ val archive = fromSdCard()
+
+ // Installing from sdcard is preferred, but only supported only in debuggable build.
+ if (Build.isDebuggable() && archive.exists()) {
+ Log.i(TAG, "trying to install /sdcard/linux/images.tar.gz")
+
+ val dest = getDefault(this).installDir
+ try {
+ archive.installTo(dest, null)
+ Log.i(TAG, "image is installed from /sdcard/linux/images.tar.gz")
+ return true
+ } catch (e: IOException) {
+ Log.i(TAG, "Failed to install /sdcard/linux/images.tar.gz", e)
+ }
+ } else {
+ Log.i(TAG, "Non-debuggable build doesn't support installation from /sdcard/linux")
+ }
+ return false
+ }
+
+ private fun checkForWifiOnly(isWifiOnly: Boolean): Boolean {
+ if (!isWifiOnly) {
+ return true
+ }
+ synchronized(lock) {
+ return hasWifi
+ }
+ }
+
+ // TODO(b/374015561): Support pause/resume download
+ private fun downloadFromUrl(isWifiOnly: Boolean): Boolean {
+ if (!checkForWifiOnly(isWifiOnly)) {
+ Log.e(TAG, "Install isn't started because Wifi isn't available")
+ notifyError(getString(R.string.installer_error_no_wifi))
+ return false
+ }
+
+ val dest = getDefault(this).installDir
+ try {
+ fromInternet().installTo(dest) {
+ val filter = WifiCheckInputStream(it)
+ filter.setWifiOnly(isWifiOnly)
+ filter
+ }
+ } catch (e: NoWifiException) {
+ Log.e(TAG, "Install failed because of Wi-Fi is gone")
+ notifyError(getString(R.string.installer_error_no_wifi))
+ return false
+ } catch (e: UnknownHostException) {
+ // Log.e() doesn't print stack trace for UnknownHostException
+ Log.e(TAG, "Install failed: " + e.message, e)
+ notifyError(getString(R.string.installer_error_network))
+ return false
+ } catch (e: SocketException) {
+ Log.e(TAG, "Install failed: " + e.message, e)
+ notifyError(getString(R.string.installer_error_network))
+ return false
+ } catch (e: IOException) {
+ Log.e(TAG, "Installation failed", e)
+ notifyError(getString(R.string.installer_error_unknown))
+ return false
+ }
+ return true
+ }
+
+ private fun notifyError(displayText: String?) {
+ var listener: IInstallProgressListener
+ synchronized(lock) { listener = this@InstallerService.listener!! }
+
+ try {
+ listener.onError(displayText)
+ } catch (e: Exception) {
+ // ignore. Activity may not exist.
+ }
+ }
+
+ private fun notifyCompleted() {
+ var listener: IInstallProgressListener
+ synchronized(lock) { listener = this@InstallerService.listener!! }
+
+ try {
+ listener.onCompleted()
+ } catch (e: Exception) {
+ // ignore. Activity may not exist.
+ }
+ }
+
+ private class InstallerServiceImpl(service: InstallerService?) : IInstallerService.Stub() {
+ // Holds weak reference to avoid Context leak
+ private val mService: WeakReference<InstallerService> =
+ WeakReference<InstallerService>(service)
+
+ @Throws(RuntimeException::class)
+ fun ensureServiceConnected(): InstallerService {
+ val service: InstallerService? = mService.get()
+ if (service == null) {
+ throw RuntimeException(
+ "Internal error: Installer service is being accessed after destroyed"
+ )
+ }
+ return service
+ }
+
+ override fun requestInstall(isWifiOnly: Boolean) {
+ val service = ensureServiceConnected()
+ synchronized(service.lock) { service.requestInstall(isWifiOnly) }
+ }
+
+ override fun setProgressListener(listener: IInstallProgressListener) {
+ val service = ensureServiceConnected()
+ synchronized(service.lock) { service.listener = listener }
+ }
+
+ override fun isInstalling(): Boolean {
+ val service = ensureServiceConnected()
+ synchronized(service.lock) {
+ return service.isInstalling
+ }
+ }
+
+ override fun isInstalled(): Boolean {
+ val service = ensureServiceConnected()
+ synchronized(service.lock) {
+ return !service.isInstalling && getDefault(service).isInstalled()
+ }
+ }
+ }
+
+ private inner class WifiCheckInputStream(private val inputStream: InputStream) : InputStream() {
+ private var isWifiOnly = false
+
+ fun setWifiOnly(isWifiOnly: Boolean) {
+ this@WifiCheckInputStream.isWifiOnly = isWifiOnly
+ }
+
+ @Throws(IOException::class)
+ override fun read(buf: ByteArray?, offset: Int, numToRead: Int): Int {
+ var remaining = numToRead
+ var totalRead = 0
+ while (remaining > 0) {
+ if (!checkForWifiOnly(isWifiOnly)) {
+ throw NoWifiException()
+ }
+ val read =
+ this@WifiCheckInputStream.inputStream.read(
+ buf,
+ offset + totalRead,
+ min(READ_BYTES, remaining),
+ )
+ if (read <= 0) {
+ break
+ }
+ totalRead += read
+ remaining -= read
+ }
+ return totalRead
+ }
+
+ @Throws(IOException::class)
+ override fun read(): Int {
+ if (!checkForWifiOnly(isWifiOnly)) {
+ throw NoWifiException()
+ }
+ return this@WifiCheckInputStream.inputStream.read()
+ }
+
+ inner class NoWifiException : SocketException()
+ }
+
+ private inner class MyNetworkCallback : ConnectivityManager.NetworkCallback() {
+ override fun onCapabilitiesChanged(network: Network, capability: NetworkCapabilities) {
+ synchronized(lock) {
+ hasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+ }
+ }
+ }
+
+ companion object {
+ private const val NOTIFICATION_ID = 1313 // any unique number among notifications
+ private const val READ_BYTES = 1024
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.java b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.java
deleted file mode 100644
index 2c0149e..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import android.system.virtualmachine.VirtualMachine;
-import android.system.virtualmachine.VirtualMachineConfig;
-import android.system.virtualmachine.VirtualMachineException;
-import android.util.Log;
-
-import libcore.io.Streams;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.concurrent.ExecutorService;
-
-/**
- * Forwards VM's console output to a file on the Android side, and VM's log output to Android logd.
- */
-class Logger {
- private Logger() {}
-
- static void setup(VirtualMachine vm, Path path, ExecutorService executor) {
- if (vm.getConfig().getDebugLevel() != VirtualMachineConfig.DEBUG_LEVEL_FULL) {
- return;
- }
-
- try {
- InputStream console = vm.getConsoleOutput();
- OutputStream file = Files.newOutputStream(path, StandardOpenOption.CREATE);
- executor.submit(() -> Streams.copy(console, new LineBufferedOutputStream(file)));
-
- InputStream log = vm.getLogOutput();
- executor.submit(() -> writeToLogd(log, vm.getName()));
- } catch (VirtualMachineException | IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static boolean writeToLogd(InputStream input, String vmName) throws IOException {
- BufferedReader reader = new BufferedReader(new InputStreamReader(input));
- String line;
- while ((line = reader.readLine()) != null && !Thread.interrupted()) {
- Log.d(vmName, line);
- }
- // TODO: find out why javac complains when the return type of this method is void. It
- // (incorrectly?) thinks that IOException should be caught inside the lambda.
- return true;
- }
-
- private static class LineBufferedOutputStream extends BufferedOutputStream {
- LineBufferedOutputStream(OutputStream out) {
- super(out);
- }
-
- @Override
- public void write(byte[] buf, int off, int len) throws IOException {
- super.write(buf, off, len);
- for (int i = 0; i < len; ++i) {
- if (buf[off + i] == '\n') {
- flush();
- break;
- }
- }
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
new file mode 100644
index 0000000..547f1a7
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.system.virtualmachine.VirtualMachine
+import android.system.virtualmachine.VirtualMachineConfig
+import android.system.virtualmachine.VirtualMachineException
+import android.util.Log
+import com.android.virtualization.terminal.Logger.LineBufferedOutputStream
+import java.io.BufferedOutputStream
+import java.io.BufferedReader
+import java.io.IOException
+import java.io.InputStream
+import java.io.InputStreamReader
+import java.io.OutputStream
+import java.lang.RuntimeException
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardOpenOption
+import java.util.concurrent.ExecutorService
+import libcore.io.Streams
+
+/**
+ * Forwards VM's console output to a file on the Android side, and VM's log output to Android logd.
+ */
+internal object Logger {
+ fun setup(vm: VirtualMachine, path: Path, executor: ExecutorService) {
+ if (vm.config.debugLevel != VirtualMachineConfig.DEBUG_LEVEL_FULL) {
+ return
+ }
+
+ try {
+ val console = vm.getConsoleOutput()
+ val file = Files.newOutputStream(path, StandardOpenOption.CREATE)
+ executor.submit<Int?> {
+ console.use { console ->
+ LineBufferedOutputStream(file).use { fileOutput ->
+ Streams.copy(console, fileOutput)
+ }
+ }
+ }
+
+ val log = vm.getLogOutput()
+ executor.submit<Unit> { log.use { writeToLogd(it, vm.name) } }
+ } catch (e: VirtualMachineException) {
+ throw RuntimeException(e)
+ } catch (e: IOException) {
+ throw RuntimeException(e)
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun writeToLogd(input: InputStream?, vmName: String?) {
+ val reader = BufferedReader(InputStreamReader(input))
+ reader
+ .useLines { lines -> lines.takeWhile { !Thread.interrupted() } }
+ .forEach { Log.d(vmName, it) }
+ }
+
+ private class LineBufferedOutputStream(out: OutputStream?) : BufferedOutputStream(out) {
+ @Throws(IOException::class)
+ override fun write(buf: ByteArray, off: Int, len: Int) {
+ super.write(buf, off, len)
+ (0 until len).firstOrNull { buf[off + it] == '\n'.code.toByte() }?.let { flush() }
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
deleted file mode 100644
index 316c8c4..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.virtualization.terminal;
-
-import static android.webkit.WebSettings.LOAD_NO_CACHE;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Icon;
-import android.graphics.fonts.FontStyle;
-import android.net.Uri;
-import android.net.http.SslError;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Environment;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.WindowInsets;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
-import android.webkit.ClientCertRequest;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebChromeClient;
-import android.webkit.WebResourceError;
-import android.webkit.WebResourceRequest;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-import androidx.activity.result.ActivityResult;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.material.appbar.MaterialToolbar;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class MainActivity extends BaseActivity
- implements VmLauncherService.VmLauncherServiceCallback, AccessibilityStateChangeListener {
- static final String TAG = "VmTerminalApp";
- static final String KEY_DISK_SIZE = "disk_size";
- private static final String VM_ADDR = "192.168.0.2";
- private static final int TTYD_PORT = 7681;
- private static final int TERMINAL_CONNECTION_TIMEOUT_MS = 20_000;
- private static final int REQUEST_CODE_INSTALLER = 0x33;
- private static final int FONT_SIZE_DEFAULT = 13;
-
- private ExecutorService mExecutorService;
- private InstalledImage mImage;
- private X509Certificate[] mCertificates;
- private PrivateKey mPrivateKey;
- private TerminalView mTerminalView;
- private AccessibilityManager mAccessibilityManager;
- private ConditionVariable mBootCompleted = new ConditionVariable();
- private static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101;
- private ActivityResultLauncher<Intent> mManageExternalStorageActivityResultLauncher;
- private static final Map<Integer, Integer> BTN_KEY_CODE_MAP =
- Map.ofEntries(
- Map.entry(R.id.btn_tab, KeyEvent.KEYCODE_TAB),
- // Alt key sends ESC keycode
- Map.entry(R.id.btn_alt, KeyEvent.KEYCODE_ESCAPE),
- Map.entry(R.id.btn_esc, KeyEvent.KEYCODE_ESCAPE),
- Map.entry(R.id.btn_left, KeyEvent.KEYCODE_DPAD_LEFT),
- Map.entry(R.id.btn_right, KeyEvent.KEYCODE_DPAD_RIGHT),
- Map.entry(R.id.btn_up, KeyEvent.KEYCODE_DPAD_UP),
- Map.entry(R.id.btn_down, KeyEvent.KEYCODE_DPAD_DOWN),
- Map.entry(R.id.btn_home, KeyEvent.KEYCODE_MOVE_HOME),
- Map.entry(R.id.btn_end, KeyEvent.KEYCODE_MOVE_END),
- Map.entry(R.id.btn_pgup, KeyEvent.KEYCODE_PAGE_UP),
- Map.entry(R.id.btn_pgdn, KeyEvent.KEYCODE_PAGE_DOWN));
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- lockOrientationIfNecessary();
-
- mImage = InstalledImage.getDefault(this);
-
- boolean launchInstaller = installIfNecessary();
-
- setContentView(R.layout.activity_headless);
-
- MaterialToolbar toolbar = (MaterialToolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- mTerminalView = (TerminalView) findViewById(R.id.webview);
- mTerminalView.getSettings().setDatabaseEnabled(true);
- mTerminalView.getSettings().setDomStorageEnabled(true);
- mTerminalView.getSettings().setJavaScriptEnabled(true);
- mTerminalView.getSettings().setCacheMode(LOAD_NO_CACHE);
- mTerminalView.setWebChromeClient(new WebChromeClient());
-
- setupModifierKeys();
-
- mAccessibilityManager = getSystemService(AccessibilityManager.class);
- mAccessibilityManager.addAccessibilityStateChangeListener(this);
-
- readClientCertificate();
-
- mManageExternalStorageActivityResultLauncher =
- registerForActivityResult(
- new ActivityResultContracts.StartActivityForResult(),
- (ActivityResult result) -> {
- startVm();
- });
- getWindow()
- .getDecorView()
- .getRootView()
- .setOnApplyWindowInsetsListener(
- (v, insets) -> {
- updateModifierKeysVisibility();
- return insets;
- });
-
- mExecutorService =
- Executors.newSingleThreadExecutor(
- new TerminalThreadFactory(getApplicationContext()));
-
- // if installer is launched, it will be handled in onActivityResult
- if (!launchInstaller) {
- if (!Environment.isExternalStorageManager()) {
- requestStoragePermissions(this, mManageExternalStorageActivityResultLauncher);
- } else {
- startVm();
- }
- }
- }
-
- private void lockOrientationIfNecessary() {
- boolean hasHwQwertyKeyboard =
- getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY;
- if (hasHwQwertyKeyboard) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- } else if (getResources().getBoolean(R.bool.terminal_portrait_only)) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
- }
-
- @Override
- public void onConfigurationChanged(@NonNull Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- lockOrientationIfNecessary();
- updateModifierKeysVisibility();
- }
-
- private void setupModifierKeys() {
- // Only ctrl key is special, it communicates with xtermjs to modify key event with ctrl key
- findViewById(R.id.btn_ctrl)
- .setOnClickListener(
- (v) -> {
- mTerminalView.mapCtrlKey();
- mTerminalView.enableCtrlKey();
- });
-
- View.OnClickListener modifierButtonClickListener =
- v -> {
- if (BTN_KEY_CODE_MAP.containsKey(v.getId())) {
- int keyCode = BTN_KEY_CODE_MAP.get(v.getId());
- mTerminalView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
- mTerminalView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
- }
- };
-
- for (int btn : BTN_KEY_CODE_MAP.keySet()) {
- View v = findViewById(btn);
- if (v != null) {
- v.setOnClickListener(modifierButtonClickListener);
- }
- }
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (Build.isDebuggable() && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
- if (event.getAction() == KeyEvent.ACTION_UP) {
- ErrorActivity.start(this, new Exception("Debug: KeyEvent.KEYCODE_UNKNOWN"));
- }
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
- private void requestStoragePermissions(
- Context context, ActivityResultLauncher<Intent> activityResultLauncher) {
- Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
- Uri uri = Uri.fromParts("package", context.getPackageName(), null);
- intent.setData(uri);
- activityResultLauncher.launch(intent);
- }
-
- private URL getTerminalServiceUrl() {
- Configuration config = getResources().getConfiguration();
-
- String query =
- "?fontSize="
- + (int) (config.fontScale * FONT_SIZE_DEFAULT)
- + "&fontWeight="
- + (FontStyle.FONT_WEIGHT_NORMAL + config.fontWeightAdjustment)
- + "&fontWeightBold="
- + (FontStyle.FONT_WEIGHT_BOLD + config.fontWeightAdjustment)
- + "&screenReaderMode="
- + mAccessibilityManager.isEnabled()
- + "&titleFixed="
- + getString(R.string.app_name);
-
- try {
- return new URL("https", VM_ADDR, TTYD_PORT, "/" + query);
- } catch (MalformedURLException e) {
- // this cannot happen
- return null;
- }
- }
-
- private void readClientCertificate() {
- KeyStore.PrivateKeyEntry pke = CertificateUtils.createOrGetKey();
- CertificateUtils.writeCertificateToFile(this, pke.getCertificate());
- mPrivateKey = pke.getPrivateKey();
- mCertificates = new X509Certificate[1];
- mCertificates[0] = (X509Certificate) pke.getCertificate();
- }
-
- private void connectToTerminalService() {
- Log.i(TAG, "URL=" + getTerminalServiceUrl().toString());
- mTerminalView.setWebViewClient(
- new WebViewClient() {
- private boolean mLoadFailed = false;
- private long mRequestId = 0;
-
- @Override
- public boolean shouldOverrideUrlLoading(
- WebView view, WebResourceRequest request) {
- return false;
- }
-
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- mLoadFailed = false;
- }
-
- @Override
- public void onReceivedError(
- WebView view, WebResourceRequest request, WebResourceError error) {
- mLoadFailed = true;
- switch (error.getErrorCode()) {
- case WebViewClient.ERROR_CONNECT:
- case WebViewClient.ERROR_HOST_LOOKUP:
- case WebViewClient.ERROR_FAILED_SSL_HANDSHAKE:
- case WebViewClient.ERROR_TIMEOUT:
- view.reload();
- return;
- default:
- String url = request.getUrl().toString();
- CharSequence msg = error.getDescription();
- Log.e(TAG, "Failed to load " + url + ": " + msg);
- }
- }
-
- @Override
- public void onPageFinished(WebView view, String url) {
- if (mLoadFailed) {
- return;
- }
-
- mRequestId++;
- view.postVisualStateCallback(
- mRequestId,
- new WebView.VisualStateCallback() {
- @Override
- public void onComplete(long requestId) {
- if (requestId == mRequestId) {
- android.os.Trace.endAsyncSection("executeTerminal", 0);
- findViewById(R.id.boot_progress)
- .setVisibility(View.GONE);
- findViewById(R.id.webview_container)
- .setVisibility(View.VISIBLE);
- mBootCompleted.open();
- updateModifierKeysVisibility();
- mTerminalView.mapTouchToMouseEvent();
- }
- }
- });
- }
-
- @Override
- public void onReceivedClientCertRequest(
- WebView view, ClientCertRequest request) {
- if (mPrivateKey != null && mCertificates != null) {
- request.proceed(mPrivateKey, mCertificates);
- return;
- }
- super.onReceivedClientCertRequest(view, request);
- }
-
- @Override
- public void onReceivedSslError(
- WebView view, SslErrorHandler handler, SslError error) {
- // ttyd uses self-signed certificate
- handler.proceed();
- }
- });
- mExecutorService.execute(
- () -> {
- // TODO(b/376793781): Remove polling
- waitUntilVmStarts();
- runOnUiThread(() -> mTerminalView.loadUrl(getTerminalServiceUrl().toString()));
- });
- }
-
- private static void waitUntilVmStarts() {
- InetAddress addr = null;
- try {
- addr = InetAddress.getByName(VM_ADDR);
- } catch (UnknownHostException e) {
- // this can never happen.
- }
- long startTime = SystemClock.elapsedRealtime();
- while (true) {
- int remainingTime =
- TERMINAL_CONNECTION_TIMEOUT_MS
- - (int) (SystemClock.elapsedRealtime() - startTime);
-
- if (Thread.interrupted()) {
- Log.d(TAG, "the waiting thread is interrupted");
- return;
- }
- if (remainingTime <= 0) {
- throw new RuntimeException("Connection to terminal timeout");
- }
- try {
- // Note: this quits immediately if VM is unreachable.
- if (addr.isReachable(remainingTime)) {
- return;
- }
- } catch (IOException e) {
- // give up on network error
- throw new RuntimeException(e);
- }
- }
- }
-
- @Override
- protected void onDestroy() {
- if (mExecutorService != null) {
- mExecutorService.shutdown();
- }
-
- getSystemService(AccessibilityManager.class).removeAccessibilityStateChangeListener(this);
- VmLauncherService.stop(this);
- super.onDestroy();
- }
-
- @Override
- public void onVmStart() {
- Log.i(TAG, "onVmStart()");
- }
-
- @Override
- public void onVmStop() {
- Log.i(TAG, "onVmStop()");
- finish();
- }
-
- @Override
- public void onVmError() {
- Log.i(TAG, "onVmError()");
- // TODO: error cause is too simple.
- ErrorActivity.start(this, new Exception("onVmError"));
- }
-
- @Override
- public void onIpAddrAvailable(String ipAddr) {
- // TODO: remove this
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main_menu, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
- if (id == R.id.menu_item_settings) {
- Intent intent = new Intent(this, SettingsActivity.class);
- this.startActivity(intent);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onAccessibilityStateChanged(boolean enabled) {
- connectToTerminalService();
- }
-
- private void updateModifierKeysVisibility() {
- boolean imeShown =
- getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.ime());
- boolean hasHwQwertyKeyboard =
- getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY;
- boolean showModifierKeys = imeShown && !hasHwQwertyKeyboard;
-
- View modifierKeys = findViewById(R.id.modifier_keys);
- modifierKeys.setVisibility(showModifierKeys ? View.VISIBLE : View.GONE);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode == REQUEST_CODE_INSTALLER) {
- if (resultCode != RESULT_OK) {
- Log.e(TAG, "Failed to start VM. Installer returned error.");
- finish();
- }
- if (!Environment.isExternalStorageManager()) {
- requestStoragePermissions(this, mManageExternalStorageActivityResultLauncher);
- } else {
- startVm();
- }
- }
- }
-
- private boolean installIfNecessary() {
- // If payload from external storage exists(only for debuggable build) or there is no
- // installed image, launch installer activity.
- if (!mImage.isInstalled()) {
- Intent intent = new Intent(this, InstallerActivity.class);
- startActivityForResult(intent, REQUEST_CODE_INSTALLER);
- return true;
- }
- return false;
- }
-
- private void startVm() {
- InstalledImage image = InstalledImage.getDefault(this);
- if (!image.isInstalled()) {
- return;
- }
-
- resizeDiskIfNecessary(image);
-
- Intent tapIntent = new Intent(this, MainActivity.class);
- tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- PendingIntent tapPendingIntent =
- PendingIntent.getActivity(this, 0, tapIntent, PendingIntent.FLAG_IMMUTABLE);
-
- Intent settingsIntent = new Intent(this, SettingsActivity.class);
- settingsIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- PendingIntent settingsPendingIntent = PendingIntent.getActivity(this, 0, settingsIntent,
- PendingIntent.FLAG_IMMUTABLE);
-
- Intent stopIntent = new Intent();
- stopIntent.setClass(this, VmLauncherService.class);
- stopIntent.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE);
- PendingIntent stopPendingIntent =
- PendingIntent.getService(
- this,
- 0,
- stopIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- Icon icon = Icon.createWithResource(getResources(), R.drawable.ic_launcher_foreground);
- Notification notification =
- new Notification.Builder(this, this.getPackageName())
- .setSilent(true)
- .setSmallIcon(R.drawable.ic_launcher_foreground)
- .setContentTitle(
- getResources().getString(R.string.service_notification_title))
- .setContentText(
- getResources().getString(R.string.service_notification_content))
- .setContentIntent(tapPendingIntent)
- .setOngoing(true)
- .addAction(
- new Notification.Action.Builder(
- icon,
- getResources()
- .getString(
- R.string
- .service_notification_settings),
- settingsPendingIntent)
- .build())
- .addAction(
- new Notification.Action.Builder(
- icon,
- getResources()
- .getString(
- R.string
- .service_notification_quit_action),
- stopPendingIntent)
- .build())
- .build();
-
- android.os.Trace.beginAsyncSection("executeTerminal", 0);
- VmLauncherService.run(this, this, notification);
- connectToTerminalService();
- }
-
- @VisibleForTesting
- public boolean waitForBootCompleted(long timeoutMillis) {
- return mBootCompleted.block(timeoutMillis);
- }
-
- private void resizeDiskIfNecessary(InstalledImage image) {
- try {
- // TODO(b/382190982): Show snackbar message instead when it's recoverable.
- image.resize(getIntent().getLongExtra(KEY_DISK_SIZE, image.getSize()));
- } catch (IOException e) {
- ErrorActivity.start(this, new Exception("Failed to resize disk", e));
- return;
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
new file mode 100644
index 0000000..1ae6ec5
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.graphics.fonts.FontStyle
+import android.net.Uri
+import android.net.http.SslError
+import android.net.nsd.NsdManager
+import android.net.nsd.NsdServiceInfo
+import android.os.Build
+import android.os.Bundle
+import android.os.ConditionVariable
+import android.os.Environment
+import android.os.SystemProperties
+import android.os.Trace
+import android.provider.Settings
+import android.util.Log
+import android.view.KeyEvent
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityManager
+import android.webkit.ClientCertRequest
+import android.webkit.SslErrorHandler
+import android.webkit.WebChromeClient
+import android.webkit.WebResourceError
+import android.webkit.WebResourceRequest
+import android.webkit.WebSettings
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.ActivityResultCallback
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
+import com.android.internal.annotations.VisibleForTesting
+import com.android.microdroid.test.common.DeviceProperties
+import com.android.virtualization.terminal.CertificateUtils.createOrGetKey
+import com.android.virtualization.terminal.CertificateUtils.writeCertificateToFile
+import com.android.virtualization.terminal.ErrorActivity.Companion.start
+import com.android.virtualization.terminal.InstalledImage.Companion.getDefault
+import com.android.virtualization.terminal.VmLauncherService.Companion.run
+import com.android.virtualization.terminal.VmLauncherService.Companion.stop
+import com.android.virtualization.terminal.VmLauncherService.VmLauncherServiceCallback
+import com.google.android.material.appbar.MaterialToolbar
+import java.io.IOException
+import java.lang.Exception
+import java.net.MalformedURLException
+import java.net.URL
+import java.security.PrivateKey
+import java.security.cert.X509Certificate
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+public class MainActivity :
+ BaseActivity(),
+ VmLauncherServiceCallback,
+ AccessibilityManager.AccessibilityStateChangeListener {
+ private lateinit var executorService: ExecutorService
+ private lateinit var image: InstalledImage
+ private var certificates: Array<X509Certificate>? = null
+ private var privateKey: PrivateKey? = null
+ private lateinit var terminalContainer: ViewGroup
+ private lateinit var terminalView: TerminalView
+ private lateinit var accessibilityManager: AccessibilityManager
+ private val bootCompleted = ConditionVariable()
+ private lateinit var manageExternalStorageActivityResultLauncher: ActivityResultLauncher<Intent>
+ private lateinit var modifierKeysController: ModifierKeysController
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ lockOrientationIfNecessary()
+
+ image = getDefault(this)
+
+ val launchInstaller = installIfNecessary()
+
+ setContentView(R.layout.activity_headless)
+
+ val toolbar = findViewById<MaterialToolbar>(R.id.toolbar)
+ setSupportActionBar(toolbar)
+ terminalView = findViewById<TerminalView>(R.id.webview)
+ terminalView.getSettings().setDomStorageEnabled(true)
+ terminalView.getSettings().setJavaScriptEnabled(true)
+ terminalView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE)
+ terminalView.setWebChromeClient(WebChromeClient())
+
+ terminalContainer = terminalView.parent as ViewGroup
+
+ modifierKeysController = ModifierKeysController(this, terminalView, terminalContainer)
+
+ accessibilityManager =
+ getSystemService<AccessibilityManager>(AccessibilityManager::class.java)
+ accessibilityManager.addAccessibilityStateChangeListener(this)
+
+ readClientCertificate()
+
+ manageExternalStorageActivityResultLauncher =
+ registerForActivityResult<Intent, ActivityResult>(
+ StartActivityForResult(),
+ ActivityResultCallback { startVm() },
+ )
+ executorService =
+ Executors.newSingleThreadExecutor(TerminalThreadFactory(applicationContext))
+
+ // if installer is launched, it will be handled in onActivityResult
+ if (!launchInstaller) {
+ if (!Environment.isExternalStorageManager()) {
+ requestStoragePermissions(this, manageExternalStorageActivityResultLauncher)
+ } else {
+ startVm()
+ }
+ }
+ }
+
+ private fun lockOrientationIfNecessary() {
+ val hasHwQwertyKeyboard = resources.configuration.keyboard == Configuration.KEYBOARD_QWERTY
+ if (hasHwQwertyKeyboard) {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
+ } else if (resources.getBoolean(R.bool.terminal_portrait_only)) {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ }
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ lockOrientationIfNecessary()
+ modifierKeysController.update()
+ }
+
+ override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+ if (Build.isDebuggable() && event.keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+ if (event.action == KeyEvent.ACTION_UP) {
+ start(this, Exception("Debug: KeyEvent.KEYCODE_UNKNOWN"))
+ }
+ return true
+ }
+ return super.dispatchKeyEvent(event)
+ }
+
+ private fun requestStoragePermissions(
+ context: Context,
+ activityResultLauncher: ActivityResultLauncher<Intent>,
+ ) {
+ val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
+ val uri = Uri.fromParts("package", context.getPackageName(), null)
+ intent.setData(uri)
+ activityResultLauncher.launch(intent)
+ }
+
+ private fun getTerminalServiceUrl(ipAddress: String?, port: Int): URL? {
+ val config = resources.configuration
+
+ val query =
+ ("?fontSize=" +
+ (config.fontScale * FONT_SIZE_DEFAULT).toInt() +
+ "&fontWeight=" +
+ (FontStyle.FONT_WEIGHT_NORMAL + config.fontWeightAdjustment) +
+ "&fontWeightBold=" +
+ (FontStyle.FONT_WEIGHT_BOLD + config.fontWeightAdjustment) +
+ "&screenReaderMode=" +
+ accessibilityManager.isEnabled +
+ "&titleFixed=" +
+ getString(R.string.app_name))
+
+ try {
+ return URL("https", ipAddress, port, "/$query")
+ } catch (e: MalformedURLException) {
+ // this cannot happen
+ return null
+ }
+ }
+
+ private fun readClientCertificate() {
+ val pke = createOrGetKey()
+ writeCertificateToFile(this, pke.certificate)
+ privateKey = pke.privateKey
+ certificates = arrayOf<X509Certificate>(pke.certificate as X509Certificate)
+ }
+
+ private fun connectToTerminalService() {
+ terminalView.setWebViewClient(
+ object : WebViewClient() {
+ private var loadFailed = false
+ private var requestId: Long = 0
+
+ override fun shouldOverrideUrlLoading(
+ view: WebView?,
+ request: WebResourceRequest?,
+ ): Boolean {
+ val intent = Intent(Intent.ACTION_VIEW, request?.url)
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ startActivity(intent)
+ return true
+ }
+
+ override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
+ loadFailed = false
+ }
+
+ override fun onReceivedError(
+ view: WebView,
+ request: WebResourceRequest,
+ error: WebResourceError,
+ ) {
+ loadFailed = true
+ when (error.getErrorCode()) {
+ ERROR_CONNECT,
+ ERROR_HOST_LOOKUP,
+ ERROR_FAILED_SSL_HANDSHAKE,
+ ERROR_TIMEOUT -> {
+ view.reload()
+ return
+ }
+
+ else -> {
+ val url: String? = request.getUrl().toString()
+ val msg = error.getDescription()
+ Log.e(TAG, "Failed to load $url: $msg")
+ }
+ }
+ }
+
+ override fun onPageFinished(view: WebView, url: String?) {
+ if (loadFailed) {
+ return
+ }
+
+ requestId++
+ view.postVisualStateCallback(
+ requestId,
+ object : WebView.VisualStateCallback() {
+ override fun onComplete(completedRequestId: Long) {
+ if (completedRequestId == requestId) {
+ Trace.endAsyncSection("executeTerminal", 0)
+ findViewById<View?>(R.id.boot_progress).visibility = View.GONE
+ terminalContainer.visibility = View.VISIBLE
+ bootCompleted.open()
+ modifierKeysController.update()
+ terminalView.mapTouchToMouseEvent()
+ }
+ }
+ },
+ )
+ }
+
+ override fun onReceivedClientCertRequest(
+ view: WebView?,
+ request: ClientCertRequest,
+ ) {
+ if (privateKey != null && certificates != null) {
+ request.proceed(privateKey, certificates)
+ return
+ }
+ super.onReceivedClientCertRequest(view, request)
+ }
+
+ override fun onReceivedSslError(
+ view: WebView?,
+ handler: SslErrorHandler,
+ error: SslError?,
+ ) {
+ // ttyd uses self-signed certificate
+ handler.proceed()
+ }
+ }
+ )
+
+ // TODO: refactor this block as a method
+ val nsdManager = getSystemService<NsdManager>(NsdManager::class.java)
+ val info = NsdServiceInfo()
+ info.serviceType = "_http._tcp"
+ info.serviceName = "ttyd"
+ nsdManager.registerServiceInfoCallback(
+ info,
+ executorService,
+ object : NsdManager.ServiceInfoCallback {
+ var loaded: Boolean = false
+
+ override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
+
+ override fun onServiceInfoCallbackUnregistered() {}
+
+ override fun onServiceLost() {}
+
+ override fun onServiceUpdated(info: NsdServiceInfo) {
+ Log.i(TAG, "Service found: $info")
+ val ipAddress = info.hostAddresses[0].hostAddress
+ val port = info.port
+ val url = getTerminalServiceUrl(ipAddress, port)
+ if (!loaded) {
+ loaded = true
+ nsdManager.unregisterServiceInfoCallback(this)
+ runOnUiThread(Runnable { terminalView.loadUrl(url.toString()) })
+ }
+ }
+ },
+ )
+ }
+
+ override fun onDestroy() {
+ executorService.shutdown()
+ getSystemService<AccessibilityManager>(AccessibilityManager::class.java)
+ .removeAccessibilityStateChangeListener(this)
+ stop(this)
+ super.onDestroy()
+ }
+
+ override fun onVmStart() {
+ Log.i(TAG, "onVmStart()")
+ }
+
+ override fun onVmStop() {
+ Log.i(TAG, "onVmStop()")
+ finish()
+ }
+
+ override fun onVmError() {
+ Log.i(TAG, "onVmError()")
+ // TODO: error cause is too simple.
+ start(this, Exception("onVmError"))
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.main_menu, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ val id = item.getItemId()
+ if (id == R.id.menu_item_settings) {
+ val intent = Intent(this, SettingsActivity::class.java)
+ this.startActivity(intent)
+ return true
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ override fun onAccessibilityStateChanged(enabled: Boolean) {
+ connectToTerminalService()
+ }
+
+ private val installerLauncher =
+ registerForActivityResult(StartActivityForResult()) { result ->
+ val resultCode = result.resultCode
+ if (resultCode != RESULT_OK) {
+ Log.e(TAG, "Failed to start VM. Installer returned error.")
+ finish()
+ }
+ if (!Environment.isExternalStorageManager()) {
+ requestStoragePermissions(this, manageExternalStorageActivityResultLauncher)
+ } else {
+ startVm()
+ }
+ }
+
+ private fun installIfNecessary(): Boolean {
+ // If payload from external storage exists(only for debuggable build) or there is no
+ // installed image, launch installer activity.
+ if (!image.isInstalled()) {
+ val intent = Intent(this, InstallerActivity::class.java)
+ installerLauncher.launch(intent)
+ return true
+ }
+ return false
+ }
+
+ private fun startVm() {
+ val image = getDefault(this)
+ if (!image.isInstalled()) {
+ return
+ }
+
+ resizeDiskIfNecessary(image)
+
+ val tapIntent = Intent(this, MainActivity::class.java)
+ tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ val tapPendingIntent =
+ PendingIntent.getActivity(this, 0, tapIntent, PendingIntent.FLAG_IMMUTABLE)
+
+ val settingsIntent = Intent(this, SettingsActivity::class.java)
+ settingsIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ val settingsPendingIntent =
+ PendingIntent.getActivity(this, 0, settingsIntent, PendingIntent.FLAG_IMMUTABLE)
+
+ val stopIntent = Intent()
+ stopIntent.setClass(this, VmLauncherService::class.java)
+ stopIntent.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE)
+ val stopPendingIntent =
+ PendingIntent.getService(
+ this,
+ 0,
+ stopIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
+ )
+ val icon = Icon.createWithResource(resources, R.drawable.ic_launcher_foreground)
+ val notification: Notification =
+ Notification.Builder(this, Application.CHANNEL_LONG_RUNNING_ID)
+ .setSilent(true)
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setContentTitle(resources.getString(R.string.service_notification_title))
+ .setContentText(resources.getString(R.string.service_notification_content))
+ .setContentIntent(tapPendingIntent)
+ .setOngoing(true)
+ .addAction(
+ Notification.Action.Builder(
+ icon,
+ resources.getString(R.string.service_notification_settings),
+ settingsPendingIntent,
+ )
+ .build()
+ )
+ .addAction(
+ Notification.Action.Builder(
+ icon,
+ resources.getString(R.string.service_notification_quit_action),
+ stopPendingIntent,
+ )
+ .build()
+ )
+ .build()
+
+ Trace.beginAsyncSection("executeTerminal", 0)
+ run(this, this, notification)
+ connectToTerminalService()
+ }
+
+ @VisibleForTesting
+ public fun waitForBootCompleted(timeoutMillis: Long): Boolean {
+ return bootCompleted.block(timeoutMillis)
+ }
+
+ private fun resizeDiskIfNecessary(image: InstalledImage) {
+ try {
+ // TODO(b/382190982): Show snackbar message instead when it's recoverable.
+ image.resize(intent.getLongExtra(KEY_DISK_SIZE, image.getSize()))
+ } catch (e: IOException) {
+ start(this, Exception("Failed to resize disk", e))
+ return
+ }
+ }
+
+ companion object {
+ const val TAG: String = "VmTerminalApp"
+ const val KEY_DISK_SIZE: String = "disk_size"
+ private val TERMINAL_CONNECTION_TIMEOUT_MS: Int
+ private const val REQUEST_CODE_INSTALLER = 0x33
+ private const val FONT_SIZE_DEFAULT = 13
+
+ init {
+ val prop =
+ DeviceProperties.create(
+ DeviceProperties.PropertyGetter { key: String -> SystemProperties.get(key) }
+ )
+ TERMINAL_CONNECTION_TIMEOUT_MS =
+ if (prop.isCuttlefish() || prop.isGoldfish()) {
+ 180000 // 3 minutes
+ } else {
+ 20000 // 20 sec
+ }
+ }
+
+ private val BTN_KEY_CODE_MAP =
+ mapOf(
+ R.id.btn_tab to KeyEvent.KEYCODE_TAB, // Alt key sends ESC keycode
+ R.id.btn_alt to KeyEvent.KEYCODE_ESCAPE,
+ R.id.btn_esc to KeyEvent.KEYCODE_ESCAPE,
+ R.id.btn_left to KeyEvent.KEYCODE_DPAD_LEFT,
+ R.id.btn_right to KeyEvent.KEYCODE_DPAD_RIGHT,
+ R.id.btn_up to KeyEvent.KEYCODE_DPAD_UP,
+ R.id.btn_down to KeyEvent.KEYCODE_DPAD_DOWN,
+ R.id.btn_home to KeyEvent.KEYCODE_MOVE_HOME,
+ R.id.btn_end to KeyEvent.KEYCODE_MOVE_END,
+ R.id.btn_pgup to KeyEvent.KEYCODE_PAGE_UP,
+ R.id.btn_pgdn to KeyEvent.KEYCODE_PAGE_DOWN,
+ )
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt
new file mode 100644
index 0000000..f8f30f9
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Activity
+import android.content.res.Configuration
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowInsets
+
+class ModifierKeysController(
+ val activity: Activity,
+ val terminalView: TerminalView,
+ val parent: ViewGroup,
+) {
+ private val window = activity.window
+ private val keysSingleLine: View
+ private val keysDoubleLine: View
+
+ private var keysInSingleLine: Boolean = false
+
+ init {
+ // Prepare the two modifier keys layout, but don't add them yet because we don't know which
+ // layout will be needed.
+ val layout = LayoutInflater.from(activity)
+ keysSingleLine = layout.inflate(R.layout.modifier_keys_singleline, parent, false)
+ keysDoubleLine = layout.inflate(R.layout.modifier_keys_doubleline, parent, false)
+
+ addClickListeners(keysSingleLine)
+ addClickListeners(keysDoubleLine)
+
+ keysSingleLine.visibility = View.GONE
+ keysDoubleLine.visibility = View.GONE
+
+ // Setup for the update to be called when needed
+ window.decorView.rootView.setOnApplyWindowInsetsListener { _: View?, insets: WindowInsets ->
+ update()
+ insets
+ }
+
+ terminalView.setOnFocusChangeListener { _: View, _: Boolean -> update() }
+ }
+
+ private fun addClickListeners(keys: View) {
+ // Only ctrl key is special, it communicates with xtermjs to modify key event with ctrl key
+ keys
+ .findViewById<View>(R.id.btn_ctrl)
+ .setOnClickListener({
+ terminalView.mapCtrlKey()
+ terminalView.enableCtrlKey()
+ })
+
+ val listener =
+ View.OnClickListener { v: View ->
+ BTN_KEY_CODE_MAP[v.id]?.also { keyCode ->
+ terminalView.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, keyCode))
+ terminalView.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, keyCode))
+ }
+ }
+
+ for (btn in BTN_KEY_CODE_MAP.keys) {
+ keys.findViewById<View>(btn).setOnClickListener(listener)
+ }
+ }
+
+ fun update() {
+ // select single line or double line
+ val needSingleLine = needsKeysInSingleLine()
+ if (keysInSingleLine != needSingleLine) {
+ if (needSingleLine) {
+ parent.removeView(keysDoubleLine)
+ parent.addView(keysSingleLine)
+ } else {
+ parent.removeView(keysSingleLine)
+ parent.addView(keysDoubleLine)
+ }
+ keysInSingleLine = needSingleLine
+ }
+
+ // set visibility
+ val needShow = needToShowKeys()
+ val keys = if (keysInSingleLine) keysSingleLine else keysDoubleLine
+ keys.visibility = if (needShow) View.VISIBLE else View.GONE
+ }
+
+ // Modifier keys are required only when IME is shown and the HW qwerty keyboard is not present
+ private fun needToShowKeys(): Boolean {
+ val imeShown = activity.window.decorView.rootWindowInsets.isVisible(WindowInsets.Type.ime())
+ val hasFocus = terminalView.hasFocus()
+ val hasHwQwertyKeyboard =
+ activity.resources.configuration.keyboard == Configuration.KEYBOARD_QWERTY
+ return imeShown && hasFocus && !hasHwQwertyKeyboard
+ }
+
+ // If terminal's height is less than 30% of the screen height, we need to show modifier keys in
+ // a single line to save the vertical space
+ private fun needsKeysInSingleLine(): Boolean =
+ (terminalView.height / activity.window.decorView.height.toFloat()) < 0.3f
+
+ companion object {
+ private val BTN_KEY_CODE_MAP =
+ mapOf(
+ R.id.btn_tab to KeyEvent.KEYCODE_TAB, // Alt key sends ESC keycode
+ R.id.btn_alt to KeyEvent.KEYCODE_ESCAPE,
+ R.id.btn_esc to KeyEvent.KEYCODE_ESCAPE,
+ R.id.btn_left to KeyEvent.KEYCODE_DPAD_LEFT,
+ R.id.btn_right to KeyEvent.KEYCODE_DPAD_RIGHT,
+ R.id.btn_up to KeyEvent.KEYCODE_DPAD_UP,
+ R.id.btn_down to KeyEvent.KEYCODE_DPAD_DOWN,
+ R.id.btn_home to KeyEvent.KEYCODE_MOVE_HOME,
+ R.id.btn_end to KeyEvent.KEYCODE_MOVE_END,
+ R.id.btn_pgup to KeyEvent.KEYCODE_PAGE_UP,
+ R.id.btn_pgdn to KeyEvent.KEYCODE_PAGE_DOWN,
+ )
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.java b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.java
deleted file mode 100644
index 0d70ab9..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.app.Notification;
-import android.app.Notification.Action;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
-
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * PortNotifier is responsible for posting a notification when a new open port is detected. User can
- * enable or disable forwarding of the port in notification panel.
- */
-class PortNotifier {
- private static final String ACTION_PORT_FORWARDING = "android.virtualization.PORT_FORWARDING";
- private static final String KEY_PORT = "port";
- private static final String KEY_ENABLED = "enabled";
-
- private final Context mContext;
- private final NotificationManager mNotificationManager;
- private final BroadcastReceiver mReceiver;
- private final PortsStateManager mPortsStateManager;
- private final PortsStateManager.Listener mPortsStateListener;
-
- public PortNotifier(Context context) {
- mContext = context;
- mNotificationManager = mContext.getSystemService(NotificationManager.class);
- mReceiver = new PortForwardingRequestReceiver();
-
- mPortsStateManager = PortsStateManager.getInstance(mContext);
- mPortsStateListener =
- new PortsStateManager.Listener() {
- @Override
- public void onPortsStateUpdated(
- Set<Integer> oldActivePorts, Set<Integer> newActivePorts) {
- Set<Integer> union = new HashSet<>(oldActivePorts);
- union.addAll(newActivePorts);
- for (int port : union) {
- if (!oldActivePorts.contains(port)) {
- showNotificationFor(port);
- } else if (!newActivePorts.contains(port)) {
- discardNotificationFor(port);
- }
- }
- }
- };
- mPortsStateManager.registerListener(mPortsStateListener);
-
- IntentFilter intentFilter = new IntentFilter(ACTION_PORT_FORWARDING);
- mContext.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED);
- }
-
- public void stop() {
- mPortsStateManager.unregisterListener(mPortsStateListener);
- mContext.unregisterReceiver(mReceiver);
- }
-
- private String getString(int resId) {
- return mContext.getString(resId);
- }
-
- private PendingIntent getPendingIntentFor(int port, boolean enabled) {
- Intent intent = new Intent(ACTION_PORT_FORWARDING);
- intent.setPackage(mContext.getPackageName());
- intent.setIdentifier(String.format(Locale.ROOT, "%d_%b", port, enabled));
- intent.putExtra(KEY_PORT, port);
- intent.putExtra(KEY_ENABLED, enabled);
- return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
- }
-
- private void showNotificationFor(int port) {
- Intent tapIntent = new Intent(mContext, SettingsPortForwardingActivity.class);
- tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- PendingIntent tapPendingIntent =
- PendingIntent.getActivity(mContext, 0, tapIntent, PendingIntent.FLAG_IMMUTABLE);
-
- String title = getString(R.string.settings_port_forwarding_notification_title);
- String content =
- mContext.getString(R.string.settings_port_forwarding_notification_content, port);
- String acceptText = getString(R.string.settings_port_forwarding_notification_accept);
- String denyText = getString(R.string.settings_port_forwarding_notification_deny);
- Icon icon = Icon.createWithResource(mContext, R.drawable.ic_launcher_foreground);
-
- Action acceptAction =
- new Action.Builder(icon, acceptText, getPendingIntentFor(port, true /* enabled */))
- .build();
- Action denyAction =
- new Action.Builder(icon, denyText, getPendingIntentFor(port, false /* enabled */))
- .build();
- Notification notification =
- new Notification.Builder(mContext, mContext.getPackageName())
- .setSmallIcon(R.drawable.ic_launcher_foreground)
- .setContentTitle(title)
- .setContentText(content)
- .setContentIntent(tapPendingIntent)
- .addAction(acceptAction)
- .addAction(denyAction)
- .build();
- mNotificationManager.notify(TAG, port, notification);
- }
-
- private void discardNotificationFor(int port) {
- mNotificationManager.cancel(TAG, port);
- }
-
- private final class PortForwardingRequestReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_PORT_FORWARDING.equals(intent.getAction())) {
- performActionPortForwarding(context, intent);
- }
- }
-
- private void performActionPortForwarding(Context context, Intent intent) {
- int port = intent.getIntExtra(KEY_PORT, 0);
- boolean enabled = intent.getBooleanExtra(KEY_ENABLED, false);
- mPortsStateManager.updateEnabledPort(port, enabled);
- discardNotificationFor(port);
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
new file mode 100644
index 0000000..7e58b36
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.graphics.drawable.Icon
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.util.Locale
+
+/**
+ * PortNotifier is responsible for posting a notification when a new open port is detected. User can
+ * enable or disable forwarding of the port in notification panel.
+ */
+internal class PortNotifier(val context: Context) {
+ private val notificationManager: NotificationManager =
+ context.getSystemService<NotificationManager>(NotificationManager::class.java)
+ private val receiver: BroadcastReceiver =
+ PortForwardingRequestReceiver().also {
+ val intentFilter = IntentFilter(ACTION_PORT_FORWARDING)
+ context.registerReceiver(it, intentFilter, Context.RECEIVER_NOT_EXPORTED)
+ }
+ private val portsStateListener: PortsStateManager.Listener =
+ object : PortsStateManager.Listener {
+ override fun onPortsStateUpdated(oldActivePorts: Set<Int>, newActivePorts: Set<Int>) {
+ // added active ports
+ (newActivePorts - oldActivePorts).forEach { showNotificationFor(it) }
+ // removed active ports
+ (oldActivePorts - newActivePorts).forEach { discardNotificationFor(it) }
+ }
+ }
+ private val portsStateManager: PortsStateManager =
+ PortsStateManager.getInstance(context).also { it.registerListener(portsStateListener) }
+
+ fun stop() {
+ portsStateManager.unregisterListener(portsStateListener)
+ context.unregisterReceiver(receiver)
+ }
+
+ private fun getString(resId: Int): String {
+ return context.getString(resId)
+ }
+
+ private fun getPendingIntentFor(port: Int, enabled: Boolean): PendingIntent {
+ val intent = Intent(ACTION_PORT_FORWARDING)
+ intent.setPackage(context.getPackageName())
+ intent.setIdentifier(String.format(Locale.ROOT, "%d_%b", port, enabled))
+ intent.putExtra(KEY_PORT, port)
+ intent.putExtra(KEY_ENABLED, enabled)
+ return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ }
+
+ private fun showNotificationFor(port: Int) {
+ val tapIntent = Intent(context, SettingsPortForwardingActivity::class.java)
+ tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ val tapPendingIntent =
+ PendingIntent.getActivity(context, 0, tapIntent, PendingIntent.FLAG_IMMUTABLE)
+
+ val title = getString(R.string.settings_port_forwarding_notification_title)
+ val content =
+ context.getString(
+ R.string.settings_port_forwarding_notification_content,
+ port,
+ portsStateManager.getActivePortInfo(port)?.comm,
+ )
+ val acceptText = getString(R.string.settings_port_forwarding_notification_accept)
+ val denyText = getString(R.string.settings_port_forwarding_notification_deny)
+ val icon = Icon.createWithResource(context, R.drawable.ic_launcher_foreground)
+
+ val acceptAction: Notification.Action =
+ Notification.Action.Builder(
+ icon,
+ acceptText,
+ getPendingIntentFor(port, true /* enabled */),
+ )
+ .build()
+ val denyAction: Notification.Action =
+ Notification.Action.Builder(
+ icon,
+ denyText,
+ getPendingIntentFor(port, false /* enabled */),
+ )
+ .build()
+ val notification: Notification =
+ Notification.Builder(context, Application.CHANNEL_SYSTEM_EVENTS_ID)
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setFullScreenIntent(tapPendingIntent, true)
+ .addAction(acceptAction)
+ .addAction(denyAction)
+ .setAutoCancel(true)
+ .build()
+ notificationManager.notify(TAG, port, notification)
+ }
+
+ private fun discardNotificationFor(port: Int) {
+ notificationManager.cancel(TAG, port)
+ }
+
+ private inner class PortForwardingRequestReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent) {
+ if (ACTION_PORT_FORWARDING == intent.action) {
+ performActionPortForwarding(intent)
+ }
+ }
+
+ fun performActionPortForwarding(intent: Intent) {
+ val port = intent.getIntExtra(KEY_PORT, 0)
+ val enabled = intent.getBooleanExtra(KEY_ENABLED, false)
+ portsStateManager.updateEnabledPort(port, enabled)
+ discardNotificationFor(port)
+ }
+ }
+
+ companion object {
+ private const val ACTION_PORT_FORWARDING = "android.virtualization.PORT_FORWARDING"
+ private const val KEY_PORT = "port"
+ private const val KEY_ENABLED = "enabled"
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.java b/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.java
deleted file mode 100644
index 5321d89..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * PortsStateManager is responsible for communicating with shared preferences and managing state of
- * ports.
- */
-public class PortsStateManager {
- private static final String PREFS_NAME = ".PORTS";
- private static final int FLAG_ENABLED = 1;
-
- private static PortsStateManager mInstance;
- private final Object mLock = new Object();
-
- private final SharedPreferences mSharedPref;
-
- @GuardedBy("mLock")
- private Set<Integer> mActivePorts;
-
- @GuardedBy("mLock")
- private final Set<Integer> mEnabledPorts;
-
- @GuardedBy("mLock")
- private final Set<Listener> mListeners;
-
- private PortsStateManager(SharedPreferences sharedPref) {
- mSharedPref = sharedPref;
- mEnabledPorts =
- mSharedPref.getAll().entrySet().stream()
- .filter(entry -> entry.getValue() instanceof Integer)
- .filter(entry -> ((int) entry.getValue() & FLAG_ENABLED) == FLAG_ENABLED)
- .map(entry -> entry.getKey())
- .filter(
- key -> {
- try {
- Integer.parseInt(key);
- return true;
- } catch (NumberFormatException e) {
- return false;
- }
- })
- .map(Integer::parseInt)
- .collect(Collectors.toSet());
- mActivePorts = new HashSet<>();
- mListeners = new HashSet<>();
- }
-
- static synchronized PortsStateManager getInstance(Context context) {
- if (mInstance == null) {
- SharedPreferences sharedPref =
- context.getSharedPreferences(
- context.getPackageName() + PREFS_NAME, Context.MODE_PRIVATE);
- mInstance = new PortsStateManager(sharedPref);
- }
- return mInstance;
- }
-
- Set<Integer> getActivePorts() {
- synchronized (mLock) {
- return new HashSet<>(mActivePorts);
- }
- }
-
- Set<Integer> getEnabledPorts() {
- synchronized (mLock) {
- return new HashSet<>(mEnabledPorts);
- }
- }
-
- void updateActivePorts(Set<Integer> ports) {
- Set<Integer> oldPorts;
- synchronized (mLock) {
- oldPorts = mActivePorts;
- mActivePorts = ports;
- }
- notifyPortsStateUpdated(oldPorts, ports);
- }
-
- void updateEnabledPort(int port, boolean enabled) {
- Set<Integer> activePorts;
- synchronized (mLock) {
- SharedPreferences.Editor editor = mSharedPref.edit();
- editor.putInt(String.valueOf(port), enabled ? FLAG_ENABLED : 0);
- editor.apply();
- if (enabled) {
- mEnabledPorts.add(port);
- } else {
- mEnabledPorts.remove(port);
- }
- activePorts = mActivePorts;
- }
- notifyPortsStateUpdated(activePorts, activePorts);
- }
-
- void clearEnabledPorts() {
- Set<Integer> activePorts;
- synchronized (mLock) {
- SharedPreferences.Editor editor = mSharedPref.edit();
- editor.clear();
- editor.apply();
- mEnabledPorts.clear();
- activePorts = mActivePorts;
- }
- notifyPortsStateUpdated(activePorts, activePorts);
- }
-
- void registerListener(Listener listener) {
- synchronized (mLock) {
- mListeners.add(listener);
- }
- }
-
- void unregisterListener(Listener listener) {
- synchronized (mLock) {
- mListeners.remove(listener);
- }
- }
-
- private void notifyPortsStateUpdated(Set<Integer> oldActivePorts, Set<Integer> newActivePorts) {
- Set<Listener> listeners;
- synchronized (mLock) {
- listeners = new HashSet<>(mListeners);
- }
- for (Listener listener : listeners) {
- listener.onPortsStateUpdated(
- new HashSet<>(oldActivePorts), new HashSet<>(newActivePorts));
- }
- }
-
- interface Listener {
- default void onPortsStateUpdated(
- Set<Integer> oldActivePorts, Set<Integer> newActivePorts) {}
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.kt b/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.kt
new file mode 100644
index 0000000..20bccc2
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.android.internal.annotations.GuardedBy
+import com.android.virtualization.terminal.proto.ActivePort
+import java.util.HashSet
+
+/**
+ * PortsStateManager is responsible for communicating with shared preferences and managing state of
+ * ports.
+ */
+class PortsStateManager private constructor(private val sharedPref: SharedPreferences) {
+ private val lock = Any()
+
+ @GuardedBy("lock") private val activePorts: MutableMap<Int, ActivePort> = hashMapOf()
+
+ @GuardedBy("lock")
+ private val enabledPorts: MutableSet<Int> =
+ sharedPref
+ .getAll()
+ .entries
+ .filterIsInstance<MutableMap.MutableEntry<String, Int>>()
+ .filter { it.value and FLAG_ENABLED == FLAG_ENABLED }
+ .map { it.key.toIntOrNull() }
+ .filterNotNull()
+ .toMutableSet()
+
+ @GuardedBy("lock") private val listeners: MutableSet<Listener> = hashSetOf()
+
+ fun getActivePorts(): Set<Int> {
+ synchronized(lock) {
+ return HashSet<Int>(activePorts.keys)
+ }
+ }
+
+ fun getActivePortInfo(port: Int): ActivePort? {
+ synchronized(lock) {
+ return activePorts[port]
+ }
+ }
+
+ fun getEnabledPorts(): Set<Int> {
+ synchronized(lock) {
+ return HashSet<Int>(enabledPorts)
+ }
+ }
+
+ fun updateActivePorts(ports: List<ActivePort>) {
+ val oldPorts = getActivePorts()
+ synchronized(lock) {
+ activePorts.clear()
+ activePorts.putAll(ports.associateBy { it.port })
+ }
+ notifyPortsStateUpdated(oldPorts, getActivePorts())
+ }
+
+ fun updateEnabledPort(port: Int, enabled: Boolean) {
+ synchronized(lock) {
+ val editor = sharedPref.edit()
+ editor.putInt(port.toString(), if (enabled) FLAG_ENABLED else 0)
+ editor.apply()
+ if (enabled) {
+ enabledPorts.add(port)
+ } else {
+ enabledPorts.remove(port)
+ }
+ }
+ notifyPortsStateUpdated(getActivePorts(), getActivePorts())
+ }
+
+ fun clearEnabledPorts() {
+ synchronized(lock) {
+ val editor = sharedPref.edit()
+ editor.clear()
+ editor.apply()
+ enabledPorts.clear()
+ }
+ notifyPortsStateUpdated(getActivePorts(), getActivePorts())
+ }
+
+ fun registerListener(listener: Listener) {
+ synchronized(lock) { listeners.add(listener) }
+ }
+
+ fun unregisterListener(listener: Listener) {
+ synchronized(lock) { listeners.remove(listener) }
+ }
+
+ // TODO: it notifies when both enabledPort and activePort are changed, but doesn't provide
+ // enabledPort's value change. Make this callback provide that information as well.
+ private fun notifyPortsStateUpdated(oldActivePorts: Set<Int>, newActivePorts: Set<Int>) {
+ synchronized(lock) { HashSet<Listener>(this@PortsStateManager.listeners) }
+ .forEach {
+ it.onPortsStateUpdated(HashSet<Int>(oldActivePorts), HashSet<Int>(newActivePorts))
+ }
+ }
+
+ interface Listener {
+ fun onPortsStateUpdated(oldActivePorts: Set<Int>, newActivePorts: Set<Int>) {}
+ }
+
+ companion object {
+ private const val PREFS_NAME = ".PORTS"
+ private const val FLAG_ENABLED = 1
+
+ private var instance: PortsStateManager? = null
+
+ @Synchronized
+ fun getInstance(context: Context): PortsStateManager {
+ if (instance == null) {
+ val sharedPref =
+ context.getSharedPreferences(
+ context.getPackageName() + PREFS_NAME,
+ Context.MODE_PRIVATE,
+ )
+ instance = PortsStateManager(sharedPref)
+ }
+ return instance!!
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Runner.java b/android/TerminalApp/java/com/android/virtualization/terminal/Runner.java
deleted file mode 100644
index 4094025..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Runner.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.content.Context;
-import android.system.virtualmachine.VirtualMachine;
-import android.system.virtualmachine.VirtualMachineCallback;
-import android.system.virtualmachine.VirtualMachineConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig;
-import android.system.virtualmachine.VirtualMachineException;
-import android.system.virtualmachine.VirtualMachineManager;
-import android.util.Log;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ForkJoinPool;
-
-/** Utility class for creating a VM and waiting for it to finish. */
-class Runner {
- private final VirtualMachine mVirtualMachine;
- private final Callback mCallback;
-
- private Runner(VirtualMachine vm, Callback cb) {
- mVirtualMachine = vm;
- mCallback = cb;
- }
-
- /** Create a virtual machine of the given config, under the given context. */
- static Runner create(Context context, VirtualMachineConfig config)
- throws VirtualMachineException {
- // context may already be the app context, but calling this again is not harmful.
- // See b/359439878 on why vmm should be obtained from the app context.
- Context appContext = context.getApplicationContext();
- VirtualMachineManager vmm = appContext.getSystemService(VirtualMachineManager.class);
- VirtualMachineCustomImageConfig customConfig = config.getCustomImageConfig();
- if (customConfig == null) {
- throw new RuntimeException("CustomImageConfig is missing");
- }
-
- String name = customConfig.getName();
- if (name == null || name.isEmpty()) {
- throw new RuntimeException("Virtual machine's name is missing in the config");
- }
-
- VirtualMachine vm = vmm.getOrCreate(name, config);
- try {
- vm.setConfig(config);
- } catch (VirtualMachineException e) {
- vmm.delete(name);
- vm = vmm.create(name, config);
- Log.w(TAG, "Re-creating virtual machine (" + name + ")", e);
- }
-
- Callback cb = new Callback();
- vm.setCallback(ForkJoinPool.commonPool(), cb);
- vm.run();
- return new Runner(vm, cb);
- }
-
- /** Give access to the underlying VirtualMachine object. */
- VirtualMachine getVm() {
- return mVirtualMachine;
- }
-
- /** Get future about VM's exit status. */
- CompletableFuture<Boolean> getExitStatus() {
- return mCallback.mFinishedSuccessfully;
- }
-
- private static class Callback implements VirtualMachineCallback {
- final CompletableFuture<Boolean> mFinishedSuccessfully = new CompletableFuture<>();
-
- @Override
- public void onPayloadStarted(VirtualMachine vm) {
- // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
- }
-
- @Override
- public void onPayloadReady(VirtualMachine vm) {
- // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
- }
-
- @Override
- public void onPayloadFinished(VirtualMachine vm, int exitCode) {
- // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
- }
-
- @Override
- public void onError(VirtualMachine vm, int errorCode, String message) {
- Log.e(TAG, "Error from VM. code: " + errorCode + " (" + message + ")");
- mFinishedSuccessfully.complete(false);
- }
-
- @Override
- public void onStopped(VirtualMachine vm, int reason) {
- Log.d(TAG, "VM stopped. Reason: " + reason);
- mFinishedSuccessfully.complete(true);
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
new file mode 100644
index 0000000..6454cbd
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.system.virtualmachine.VirtualMachine
+import android.system.virtualmachine.VirtualMachineCallback
+import android.system.virtualmachine.VirtualMachineConfig
+import android.system.virtualmachine.VirtualMachineException
+import android.system.virtualmachine.VirtualMachineManager
+import android.util.Log
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.ForkJoinPool
+
+/** Utility class for creating a VM and waiting for it to finish. */
+internal class Runner private constructor(val vm: VirtualMachine?, callback: Callback) {
+ /** Get future about VM's exit status. */
+ val exitStatus = callback.finishedSuccessfully
+
+ private class Callback : VirtualMachineCallback {
+ val finishedSuccessfully: CompletableFuture<Boolean> = CompletableFuture<Boolean>()
+
+ override fun onPayloadStarted(vm: VirtualMachine) {
+ // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
+ }
+
+ override fun onPayloadReady(vm: VirtualMachine) {
+ // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
+ }
+
+ override fun onPayloadFinished(vm: VirtualMachine, exitCode: Int) {
+ // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
+ }
+
+ override fun onError(vm: VirtualMachine, errorCode: Int, message: String) {
+ Log.e(TAG, "Error from VM. code: $errorCode ($message)")
+ finishedSuccessfully.complete(false)
+ }
+
+ override fun onStopped(vm: VirtualMachine, reason: Int) {
+ Log.d(TAG, "VM stopped. Reason: $reason")
+ finishedSuccessfully.complete(true)
+ }
+ }
+
+ companion object {
+ /** Create a virtual machine of the given config, under the given context. */
+ @Throws(VirtualMachineException::class)
+ fun create(context: Context, config: VirtualMachineConfig): Runner {
+ // context may already be the app context, but calling this again is not harmful.
+ // See b/359439878 on why vmm should be obtained from the app context.
+ val appContext = context.getApplicationContext()
+ val vmm =
+ appContext.getSystemService<VirtualMachineManager>(
+ VirtualMachineManager::class.java
+ )
+ val customConfig = config.customImageConfig
+ requireNotNull(customConfig) { "CustomImageConfig is missing" }
+
+ val name = customConfig.name
+ require(!name.isNullOrEmpty()) { "Virtual machine's name is missing in the config" }
+
+ var vm = vmm.getOrCreate(name, config)
+ try {
+ vm.config = config
+ } catch (e: VirtualMachineException) {
+ vmm.delete(name)
+ vm = vmm.create(name, config)
+ Log.w(TAG, "Re-creating virtual machine ($name)", e)
+ }
+
+ val cb = Callback()
+ vm.setCallback(ForkJoinPool.commonPool(), cb)
+ vm.run()
+ return Runner(vm, cb)
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
index c46effa..7076084 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
@@ -15,6 +15,7 @@
*/
package com.android.virtualization.terminal
+import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -22,12 +23,14 @@
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.materialswitch.MaterialSwitch
-class SettingsPortForwardingActiveAdapter(private val mPortsStateManager: PortsStateManager) :
- SettingsPortForwardingBaseAdapter<SettingsPortForwardingActiveAdapter.ViewHolder>() {
+class SettingsPortForwardingActiveAdapter(
+ private val portsStateManager: PortsStateManager,
+ private val context: Context,
+) : SettingsPortForwardingBaseAdapter<SettingsPortForwardingActiveAdapter.ViewHolder>() {
override fun getItems(): ArrayList<SettingsPortForwardingItem> {
- val enabledPorts = mPortsStateManager.getEnabledPorts()
- return mPortsStateManager
+ val enabledPorts = portsStateManager.getEnabledPorts()
+ return portsStateManager
.getActivePorts()
.map { SettingsPortForwardingItem(it, enabledPorts.contains(it)) }
.toCollection(ArrayList())
@@ -47,12 +50,18 @@
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
- val port = mItems[position].port
- viewHolder.port.text = port.toString()
+ val port = items[position].port
+ viewHolder.port.text =
+ context.getString(
+ R.string.settings_port_forwarding_active_ports_content,
+ port,
+ portsStateManager.getActivePortInfo(port)?.comm,
+ )
viewHolder.enabledSwitch.contentDescription = viewHolder.port.text
- viewHolder.enabledSwitch.isChecked = mItems[position].enabled
+ viewHolder.enabledSwitch.setOnCheckedChangeListener(null)
+ viewHolder.enabledSwitch.isChecked = items[position].enabled
viewHolder.enabledSwitch.setOnCheckedChangeListener { _, isChecked ->
- mPortsStateManager.updateEnabledPort(port, isChecked)
+ portsStateManager.updateEnabledPort(port, isChecked)
}
}
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
index 27d6ce7..db3926d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
@@ -31,30 +31,30 @@
private const val PORT_RANGE_MAX: Int = 65535
class SettingsPortForwardingActivity : AppCompatActivity() {
- private lateinit var mPortsStateManager: PortsStateManager
- private lateinit var mPortsStateListener: Listener
- private lateinit var mActivePortsAdapter: SettingsPortForwardingActiveAdapter
- private lateinit var mInactivePortsAdapter: SettingsPortForwardingInactiveAdapter
+ private lateinit var portsStateManager: PortsStateManager
+ private lateinit var portsStateListener: Listener
+ private lateinit var activePortsAdapter: SettingsPortForwardingActiveAdapter
+ private lateinit var inactivePortsAdapter: SettingsPortForwardingInactiveAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_port_forwarding)
- mPortsStateManager = PortsStateManager.getInstance(this)
+ portsStateManager = PortsStateManager.getInstance(this)
- mActivePortsAdapter = SettingsPortForwardingActiveAdapter(mPortsStateManager)
+ activePortsAdapter = SettingsPortForwardingActiveAdapter(portsStateManager, this)
val activeRecyclerView: RecyclerView =
findViewById(R.id.settings_port_forwarding_active_recycler_view)
activeRecyclerView.layoutManager = LinearLayoutManager(this)
- activeRecyclerView.adapter = mActivePortsAdapter
+ activeRecyclerView.adapter = activePortsAdapter
- mInactivePortsAdapter = SettingsPortForwardingInactiveAdapter(mPortsStateManager, this)
+ inactivePortsAdapter = SettingsPortForwardingInactiveAdapter(portsStateManager, this)
val inactiveRecyclerView: RecyclerView =
findViewById(R.id.settings_port_forwarding_inactive_recycler_view)
inactiveRecyclerView.layoutManager = LinearLayoutManager(this)
- inactiveRecyclerView.adapter = mInactivePortsAdapter
+ inactiveRecyclerView.adapter = inactivePortsAdapter
- mPortsStateListener = Listener()
+ portsStateListener = Listener()
val addButton = findViewById<ImageButton>(R.id.settings_port_forwarding_inactive_add_button)
addButton.setOnClickListener {
@@ -71,7 +71,7 @@
R.id.settings_port_forwarding_inactive_add_dialog_text
)!!
val port = editText.text.toString().toInt()
- mPortsStateManager.updateEnabledPort(port, true)
+ portsStateManager.updateEnabledPort(port, true)
}
.setNegativeButton(R.string.settings_port_forwarding_dialog_cancel, null)
.create()
@@ -121,8 +121,8 @@
)
positiveButton.setEnabled(false)
} else if (
- mPortsStateManager.getActivePorts().contains(port) ||
- mPortsStateManager.getEnabledPorts().contains(port)
+ portsStateManager.getActivePorts().contains(port) ||
+ portsStateManager.getEnabledPorts().contains(port)
) {
editText.setError(
getString(
@@ -140,18 +140,20 @@
}
private fun refreshAdapters() {
- mActivePortsAdapter.refreshItems()
- mInactivePortsAdapter.refreshItems()
+ runOnUiThread {
+ activePortsAdapter.refreshItems()
+ inactivePortsAdapter.refreshItems()
+ }
}
override fun onResume() {
super.onResume()
- mPortsStateManager.registerListener(mPortsStateListener)
+ portsStateManager.registerListener(portsStateListener)
refreshAdapters()
}
override fun onPause() {
- mPortsStateManager.unregisterListener(mPortsStateListener)
+ portsStateManager.unregisterListener(portsStateListener)
super.onPause()
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
index 4595372..5b8d022 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
@@ -21,10 +21,10 @@
abstract class SettingsPortForwardingBaseAdapter<T : RecyclerView.ViewHolder>() :
RecyclerView.Adapter<T>() {
- var mItems: SortedList<SettingsPortForwardingItem>
+ var items: SortedList<SettingsPortForwardingItem>
init {
- mItems =
+ items =
SortedList(
SettingsPortForwardingItem::class.java,
object : SortedListAdapterCallback<SettingsPortForwardingItem>(this) {
@@ -52,11 +52,11 @@
)
}
- override fun getItemCount() = mItems.size()
+ override fun getItemCount() = items.size()
abstract fun getItems(): ArrayList<SettingsPortForwardingItem>
fun refreshItems() {
- mItems.replaceAll(getItems())
+ items.replaceAll(getItems())
}
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
index d572129..e1fe468 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
@@ -24,14 +24,14 @@
import androidx.recyclerview.widget.RecyclerView
class SettingsPortForwardingInactiveAdapter(
- private val mPortsStateManager: PortsStateManager,
- private val mContext: Context,
+ private val portsStateManager: PortsStateManager,
+ private val context: Context,
) : SettingsPortForwardingBaseAdapter<SettingsPortForwardingInactiveAdapter.ViewHolder>() {
override fun getItems(): ArrayList<SettingsPortForwardingItem> {
- return mPortsStateManager
+ return portsStateManager
.getEnabledPorts()
- .subtract(mPortsStateManager.getActivePorts())
+ .subtract(portsStateManager.getActivePorts())
.map { SettingsPortForwardingItem(it, true) }
.toCollection(ArrayList())
}
@@ -50,15 +50,15 @@
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
- val port = mItems[position].port
+ val port = items[position].port
viewHolder.port.text = port.toString()
viewHolder.closeButton.contentDescription =
- mContext.getString(
+ context.getString(
R.string.settings_port_forwarding_other_enabled_port_close_button,
port,
)
viewHolder.closeButton.setOnClickListener { _ ->
- mPortsStateManager.updateEnabledPort(port, false)
+ portsStateManager.updateEnabledPort(port, false)
}
}
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
index a4d43b8..319a53b 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
@@ -22,7 +22,7 @@
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
import com.google.android.material.card.MaterialCardView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalExceptionHandler.java b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalExceptionHandler.java
deleted file mode 100644
index 4ab2b77..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalExceptionHandler.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import android.content.Context;
-import android.util.Log;
-
-public class TerminalExceptionHandler implements Thread.UncaughtExceptionHandler {
- private static final String TAG = "TerminalExceptionHandler";
-
- private final Context mContext;
-
- public TerminalExceptionHandler(Context context) {
- mContext = context;
- }
-
- @Override
- public void uncaughtException(Thread thread, Throwable throwable) {
- Exception exception;
- if (throwable instanceof Exception) {
- exception = (Exception) throwable;
- } else {
- exception = new Exception(throwable);
- }
- try {
- ErrorActivity.start(mContext, exception);
- } catch (Exception ex) {
- Log.wtf(TAG, "Failed to launch error activity for an exception", exception);
- }
-
- thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, throwable);
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalExceptionHandler.kt b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalExceptionHandler.kt
new file mode 100644
index 0000000..3a8c444
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalExceptionHandler.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.util.Log
+import java.lang.Exception
+
+class TerminalExceptionHandler(private val context: Context) : Thread.UncaughtExceptionHandler {
+
+ override fun uncaughtException(thread: Thread, throwable: Throwable) {
+ val exception = (throwable as? Exception) ?: Exception(throwable)
+ try {
+ ErrorActivity.start(context, exception)
+ } catch (_: Exception) {
+ Log.wtf(TAG, "Failed to launch error activity for an exception", exception)
+ }
+ Thread.getDefaultUncaughtExceptionHandler()?.uncaughtException(thread, throwable)
+ }
+
+ companion object {
+ private const val TAG = "TerminalExceptionHandler"
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalThreadFactory.java b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalThreadFactory.java
deleted file mode 100644
index 5ee535d..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalThreadFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import android.content.Context;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-
-public class TerminalThreadFactory implements ThreadFactory {
- private final Context mContext;
-
- public TerminalThreadFactory(Context context) {
- mContext = context;
- }
-
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = Executors.defaultThreadFactory().newThread(r);
- thread.setUncaughtExceptionHandler(new TerminalExceptionHandler(mContext));
- return thread;
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalThreadFactory.kt b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalThreadFactory.kt
new file mode 100644
index 0000000..f8e909d
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalThreadFactory.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import java.util.concurrent.Executors
+import java.util.concurrent.ThreadFactory
+
+class TerminalThreadFactory(private val context: Context) : ThreadFactory {
+ override fun newThread(r: Runnable): Thread {
+ return Executors.defaultThreadFactory().newThread(r).also {
+ it.uncaughtExceptionHandler = TerminalExceptionHandler(context)
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.java b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.java
deleted file mode 100644
index 0ffc093..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
-import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import android.view.accessibility.AccessibilityNodeProvider;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.webkit.WebView;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-
-public class TerminalView extends WebView
- implements AccessibilityStateChangeListener, TouchExplorationStateChangeListener {
- // Maximum length of texts the talk back announcements can be. This value is somewhat
- // arbitrarily set. We may want to adjust this in the future.
- private static final int TEXT_TOO_LONG_TO_ANNOUNCE = 200;
-
- private final String CTRL_KEY_HANDLER;
- private final String ENABLE_CTRL_KEY;
- private final String TOUCH_TO_MOUSE_HANDLER;
-
- private final AccessibilityManager mA11yManager;
-
- public TerminalView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mA11yManager = context.getSystemService(AccessibilityManager.class);
- mA11yManager.addTouchExplorationStateChangeListener(this);
- mA11yManager.addAccessibilityStateChangeListener(this);
- adjustToA11yStateChange();
- try {
- CTRL_KEY_HANDLER = readAssetAsString(context, "js/ctrl_key_handler.js");
- ENABLE_CTRL_KEY = readAssetAsString(context, "js/enable_ctrl_key.js");
- TOUCH_TO_MOUSE_HANDLER = readAssetAsString(context, "js/touch_to_mouse_handler.js");
- } catch (IOException e) {
- // It cannot happen
- throw new IllegalArgumentException("cannot read code from asset", e);
- }
- }
-
- private String readAssetAsString(Context context, String filePath) throws IOException {
- try (InputStream is = context.getAssets().open(filePath)) {
- return new String(is.readAllBytes());
- }
- }
-
- public void mapTouchToMouseEvent() {
- this.evaluateJavascript(TOUCH_TO_MOUSE_HANDLER, null);
- }
-
- public void mapCtrlKey() {
- this.evaluateJavascript(CTRL_KEY_HANDLER, null);
- }
-
- public void enableCtrlKey() {
- this.evaluateJavascript(ENABLE_CTRL_KEY, null);
- }
-
- @Override
- public void onAccessibilityStateChanged(boolean enabled) {
- Log.d(TAG, "accessibility " + enabled);
- adjustToA11yStateChange();
- }
-
- @Override
- public void onTouchExplorationStateChanged(boolean enabled) {
- Log.d(TAG, "touch exploration " + enabled);
- adjustToA11yStateChange();
- }
-
- private void adjustToA11yStateChange() {
- if (!mA11yManager.isEnabled()) {
- setFocusable(true);
- return;
- }
-
- // When accessibility is on, the webview itself doesn't have to be focusable. The (virtual)
- // edittext will be focusable to accept inputs. However, the webview has to be focusable for
- // an accessibility purpose so that users can read the contents in it or scroll the view.
- setFocusable(false);
- setFocusableInTouchMode(true);
- }
-
- // AccessibilityEvents for WebView are sent directly from WebContentsAccessibilityImpl to the
- // parent of WebView, without going through WebView. So, there's no WebView methods we can
- // override to intercept the event handling process. To work around this, we attach an
- // AccessibilityDelegate to the parent view where the events are sent to. And to guarantee that
- // the parent view exists, wait until the WebView is attached to the window by when the parent
- // must exist.
- private final AccessibilityDelegate mA11yEventFilter =
- new AccessibilityDelegate() {
- @Override
- public boolean onRequestSendAccessibilityEvent(
- ViewGroup host, View child, AccessibilityEvent e) {
- // We filter only the a11y events from the WebView
- if (child != TerminalView.this) {
- return super.onRequestSendAccessibilityEvent(host, child, e);
- }
- final int eventType = e.getEventType();
- switch (e.getEventType()) {
- // Skip reading texts that are too long. Right now, ttyd emits entire
- // text on the terminal to the live region, which is very annoying to
- // screen reader users.
- case AccessibilityEvent.TYPE_ANNOUNCEMENT:
- CharSequence text = e.getText().get(0); // there always is a text
- if (text.length() >= TEXT_TOO_LONG_TO_ANNOUNCE) {
- Log.i(TAG, "Announcement skipped because it's too long: " + text);
- return false;
- }
- break;
- }
- return super.onRequestSendAccessibilityEvent(host, child, e);
- }
- };
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mA11yManager.isEnabled()) {
- View parent = (View) getParent();
- parent.setAccessibilityDelegate(mA11yEventFilter);
- }
- }
-
- private final AccessibilityNodeProvider mA11yNodeProvider =
- new AccessibilityNodeProvider() {
-
- /** Returns the original NodeProvider that WebView implements. */
- private AccessibilityNodeProvider getParent() {
- return TerminalView.super.getAccessibilityNodeProvider();
- }
-
- /** Convenience method for reading a string resource. */
- private String getString(int resId) {
- return TerminalView.this.getContext().getResources().getString(resId);
- }
-
- /** Checks if NodeInfo renders an empty line in the terminal. */
- private boolean isEmptyLine(AccessibilityNodeInfo info) {
- final CharSequence text = info.getText();
- // Node with no text is not consiered a line. ttyd emits at least one character,
- // which usually is NBSP.
- if (text == null) {
- return false;
- }
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- // Note: don't use Characters.isWhitespace as it doesn't recognize NBSP as a
- // whitespace.
- if (!TextUtils.isWhitespace(c)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public AccessibilityNodeInfo createAccessibilityNodeInfo(int id) {
- AccessibilityNodeInfo info = getParent().createAccessibilityNodeInfo(id);
- if (info == null) {
- return null;
- }
-
- final String className = info.getClassName().toString();
-
- // By default all views except the cursor is not click-able. Other views are
- // read-only. This ensures that user is not navigated to non-clickable elements
- // when using switches.
- if (!"android.widget.EditText".equals(className)) {
- info.removeAction(AccessibilityAction.ACTION_CLICK);
- }
-
- switch (className) {
- case "android.webkit.WebView":
- // There are two NodeInfo objects of class name WebView. The one is the
- // real WebView whose ID is View.NO_ID as it's at the root of the
- // virtual view hierarchy. The second one is a virtual view for the
- // iframe. The latter one's text is set to the command that we give to
- // ttyd, which is "login -f droid ...". This is an impl detail which
- // doesn't have to be announced. Replace the text with "Terminal
- // display".
- if (id != View.NO_ID) {
- info.setText(null);
- info.setContentDescription(getString(R.string.terminal_display));
- // b/376827536
- info.setHintText(getString(R.string.double_tap_to_edit_text));
- }
-
- // These two lines below are to prevent this WebView element from being
- // fousable by the screen reader, while allowing any other element in
- // the WebView to be focusable by the reader. In our case, the EditText
- // is a117_focusable.
- info.setScreenReaderFocusable(false);
- info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
- break;
- case "android.view.View":
- // Empty line was announced as "space" (via the NBSP character).
- // Localize the spoken text.
- if (isEmptyLine(info)) {
- info.setContentDescription(getString(R.string.empty_line));
- // b/376827536
- info.setHintText(getString(R.string.double_tap_to_edit_text));
- }
- break;
- case "android.widget.TextView":
- // There are several TextViews in the terminal, and one of them is an
- // invisible TextView which seems to be from the <div
- // class="live-region"> tag. Interestingly, its text is often populated
- // with the entire text on the screen. Silence this by forcibly setting
- // the text to null. Note that this TextView is identified by having a
- // zero width. This certainly is not elegant, but I couldn't find other
- // options.
- Rect rect = new Rect();
- info.getBoundsInScreen(rect);
- if (rect.width() == 0) {
- info.setText(null);
- info.setContentDescription(getString(R.string.empty_line));
- }
- info.setScreenReaderFocusable(false);
- break;
- case "android.widget.EditText":
- // This EditText is for the <textarea> accepting user input; the cursor.
- // ttyd name it as "Terminal input" but it's not i18n'ed. Override it
- // here for better i18n.
- info.setText(null);
- info.setHintText(getString(R.string.double_tap_to_edit_text));
- info.setContentDescription(getString(R.string.terminal_input));
- info.setScreenReaderFocusable(true);
- info.addAction(AccessibilityAction.ACTION_FOCUS);
- break;
- }
- return info;
- }
-
- @Override
- public boolean performAction(int id, int action, Bundle arguments) {
- return getParent().performAction(id, action, arguments);
- }
-
- @Override
- public void addExtraDataToAccessibilityNodeInfo(
- int virtualViewId,
- AccessibilityNodeInfo info,
- String extraDataKey,
- Bundle arguments) {
- getParent()
- .addExtraDataToAccessibilityNodeInfo(
- virtualViewId, info, extraDataKey, arguments);
- }
-
- @Override
- public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(
- String text, int virtualViewId) {
- return getParent().findAccessibilityNodeInfosByText(text, virtualViewId);
- }
-
- @Override
- public AccessibilityNodeInfo findFocus(int focus) {
- return getParent().findFocus(focus);
- }
- };
-
- @Override
- public AccessibilityNodeProvider getAccessibilityNodeProvider() {
- AccessibilityNodeProvider p = super.getAccessibilityNodeProvider();
- if (p != null && mA11yManager.isEnabled()) {
- return mA11yNodeProvider;
- }
- return p;
- }
-
- @Override
- public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
- if (outAttrs != null) {
- outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
- }
- return inputConnection;
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.kt b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.kt
new file mode 100644
index 0000000..4d9a89d
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.kt
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.graphics.Rect
+import android.os.Bundle
+import android.text.InputType
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityNodeInfo
+import android.view.accessibility.AccessibilityNodeProvider
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputConnection
+import android.webkit.WebView
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.io.IOException
+
+class TerminalView(context: Context, attrs: AttributeSet?) :
+ WebView(context, attrs),
+ AccessibilityManager.AccessibilityStateChangeListener,
+ AccessibilityManager.TouchExplorationStateChangeListener {
+ private val ctrlKeyHandler: String = readAssetAsString(context, "js/ctrl_key_handler.js")
+ private val enableCtrlKey: String = readAssetAsString(context, "js/enable_ctrl_key.js")
+ private val touchToMouseHandler: String =
+ readAssetAsString(context, "js/touch_to_mouse_handler.js")
+ private val a11yManager =
+ context.getSystemService<AccessibilityManager>(AccessibilityManager::class.java).also {
+ it.addTouchExplorationStateChangeListener(this)
+ it.addAccessibilityStateChangeListener(this)
+ }
+
+ @Throws(IOException::class)
+ private fun readAssetAsString(context: Context, filePath: String): String {
+ return String(context.assets.open(filePath).readAllBytes())
+ }
+
+ fun mapTouchToMouseEvent() {
+ this.evaluateJavascript(touchToMouseHandler, null)
+ }
+
+ fun mapCtrlKey() {
+ this.evaluateJavascript(ctrlKeyHandler, null)
+ }
+
+ fun enableCtrlKey() {
+ this.evaluateJavascript(enableCtrlKey, null)
+ }
+
+ override fun onAccessibilityStateChanged(enabled: Boolean) {
+ Log.d(TAG, "accessibility $enabled")
+ adjustToA11yStateChange()
+ }
+
+ override fun onTouchExplorationStateChanged(enabled: Boolean) {
+ Log.d(TAG, "touch exploration $enabled")
+ adjustToA11yStateChange()
+ }
+
+ private fun adjustToA11yStateChange() {
+ if (!a11yManager.isEnabled) {
+ setFocusable(true)
+ return
+ }
+
+ // When accessibility is on, the webview itself doesn't have to be focusable. The (virtual)
+ // edittext will be focusable to accept inputs. However, the webview has to be focusable for
+ // an accessibility purpose so that users can read the contents in it or scroll the view.
+ setFocusable(false)
+ setFocusableInTouchMode(true)
+ }
+
+ // AccessibilityEvents for WebView are sent directly from WebContentsAccessibilityImpl to the
+ // parent of WebView, without going through WebView. So, there's no WebView methods we can
+ // override to intercept the event handling process. To work around this, we attach an
+ // AccessibilityDelegate to the parent view where the events are sent to. And to guarantee that
+ // the parent view exists, wait until the WebView is attached to the window by when the parent
+ // must exist.
+ private val a11yEventFilter: AccessibilityDelegate =
+ object : AccessibilityDelegate() {
+ override fun onRequestSendAccessibilityEvent(
+ host: ViewGroup,
+ child: View,
+ e: AccessibilityEvent,
+ ): Boolean {
+ // We filter only the a11y events from the WebView
+ if (child !== this@TerminalView) {
+ return super.onRequestSendAccessibilityEvent(host, child, e)
+ }
+ when (e.eventType) {
+ AccessibilityEvent.TYPE_ANNOUNCEMENT -> {
+ val text = e.text[0] // there always is a text
+ if (text.length >= TEXT_TOO_LONG_TO_ANNOUNCE) {
+ Log.i(TAG, "Announcement skipped because it's too long: $text")
+ return false
+ }
+ }
+ }
+ return super.onRequestSendAccessibilityEvent(host, child, e)
+ }
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ if (a11yManager.isEnabled) {
+ val parent = getParent() as View
+ parent.setAccessibilityDelegate(a11yEventFilter)
+ }
+ }
+
+ private val a11yNodeProvider: AccessibilityNodeProvider =
+ object : AccessibilityNodeProvider() {
+ /** Returns the original NodeProvider that WebView implements. */
+ private fun getParent(): AccessibilityNodeProvider? {
+ return super@TerminalView.getAccessibilityNodeProvider()
+ }
+
+ /** Convenience method for reading a string resource. */
+ private fun getString(resId: Int): String {
+ return this@TerminalView.context.getResources().getString(resId)
+ }
+
+ /** Checks if NodeInfo renders an empty line in the terminal. */
+ private fun isEmptyLine(info: AccessibilityNodeInfo): Boolean {
+ // Node with no text is not considered a line. ttyd emits at least one character,
+ // which usually is NBSP.
+ // Note: don't use Characters.isWhitespace as it doesn't recognize NBSP as a
+ // whitespace.
+ return (info.getText()?.all { TextUtils.isWhitespace(it.code) }) == true
+ }
+
+ override fun createAccessibilityNodeInfo(id: Int): AccessibilityNodeInfo? {
+ val info: AccessibilityNodeInfo? = getParent()?.createAccessibilityNodeInfo(id)
+ if (info == null) {
+ return null
+ }
+
+ val className = info.className.toString()
+
+ // By default all views except the cursor is not click-able. Other views are
+ // read-only. This ensures that user is not navigated to non-clickable elements
+ // when using switches.
+ if ("android.widget.EditText" != className) {
+ info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)
+ }
+
+ when (className) {
+ "android.webkit.WebView" -> {
+ // There are two NodeInfo objects of class name WebView. The one is the
+ // real WebView whose ID is View.NO_ID as it's at the root of the
+ // virtual view hierarchy. The second one is a virtual view for the
+ // iframe. The latter one's text is set to the command that we give to
+ // ttyd, which is "login -f droid ...". This is an impl detail which
+ // doesn't have to be announced. Replace the text with "Terminal
+ // display".
+ if (id != NO_ID) {
+ info.setText(null)
+ info.setContentDescription(getString(R.string.terminal_display))
+ // b/376827536
+ info.setHintText(getString(R.string.double_tap_to_edit_text))
+ }
+
+ // These two lines below are to prevent this WebView element from being
+ // focusable by the screen reader, while allowing any other element in
+ // the WebView to be focusable by the reader. In our case, the EditText
+ // is a117_focusable.
+ info.isScreenReaderFocusable = false
+ info.addAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS
+ )
+ }
+
+ "android.view.View" ->
+ // Empty line was announced as "space" (via the NBSP character).
+ // Localize the spoken text.
+ if (isEmptyLine(info)) {
+ info.setContentDescription(getString(R.string.empty_line))
+ // b/376827536
+ info.setHintText(getString(R.string.double_tap_to_edit_text))
+ }
+
+ "android.widget.TextView" -> {
+ // There are several TextViews in the terminal, and one of them is an
+ // invisible TextView which seems to be from the <div
+ // class="live-region"> tag. Interestingly, its text is often populated
+ // with the entire text on the screen. Silence this by forcibly setting
+ // the text to null. Note that this TextView is identified by having a
+ // zero width. This certainly is not elegant, but I couldn't find other
+ // options.
+ val rect = Rect()
+ info.getBoundsInScreen(rect)
+ if (rect.width() == 0) {
+ info.setText(null)
+ info.setContentDescription(getString(R.string.empty_line))
+ }
+ info.isScreenReaderFocusable = false
+ }
+
+ "android.widget.EditText" -> {
+ // This EditText is for the <textarea> accepting user input; the cursor.
+ // ttyd name it as "Terminal input" but it's not i18n'ed. Override it
+ // here for better i18n.
+ info.setText(null)
+ info.setHintText(getString(R.string.double_tap_to_edit_text))
+ info.setContentDescription(getString(R.string.terminal_input))
+ info.isScreenReaderFocusable = true
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_FOCUS)
+ }
+ }
+ return info
+ }
+
+ override fun performAction(id: Int, action: Int, arguments: Bundle?): Boolean {
+ return getParent()?.performAction(id, action, arguments) == true
+ }
+
+ override fun addExtraDataToAccessibilityNodeInfo(
+ virtualViewId: Int,
+ info: AccessibilityNodeInfo?,
+ extraDataKey: String?,
+ arguments: Bundle?,
+ ) {
+ getParent()
+ ?.addExtraDataToAccessibilityNodeInfo(
+ virtualViewId,
+ info,
+ extraDataKey,
+ arguments,
+ )
+ }
+
+ override fun findAccessibilityNodeInfosByText(
+ text: String?,
+ virtualViewId: Int,
+ ): MutableList<AccessibilityNodeInfo?>? {
+ return getParent()?.findAccessibilityNodeInfosByText(text, virtualViewId)
+ }
+
+ override fun findFocus(focus: Int): AccessibilityNodeInfo? {
+ return getParent()?.findFocus(focus)
+ }
+ }
+
+ override fun getAccessibilityNodeProvider(): AccessibilityNodeProvider? {
+ val p = super.getAccessibilityNodeProvider()
+ if (p != null && a11yManager.isEnabled) {
+ return a11yNodeProvider
+ }
+ return p
+ }
+
+ override fun onCreateInputConnection(outAttrs: EditorInfo?): InputConnection? {
+ val inputConnection = super.onCreateInputConnection(outAttrs)
+ if (outAttrs != null) {
+ outAttrs.inputType = outAttrs.inputType or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
+ }
+ return inputConnection
+ }
+
+ companion object {
+ // Maximum length of texts the talk back announcements can be. This value is somewhat
+ // arbitrarily set. We may want to adjust this in the future.
+ private const val TEXT_TOO_LONG_TO_ANNOUNCE = 200
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
deleted file mode 100644
index f262f1f..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.ResultReceiver;
-import android.system.virtualmachine.VirtualMachine;
-import android.system.virtualmachine.VirtualMachineConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.Disk;
-import android.system.virtualmachine.VirtualMachineException;
-import android.util.Log;
-import android.widget.Toast;
-
-import io.grpc.Grpc;
-import io.grpc.InsecureServerCredentials;
-import io.grpc.Metadata;
-import io.grpc.Server;
-import io.grpc.ServerCall;
-import io.grpc.ServerCallHandler;
-import io.grpc.ServerInterceptor;
-import io.grpc.Status;
-import io.grpc.okhttp.OkHttpServerBuilder;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Objects;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class VmLauncherService extends Service implements DebianServiceImpl.DebianServiceCallback {
- private static final String EXTRA_NOTIFICATION = "EXTRA_NOTIFICATION";
- private static final String ACTION_START_VM_LAUNCHER_SERVICE =
- "android.virtualization.START_VM_LAUNCHER_SERVICE";
-
- public static final String ACTION_STOP_VM_LAUNCHER_SERVICE =
- "android.virtualization.STOP_VM_LAUNCHER_SERVICE";
-
- private static final int RESULT_START = 0;
- private static final int RESULT_STOP = 1;
- private static final int RESULT_ERROR = 2;
- private static final int RESULT_IPADDR = 3;
- private static final String KEY_VM_IP_ADDR = "ip_addr";
-
- private ExecutorService mExecutorService;
- private VirtualMachine mVirtualMachine;
- private ResultReceiver mResultReceiver;
- private Server mServer;
- private DebianServiceImpl mDebianService;
- private PortNotifier mPortNotifier;
-
- private static Intent getMyIntent(Context context) {
- return new Intent(context.getApplicationContext(), VmLauncherService.class);
- }
-
- public interface VmLauncherServiceCallback {
- void onVmStart();
-
- void onVmStop();
-
- void onVmError();
-
- void onIpAddrAvailable(String ipAddr);
- }
-
- public static void run(
- Context context, VmLauncherServiceCallback callback, Notification notification) {
- Intent i = getMyIntent(context);
- if (i == null) {
- return;
- }
- ResultReceiver resultReceiver =
- new ResultReceiver(new Handler(Looper.myLooper())) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (callback == null) {
- return;
- }
- switch (resultCode) {
- case RESULT_START:
- callback.onVmStart();
- return;
- case RESULT_STOP:
- callback.onVmStop();
- return;
- case RESULT_ERROR:
- callback.onVmError();
- return;
- case RESULT_IPADDR:
- callback.onIpAddrAvailable(resultData.getString(KEY_VM_IP_ADDR));
- return;
- }
- }
- };
- i.putExtra(Intent.EXTRA_RESULT_RECEIVER, getResultReceiverForIntent(resultReceiver));
- i.putExtra(VmLauncherService.EXTRA_NOTIFICATION, notification);
- context.startForegroundService(i);
- }
-
- private static ResultReceiver getResultReceiverForIntent(ResultReceiver r) {
- Parcel parcel = Parcel.obtain();
- r.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- r = ResultReceiver.CREATOR.createFromParcel(parcel);
- parcel.recycle();
- return r;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- if (Objects.equals(intent.getAction(), ACTION_STOP_VM_LAUNCHER_SERVICE)) {
-
- if (mDebianService != null && mDebianService.shutdownDebian()) {
- // During shutdown, change the notification content to indicate that it's closing
- Notification notification = createNotificationForTerminalClose();
- getSystemService(NotificationManager.class).notify(this.hashCode(), notification);
- } else {
- // If there is no Debian service or it fails to shutdown, just stop the service.
- stopSelf();
- }
- return START_NOT_STICKY;
- }
- if (mVirtualMachine != null) {
- Log.d(TAG, "VM instance is already started");
- return START_NOT_STICKY;
- }
- mExecutorService =
- Executors.newCachedThreadPool(new TerminalThreadFactory(getApplicationContext()));
-
- InstalledImage image = InstalledImage.getDefault(this);
- ConfigJson json = ConfigJson.from(this, image.getConfigPath());
- VirtualMachineConfig.Builder configBuilder = json.toConfigBuilder(this);
- VirtualMachineCustomImageConfig.Builder customImageConfigBuilder =
- json.toCustomImageConfigBuilder(this);
- if (overrideConfigIfNecessary(customImageConfigBuilder)) {
- configBuilder.setCustomImageConfig(customImageConfigBuilder.build());
- }
- VirtualMachineConfig config = configBuilder.build();
-
- Runner runner;
- try {
- android.os.Trace.beginSection("vmCreate");
- runner = Runner.create(this, config);
- android.os.Trace.endSection();
- android.os.Trace.beginAsyncSection("debianBoot", 0);
- } catch (VirtualMachineException e) {
- throw new RuntimeException("cannot create runner", e);
- }
- mVirtualMachine = runner.getVm();
- mResultReceiver =
- intent.getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER, ResultReceiver.class);
-
- runner.getExitStatus()
- .thenAcceptAsync(
- success -> {
- if (mResultReceiver != null) {
- mResultReceiver.send(success ? RESULT_STOP : RESULT_ERROR, null);
- }
- stopSelf();
- });
- Path logPath = getFileStreamPath(mVirtualMachine.getName() + ".log").toPath();
- Logger.setup(mVirtualMachine, logPath, mExecutorService);
-
- Notification notification =
- intent.getParcelableExtra(EXTRA_NOTIFICATION, Notification.class);
-
- startForeground(this.hashCode(), notification);
-
- mResultReceiver.send(RESULT_START, null);
-
- mPortNotifier = new PortNotifier(this);
- startDebianServer();
-
- return START_NOT_STICKY;
- }
-
- private Notification createNotificationForTerminalClose() {
- Intent stopIntent = new Intent();
- stopIntent.setClass(this, VmLauncherService.class);
- stopIntent.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE);
- PendingIntent stopPendingIntent =
- PendingIntent.getService(
- this,
- 0,
- stopIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- Icon icon = Icon.createWithResource(getResources(), R.drawable.ic_launcher_foreground);
- String stopActionText =
- getResources().getString(R.string.service_notification_force_quit_action);
- String stopNotificationTitle =
- getResources().getString(R.string.service_notification_close_title);
- return new Notification.Builder(this, this.getPackageName())
- .setSmallIcon(R.drawable.ic_launcher_foreground)
- .setContentTitle(stopNotificationTitle)
- .setOngoing(true)
- .setSilent(true)
- .addAction(
- new Notification.Action.Builder(icon, stopActionText, stopPendingIntent)
- .build())
- .build();
- }
-
- private boolean overrideConfigIfNecessary(VirtualMachineCustomImageConfig.Builder builder) {
- boolean changed = false;
- // TODO: check if ANGLE is enabled for the app.
- if (Files.exists(ImageArchive.getSdcardPathForTesting().resolve("virglrenderer"))) {
- builder.setGpuConfig(
- new VirtualMachineCustomImageConfig.GpuConfig.Builder()
- .setBackend("virglrenderer")
- .setRendererUseEgl(true)
- .setRendererUseGles(true)
- .setRendererUseGlx(false)
- .setRendererUseSurfaceless(true)
- .setRendererUseVulkan(false)
- .setContextTypes(new String[] {"virgl2"})
- .build());
- Toast.makeText(this, R.string.virgl_enabled, Toast.LENGTH_SHORT).show();
- changed = true;
- }
-
- InstalledImage image = InstalledImage.getDefault(this);
- if (image.hasBackup()) {
- Path backup = image.getBackupFile();
- builder.addDisk(Disk.RWDisk(backup.toString()));
- changed = true;
- }
- return changed;
- }
-
- private void startDebianServer() {
- ServerInterceptor interceptor =
- new ServerInterceptor() {
- @Override
- public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
- ServerCall<ReqT, RespT> call,
- Metadata headers,
- ServerCallHandler<ReqT, RespT> next) {
- // Refer to VirtualizationSystemService.TetheringService
- final String VM_STATIC_IP_ADDR = "192.168.0.2";
- InetSocketAddress remoteAddr =
- (InetSocketAddress)
- call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
-
- if (remoteAddr != null
- && Objects.equals(
- remoteAddr.getAddress().getHostAddress(),
- VM_STATIC_IP_ADDR)) {
- // Allow the request only if it is from VM
- return next.startCall(call, headers);
- }
- Log.d(TAG, "blocked grpc request from " + remoteAddr);
- call.close(Status.Code.PERMISSION_DENIED.toStatus(), new Metadata());
- return new ServerCall.Listener<ReqT>() {};
- }
- };
- try {
- // TODO(b/372666638): gRPC for java doesn't support vsock for now.
- int port = 0;
- mDebianService = new DebianServiceImpl(this, this);
- mServer =
- OkHttpServerBuilder.forPort(port, InsecureServerCredentials.create())
- .intercept(interceptor)
- .addService(mDebianService)
- .build()
- .start();
- } catch (IOException e) {
- Log.d(TAG, "grpc server error", e);
- return;
- }
-
- mExecutorService.execute(
- () -> {
- // TODO(b/373533555): we can use mDNS for that.
- String debianServicePortFileName = "debian_service_port";
- File debianServicePortFile = new File(getFilesDir(), debianServicePortFileName);
- try (FileOutputStream writer = new FileOutputStream(debianServicePortFile)) {
- writer.write(String.valueOf(mServer.getPort()).getBytes());
- } catch (IOException e) {
- Log.d(TAG, "cannot write grpc port number", e);
- }
- });
- }
-
- @Override
- public void onIpAddressAvailable(String ipAddr) {
- android.os.Trace.endAsyncSection("debianBoot", 0);
- Bundle b = new Bundle();
- b.putString(VmLauncherService.KEY_VM_IP_ADDR, ipAddr);
- mResultReceiver.send(VmLauncherService.RESULT_IPADDR, b);
- }
-
- public static void stop(Context context) {
- Intent i = getMyIntent(context);
- i.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE);
- context.startService(i);
- }
-
- @Override
- public void onDestroy() {
- if (mPortNotifier != null) {
- mPortNotifier.stop();
- }
- getSystemService(NotificationManager.class).cancelAll();
- stopDebianServer();
- if (mVirtualMachine != null) {
- if (mVirtualMachine.getStatus() == VirtualMachine.STATUS_RUNNING) {
- try {
- mVirtualMachine.stop();
- stopForeground(STOP_FOREGROUND_REMOVE);
- } catch (VirtualMachineException e) {
- Log.e(TAG, "failed to stop a VM instance", e);
- }
- }
- mExecutorService.shutdownNow();
- mExecutorService = null;
- mVirtualMachine = null;
- }
- super.onDestroy();
- }
-
- private void stopDebianServer() {
- if (mDebianService != null) {
- mDebianService.killForwarderHost();
- }
- if (mServer != null) {
- mServer.shutdown();
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
new file mode 100644
index 0000000..f8b1b45
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.net.nsd.NsdManager
+import android.net.nsd.NsdServiceInfo
+import android.os.Bundle
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.os.Parcel
+import android.os.ResultReceiver
+import android.os.Trace
+import android.system.virtualmachine.VirtualMachine
+import android.system.virtualmachine.VirtualMachineCustomImageConfig
+import android.system.virtualmachine.VirtualMachineException
+import android.util.Log
+import android.widget.Toast
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import com.android.virtualization.terminal.Runner.Companion.create
+import com.android.virtualization.terminal.VmLauncherService.VmLauncherServiceCallback
+import io.grpc.Grpc
+import io.grpc.InsecureServerCredentials
+import io.grpc.Metadata
+import io.grpc.Server
+import io.grpc.ServerCall
+import io.grpc.ServerCallHandler
+import io.grpc.ServerInterceptor
+import io.grpc.Status
+import io.grpc.okhttp.OkHttpServerBuilder
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.lang.RuntimeException
+import java.net.InetSocketAddress
+import java.net.SocketAddress
+import java.nio.file.Files
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+class VmLauncherService : Service() {
+ // TODO: using lateinit for some fields to avoid null
+ private var executorService: ExecutorService? = null
+ private var virtualMachine: VirtualMachine? = null
+ private var resultReceiver: ResultReceiver? = null
+ private var server: Server? = null
+ private var debianService: DebianServiceImpl? = null
+ private var portNotifier: PortNotifier? = null
+
+ interface VmLauncherServiceCallback {
+ fun onVmStart()
+
+ fun onVmStop()
+
+ fun onVmError()
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return null
+ }
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ if (intent.action == ACTION_STOP_VM_LAUNCHER_SERVICE) {
+ if (debianService != null && debianService!!.shutdownDebian()) {
+ // During shutdown, change the notification content to indicate that it's closing
+ val notification = createNotificationForTerminalClose()
+ getSystemService<NotificationManager?>(NotificationManager::class.java)
+ .notify(this.hashCode(), notification)
+ } else {
+ // If there is no Debian service or it fails to shutdown, just stop the service.
+ stopSelf()
+ }
+ return START_NOT_STICKY
+ }
+ if (virtualMachine != null) {
+ Log.d(TAG, "VM instance is already started")
+ return START_NOT_STICKY
+ }
+ executorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
+
+ val image = InstalledImage.getDefault(this)
+ val json = ConfigJson.from(this, image.configPath)
+ val configBuilder = json.toConfigBuilder(this)
+ val customImageConfigBuilder = json.toCustomImageConfigBuilder(this)
+ if (overrideConfigIfNecessary(customImageConfigBuilder)) {
+ configBuilder.setCustomImageConfig(customImageConfigBuilder.build())
+ }
+ val config = configBuilder.build()
+
+ Trace.beginSection("vmCreate")
+ val runner: Runner =
+ try {
+ create(this, config)
+ } catch (e: VirtualMachineException) {
+ throw RuntimeException("cannot create runner", e)
+ }
+ Trace.endSection()
+ Trace.beginAsyncSection("debianBoot", 0)
+
+ virtualMachine = runner.vm
+ resultReceiver =
+ intent.getParcelableExtra<ResultReceiver?>(
+ Intent.EXTRA_RESULT_RECEIVER,
+ ResultReceiver::class.java,
+ )
+
+ runner.exitStatus.thenAcceptAsync { success: Boolean ->
+ resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
+ stopSelf()
+ }
+ val logPath = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
+ Logger.setup(virtualMachine!!, logPath, executorService!!)
+
+ val notification =
+ intent.getParcelableExtra<Notification?>(EXTRA_NOTIFICATION, Notification::class.java)
+
+ startForeground(this.hashCode(), notification)
+
+ resultReceiver!!.send(RESULT_START, null)
+
+ portNotifier = PortNotifier(this)
+
+ // TODO: dedup this part
+ val nsdManager = getSystemService<NsdManager?>(NsdManager::class.java)
+ val info = NsdServiceInfo()
+ info.serviceType = "_http._tcp"
+ info.serviceName = "ttyd"
+ nsdManager.registerServiceInfoCallback(
+ info,
+ executorService!!,
+ object : NsdManager.ServiceInfoCallback {
+ var started: Boolean = false
+
+ override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
+
+ override fun onServiceInfoCallbackUnregistered() {}
+
+ override fun onServiceLost() {}
+
+ override fun onServiceUpdated(info: NsdServiceInfo) {
+ Log.i(TAG, "Service found: $info")
+ if (!started) {
+ started = true
+ nsdManager.unregisterServiceInfoCallback(this)
+ startDebianServer(info.hostAddresses[0].hostAddress)
+ }
+ }
+ },
+ )
+
+ return START_NOT_STICKY
+ }
+
+ private fun createNotificationForTerminalClose(): Notification {
+ val stopIntent = Intent()
+ stopIntent.setClass(this, VmLauncherService::class.java)
+ stopIntent.setAction(ACTION_STOP_VM_LAUNCHER_SERVICE)
+ val stopPendingIntent =
+ PendingIntent.getService(
+ this,
+ 0,
+ stopIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
+ )
+ val icon = Icon.createWithResource(resources, R.drawable.ic_launcher_foreground)
+ val stopActionText: String? =
+ resources.getString(R.string.service_notification_force_quit_action)
+ val stopNotificationTitle: String? =
+ resources.getString(R.string.service_notification_close_title)
+ return Notification.Builder(this, Application.CHANNEL_SYSTEM_EVENTS_ID)
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setContentTitle(stopNotificationTitle)
+ .setOngoing(true)
+ .setSilent(true)
+ .addAction(Notification.Action.Builder(icon, stopActionText, stopPendingIntent).build())
+ .build()
+ }
+
+ private fun overrideConfigIfNecessary(
+ builder: VirtualMachineCustomImageConfig.Builder
+ ): Boolean {
+ var changed = false
+ // TODO: check if ANGLE is enabled for the app.
+ if (Files.exists(ImageArchive.getSdcardPathForTesting().resolve("virglrenderer"))) {
+ builder.setGpuConfig(
+ VirtualMachineCustomImageConfig.GpuConfig.Builder()
+ .setBackend("virglrenderer")
+ .setRendererUseEgl(true)
+ .setRendererUseGles(true)
+ .setRendererUseGlx(false)
+ .setRendererUseSurfaceless(true)
+ .setRendererUseVulkan(false)
+ .setContextTypes(arrayOf<String>("virgl2"))
+ .build()
+ )
+ Toast.makeText(this, R.string.virgl_enabled, Toast.LENGTH_SHORT).show()
+ changed = true
+ }
+
+ val image = InstalledImage.getDefault(this)
+ if (image.hasBackup()) {
+ val backup = image.backupFile
+ builder.addDisk(VirtualMachineCustomImageConfig.Disk.RWDisk(backup.toString()))
+ changed = true
+ }
+ return changed
+ }
+
+ private fun startDebianServer(ipAddress: String?) {
+ val interceptor: ServerInterceptor =
+ object : ServerInterceptor {
+ override fun <ReqT, RespT> interceptCall(
+ call: ServerCall<ReqT?, RespT?>,
+ headers: Metadata?,
+ next: ServerCallHandler<ReqT?, RespT?>,
+ ): ServerCall.Listener<ReqT?>? {
+ val remoteAddr =
+ call.attributes.get<SocketAddress?>(Grpc.TRANSPORT_ATTR_REMOTE_ADDR)
+ as InetSocketAddress?
+
+ if (remoteAddr?.address?.hostAddress == ipAddress) {
+ // Allow the request only if it is from VM
+ return next.startCall(call, headers)
+ }
+ Log.d(TAG, "blocked grpc request from $remoteAddr")
+ call.close(Status.Code.PERMISSION_DENIED.toStatus(), Metadata())
+ return object : ServerCall.Listener<ReqT?>() {}
+ }
+ }
+ try {
+ // TODO(b/372666638): gRPC for java doesn't support vsock for now.
+ val port = 0
+ debianService = DebianServiceImpl(this)
+ server =
+ OkHttpServerBuilder.forPort(port, InsecureServerCredentials.create())
+ .intercept(interceptor)
+ .addService(debianService)
+ .build()
+ .start()
+ } catch (e: IOException) {
+ Log.d(TAG, "grpc server error", e)
+ return
+ }
+
+ executorService!!.execute(
+ Runnable {
+ // TODO(b/373533555): we can use mDNS for that.
+ val debianServicePortFile = File(filesDir, "debian_service_port")
+ try {
+ FileOutputStream(debianServicePortFile).use { writer ->
+ writer.write(server!!.port.toString().toByteArray())
+ }
+ } catch (e: IOException) {
+ Log.d(TAG, "cannot write grpc port number", e)
+ }
+ }
+ )
+ }
+
+ override fun onDestroy() {
+ portNotifier?.stop()
+ getSystemService<NotificationManager?>(NotificationManager::class.java).cancelAll()
+ stopDebianServer()
+ if (virtualMachine != null) {
+ if (virtualMachine!!.getStatus() == VirtualMachine.STATUS_RUNNING) {
+ try {
+ virtualMachine!!.stop()
+ stopForeground(STOP_FOREGROUND_REMOVE)
+ } catch (e: VirtualMachineException) {
+ Log.e(TAG, "failed to stop a VM instance", e)
+ }
+ }
+ executorService?.shutdownNow()
+ executorService = null
+ virtualMachine = null
+ }
+ super.onDestroy()
+ }
+
+ private fun stopDebianServer() {
+ debianService?.killForwarderHost()
+ server?.shutdown()
+ }
+
+ companion object {
+ private const val EXTRA_NOTIFICATION = "EXTRA_NOTIFICATION"
+ private const val ACTION_START_VM_LAUNCHER_SERVICE =
+ "android.virtualization.START_VM_LAUNCHER_SERVICE"
+
+ const val ACTION_STOP_VM_LAUNCHER_SERVICE: String =
+ "android.virtualization.STOP_VM_LAUNCHER_SERVICE"
+
+ private const val RESULT_START = 0
+ private const val RESULT_STOP = 1
+ private const val RESULT_ERROR = 2
+
+ private fun getMyIntent(context: Context): Intent {
+ return Intent(context.getApplicationContext(), VmLauncherService::class.java)
+ }
+
+ fun run(
+ context: Context,
+ callback: VmLauncherServiceCallback?,
+ notification: Notification?,
+ ) {
+ val i = getMyIntent(context)
+ val resultReceiver: ResultReceiver =
+ object : ResultReceiver(Handler(Looper.myLooper()!!)) {
+ override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
+ if (callback == null) {
+ return
+ }
+ when (resultCode) {
+ RESULT_START -> callback.onVmStart()
+ RESULT_STOP -> callback.onVmStop()
+ RESULT_ERROR -> callback.onVmError()
+ }
+ }
+ }
+ i.putExtra(Intent.EXTRA_RESULT_RECEIVER, getResultReceiverForIntent(resultReceiver))
+ i.putExtra(EXTRA_NOTIFICATION, notification)
+ context.startForegroundService(i)
+ }
+
+ private fun getResultReceiverForIntent(r: ResultReceiver): ResultReceiver {
+ val parcel = Parcel.obtain()
+ r.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ return ResultReceiver.CREATOR.createFromParcel(parcel).also { parcel.recycle() }
+ }
+
+ fun stop(context: Context) {
+ val i = getMyIntent(context)
+ i.setAction(ACTION_STOP_VM_LAUNCHER_SERVICE)
+ context.startService(i)
+ }
+ }
+}
diff --git a/android/TerminalApp/res/layout/activity_error.xml b/android/TerminalApp/res/layout/activity_error.xml
index 054478f..c0409a7 100644
--- a/android/TerminalApp/res/layout/activity_error.xml
+++ b/android/TerminalApp/res/layout/activity_error.xml
@@ -51,7 +51,9 @@
android:layout_marginTop="24dp"
android:layout_marginHorizontal="60dp"
android:layout_below="@id/desc"
- android:textSize="14sp" />
+ android:textSize="14sp"
+ android:scrollbars="vertical|horizontal"
+ android:scrollHorizontally="true" />
<Button
android:id="@+id/recovery"
diff --git a/android/TerminalApp/res/layout/activity_headless.xml b/android/TerminalApp/res/layout/activity_headless.xml
index b4a65cc..e18aa5c 100644
--- a/android/TerminalApp/res/layout/activity_headless.xml
+++ b/android/TerminalApp/res/layout/activity_headless.xml
@@ -48,7 +48,6 @@
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
- android:id="@+id/webview_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="5dp"
@@ -59,7 +58,6 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
- <include layout="@layout/layout_modifier_keys" />
</LinearLayout>
</FrameLayout>
diff --git a/android/TerminalApp/res/layout/layout_modifier_keys.xml b/android/TerminalApp/res/layout/modifier_keys_doubleline.xml
similarity index 100%
rename from android/TerminalApp/res/layout/layout_modifier_keys.xml
rename to android/TerminalApp/res/layout/modifier_keys_doubleline.xml
diff --git a/android/TerminalApp/res/layout/modifier_keys_singleline.xml b/android/TerminalApp/res/layout/modifier_keys_singleline.xml
new file mode 100644
index 0000000..6ccf48f
--- /dev/null
+++ b/android/TerminalApp/res/layout/modifier_keys_singleline.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<!--TODO(b/376813452): we might want tablet UI for that-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/modifier_keys"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_esc"
+ android:textSize="10sp"
+ android:text="@string/btn_esc_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_tab"
+ android:textSize="10sp"
+ android:text="@string/btn_tab_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_ctrl"
+ android:textSize="10sp"
+ android:text="@string/btn_ctrl_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_alt"
+ android:textSize="10sp"
+ android:text="@string/btn_alt_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_home"
+ android:textSize="10sp"
+ android:text="@string/btn_home_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_end"
+ android:textSize="10sp"
+ android:text="@string/btn_end_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_left"
+ android:textSize="10sp"
+ android:text="@string/btn_left_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_down"
+ android:textSize="10sp"
+ android:text="@string/btn_down_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_up"
+ android:textSize="10sp"
+ android:text="@string/btn_up_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_right"
+ android:textSize="10sp"
+ android:text="@string/btn_right_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_pgdn"
+ android:textSize="10sp"
+ android:text="@string/btn_pgdn_text" />
+ <Button
+ style="@style/ModifierKeyStyle"
+ android:id="@+id/btn_pgup"
+ android:textSize="10sp"
+ android:text="@string/btn_pgup_text" />
+</LinearLayout>
diff --git a/android/TerminalApp/res/values-af/strings.xml b/android/TerminalApp/res/values-af/strings.xml
index b5b47d9..1e8d8ff 100644
--- a/android/TerminalApp/res/values-af/strings.xml
+++ b/android/TerminalApp/res/values-af/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminaal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminaalskerm"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Skermpyltjie"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Leë reël"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dubbeltik om invoer te tik"</string>
<string name="installer_title_text" msgid="500663060973466805">"Installeer Linux-terminaal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"As jy Linux-terminaal wil begin, moet jy omtrent <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> se data oor die netwerk aflaai.\nWil jy voortgaan?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Laai af wanneer wi-fi beskikbaar is"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Jy sal omtrent <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> se data oor die netwerk moet aflaai om Linux Terminaal te begin.\nWil jy voortgaan?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Laai net oor wi-fi af"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installeer"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installeer tans"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Netwerkfout. Gaan verbinding na en probeer weer."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Kon weens ’n netwerkfout nie installeer nie. Gaan jou verbinding na en probeer weer."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linus-terminaal word tans geïnstalleer"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-terminaal sal begin wanneer jy klaar is"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Kon weens die netwerkkwessie nie installeer nie"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Kon nie installeer nie. Probeer weer."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux Terminaal sal begin nadat die installasie voltooi is"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Kon weens ’n netwerkkwessie nie installeer nie"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Kon nie installeer nie omdat wi-fi nie beskikbaar is nie"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Kon nie installeer nie. Probeer asseblief weer"</string>
<string name="action_settings" msgid="5729342767795123227">"Instellings"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Maak terminaal gereed"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stop tans terminaal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminaal het omgeval"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Verander grootte van skyf"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Verander grootte / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Verander grootte van skyf"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Verander die grootte van die kernafdeling"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Skyfgrootte is gestel"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> toegewys"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> maks."</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Kanselleer"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Herbegin om aansoek te doen"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Poortaanstuur"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Stel poortaanstuur op"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminaal probeer om ’n nuwe poort oop te maak"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Poort versoek om oop te wees: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Pas toe"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminaal sal herbegin word om die skyf se grootte te verander"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Bevestig"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Poortkontrole"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Laat luisterpoorte toe of weier hulle"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Luisterpoorte"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Het toegelate poorte gestoor"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Voeg by"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Vee <xliff:g id="PORT_NUMBER">%d</xliff:g> uit"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Laat ’n nuwe poort toe"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Voer ’n nuwe poortnommer in"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Stoor"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Kanselleer"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Voer ’n nommer in"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ongeldige poortnommer"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Poort bestaan reeds"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminaal probeer om ’n nuwe poort oop te maak"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Poort versoek: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aanvaar"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Weier"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Herwin"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Afdelingherwinningopsies"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Verander na aanvanklike weergawe"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Verwyder almal"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Afdelingherwinningopsies"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Stel terug na aanvanklike weergawe"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Verwyder alle -data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Stel terminaal terug"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data sal uitgevee word"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Bevestig"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data sal verwyder word"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Stel terug"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Kanselleer"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Rugsteun data na <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Terugstel het misluk omdat rugsteun misluk het"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Kon weens ’n rugsteunfout nie terugstel nie"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Kon nie terugstel nie"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Kan nie rugsteunlêer verwyder nie"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Kon nie rugsteundata verwyder nie"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Verwyder rugsteundata"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Maak skoon <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Verwyder <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Onterugstelbare fout"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Kon nie ná ’n fout terugstel nie.\nJy kan probeer om die terminaal te herbegin of een van die herwinningopsies probeer.\nAs alle pogings misluk, vee alle data skoon deur Linux-terminaal in ontwikkelaaropsies aan/af te skakel."</string>
+ <string name="error_code" msgid="3585291676855383649">"Foutkode: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Instellings"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminaal loop tans"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klik om die terminaal oop te maak"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klik om Terminaal oop te maak"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Maak toe"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminaal maak toe"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Verplig toemaak"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> is geaktiveer"</string>
</resources>
diff --git a/android/TerminalApp/res/values-am/strings.xml b/android/TerminalApp/res/values-am/strings.xml
index aa97b52..faa7339 100644
--- a/android/TerminalApp/res/values-am/strings.xml
+++ b/android/TerminalApp/res/values-am/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ተርሚናል"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ተርሚናል ማሳያ"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"ጠቋሚ"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ባዶ መስመር"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ግብዓት ለመተየብ ሁለቴ መታ ያድርጉ"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ተርሚናልን ይጫኑ"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ተርሚናልን ለማስጀመር በአውታረ መረብ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> የሚገመት ውሂብ ማውረድ ያስፈልግዎታል። \nይቀጥላሉ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi ሲገኝ አውርድ"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ተርሚናልን ለማስጀመር በአውታረ መረቡ ላይ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> የሚሆን ውሂብ ማውረድ ያስፈልግዎታል። \nመቀጠል ይፈልጋሉ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fi ብቻ በመጠቀም አውርድ"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ጫን"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"በመጫን ላይ"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"የአውታረ መረብ ስህተት። ግንኙነት ይፈትሹ እና እንደገና ይሞክሩ።"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"በአውታረ መረብ ስሕተት ምክንያት መጫን አልተሳካም። ግንኙነትዎን ይፈትሹ እና እንደገና ይሞክሩ።"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ተርሚናልን በመጫን ላይ"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux ተርሚናል ከጨረሰ በኋላ ይጀምራል"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"በአውታረ መረብ ችግር ምክንያት መጫን አልተሳካም"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"መጫን አልተሳካም። እንደገና ይሞክሩ።"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ጭነቱ ከተጠናቀቀ በኋላ Linux ተርሚናል ይጀምራል።"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"በአውታረ መረቡ ችግር ምክንያት መጫን አልተሳካም"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi ስለማይገኝ መጫን አልተሳካም"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"መጫን አልተሳካም። እባክዎ እንደገና ይሞክሩ"</string>
<string name="action_settings" msgid="5729342767795123227">"ቅንብሮች"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ተርሚናልን በማዘጋጀት ላይ"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ተርሚናልን በማቆም ላይ"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ተርሚናል ተበላሽቷል"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"የዲስክ መጠን ቀይር"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"መጠን ቀይር / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"የዲስክ መጠንን ቀይር"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"የስር ክፍልፋይ መጠንን ቀይር"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"የዲስክ መጠን ተቀናብሯል"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ተመድቧል"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> ከፍተኛ"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ይቅር"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"ለመተግበር እንደገና ይጀምሩ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ወደብ ማስተላለፍ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ወደብ ማስተላለፍን ያዋቅሩ"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ተርሚናል አዲስ ወደብ ለመክፈት እየሞከረ ነው"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"እንዲከፈት የተጠየቀ ወደብ፦ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ተግብር"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"የዲስክ መጠንን ለመቀየር ተርሚናል እንደገና ይጀምራል"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"አረጋግጥ"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"የወደብ ቁጥጥር"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"የማዳመጫ ወደቦችን ይፍቀዱ/ይከልክሉ"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"የማዳመጫ ወደቦች"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"የተቀመጡ የሚፈቀዱ ወደቦች"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"አክል"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>ን ሰርዝ"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"አዲስ ወደብ ይፍቀዱ"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"አዲስ የወደብ ቁጥር ያስገቡ"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"አስቀምጥ"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ይቅር"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"እባክዎ ቁጥር ያስገቡ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ልክ ያልሆነ የወደብ ቁጥር"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ወደብ ቀድሞውኑ ይገኛል"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ተርሚናል አዲስ ወደብ ለመክፈት እየጠየቀ ነው"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"የተጠየቀ ወደብ፦ <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ተቀበል"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ከልክል"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"መልሶ ማግኘት"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"የክፍልፋይ መልሶ ማግኛ አማራጮች"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ወደ የመጀመሪያ ሥሪት ለውጥ"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"ሁሉንም አስወግድ"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"የክፍልፋይ መልሶ ማግኛ አማራጮች"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ወደ የመጀመሪያ ሥሪት ዳግም አስጀምር"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ሁሉንም ውሂብ አስወግድ"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ተርሚናልን ዳግም አስጀምር"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ውሂብ ይሰረዛል"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"አረጋግጥ"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ውሂብ ይወገዳል"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ዳግም አስጀምር"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ይቅር"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"ውሂብን ወደ <xliff:g id="PATH">/mnt/backup</xliff:g> ምትኬ አስቀምጥ"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ምትኬ ስላልተሳካ መልሶ ማግኘት አልተሳካም"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"በምትኬ ስሕተት ምክንያት መልሶ ማግኘት አልተሳካም"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"መልሶ ማግኘት አልተሳካም"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"የመጠባበቂያ ፋይልን ማስወገድ አይቻልም"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"የምትኬ ውሂብን ማስወገድ አልተሳካም"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ምትኬ ውሂብን አስወግድ"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> አጽዳ"</string>
- <string name="error_title" msgid="7196464038692913778">"ሊመለስ የማይችል ስሕተት"</string>
- <string name="error_desc" msgid="1939028888570920661">"ከስሕተት መልሶ ማግኘት አልተሳካም።\nመተግበሪያውን እንደገና ለማስጀመር መሞከር ወይም አንዱን የመልሶ ማግኛ አማራጭ መሞከር ይችላሉ።"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> አስወግድ"</string>
+ <string name="error_title" msgid="405150657301906598">"ሊመለስ የማይችል ስሕተት"</string>
+ <string name="error_desc" msgid="4588252235686826721">"ከስሕተት መልሶ ማግኘት አልተሳካም።\nተርሚናልን እንደገና ማስጀመርን መሞከር ወይም ከመልሶ ማግኛ አማራጮች አንዱን መሞከር ይችላሉ።\nሁሉም ሙከራዎች ካልተሳኩ Linux ተርሚናልን ከገንቢ አማራጮች ላይ በማብራት/ማጥፋት ሁሉንም ውሂብ ይጥረጉ።"</string>
<string name="error_code" msgid="3585291676855383649">"የስሕተት ኮድ፦ <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ቅንብሮች"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ተርሚናል በመሄድ ላይ ነው"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ተርሚናሉን ለመክፈት ጠቅ ያድርጉ"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ተርሚናልን ለመክፈት ጠቅ ያድርጉ"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"ዝጋ"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ተርሚናል በመዝጋት ላይ ነው"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"በግድ ዝጋ"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ነቅቷል"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ar/strings.xml b/android/TerminalApp/res/values-ar/strings.xml
index 5f9ad2e..9d1f2b7 100644
--- a/android/TerminalApp/res/values-ar/strings.xml
+++ b/android/TerminalApp/res/values-ar/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"شاشة الوحدة الطرفية"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"المؤشر"</string>
+ <string name="empty_line" msgid="5012067143408427178">"سطر فارغ"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"انقر مرّتين لإدخال نص"</string>
<string name="installer_title_text" msgid="500663060973466805">"تثبيت الوحدة الطرفية بنظام التشغيل Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"لتشغيل الوحدة الطرفية بنظام التشغيل Linux، عليك تنزيل <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> من البيانات تقريبًا عبر الشبكة.\nهل تريد المتابعة؟"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"التنزيل عند توفُّر شبكة Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"لتشغيل وحدة Linux الطرفية، عليك تنزيل <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> من البيانات تقريبًا عبر الشبكة.\nهل تريد المتابعة؟"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"التنزيل باستخدام Wi-Fi فقط"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"تثبيت"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"جارٍ التثبيت"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"حدث خطأ في الشبكة. يُرجى التحقُّق من الاتصال وإعادة المحاولة."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"تعذَّر التثبيت بسبب خطأ في الشبكة. يُرجى التأكُّد من الاتصال وإعادة المحاولة."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"جارٍ تثبيت الوحدة الطرفية بنظام التشغيل Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"سيتم تشغيل الوحدة الطرفية بنظام التشغيل Linux بعد الانتهاء"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"تعذَّر التثبيت بسبب مشكلة في الشبكة"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"تعذَّر التثبيت. يُرجى إعادة المحاولة."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"سيتم تشغيل وحدة Linux الطرفية بعد اكتمال عملية التثبيت"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"تعذَّر التثبيت بسبب مشكلة في الشبكة"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"تعذَّر التثبيت لأنّ شبكة Wi-Fi غير متاحة"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"تعذَّر التثبيت. يُرجى إعادة المحاولة"</string>
<string name="action_settings" msgid="5729342767795123227">"الإعدادات"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"جارٍ تحضير Terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"جارٍ إيقاف Terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"تعطَّل Terminal"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"تغيير حجم القرص"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"تغيير الحجم / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"تغيير حجم القرص"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"تغيير حجم قسم الجذر"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"تم ضبط حجم القرص"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"تم تخصيص <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> كحد أقصى"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"إلغاء"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"إعادة التشغيل لتطبيق التغييرات"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"إعادة توجيه المنفذ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ضبط إعادة توجيه المنفذ"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"تحاول الوحدة الطرفية فتح منفذ جديد"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"المنفذ المطلوب فتحه: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"تطبيق"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ستتم إعادة تشغيل الوحدة الطرفية لتغيير حجم القرص"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"تأكيد"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"التحكّم في المنافذ"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"السماح بمنافذ الاستماع أو حظرها"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"منافذ الاستماع"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"المنافذ المسموح بها المحفوظة"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"إضافة"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"حذف <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"السماح بمنفذ جديد"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"إدخال رقم منفذ جديد"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"حفظ"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"إلغاء"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"يُرجى إدخال رقم"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"رقم المنفذ غير صالح"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"المنفذ متوفِّر حاليًا"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"تطلُب الوحدة الطرفية فتح منفذ جديد"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"المنفذ المطلوب: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"قبول"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"رفض"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"الاسترداد"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"خيارات استرداد القسم"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"التبديل إلى الإصدار الأولي"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"إزالة الكل"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"خيارات استرداد القسم"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"إعادة الضبط إلى الإصدار الأوليّ"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"إزالة كل البيانات"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"إعادة ضبط الوحدة الطرفية"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"سيتم حذف البيانات"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"تأكيد"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ستتم إزالة البيانات"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"إعادة الضبط"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"إلغاء"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"الاحتفاظ بنسخة احتياطية من البيانات في <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"تعذّر الاسترداد بسبب عدم نجاح عملية الاحتفاظ بنسخة احتياطية"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"تعذَّر الاسترداد بسبب حدوث خطأ في النسخة الاحتياطية"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"تعذّر الاسترداد"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"تتعذّر إزالة ملف النسخة الاحتياطية"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"تعذَّرت إزالة بيانات النسخة الاحتياطية"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"إزالة بيانات النسخة الاحتياطية"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"حذف بيانات النسخة الاحتياطية في <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"خطأ غير قابل للإصلاح"</string>
- <string name="error_desc" msgid="1939028888570920661">"تعذَّر استرداد البيانات من خطأ.\nيمكنك محاولة إعادة تشغيل التطبيق أو تجربة أحد خيارات استرداد الحساب."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"إزالة بيانات <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"خطأ غير قابل للإصلاح"</string>
+ <string name="error_desc" msgid="4588252235686826721">"تعذَّر استرداد البيانات من خطأ.\nيمكنك محاولة إعادة تشغيل الوحدة الطرفية أو تجربة أحد خيارات استرداد الحساب.\nإذا فشلت كل المحاولات، يمكنك حجب كل البيانات من خلال تفعيل وحدة Linux الطرفية أو إيقافها من \"خيارات المطوّرين\"."</string>
<string name="error_code" msgid="3585291676855383649">"رمز الخطأ: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"الإعدادات"</string>
<string name="service_notification_title" msgid="2918088850910713393">"الوحدة الطرفية قيد التشغيل"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"انقر لفتح الوحدة الطرفية"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"انقر لفتح الوحدة الطرفية"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"إغلاق"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"جارٍ إغلاق الوحدة الطرفية"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"فرض الإغلاق"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"تم تفعيل <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-as/strings.xml b/android/TerminalApp/res/values-as/strings.xml
index ce4f6ab..630efc4 100644
--- a/android/TerminalApp/res/values-as/strings.xml
+++ b/android/TerminalApp/res/values-as/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"টাৰ্মিনেল"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"টাৰ্মিনেল ডিছপ্লে’"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"কাৰ্ছৰ"</string>
+ <string name="empty_line" msgid="5012067143408427178">"খালী শাৰী"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ইনপুট টাইপ কৰিবলৈ দুবাৰ টিপক"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux টাৰ্মিনেল ইনষ্টল কৰক"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux টাৰ্মিনেল লঞ্চ কৰিবলৈ, আপুনি নেটৱৰ্কত প্ৰায় <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ডেটা ডাউনল’ড কৰিব লাগিব।\nআপুনি আগবাঢ়িবনে?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ৱাই-ফাই সেৱা উপলব্ধ হ’লে ডাউনল’ড কৰক"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux টাৰ্মিনেল লঞ্চ কৰিবলৈ, আপুনি নেটৱৰ্কত প্ৰায় <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ডেটা ডাউনল’ড কৰিব লাগিব।\nআপুনি আগবাঢ়িবনে?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"কেৱল ৱাই-ফাই ব্যৱহাৰ কৰি ডাউনল’ড কৰক"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ইনষ্টল কৰক"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ইনষ্টল কৰি থকা হৈছে"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"নেটৱৰ্কৰ আসোঁৱাহ। সংযোগ পৰীক্ষা কৰক আৰু পুনৰ চেষ্টা কৰক।"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"নেটৱৰ্ক সম্পৰ্কীয় সমস্যাৰ বাবে ইনষ্টল কৰিব পৰা নগ’ল। আপোনাৰ সংযোগ পৰীক্ষা কৰি পুনৰ চেষ্টা কৰক।"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux টাৰ্মিনেল ইনষ্টল কৰি থকা হৈছে"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"সমাপ্ত হোৱাৰ পাছত Linux টাৰ্মিনেল আৰম্ভ কৰা হ’ব"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"নেটৱৰ্ক সম্পৰ্কীয় সমস্যাৰ বাবে ইনষ্টল কৰিব পৰা নগ’ল"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ইনষ্টল কৰিব পৰা নগ’ল। পুনৰ চেষ্টা কৰক।"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux টাৰ্মিনেল ইনষ্টলেশ্বন সম্পূৰ্ণ হোৱাৰ পাছত আৰম্ভ হ\'ব"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"নেটৱৰ্ক সম্পৰ্কীয় সমস্যাৰ বাবে ইনষ্টল কৰিব পৰা নগ’ল"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ৱাই-ফাই উপলব্ধ নোহোৱাৰ কাৰণে ইনষ্টল কৰিব পৰা নগ’ল"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ইনষ্টল কৰিব পৰা নগ’ল। অনুগ্ৰহ কৰি পুনৰ চেষ্টা কৰক"</string>
<string name="action_settings" msgid="5729342767795123227">"ছেটিং"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"টাৰ্মিনেল সাজু কৰি থকা হৈছে"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"টাৰ্মিনেল বন্ধ কৰি থকা হৈছে"</string>
<string name="vm_error_message" msgid="5231867246177661525">"টাৰ্মিনেল ক্ৰেশ্ব হৈছে"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ডিস্কৰ আকাৰ সলনি কৰক"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"আকাৰ সলনি কৰক / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ডিস্কৰ আকাৰ সলনি কৰক"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ৰুট পাৰ্টিশ্বনৰ আকাৰ সলনি কৰক"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ডিস্কৰ আকাৰ ছেট কৰা হৈছে"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> আৱণ্টন কৰা হৈছে"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"সৰ্বাধিক <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"বাতিল কৰক"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"প্ৰয়োগ কৰিবলৈ ৰিষ্টাৰ্ট কৰক"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"প’ৰ্ট ফৰৱাৰ্ডিং"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"প’ৰ্ট ফৰৱাৰ্ডিং কনফিগাৰ কৰক"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"টাৰ্মিনেলটোৱে এটা নতুন প’ৰ্ট খুলিবলৈ চেষ্টা কৰি আছে"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"প’ৰ্ট খোলা ৰখাৰ বাবে অনুৰোধ কৰা হৈছে: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"প্ৰয়োগ কৰক"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ডিস্কৰ আকাৰ সলনি কৰিবলৈ টাৰ্মিনেলটো ৰিষ্টাৰ্ট কৰা হ\'ব"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"নিশ্চিত কৰক"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"প’ৰ্ট নিয়ন্ত্ৰণ"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"শুনা প’ৰ্টৰ অনুমতি দিয়ক/অস্বীকাৰ কৰক"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"শুনা প’ৰ্ট"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ছেভ কৰা অনুমোদিত প’ৰ্ট"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"যোগ দিয়ক"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> মচক"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"এটা নতুন প’ৰ্টৰ অনুমতি দিয়ক"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"এটা নতুন প’ৰ্ট নম্বৰ দিয়ক"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"ছেভ কৰক"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"বাতিল কৰক"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"অনুগ্ৰহ কৰি এটা নম্বৰ দিয়ক"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"অমান্য প’ৰ্টৰ নম্বৰ"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"প’ৰ্ট ইতিমধ্যে আছে"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"টাৰ্মিনেলটোৱে এটা নতুন প’ৰ্ট খুলিবলৈ অনুৰোধ কৰি আছে"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"প’ৰ্ট অনুৰোধ কৰা হৈছে: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"গ্ৰহণ কৰক"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"অস্বীকাৰ কৰক"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"পুনৰুদ্ধাৰ"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"পাৰ্টিশ্বন পুনৰুদ্ধাৰৰ বিকল্প"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"প্ৰাৰম্ভিক সংস্কৰণলৈ সলনি কৰক"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"আটাইবোৰ আঁতৰাওক"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"পাৰ্টিশ্বন পুনৰুদ্ধাৰৰ বিকল্প"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"প্ৰাৰম্ভিক সংস্কৰণলৈ ৰিছেট কৰক"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"আটাইবোৰ ডেটা আঁতৰাওক"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"টাৰ্মিনেল ৰিছেট কৰক"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ডেটাখিনি মচা হ’ব"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"নিশ্চিত কৰক"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ডেটাখিনি আঁতৰোৱা হ\'ব"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ৰিছেট কৰক"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"বাতিল কৰক"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g>লৈ ডেটাৰ বেকআপ লওক"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"বেকআপ ল\'ব পৰা নগ\'ল বাবে পুনৰুদ্ধাৰ কৰিব পৰা নগ’ল"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"বেকআপ সম্পৰ্কীয় এটা আসোঁৱাহৰ বাবে পুনৰুদ্ধাৰ কৰিব পৰা নগ\'ল"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"পুনৰুদ্ধাৰ কৰিব পৰা নগ’ল"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"বেকআপ লোৱা ফাইল আঁতৰাব নোৱাৰি"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"বেকআপৰ ডেটা আঁতৰাব পৰা নগ\'ল"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"বেকআপ লোৱা ডেটা আঁতৰাওক"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> মচক"</string>
- <string name="error_title" msgid="7196464038692913778">"পুনৰুদ্ধাৰ কৰিব নোৱৰা আসোঁৱাহ"</string>
- <string name="error_desc" msgid="1939028888570920661">"এটা আসোঁৱাহৰ পৰা পুনৰুদ্ধাৰ কৰিব পৰা নগ’ল।\nআপুনি এপ্টো ৰিষ্টাৰ্ট কৰি চাব পাৰে বা পুনৰুদ্ধাৰৰ বিকল্পসমূহৰ মাজৰ পৰা এটা ব্যৱহাৰ কৰি চাব পাৰে।"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> আঁতৰাওক"</string>
+ <string name="error_title" msgid="405150657301906598">"পুনৰুদ্ধাৰ কৰিব নোৱৰা আসোঁৱাহ"</string>
+ <string name="error_desc" msgid="4588252235686826721">"এটা আসোঁৱাহৰ পৰা পুনৰুদ্ধাৰ কৰিব পৰা নগ’ল।\nআপুনি টাৰ্মিনেলটো ৰিষ্টাৰ্ট কৰি চাব পাৰে বা পুনৰুদ্ধাৰৰ বিকল্পসমূহৰ মাজৰ পৰা এটা ব্যৱহাৰ কৰি চাব পাৰে।\nযদি আটাইবোৰ প্ৰয়াস বিফল হয়, বিকাশকৰ্তাৰ বিকল্পসমূহৰ পৰা Linux টাৰ্মিনেল অন/অফ কৰি আটাইবোৰ ডেটা মচি পেলাওক।"</string>
<string name="error_code" msgid="3585291676855383649">"আসোঁৱাহ ক’ড: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ছেটিং"</string>
<string name="service_notification_title" msgid="2918088850910713393">"টাৰ্মিনেলটো চলি আছে"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"টাৰ্মিনেলটো খুলিবলৈ ক্লিক কৰক"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"টাৰ্মিনেল খুলিবলৈ ক্লিক কৰক"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"বন্ধ কৰক"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"টাৰ্মিনেলটো বন্ধ কৰি থকা হৈছে"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"বলেৰে বন্ধ কৰক"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> সক্ষম কৰা আছে"</string>
</resources>
diff --git a/android/TerminalApp/res/values-az/strings.xml b/android/TerminalApp/res/values-az/strings.xml
index f816d81..7c134f0 100644
--- a/android/TerminalApp/res/values-az/strings.xml
+++ b/android/TerminalApp/res/values-az/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminal displeyi"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Boş sətir"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Mətn daxil etmək üçün iki dəfə toxunun"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux terminalını quraşdırın"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux terminalını işə salmaq üçün şəbəkə vasitəsilə təxminən <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> həcmində data endirməlisiniz.\nDavam etmək istəyirsiniz?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi əlçatan olduqda endirin"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux terminalını işə salmaq üçün şəbəkə vasitəsilə təxminən <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> həcmində data endirməlisiniz.\nDavam etmək istəyirsiniz?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Yalnız Wi-Fi istifadə edərək endirin"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Quraşdırın"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Quraşdırılır"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Şəbəkə xətası. Bağlantını yoxlayıb yenidən cəhd edin."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Şəbəkə xətası səbəbilə quraşdırmaq alınmadı. Bağlantını yoxlayın və yenidən cəhd edin."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux terminalı quraşdırılır"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Tamamlandıqan sonra Linux terminalı işə salınacaq"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Şəbəkə problemi səbəbilə quraşdırmaq alınmadı"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Quraşdırmaq alınmadı. Yenidən cəhd edin."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Quraşdırma tamamlandıqdan sonra Linux terminalı işə düşəcək"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Şəbəkə problemi səbəbilə quraşdırmaq alınmadı"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi əlçatan olmadığı üçün quraşdırmaq alınmadı"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Quraşdırmaq alınmadı. Yenidən cəhd edin"</string>
<string name="action_settings" msgid="5729342767795123227">"Ayarlar"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminal hazırlanır"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminal dayandırılır"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal çökdü"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Disk ölçüsü dəyişdirilməsi"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Yenidən ölçüləndirin / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Disk ölçüsünün dəyişdirilməsi"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Kök bölməsinin ölçüsünü dəyişin"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disk ölçüsü ayarlandı"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> təyin edildi"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"maks <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Ləğv edin"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Tətbiq etmək üçün yenidən başladın"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Port yönləndirməsi"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Port yönləndirməsini konfiqurasiya edin"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal yeni port açmağa çalışır"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Portun açıq olması tələb edildi: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Tətbiq edin"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Diskin ölçüsünü dəyişmək üçün terminal yenidən başladılacaq"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Təsdiq edin"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port nəzarəti"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dinləmə portlarına icazə verin/imtina edin"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Dinləmə portları"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Yadda saxlanılmış icazə verilən portlar"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Əlavə edin"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Silin: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Yeni porta icazə verin"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Yeni port nömrəsi daxil edin"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Yadda saxlayın"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Ləğv edin"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Nömrə daxil edin"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Yanlış port nömrəsi"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port artıq mövcuddur"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal yeni port açmağı tələb edir"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port tələb edildi: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Qəbul edin"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rədd edin"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Bərpa"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Bölmə üzrə bərpa seçimləri"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"İlkin versiyaya dəyişin"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Hamısını silin"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Bölmə üzrə bərpa seçimləri"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"İlkin versiyaya sıfırlayın"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Bütün datanı silin"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminalı sıfırlayın"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data silinəcək"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Təsdiq edin"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data silinəcək"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Sıfırlayın"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Ləğv edin"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Datanı buraya yedəkləyin: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Yedəkləmə alınmadığı üçün bərpa etmək mümkün olmadı"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Yedəkləmə xətası səbəbilə bərpa olunmadı"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Bərpa etmək alınmadı"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Yedək faylı silmək mümkün deyil"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Yedək datanı silmək alınmadı"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Yedək datanı silin"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Təmizləyin: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Düzəldilməyən xəta"</string>
- <string name="error_desc" msgid="1939028888570920661">"Xətanı bərpa etmək alınmadı.\nTətbiqi yenidən başladın və ya bərpa seçimlərindən birini sınayın."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Silin: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Düzəldilməyən xəta"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Xətanı bərpa edilmədi.\nTerminalı yenidən başlatmağa cəhd edə və ya bərpa seçimlərindən birini sınaya bilərsiniz.\nBütün cəhdlər uğursuz olarsa, Linux terminalını developer seçimlərindən yandırıb-söndürməklə bütün datanı silin."</string>
<string name="error_code" msgid="3585291676855383649">"Xəta kodu: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Ayarlar"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal işləyir"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Terminalı açmaq üçün klikləyin"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Terminalı açmaq üçün klikləyin"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Bağlayın"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal bağlanır"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Məcburi bağlanma"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> aktivləşdirilib"</string>
</resources>
diff --git a/android/TerminalApp/res/values-b+sr+Latn/strings.xml b/android/TerminalApp/res/values-b+sr+Latn/strings.xml
index e454a8b..0e77081 100644
--- a/android/TerminalApp/res/values-b+sr+Latn/strings.xml
+++ b/android/TerminalApp/res/values-b+sr+Latn/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Prikaz terminala"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Prazan red"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dvaput dodirnite da biste uneli tekst"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalirajte Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Da biste pokrenuli Linux terminal, treba da preuzmete oko <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podataka preko mreže.\nŽelite da nastavite?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Preuzmi kada WiFi bude dostupan"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Da biste pokrenuli Linux terminal, treba da preuzmete oko <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podataka preko mreže.\nŽelite li da nastavite?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Preuzimaj samo preko WiFi mreže"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instaliraj"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalira se"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Greška na mreži. Proverite vezu i probajte ponovo."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Instaliranje nije uspelo zbog greške na mreži. Proverite vezu i probajte ponovo."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instalira se Linux terminal"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal će se pokrenuti posle završetka"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Instaliranje nije uspelo zbog problema sa mrežom"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Instaliranje nije uspelo. Probajte ponovo."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminal će se pokrenuti kada se instalacija završi"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Instaliranje nije uspelo zbog problema sa mrežom"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Instaliranje nije uspelo jer WiFi nije dostupan"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Instaliranje nije uspelo. Probajte ponovo"</string>
<string name="action_settings" msgid="5729342767795123227">"Podešavanja"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminal se priprema"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminal se zaustavlja"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal je otkazao"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Promena veličine diska"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Promenite veličinu / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Promena veličine diska"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Promenite veličinu osnovne particije"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Veličina diska je podešena"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Dodeljeno <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maks. <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Otkaži"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Restartuj i primeni"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Prosleđivanje porta"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurišite prosleđivanje porta"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal pokušava da otvori novi port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port čije je otvaranje traženo: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Primeni"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal će se restartovati da bi se promenila veličina diska"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Potvrdi"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrola porta"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dozvolite ili zabranite portove za slušanje"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portovi za slušanje"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Sačuvani dozvoljeni portovi"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Izbriši <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Dozvolite novi port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Unesite novi broj porta"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Sačuvaj"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Otkaži"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Unesite broj"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nevažeći broj porta"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port već postoji"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal traži da otvori novi port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Obavezan port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prihvati"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odbij"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Oporavak"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opcije oporavka particija"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Promeni na početnu verziju"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Uklonite sve"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opcije oporavka particija"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Vratite na početnu verziju"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Uklonite sve podatke"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Resetujte terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Podaci će biti izbrisani"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Potvrdi"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Podaci će biti uklonjeni"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Resetuj"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Otkaži"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Napravi rezervnu kopiju podataka na <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Oporavak nije uspeo jer pravljenje rezervne kopije nije uspelo"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Oporavak nije uspeo zbog greške pri pravljenju rezervne kopije"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Oporavak nije uspeo"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Uklanjanje fajla rezervne kopije nije uspelo"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Uklanjanje rezervne kopije podataka nije uspelo"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Uklonite rezervnu kopiju"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Obrišite <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Nepopravljiva greška"</string>
- <string name="error_desc" msgid="1939028888570920661">"Oporavak od greške nije uspeo.\nProbajte da restartujete aplikaciju ili probajte jednu od opcija za vraćanje."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Uklonite <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Nepopravljiva greška"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Oporavak od greške nije uspeo.\nPokušajte da restartujete terminal ili isprobajte jednu od opcija za vraćanje.\nAko nijedan pokušaj ne uspe, obrišite sve podatke tako što ćete uključiti ili isključiti Linux terminal u opcijama za programere."</string>
<string name="error_code" msgid="3585291676855383649">"Kôd greške: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Podešavanja"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal je aktivan"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliknite da biste otvorili terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliknite da biste otvorili terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Zatvori"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal se zatvara"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Prinudno zatvori"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> je omogućen"</string>
</resources>
diff --git a/android/TerminalApp/res/values-be/strings.xml b/android/TerminalApp/res/values-be/strings.xml
index 6b982ca..31d1341 100644
--- a/android/TerminalApp/res/values-be/strings.xml
+++ b/android/TerminalApp/res/values-be/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Тэрмінал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Дысплэй тэрмінала"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Пусты радок"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Двойчы націсніце, каб увесці тэкст з клавіятуры"</string>
<string name="installer_title_text" msgid="500663060973466805">"Усталяванне тэрмінала Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Каб запусціць тэрмінал Linux, трэба спампаваць каля <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> даных па сетцы.\nПрацягнуць?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Спампаваць, калі будзе даступная сетка Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Каб запусціць тэрмінал Linux, трэба спампаваць каля <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> даных па сетцы.\nПрацягнуць?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Спампоўваць толькі праз сетку Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Усталяваць"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Ідзе ўсталяванне"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Памылка сеткі. Праверце падключэнне і паўтарыце спробу."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Не ўдалося ўсталяваць з-за памылкі сеткі. Праверце падключэнне і паўтарыце спробу."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Ідзе ўсталяванне тэрмінала Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Тэрмінал Linux будзе запушчаны пасля завяршэння"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Не ўдалося ўсталяваць з-за праблемы з сеткай"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Не ўдалося ўсталяваць. Паўтарыце спробу."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Тэрмінал Linux запусціцца пасля завяршэння ўсталявання"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Не ўдалося ўсталяваць з-за праблемы з сеткай"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Не ўдалося ўсталяваць, бо сетка Wi-Fi недаступная"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Не ўдалося ўсталяваць. Паўтарыце спробу."</string>
<string name="action_settings" msgid="5729342767795123227">"Налады"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Ідзе падрыхтоўка тэрмінала"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Спыненне тэрмінала"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Збой тэрмінала"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Змяніць памер дыска"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Змяніць памер / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Змяніць памер дыска"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Змяніць памер каранёвага раздзела"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Памер дыска зададзены"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Прызначана <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Максімальны памер: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Скасаваць"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Ужыць (перазапуск)"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Пераадрасацыя партоў"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Наладзіць пераадрасацыю партоў"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Тэрмінал спрабуе адкрыць новы порт"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Запыт адкрыць порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Прымяніць"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Каб прымяніць змяненне памеру дыска, тэрмінал будзе перазапушчаны"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Пацвердзіць"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Кіраванне портам"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дазволіць (адмовіць) доступ да партоў праслухоўвання"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Парты праслухоўвання"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Захаваць дазволеныя парты"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Дадаць"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Выдаліць порт <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Дазволіць доступ да новага порта"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Увядзіце нумар новага порта"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Захаваць"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Скасаваць"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Увядзіце нумар"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Няправільны нумар порта"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт ужо існуе"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Тэрмінал запытвае адкрыць новы порт"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Запытаны порт: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прыняць"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Адмовіць"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Аднаўленне"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Варыянты аднаўлення раздзела"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Змяніць на зыходную версію"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Выдаліць усе"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Варыянты аднаўлення раздзела"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Скінуць да зыходнай версіі"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Выдаліць усе даныя"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Скінуць тэрмінал"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Даныя будуць выдалены"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Пацвердзіць"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Даныя будуць выдалены"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Скінуць"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Скасаваць"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Стварыць рэзервовую копію даных у <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Аднавіць не ўдалося: рэзервовая копія не створана"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Не ўдалося аднавіць з-за памылкі рэзервовага капіравання"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Не ўдалося аднавіць"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Не ўдаецца выдаліць файл рэзервовай копіі"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Не ўдалося выдаліць даныя рэзервовай копіі"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Выдаліць даныя рэзервовай копіі"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Ачысціць <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Непапраўная памылка"</string>
- <string name="error_desc" msgid="1939028888570920661">"Не ўдалося аднавіць праграму пасля памылкі.\nПеразапусціце яе або скарыстайце адзін з варыянтаў аднаўлення доступу."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Выдаліць: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Непапраўная памылка"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Не ўдалося аднавіць праграму пасля памылкі.\nПеразапусціце тэрмінал ці паспрабуйце скарыстаць адзін з варыянтаў аднаўлення.\nКалі гэтыя спробы не дадуць вынікаў, ачысціце ўсе даныя, уключыўшы (выключыўшы) тэрмінал Linux у параметрах распрацоўшчыка."</string>
<string name="error_code" msgid="3585291676855383649">"Код памылкі: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Налады"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Тэрмінал запушчаны"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Націсніце, каб адкрыць тэрмінал"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Каб адкрыць тэрмінал, націсніце тут"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Закрыць"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Тэрмінал закрываецца"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Закрыць прымусова"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Модуль <xliff:g id="ID_1">VirGL</xliff:g> уключаны"</string>
</resources>
diff --git a/android/TerminalApp/res/values-bg/strings.xml b/android/TerminalApp/res/values-bg/strings.xml
index e987a06..5112c08 100644
--- a/android/TerminalApp/res/values-bg/strings.xml
+++ b/android/TerminalApp/res/values-bg/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"Екран на Терминал"</string>
<string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
<string name="empty_line" msgid="5012067143408427178">"Празен ред"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Докоснете двукратно, за да въведете текст"</string>
<string name="installer_title_text" msgid="500663060973466805">"Инсталиране на терминала на Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"За да стартирате терминала на Linux, трябва да изтеглите около <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> данни през мрежата.\nИскате ли да продължите?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Изтегляне, когато е налице Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"За да стартирате терминала на Linux, трябва да изтеглите около <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> данни през мрежата.\nИскате ли да продължите?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Изтегляне само посредством Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Инсталиране"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Инсталира се"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Грешка в мрежата. Проверете връзката и опитайте отново."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Инсталирането не бе успешно поради грешка в мрежата. Проверете връзката си и опитайте отново."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Терминалът на Linux се инсталира"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Терминалът на Linux ще бъде стартиран след завършване"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Инсталирането не бе успешно поради проблем с мрежата"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"Инсталирането не бе успешно, защото не е налице Wi-Fi"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"Инсталирането не бе успешно. Опитайте отново."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Терминалът на Linux ще стартира, след като инсталирането завърши"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Инсталирането не бе успешно поради проблем с мрежата"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Инсталирането не бе успешно, защото не е налице Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Инсталирането не бе успешно. Моля, опитайте отново"</string>
<string name="action_settings" msgid="5729342767795123227">"Настройки"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Терминалът се подготвя"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Терминалът спира"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Терминалът претърпя срив"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Преоразмеряване на диска"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Преоразмеряване/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Преоразмеряване на диска"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Преоразмеряване на размера на основния дял"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Размерът на диска е зададен"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Зададено: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Макс.: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Отказ"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Рестарт за прилагане"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Пренасочване на портове"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Конфигуриране на пренасочването на портове"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Терминалът се опитва да отвори нов порт"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Заявено отваряне на порта: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Прилагане"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Терминалът ще се рестартира, за да се преоразмери дискът"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Потвърждаване"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Контрол на портовете"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Разрешаване/отхвърляне на портовете за слушане"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Портове за слушане"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Запазени разрешени портове"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Добавяне"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Изтриване на <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Разрешаване на нов порт"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Въведете номера на новия порт"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Запазване"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Отказ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Моля, въведете номер."</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Невалиден номер на порт"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Портът вече съществува"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминалът заявява отварянето на нов порт"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Заявен порт: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Приемам"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Отказ"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Възстановяване"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Опции за възстановяване на дяловете"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Промяна към първоначалната версия"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Премахване на всички"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Опции за възстановяване на дяловете"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Възстановяване на първоначалната версия"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Премахване на всички данни"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Нулиране на терминала"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Данните ще бъдат изтрити"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Потвърждаване"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Данните ще бъдат премахнати"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Нулиране"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Отказ"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Създаване на резервно копие на данните в(ъв) <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Възстановяването не бе успешно, защото създаването на резервно копие не бе успешно"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Възстановяването не бе успешно поради грешка при създаването на резервно копие"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Възстановяването не бе успешно"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Файлът с резервното копие не може да се премахне"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Премахването на резервното копие на данните не бе успешно"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Премахване на резервното копие на данните"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Изчистване на <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Непоправима грешка"</string>
- <string name="error_desc" msgid="1939028888570920661">"Неуспешно възстановяване от грешка.\nМожете да рестартирате приложението или да изпробвате една от опциите за възстановяване."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Премахване на <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Непоправима грешка"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Неуспешно възстановяване от грешка.\nМожете да рестартирате терминала или да изпробвате една от опциите за възстановяване.\nАко всички опити са неуспешни, изчистете всички данни, като включите/изключите терминала на Linux от опциите за програмисти."</string>
<string name="error_code" msgid="3585291676855383649">"Код на грешката: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Настройки"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Терминалът работи"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Кликнете, за да отворите терминала"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Кликнете, за да отворите терминала"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Затваряне"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Терминалът се затваря"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Принудително затваряне"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> е активирано"</string>
</resources>
diff --git a/android/TerminalApp/res/values-bn/strings.xml b/android/TerminalApp/res/values-bn/strings.xml
index a0f37dd..fdf59b3 100644
--- a/android/TerminalApp/res/values-bn/strings.xml
+++ b/android/TerminalApp/res/values-bn/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"টার্মিনাল"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"টার্মিনাল ডিসপ্লে"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"কার্সর"</string>
+ <string name="empty_line" msgid="5012067143408427178">"খালি লাইন"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ইনপুট টাইপ করতে ডবল ট্যাপ করুন"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux টার্মিনাল ইনস্টল করুন"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux টার্মিনাল চালু করার জন্য আপনাকে নেটওয়ার্কের মাধ্যমে মোটামুটিভাবে <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ডেটা ডাউনলোড করতে হবে।\nআপনি কি চালিয়ে যাবেন?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ওয়াই-ফাই পাওয়া গেলে ডাউনলোড করুন"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux টার্মিনাল চালু করতে, নেটওয়ার্কের মাধ্যমে মোটামুটি <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ডেটা ডাউনলোড করতে হবে।\nআপনি কি এগোতে চান?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"শুধুমাত্র ওয়াই-ফাই ব্যবহার করে ডাউনলোড করুন"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ইনস্টল করুন"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ইনস্টল করা হচ্ছে"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"নেটওয়ার্কের সমস্যা। কানেকশন চেক করে আবার চেষ্টা করুন।"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"নেটওয়ার্কের সমস্যা থাকায় ইনস্টল করা যায়নি। কানেকশন চেক করে আবার চেষ্টা করুন।"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux টার্মিনাল ইনস্টল করা হচ্ছে"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"শেষ হয়ে গেলে Linux টার্মিনাল ইনস্টল করা শুরু হবে।"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"নেটওয়ার্কে সমস্যা থাকায় ইনস্টল করা যায়নি"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ইনস্টল করা যায়নি। আবার চেষ্টা করুন।"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ইনস্টলেশন সম্পূর্ণ হওয়ার পরে Linux টার্মিনাল চালু হবে"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"নেটওয়ার্কের সমস্যা থাকায় ইনস্টল করা যায়নি"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ওয়াই-ফাই উপলভ্য না থাকায় ইনস্টল করা যায়নি"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ইনস্টল করা যায়নি। আবার চেষ্টা করুন"</string>
<string name="action_settings" msgid="5729342767795123227">"সেটিংস"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"টার্মিনাল তৈরি করা হচ্ছে"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"টার্মিনাল বন্ধ করা হচ্ছে"</string>
<string name="vm_error_message" msgid="5231867246177661525">"টার্মিনাল ক্র্যাশ করেছে"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ডিস্ক ছোট বড় করা"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ছোট বড় করুন / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ডিস্ক ছোট বড় করা"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"রুট পার্টিশনের সাইজ ছোট বড় করুন"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ডিস্কের সাইজ সেট করা হয়েছে"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> অ্যাসাইন করা হয়েছে"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"সর্বাধিক <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"বাতিল করুন"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"প্রয়োগ করতে রিস্টার্ট করুন"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"পোর্ট ফরওয়ার্ড করা"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"পোর্ট ফরওয়ার্ড করা কনফিগার করুন"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"টার্মিনাল নতুন পোর্ট খোলার চেষ্টা করছে"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"পোর্ট খোলার অনুরোধ করা হয়েছে: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"প্রয়োগ করুন"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ডিস্ক ছোট বড় করতে টার্মিনাল রিস্টার্ট করা হবে"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"কনফার্ম করুন"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"পোর্ট কন্ট্রোল"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"লিসিনিং পোর্টের অনুমতি দিন/অনুমতি দেবেন না"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"লিসিনিং পোর্ট"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"অনুমতি দেওয়া পোর্ট সেভ করা হয়েছে"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"যোগ করুন"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> মুছুন"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"নতুন পোর্টের অনুমতি দিন"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"নতুন পোর্ট নম্বর লিখুন"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"সেভ করুন"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"বাতিল করুন"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"কোনও নম্বর লিখুন"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"পোর্ট নম্বর ভুল আছে"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"পোর্ট আগে থেকেই রয়েছে"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"টার্মিনাল নতুন পোর্ট খোলার অনুরোধ করছে"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"পোর্টের অনুরোধ করা হয়েছে: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"সম্মতি দিন"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"বাতিল করুন"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"আগের অবস্থায় ফেরানো"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"পার্টিশন আগের অবস্থায় ফেরানোর বিকল্প"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"প্রাথমিক ভার্সনে পরিবর্তন করুন"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"সবকটি সরান"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"পার্টিশন আগের অবস্থায় ফেরানোর বিকল্প"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"প্রাথমিক ভার্সনে রিসেট করুন"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"সব ডেটা সরান"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"টার্মিনাল রিসেট করুন"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ডেটা মুছে ফেলা হবে"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"কনফার্ম করুন"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ডেটা সরানো হবে"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"রিসেট করুন"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"বাতিল করুন"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g>-এ ডেটা ব্যাক-আপ নিন"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ব্যাকআপ কাজ না করায় আগের অবস্থায় ফেরানো যায়নি"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"ব্যাক-আপ সম্পর্কিত সমস্যার জন্য ডেটা আগের অবস্থায় ফেরানো যায়নি"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"আগের অবস্থায় ফেরানো যায়নি"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"ব্যাকআপ ফাইল সরানো যায়নি"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ব্যাক-আপ ডেটা সরানো যায়নি"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ব্যাকআপ ডেটা সরান"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"ক্লিন আপ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> সরান"</string>
+ <string name="error_title" msgid="405150657301906598">"ডেটা ফিরিয়ে আনা যাবে না এমন সমস্যা"</string>
+ <string name="error_desc" msgid="4588252235686826721">"এই সমস্যার জন্য ডেটা আগের অবস্থায় ফেরানো যায়নি।\nআপনি টার্মিনাল রিস্টার্ট করে বা অ্যাকাউন্ট ফিরিয়ে আনার বিকল্পের মধ্যে কোনও একটি ব্যবহার করে দেখতে পারেন। \nসব প্রচেষ্টা ব্যর্থ হলে, ডেভেলপার বিকল্প থেকে Linux টার্মিনাল চালু/বন্ধ করার মাধ্যমে সব ডেটা ওয়াইপ করুন।"</string>
+ <string name="error_code" msgid="3585291676855383649">"এরর কোড: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"সেটিংস"</string>
<string name="service_notification_title" msgid="2918088850910713393">"টার্মিনাল চলছে"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"টার্মিনাল খুলতে ক্লিক করুন"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"টার্মিনাল খুলতে ক্লিক করুন"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"বন্ধ করুন"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"টার্মিনাল বন্ধ হচ্ছে"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"জোর করে বন্ধ করুন"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> চালু করা আছে"</string>
</resources>
diff --git a/android/TerminalApp/res/values-bs/strings.xml b/android/TerminalApp/res/values-bs/strings.xml
index db6833f..b59bdf5 100644
--- a/android/TerminalApp/res/values-bs/strings.xml
+++ b/android/TerminalApp/res/values-bs/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Ekran terminala"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Prazan red"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Unos pisanjem dvostrukim dodirom"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalirajte Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Da pokrenete Linux terminal, trebate preuzeti otprilike <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podataka putem mreže.\nŽelite li nastaviti?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Preuzmi kada je WiFi dostupan"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Da pokrenete Linux terminal, trebate preuzeti otprilike <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podataka putem mreže.\nŽelite li nastaviti?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Preuzmi koristeći isključivo WiFi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instaliraj"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instaliranje"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Greška na mreži. Provjeriti vezu i pokušajte ponovo."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Instaliranje nije uspjelo zbog greške na mreži. Provjerite vezu i pokušajte ponovo."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instaliranje Linux terminala"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal će se pokrenuti nakon završetka"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Instaliranje nije uspjelo zbog problema s mrežom"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Instaliranje nije uspjelo. Pokušajte ponovo."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminal će se pokrenuti nakon što se instalacija završi"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Instaliranje nije uspjelo zbog problema s mrežom"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Instaliranje nije uspjelo jer WiFi nije dostupan"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Instaliranje nije uspjelo. Pokušajte ponovo"</string>
<string name="action_settings" msgid="5729342767795123227">"Postavke"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Priprema terminala"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Zaustavljanje terminala"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal je pao"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Promjena veličine diska"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Promijenite veličinu / rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Promjena veličine diska"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Promijenite veličinu korijenske particije"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Veličina diska je postavljena"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Dodijeljeno: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maksimalno <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Otkaži"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Ponovo pokrenite da primijenite"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Prosljeđivanje priključka"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurirajte prosljeđivanje priključka"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal pokušava otvoriti novi priključak"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Priključak je zatražio otvaranje: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Primijeni"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal će se ponovo pokrenuti radi promjene veličine diska"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Potvrdi"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Upravljanje priključkom"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dozvoli/odbij priključke za slušanje"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Priključci za slušanje"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Sačuvani dozvoljeni priključci"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodavanje"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Brisanje priključka <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Dozvolite novi priključak"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Unesite broj novog priključka"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Sačuvaj"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Otkaži"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Unesite broj"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nevažeći broj priključka"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Priključak već postoji"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal zahtijeva otvaranje novog priključka"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Zatražen je priključak: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prihvati"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odbij"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Oporavak"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opcije za oporavak particije"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Promijeni u početnu verziju"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Ukloni sve"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opcije za oporavak particije"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Vrati na početnu verziju"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Uklonite sve podatke"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Poništite terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Podaci će se izbrisati"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Potvrdi"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Podaci će se ukloniti"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Vrati na zadano"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Otkaži"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Napravi sigurnosnu kopiju podataka na <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Oporavak nije uspio jer sigurnosna kopija nije uspjela"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Oporavak nije uspio zbog greške sigurnosne kopije"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Oporavak nije uspio"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Nije moguće ukloniti fajl sigurnosne kopije"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Uklanjanje podataka sigurnosne kopije nije uspjelo"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Ukloni podatke sigurnosne kopije"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Očisti <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Ukloni <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Nepopravljiva greška"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Oporavak od greške nije uspio.\nMožete ponovo pokrenuti terminal ili isprobati jednu od opcija za oporavak.\nAko svi pokušaji ne uspiju, uništite sve podatke uključivanjem/isključivanjem Linux terminala u opcijama za programere."</string>
+ <string name="error_code" msgid="3585291676855383649">"Kȏd greške: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Postavke"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal je pokrenut"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliknite da otvorite terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliknite da otvorite terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Zatvori"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal je zatvoren"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Prisilno zatvori"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Omogućeno: <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ca/strings.xml b/android/TerminalApp/res/values-ca/strings.xml
index 8fcb422..58fdeaf 100644
--- a/android/TerminalApp/res/values-ca/strings.xml
+++ b/android/TerminalApp/res/values-ca/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Pantalla del terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Línia buida"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Fes doble toc per escriure una entrada"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instal·la el terminal de Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Per iniciar el terminal de Linux, has de baixar uns <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de dades a través de la xarxa.\nVols continuar?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Baixa quan hi hagi una Wi‐Fi disponible"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Per iniciar el terminal de Linux, has de baixar uns <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de dades a través de la xarxa.\nVols continuar?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Baixa només mitjançant la Wi‑Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instal·la"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instal·lant"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Error de la xarxa. Comprova la connexió i torna-ho a provar."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"No s\'ha pogut instal·lar a causa d\'un error de la xarxa. Comprova la connexió i torna-ho a provar."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"S\'està instal·lant el terminal de Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"El terminal de Linux s\'iniciarà quan hagi acabat"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"No s\'ha pogut instal·lar a causa d\'un problema de la xarxa"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"No s\'ha pogut instal·lar. Torna-ho a provar."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"El terminal de Linux s\'iniciarà quan hagi acabat la instal·lació"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"No s\'ha pogut instal·lar a causa d\'un problema de la xarxa"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"No s\'ha pogut instal·lar perquè la Wi‑Fi no està disponible"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"No s\'ha pogut instal·lar. Torna-ho a provar."</string>
<string name="action_settings" msgid="5729342767795123227">"Configuració"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"S\'està preparant el terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"S\'està aturant el terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"El terminal s\'ha bloquejat"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Canvia la mida del disc"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Canvia la mida / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Canvia la mida del disc"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Canvia la mida de la partició d\'arrel"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Mida del disc definida"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> assignats"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> màx."</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancel·la"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Reinicia per aplicar"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Redirecció de ports"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configura la redirecció de ports"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"El terminal està provant d\'obrir un port nou"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port que se sol·licita obrir: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplica"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"El terminal es reiniciarà per canviar la mida del disc"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirma"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control de ports"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permet o denega els ports d\'escolta"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ports d\'escolta"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ports permesos desats"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Afegeix"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Suprimeix <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Permet un port nou"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Introdueix un número de port nou"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Desa"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancel·la"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Introdueix un número"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"El número de port no és vàlid"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"El port ja existeix"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"El terminal està sol·licitant obrir un port nou"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port sol·licitat: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepta"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Denega"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recuperació"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opcions de recuperació de la partició"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Canvia a la versió inicial"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Suprimeix-ho tot"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opcions de recuperació de la partició"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Restableix a la versió inicial"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Suprimeix totes les dades"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Restableix el terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Les dades se suprimiran"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirma"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Les dades se suprimiran"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Restableix"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancel·la"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Crea una còpia de seguretat de les dades a <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"No s\'ha pogut recuperar perquè la còpia de seguretat ha fallat"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"No s\'ha pogut recuperar a causa d\'un error de còpia de seguretat"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"La recuperació ha fallat"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"No es pot suprimir el fitxer de còpia de seguretat"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"No s\'han pogut suprimir les dades de la còpia de seguretat"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Suprimeix les dades de la còpia de seguretat"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Elimina <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Error irrecuperable"</string>
- <string name="error_desc" msgid="1939028888570920661">"No s\'ha pogut recuperar després de l\'error.\nPots provar de reiniciar l\'aplicació o provar una de les opcions de recuperació."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Suprimeix <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Error irrecuperable"</string>
+ <string name="error_desc" msgid="4588252235686826721">"No s\'ha pogut recuperar després de l\'error.\nPots provar de reiniciar el terminal o provar una de les opcions de recuperació.\nSi tots els intents fallen, suprimeix totes les dades activant o desactivant el terminal de Linux des de les opcions per a desenvolupadors."</string>
<string name="error_code" msgid="3585291676855383649">"Codi d\'error: <xliff:g id="ERROR_CODE">%s</xliff:g>."</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Configuració"</string>
<string name="service_notification_title" msgid="2918088850910713393">"El terminal s\'està executant"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Fes clic per obrir el terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Fes clic per obrir el terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Tanca"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"El terminal s\'està tancant"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Força el tancament"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> està activat"</string>
</resources>
diff --git a/android/TerminalApp/res/values-cs/strings.xml b/android/TerminalApp/res/values-cs/strings.xml
index 376a89d..563ad9f 100644
--- a/android/TerminalApp/res/values-cs/strings.xml
+++ b/android/TerminalApp/res/values-cs/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminál"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Zobrazení terminálu"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kurzor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Prázdný řádek"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dvojitým klepnutím zadáte vstup"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalovat terminál Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Ke spuštění terminálu Linux si musíte přes datovou síť stáhnout přibližně <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dat.\nChcete pokračovat?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Stáhnout, když bude dostupná Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Ke spuštění terminálu Linux je potřeba stáhnout přes datovou síť přibližně <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dat.\nChcete pokračovat?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Stahovat jen přes Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalovat"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalování"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Chyba sítě. Zkontrolujte připojení a zkuste to znovu."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Instalace se kvůli chybě sítě nezdařila. Zkontrolujte připojení a zkuste to znovu."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instalace terminálu Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Terminál Linux bude spuštěn po dokončení"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Instalace se nezdařila kvůli problému se sítí"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Instalace se nezdařila. Zkuste to znovu."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Po dokončení instalace se spustí terminál Linux"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Instalace se kvůli problému se sítí nezdařila"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Instalace se nezdařila, protože není k dispozici Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Instalace se nezdařila. Zkuste to znovu"</string>
<string name="action_settings" msgid="5729342767795123227">"Nastavení"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Probíhá příprava terminálu"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Ukončování terminálu"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminál selhal"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Změna velikosti disku"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Změnit velikost"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Změnit velikost disku"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Změnit velikost kořenového oddílu"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Velikost disku nastavena"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Přiděleno <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Max. <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Zrušit"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Je třeba restartovat"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Přesměrování portů"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Nakonfigurovat přesměrování portů"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminál se pokouší otevřít nový port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Vyžádáno otevření portu: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Použít"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminál se za účelem změny velikosti disku restartuje"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Potvrdit"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ovládání portů"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Povolit/zakázat naslouchající porty"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Naslouchající porty"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Uložené povolené porty"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Přidat"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Smazat port <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Povolení nového portu"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Zadejte nové číslo portu"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Uložit"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Zrušit"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Zadejte číslo"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Neplatné číslo portu"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port už existuje"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminál se pokouší otevřít nový port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Požadovaný port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Přijmout"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Zamítnout"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Obnovení"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Možnosti obnovení oddílu"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Změnit na původní verzi"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Odstranit vše"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Možnosti obnovení oddílu"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Resetovat na původní verzi"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Odstranit všechna data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Resetovat terminál"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data budou smazána"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Potvrdit"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data budou odstraněna"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Resetovat"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Zrušit"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Zálohovat data do <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Obnovení se nezdařilo, protože záloha selhala"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Obnovení se kvůli chybě zálohy nezdařilo"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Obnovení se nezdařilo"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Soubor zálohy se nepodařilo odstranit"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Zálohovaná data se nepodařilo odstranit"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Odstranit data zálohy"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Vyčistit <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Neopravitelná chyba"</string>
- <string name="error_desc" msgid="1939028888570920661">"Z chybového stavu se nepodařilo dostat.\nRestartujte aplikaci nebo vyzkoušejte některou z možností obnovení."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Odstranit <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Neopravitelná chyba"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Z chybového stavu se nepodařilo dostat.\nMůžete terminál zkusit restartovat, nebo vyzkoušet některou z možností obnovení.\nPokud všechny pokusy selžou, nevratně smažte všechna data tím, že v možnostech pro vývojáře zapnete/vypnete terminál Linux."</string>
<string name="error_code" msgid="3585291676855383649">"Kód chyby: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Nastavení"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminál běží"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliknutím otevřete terminál"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliknutím otevřete terminál"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Zavřít"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminál se zavírá"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Vynutit ukončení"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Modul <xliff:g id="ID_1">VirGL</xliff:g> je aktivován"</string>
</resources>
diff --git a/android/TerminalApp/res/values-da/strings.xml b/android/TerminalApp/res/values-da/strings.xml
index dddfaaf..2382c4b 100644
--- a/android/TerminalApp/res/values-da/strings.xml
+++ b/android/TerminalApp/res/values-da/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminalskærm"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Markør"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Tom linje"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Tryk to gange for at indtaste tekst"</string>
<string name="installer_title_text" msgid="500663060973466805">"Installer Linux-terminalen"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Du skal downloade ca. <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data via netværket for at åbne Linux-terminalen.\nVil du fortsætte?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Download, når du har Wi-Fi-forbindelse"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Du skal downloade ca. <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data via netværket for at starte Linux-terminalen.\nVil du fortsætte?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Download kun via Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installer"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installerer"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Netværksfejl. Tjek forbindelsen, og prøv igen."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Installationen mislykkedes på grund af en netværksfejl. Tjek din forbindelse, og prøv igen."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux-terminalen installeres"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-terminalen startes, når installationen er gennemført"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Installationen mislykkedes på grund af et netværksproblem"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Installationen mislykkedes. Prøv igen."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux-terminalen starter, når installationen er gennemført"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Installationen mislykkedes på grund af et netværksproblem"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Installationen mislykkedes, fordi Wi-Fi ikke er tilgængeligt"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Installationen mislykkedes. Prøv igen"</string>
<string name="action_settings" msgid="5729342767795123227">"Indstillinger"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Forbereder terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stopper terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminalen er gået ned"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Tilpas diskens størrelse"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Tilpas størrelse/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Tilpas diskens størrelse"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Tilpas rodpartitionens størrelse"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Diskstørrelsen er angivet"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Tildelt: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maks.: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Annuller"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Genstart for at bruge"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Omdirigering af port"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurer omdirigering af port"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminalen forsøger at åbne en ny port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Porten, der anmodes om at være åben: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Anvend"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminalen genstartes for at tilpasse diskens størrelse"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Bekræft"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portstyring"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Tillad/afvis aktive porte"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Aktive porte"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gemte tilladte porte"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Tilføj"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Slet <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Tillad en ny port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Angiv et nyt portnummer"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Gem"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Annuller"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Angiv et nummer"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ugyldigt portnummer"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porten findes allerede"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalen anmoder om at åbne en ny port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port, der anmodes om: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Acceptér"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Afvis"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Gendannelse"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Muligheder for gendannelse af partition"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Skift til oprindelig version"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Fjern alle"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Muligheder for gendannelse af partition"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Nulstil til oprindelig version"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Fjern alle data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Nulstil terminalen"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Dataene slettes"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Bekræft"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Dataene fjernes"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Nulstil"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Annuller"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sikkerhedskopiér data til <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Gendannelsen mislykkedes, fordi sikkerhedskopieringen ikke kunne udføres"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Gendannelsen mislykkedes på grund af en fejl i sikkerhedskopien"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Gendannelsen mislykkedes"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Sikkerhedskopifilen kan ikke fjernes"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"De sikkerhedskopierede data kunne ikke fjernes"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Fjern data for sikkerhedskopi"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Ryd op på <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Uoprettelig fejl"</string>
- <string name="error_desc" msgid="1939028888570920661">"Gendannelse efter fejl mislykkedes.\nDu kan prøve at genstarte appen eller prøve en af gendannelsesmulighederne."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Fjern <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Uoprettelig fejl"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Gendannelse efter fejl mislykkedes.\nDu kan prøve at genstarte terminalen eller prøve en af gendannelsesmulighederne.\nHvis alle forsøg mislykkes, skal du rydde alle data ved at slå Linux-terminalen til/fra i indstillingerne for udviklere."</string>
<string name="error_code" msgid="3585291676855383649">"Fejlkode: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Indstillinger"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminalen kører"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klik for at åbne terminalen"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klik for at åbne terminalen"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Luk"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminalen lukker"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Tving til at lukke"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> er aktiveret"</string>
</resources>
diff --git a/android/TerminalApp/res/values-de/strings.xml b/android/TerminalApp/res/values-de/strings.xml
index 2d6eadc..bb71de3 100644
--- a/android/TerminalApp/res/values-de/strings.xml
+++ b/android/TerminalApp/res/values-de/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminalanzeige"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Leere Zeile"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Doppeltippen, um Text einzugeben"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux-Terminal installieren"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Damit du das Linux-Terminal starten kannst, musst du ungefähr <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> an Daten über das Netzwerk herunterladen.\nMöchtest du fortfahren?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Herunterladen, wenn WLAN verfügbar ist"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Damit du das Linux-Terminal starten kannst, musst du ungefähr <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> an Daten über das Netzwerk herunterladen.\nMöchtest du fortfahren?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Nur über WLAN herunterladen"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installieren"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Wird installiert"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Netzwerkfehler. Prüfe die Verbindung und versuche es noch einmal."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Die Installation ist aufgrund eines Netzwerkfehlers fehlgeschlagen. Prüfe deine Verbindung und versuche es dann noch einmal."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux-Terminal wird installiert"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-Terminal wird nach der Installation gestartet"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Die Installation ist aufgrund eines Netzwerkproblems fehlgeschlagen"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Die Installation ist fehlgeschlagen. Versuche es noch einmal."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Das Linux-Terminal wird gestartet, nachdem die Installation abgeschlossen ist"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Die Installation ist aufgrund eines Netzwerkproblems fehlgeschlagen"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Die Installation ist fehlgeschlagen, weil kein WLAN verfügbar ist"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Die Installation ist fehlgeschlagen. Bitte versuche es noch einmal."</string>
<string name="action_settings" msgid="5729342767795123227">"Einstellungen"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminal wird vorbereitet"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminal wird beendet"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal ist abgestürzt"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Größe des Laufwerks anpassen"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Größe anpassen / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Größe des Laufwerks anpassen"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Größe der Stamm-Partition anpassen"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Größe des Laufwerks wurde festgelegt"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> zugewiesen"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maximal <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Abbrechen"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Anwenden (Neustart)"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Portweiterleitung"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Portweiterleitung konfigurieren"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal versucht, einen neuen Port zu öffnen"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port, der geöffnet werden soll: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Anwenden"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal wird neu gestartet, um die Größe des Laufwerks anzupassen"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Bestätigen"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portsteuerung"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Überwachungsports zulassen / ablehnen"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Überwachungsports"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gespeicherte zulässige Ports"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Hinzufügen"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"„<xliff:g id="PORT_NUMBER">%d</xliff:g>“ löschen"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Neuen Port zulassen"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Neue Portnummer eingeben"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Speichern"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Abbrechen"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Bitte gib eine Zahl ein"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ungültige Portnummer"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port ist bereits vorhanden"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal fordert an, einen neuen Port zu öffnen"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Angeforderter Port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Akzeptieren"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Ablehnen"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Wiederherstellung"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Optionen für die Partitionswiederherstellung"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Zur ersten Version wechseln"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Alle entfernen"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Wiederherstellungsoptionen für die Partition"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Auf erste Version zurücksetzen"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Alle Daten entfernen"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminal zurücksetzen"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Daten werden gelöscht"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Bestätigen"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Daten werden entfernt"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Zurücksetzen"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Abbrechen"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Daten unter <xliff:g id="PATH">/mnt/backup</xliff:g> sichern"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Wiederherstellung aufgrund eines Sicherungsproblems fehlgeschlagen"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Wiederherstellung aufgrund eines Sicherungsfehlers nicht möglich"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Wiederherstellung fehlgeschlagen"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Sicherungsdatei kann nicht entfernt werden"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Sicherungsdaten konnten nicht entfernt werden"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Sicherungsdaten entfernen"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Daten unter <xliff:g id="PATH">/mnt/backup</xliff:g> entfernen"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"„<xliff:g id="PATH">/mnt/backup</xliff:g>“ entfernen"</string>
+ <string name="error_title" msgid="405150657301906598">"Nicht behebbarer Fehler"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Fehler konnte nicht behoben werden.\nDu kannst versuchen, das Terminal neu zu starten, oder eine der Wiederherstellungsoptionen ausprobieren.\nWenn alle Versuche fehlschlagen, lösche sämtliche Daten, indem du das Linux-Terminal in den Entwickleroptionen aktivierst und wieder deaktivierst."</string>
+ <string name="error_code" msgid="3585291676855383649">"Fehlercode: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Einstellungen"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal wird ausgeführt"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Zum Öffnen des Terminals klicken"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Zum Öffnen des Terminals klicken"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Schließen"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal wird geschlossen"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Schließen erzwingen"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ist aktiviert"</string>
</resources>
diff --git a/android/TerminalApp/res/values-el/strings.xml b/android/TerminalApp/res/values-el/strings.xml
index f25d4cb..72882b8 100644
--- a/android/TerminalApp/res/values-el/strings.xml
+++ b/android/TerminalApp/res/values-el/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Τερματικό"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Προβολή τερματικού"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Δείκτης"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Κενή γραμμή"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Πατήστε δύο φορές, για να πληκτρολογήσετε είσοδο"</string>
<string name="installer_title_text" msgid="500663060973466805">"Εγκατάσταση τερματικού Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Για την εκκίνηση του τερματικού Linux, πρέπει να κατεβάσετε περίπου <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> δεδομένων μέσω δικτύου.\nΘέλετε να συνεχίσετε;"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Λήψη όταν υπάρχει διαθέσιμο Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Για την εκκίνηση του τερματικού Linux, πρέπει να κατεβάσετε περίπου <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> δεδομένων μέσω δικτύου.\nΘέλετε να συνεχίσετε;"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Λήψη μόνο μέσω Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Εγκατάσταση"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Εγκατάσταση"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Σφάλμα δικτύου. Ελέγξτε τη σύνδεση και δοκιμάστε ξανά."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Η εγκατάσταση απέτυχε λόγω σφάλματος δικτύου. Ελέγξτε τη σύνδεση και δοκιμάστε ξανά."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Γίνεται εγκατάσταση τερματικού Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Το τερματικό Linux θα ξεκινήσει μετά την ολοκλήρωση"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Η εγκατάσταση απέτυχε λόγω προβλήματος δικτύου"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Η εγκατάσταση απέτυχε. Δοκιμάστε ξανά."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Το τερματικό Linux θα ξεκινήσει μετά την ολοκλήρωση της εγκατάστασης"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Η εγκατάσταση απέτυχε λόγω προβλήματος δικτύου"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Η εγκατάσταση απέτυχε, επειδή το Wi-Fi δεν είναι διαθέσιμο"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Η εγκατάσταση απέτυχε. Δοκιμάστε ξανά"</string>
<string name="action_settings" msgid="5729342767795123227">"Ρυθμίσεις"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Προετοιμασία τερματικού σε εξέλιξη"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Διακοπή τερματικού σε εξέλιξη"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Το τερματικό παρουσίασε σφάλμα"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Αλλαγή μεγέθους δίσκου"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Αλλαγή μεγέθους/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Αλλαγή μεγέθους δίσκου"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Αλλαγή μεγέθους κύριου διαμερίσματος"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Το μέγεθος δίσκου έχει οριστεί"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Ανατέθηκαν <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Έως <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Ακύρωση"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Επανεκ. για εφαρμογή"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Προώθηση θύρας"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Διαμόρφωση προώθησης θύρας"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Το τερματικό προσπαθεί να ανοίξει μια νέα θύρα"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Υποβλήθηκε αίτημα για άνοιγμα της θύρας: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Εφαρμογή"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Θα γίνει επανεκκίνηση του τερματικού για αλλαγή μεγέθους δίσκου"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Επιβεβαίωση"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Έλεγχος θυρών"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Να επιτρέπονται/μην επιτρέπονται οι θύρες ακρόασης"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Θύρες ακρόασης"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Αποθηκευμένες επιτρεπόμενες θύρες"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Προσθήκη"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Διαγραφή θύρας <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Να επιτρέπεται νέα θύρα"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Καταχωρίστε νέο αριθμό θύρας"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Αποθήκευση"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Ακύρωση"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Εισαγάγετε έναν αριθμό"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Μη έγκυρος αριθμός θύρας"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Η θύρα υπάρχει ήδη"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Το τερματικό ζητά να ανοίξει μια νέα θύρα"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Ζητήθηκε θύρα: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Αποδοχή"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Απόρριψη"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Ανάκτηση"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Επιλογές ανάκτησης διαμερισμάτων"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Αλλαγή σε αρχική έκδοση"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Κατάργηση όλων"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Επιλογές ανάκτησης διαμερισμάτων"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Επαναφορά στην αρχική έκδοση"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Κατάργηση όλων των δεδομένων"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Επαναφορά τερματικού"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Τα δεδομένα θα διαγραφούν"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Επιβεβαίωση"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Τα δεδομένα θα καταργηθούν"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Επαναφορά"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Ακύρωση"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Δημιουργία αντιγράφου ασφαλείας δεδομένων στο <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Αποτυχία ανάκτησης λόγω αποτυχίας δημιουργίας αντιγράφου ασφαλείας"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Η ανάκτηση απέτυχε λόγω σφάλματος δημιουργίας αντιγράφου ασφαλείας"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Αποτυχία ανάκτησης"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Δεν είναι δυνατή η κατάργηση του αρχείου αντιγράφου ασφαλείας"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Η κατάργηση των δεδομένων αντιγράφου ασφαλείας απέτυχε"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Κατάργηση δεδομένων αντιγράφου ασφαλείας"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Διαγραφή <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Ανεπανόρθωτο σφάλμα"</string>
- <string name="error_desc" msgid="1939028888570920661">"Αποτυχία ανάκτησης από σφάλμα.\nΜπορείτε να δοκιμάσετε να επανεκκινήσετε την εφαρμογή ή να δοκιμάσετε μία από τις επιλογές ανάκτησης."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Κατάργηση <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Ανεπανόρθωτο σφάλμα"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Αποτυχία ανάκτησης από σφάλμα.\nΜπορείτε να δοκιμάσετε να επανεκκινήσετε το τερματικό ή να δοκιμάσετε μια από τις επιλογές ανάκτησης.\nΕάν όλες οι προσπάθειες αποτύχουν, κάντε εκκαθάριση όλων των δεδομένων ενεργοποιώντας/απενεργοποιώντας το τερματικό Linux από τις επιλογές για προγραμματιστές."</string>
<string name="error_code" msgid="3585291676855383649">"Κωδικός σφάλματος: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Ρυθμίσεις"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Το τερματικό εκτελείται"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Κάντε κλικ για άνοιγμα του τερματικού"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Κάντε κλικ για άνοιγμα του τερματικού"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Κλείσιμο"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Το τερματικό κλείνει"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Αναγκαστικό κλείσιμο"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Το <xliff:g id="ID_1">VirGL</xliff:g> είναι ενεργοποιημένο"</string>
</resources>
diff --git a/android/TerminalApp/res/values-en-rAU/strings.xml b/android/TerminalApp/res/values-en-rAU/strings.xml
index 90f282e..f208e38 100644
--- a/android/TerminalApp/res/values-en-rAU/strings.xml
+++ b/android/TerminalApp/res/values-en-rAU/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminal display"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Empty line"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Double-tap to type input"</string>
<string name="installer_title_text" msgid="500663060973466805">"Install Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"To launch a Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over the network.\nWould you like to proceed?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Download when Wi-Fi is available"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"To launch Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over the network.\nWould you like to proceed?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Download using Wi-Fi only"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Install"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installing"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Network error. Check connection and retry."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Failed to install due to a network error. Check your connection and try again."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installing Linux terminal"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal will be started after finish"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Failed to install due to the network issue"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Failed to install. Try again."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminal will start after the installation is finished"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Failed to install due to a network issue"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Failed to install because Wi-Fi is not available"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Failed to install. Please try again"</string>
<string name="action_settings" msgid="5729342767795123227">"Settings"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparing terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stopping terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal crashed"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Disk resize"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Resize/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Disk resize"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Resize the root partition size"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disk size set"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> assigned"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> max"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancel"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Restart to apply"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Port forwarding"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configure port forwarding"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal is trying to open a new port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port requested to be open: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Apply"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal will be restarted to resize disk"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirm"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Allow a new port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Enter a new port number"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Save"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancel"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Please enter a number"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port requested: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Partition recovery options"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Change to initial version"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Remove all"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Partition recovery options"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Reset to initial version"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Remove all data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Reset terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data will be deleted"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirm"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data will be removed"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Reset"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancel"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Back up data to <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Recovery failed because backup failed"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Failed to recover due to a backup error"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Recovery failed"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Cannot remove backup file"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Failed to remove backup data"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Remove backup data"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Clean up <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Unrecoverable error"</string>
- <string name="error_desc" msgid="1939028888570920661">"Failed to recover from an error.\nYou can try restarting the app or try one of the recovery options."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Remove <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Unrecoverable error"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Failed to recover from an error.\nYou can try restarting terminal or try one of the recovery options.\nIf all attempts fail, wipe all data by turning on/off Linux terminal from developer options."</string>
<string name="error_code" msgid="3585291676855383649">"Error code: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Settings"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal is running"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Click to open the terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Click to open terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Close"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal is closing"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Force close"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> is enabled"</string>
</resources>
diff --git a/android/TerminalApp/res/values-en-rCA/strings.xml b/android/TerminalApp/res/values-en-rCA/strings.xml
index 49c8af1..f208e38 100644
--- a/android/TerminalApp/res/values-en-rCA/strings.xml
+++ b/android/TerminalApp/res/values-en-rCA/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"Terminal display"</string>
<string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
<string name="empty_line" msgid="5012067143408427178">"Empty line"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Double-tap to type input"</string>
<string name="installer_title_text" msgid="500663060973466805">"Install Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"To launch Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over network.\nWould you proceed?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Download when Wi-Fi is available"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"To launch Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over the network.\nWould you like to proceed?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Download using Wi-Fi only"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Install"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installing"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Network error. Check connection and retry."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Failed to install due to a network error. Check your connection and try again."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installing Linux terminal"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal will be started after finish"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Failed to install due to the network issue"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"Failed to install because Wi-Fi isn\'t available"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"Failed to install. Try again."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminal will start after the installation is finished"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Failed to install due to a network issue"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Failed to install because Wi-Fi is not available"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Failed to install. Please try again"</string>
<string name="action_settings" msgid="5729342767795123227">"Settings"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparing terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stopping terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal crashed"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Disk Resize"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Resize / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Disk resize"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Resize the root partition size"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disk size set"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> assigned"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> max"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancel"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Restart to apply"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Port Forwarding"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configure port forwarding"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal is trying to open a new port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port requested to be open: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Apply"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal will be restarted to resize disk"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirm"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Allow a new port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Enter a new port number"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Save"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancel"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Please enter a number"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port requested: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Partition Recovery options"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Change to Initial version"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Remove all"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Partition recovery options"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Reset to initial version"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Remove all data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Reset terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data will be deleted"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirm"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data will be removed"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Reset"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancel"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Back up data to <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Recovery failed because backup failed"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Failed to recover due to a backup error"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Recovery failed"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Cannot remove backup file"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Failed to remove backup data"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Remove backup data"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Clean up <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Unrecoverable Error"</string>
- <string name="error_desc" msgid="1939028888570920661">"Failed to recover from an error.\nYou can try restart the app, or try one of recovery option."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Remove <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Unrecoverable error"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Failed to recover from an error.\nYou can try restarting terminal or try one of the recovery options.\nIf all attempts fail, wipe all data by turning on/off Linux terminal from developer options."</string>
<string name="error_code" msgid="3585291676855383649">"Error code: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Settings"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal is running"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Click to open the terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Click to open terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Close"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal is closing"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Force close"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> is enabled"</string>
</resources>
diff --git a/android/TerminalApp/res/values-en-rGB/strings.xml b/android/TerminalApp/res/values-en-rGB/strings.xml
index 90f282e..f208e38 100644
--- a/android/TerminalApp/res/values-en-rGB/strings.xml
+++ b/android/TerminalApp/res/values-en-rGB/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminal display"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Empty line"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Double-tap to type input"</string>
<string name="installer_title_text" msgid="500663060973466805">"Install Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"To launch a Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over the network.\nWould you like to proceed?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Download when Wi-Fi is available"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"To launch Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over the network.\nWould you like to proceed?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Download using Wi-Fi only"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Install"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installing"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Network error. Check connection and retry."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Failed to install due to a network error. Check your connection and try again."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installing Linux terminal"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal will be started after finish"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Failed to install due to the network issue"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Failed to install. Try again."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminal will start after the installation is finished"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Failed to install due to a network issue"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Failed to install because Wi-Fi is not available"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Failed to install. Please try again"</string>
<string name="action_settings" msgid="5729342767795123227">"Settings"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparing terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stopping terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal crashed"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Disk resize"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Resize/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Disk resize"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Resize the root partition size"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disk size set"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> assigned"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> max"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancel"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Restart to apply"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Port forwarding"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configure port forwarding"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal is trying to open a new port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port requested to be open: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Apply"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal will be restarted to resize disk"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirm"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Allow a new port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Enter a new port number"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Save"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancel"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Please enter a number"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port requested: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Partition recovery options"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Change to initial version"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Remove all"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Partition recovery options"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Reset to initial version"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Remove all data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Reset terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data will be deleted"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirm"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data will be removed"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Reset"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancel"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Back up data to <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Recovery failed because backup failed"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Failed to recover due to a backup error"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Recovery failed"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Cannot remove backup file"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Failed to remove backup data"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Remove backup data"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Clean up <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Unrecoverable error"</string>
- <string name="error_desc" msgid="1939028888570920661">"Failed to recover from an error.\nYou can try restarting the app or try one of the recovery options."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Remove <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Unrecoverable error"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Failed to recover from an error.\nYou can try restarting terminal or try one of the recovery options.\nIf all attempts fail, wipe all data by turning on/off Linux terminal from developer options."</string>
<string name="error_code" msgid="3585291676855383649">"Error code: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Settings"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal is running"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Click to open the terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Click to open terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Close"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal is closing"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Force close"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> is enabled"</string>
</resources>
diff --git a/android/TerminalApp/res/values-en-rIN/strings.xml b/android/TerminalApp/res/values-en-rIN/strings.xml
index 90f282e..f208e38 100644
--- a/android/TerminalApp/res/values-en-rIN/strings.xml
+++ b/android/TerminalApp/res/values-en-rIN/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminal display"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Empty line"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Double-tap to type input"</string>
<string name="installer_title_text" msgid="500663060973466805">"Install Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"To launch a Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over the network.\nWould you like to proceed?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Download when Wi-Fi is available"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"To launch Linux terminal, you need to download roughly <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> of data over the network.\nWould you like to proceed?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Download using Wi-Fi only"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Install"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installing"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Network error. Check connection and retry."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Failed to install due to a network error. Check your connection and try again."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installing Linux terminal"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal will be started after finish"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Failed to install due to the network issue"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Failed to install. Try again."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminal will start after the installation is finished"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Failed to install due to a network issue"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Failed to install because Wi-Fi is not available"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Failed to install. Please try again"</string>
<string name="action_settings" msgid="5729342767795123227">"Settings"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparing terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stopping terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal crashed"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Disk resize"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Resize/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Disk resize"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Resize the root partition size"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disk size set"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> assigned"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> max"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancel"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Restart to apply"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Port forwarding"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configure port forwarding"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal is trying to open a new port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port requested to be open: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Apply"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal will be restarted to resize disk"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirm"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Allow a new port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Enter a new port number"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Save"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancel"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Please enter a number"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port requested: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Partition recovery options"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Change to initial version"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Remove all"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Partition recovery options"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Reset to initial version"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Remove all data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Reset terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data will be deleted"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirm"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data will be removed"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Reset"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancel"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Back up data to <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Recovery failed because backup failed"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Failed to recover due to a backup error"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Recovery failed"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Cannot remove backup file"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Failed to remove backup data"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Remove backup data"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Clean up <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Unrecoverable error"</string>
- <string name="error_desc" msgid="1939028888570920661">"Failed to recover from an error.\nYou can try restarting the app or try one of the recovery options."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Remove <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Unrecoverable error"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Failed to recover from an error.\nYou can try restarting terminal or try one of the recovery options.\nIf all attempts fail, wipe all data by turning on/off Linux terminal from developer options."</string>
<string name="error_code" msgid="3585291676855383649">"Error code: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Settings"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal is running"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Click to open the terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Click to open terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Close"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal is closing"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Force close"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> is enabled"</string>
</resources>
diff --git a/android/TerminalApp/res/values-es-rUS/strings.xml b/android/TerminalApp/res/values-es-rUS/strings.xml
index 1cbed7d..ff2ae6d 100644
--- a/android/TerminalApp/res/values-es-rUS/strings.xml
+++ b/android/TerminalApp/res/values-es-rUS/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Pantalla de la terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Línea vacía"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Presiona dos veces para escribir la entrada"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instala la terminal de Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Para iniciar la terminal de Linux, debes descargar aproximadamente <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de datos a través de la red.\n¿Quieres continuar?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Descargar cuando haya una red Wi-Fi disponible"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Para iniciar la terminal de Linux, debes descargar aproximadamente <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de datos a través de la red.\n¿Quieres continuar?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Descargar solo con Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalar"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalando"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Error de red. Comprueba la conexión y vuelve a intentarlo."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"No se pudo instalar debido a un error de red. Verifica la conexión y vuelve a intentarlo."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instalando la terminal de Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Se iniciará la terminal de Linux después de finalizar"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"No se pudo instalar debido a un problema de red"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"No se pudo instalar. Vuelve a intentarlo."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"La terminal de Linux se iniciará después de que finalice la instalación"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"No se pudo instalar debido a un problema de red"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"La instalación falló porque no hay una conexión Wi-Fi disponible"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"No se pudo instalar; vuelve a intentarlo"</string>
<string name="action_settings" msgid="5729342767795123227">"Configuración"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparando la terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Deteniendo la terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Se produjo un error en la terminal"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Cambiar el tamaño del disco"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Cambiar el tamaño/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Cambiar el tamaño del disco"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Cambia el tamaño de la partición raíz"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Se estableció el tamaño del disco"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> asignados"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> máx."</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancelar"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Reiniciar y aplicar"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Redirección de puertos"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configurar la redirección de puertos"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"La terminal está intentando abrir un puerto nuevo"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Puerto solicitado para abrir: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplicar"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Se reiniciará la terminal para cambiar el tamaño del disco"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmar"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control del puerto"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir o denegar los puertos de escucha"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Puertos de escucha"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Puertos permitidos guardados"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Agregar"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Borrar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Permite un puerto nuevo"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Ingresa un nuevo número de portabilidad"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Guardar"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancelar"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Ingresa un número"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"El número de puerto no es válido"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"El puerto ya existe"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"La terminal está solicitando abrir un puerto nuevo"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Puerto solicitado: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceptar"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rechazar"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recuperación"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opciones de recuperación de particiones"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Cambiar a la versión inicial"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Quitar todos"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opciones de recuperación de particiones"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Restablecer a la versión inicial"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Quitar todos los datos"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Restablecer terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Se borrarán los datos"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmar"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Se quitarán los datos"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Restablecer"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancelar"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Crear una copia de seguridad de los datos en <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Falló la recuperación porque no se pudo crear la copia de seguridad"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"No se pudo recuperar debido a un error de copia de seguridad"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Falló la recuperación"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"No se puede quitar el archivo de copia de seguridad"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"No se pudieron quitar los datos de copia de seguridad"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Quitar datos de copia de seguridad"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Liberar espacio en <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Error irrecuperable"</string>
- <string name="error_desc" msgid="1939028888570920661">"No se pudo recuperar después del error.\nPuedes reiniciar la app o probar una de las opciones de recuperación."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Quitar <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Error irrecuperable"</string>
+ <string name="error_desc" msgid="4588252235686826721">"No se pudo recuperar después del error.\nPuedes reiniciar la terminal o probar una de las opciones de recuperación.\nSi estos intentos fallan, borra todos los datos activando o desactivando la terminal de Linux desde las opciones para desarrolladores."</string>
<string name="error_code" msgid="3585291676855383649">"Código de error: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Configuración"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Se está ejecutando la terminal"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Haz clic para abrir la terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Haz clic para abrir la terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Cerrar"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Se está cerrando la terminal"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forzar cierre"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Se habilitó <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-es/strings.xml b/android/TerminalApp/res/values-es/strings.xml
index a0bc767..0a8932e 100644
--- a/android/TerminalApp/res/values-es/strings.xml
+++ b/android/TerminalApp/res/values-es/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Pantalla del terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Línea vacía"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Toca dos veces para escribir"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instala el terminal de Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Para iniciar el terminal de Linux, debes descargar unos <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de datos a través de la red.\n¿Quieres continuar?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Descargar cuando haya una red Wi-Fi disponible"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Para iniciar el terminal de Linux, debes descargar unos <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de datos a través de la red.\n¿Quieres continuar?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Descargar contenido solo con una conexión Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalar"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalando"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Error de red. Comprueba la conexión y vuelve a intentarlo."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"No se ha podido instalar debido a un error de red. Comprueba tu conexión y vuelve a intentarlo."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instalando terminal de Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"El terminal de Linux se iniciará cuando finalice"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"No se ha podido instalar debido a un problema de red"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"No se ha podido instalar. Inténtalo de nuevo."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"El terminal de Linux se iniciará cuando finalice la instalación"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"No se ha podido instalar debido a un problema de red"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"No se ha podido instalar porque no hay conexión Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"No se ha podido instalar. Vuelve a intentarlo."</string>
<string name="action_settings" msgid="5729342767795123227">"Ajustes"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparando terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Deteniendo terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Fallo del terminal"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Cambiar tamaño de disco"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Cambiar tamaño/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Cambiar tamaño del disco"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Cambia el tamaño de la partición raíz"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Tamaño de disco definido"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> asignados"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> como máximo"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancelar"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Reiniciar y aplicar"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Redirección de puertos"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configurar la redirección de puertos"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"El terminal está intentando abrir un nuevo puerto"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Puerto que se solicita que esté abierto: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplicar"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"El terminal se reiniciará para cambiar el tamaño del disco"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmar"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control de puerto"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir/Denegar puertos de escucha"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Puertos de escucha"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Puertos permitidos guardados"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Añadir"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eliminar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Permitir un nuevo puerto"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Introduce un nuevo número de puerto"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Guardar"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancelar"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Introduce un número"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Número de puerto no válido"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"El puerto ya existe"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"El terminal está solicitando abrir un nuevo puerto"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Puerto solicitado: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceptar"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Denegar"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recuperación"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opciones de recuperación de particiones"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Cambiar a versión inicial"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Quitar todo"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opciones de recuperación de particiones"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Restablecer a la versión inicial"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Elimina todos los datos"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Restablecer terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Los datos se eliminarán"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmar"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Los datos se eliminarán"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Restablecer"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancelar"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Crear copia de seguridad de los datos en <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"No se ha podido recuperar la copia de seguridad"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"No se ha podido recuperar debido a un error de copia de seguridad"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"No se ha podido recuperar"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"No se puede quitar el archivo de copia de seguridad"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"No se han podido eliminar los datos de copia de seguridad"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Eliminar datos de copia de seguridad"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Liberar espacio de <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Error irrecuperable"</string>
- <string name="error_desc" msgid="1939028888570920661">"No se ha podido recuperar después del error.\nPuedes intentar reiniciar la aplicación o probar una de las opciones de recuperación."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Eliminar <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Error irrecuperable"</string>
+ <string name="error_desc" msgid="4588252235686826721">"No se ha podido recuperar después del error.\nPuedes intentar reiniciar el terminal o probar una de las opciones de recuperación.\nSi todos los intentos fallan, borra todos los datos activando o desactivando el terminal de Linux en las opciones para desarrolladores."</string>
<string name="error_code" msgid="3585291676855383649">"Código de error: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Ajustes"</string>
<string name="service_notification_title" msgid="2918088850910713393">"El terminal se está ejecutando"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Toca para abrir el terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Haz clic para abrir el terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Cerrar"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"El terminal se está cerrando"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forzar cierre"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> se ha habilitado"</string>
</resources>
diff --git a/android/TerminalApp/res/values-et/strings.xml b/android/TerminalApp/res/values-et/strings.xml
index 1d25c0a..d6754d8 100644
--- a/android/TerminalApp/res/values-et/strings.xml
+++ b/android/TerminalApp/res/values-et/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminali ekraan"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Tühi rida"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Tekstisisestuseks topeltpuudutage"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linuxi terminali installimine"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linuxi terminali käivitamiseks tuleb teil võrgu kaudu alla laadida umbes <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> andmeid.\nKas soovite jätkata?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Laadi alla, kui WiFi on saadaval"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linuxi terminali käivitamiseks tuleb teil võrgu kaudu alla laadida umbes <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> andmeid.\nKas soovite jätkata?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Laadi alla ainult WiFi kaudu"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installi"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installimine"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Võrgu viga. Kontrollige ühendust ja proovige uuesti."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Installimine ebaõnnestus võrguvea tõttu. Kontrollige ühendust ja proovige uuesti."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linuxi terminali installimine"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linuxi terminal käivitatakse pärast lõpetamist"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Installimine ebaõnnestus võrguprobleemi tõttu"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Installimine ebaõnnestus. Proovige uuesti."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linuxi terminal käivitatakse pärast installimise lõpulejõudmist"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Installimine ebaõnnestus võrguprobleemi tõttu"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Installimine ebaõnnestus, kuna WiFi pole saadaval"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Installimine ebaõnnestus. Proovige uuesti"</string>
<string name="action_settings" msgid="5729342767795123227">"Seaded"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminali ettevalmistamine"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminali peatamine"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal jooksis kokku"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Ketta suuruse muutmine"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Suuruse muutmine / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Ketta suuruse muutmine"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Juursektsiooni suuruse muutmine"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Ketta suurus on määratud"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> on määratud"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Max <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Tühista"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Rakendamiseks taaskäivitage"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Pordisiire"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigureerige pordisiire"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal üritab uut porti avada"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port, mille avamist taotleti: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Rakenda"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal taaskäivitatakse ketta suuruse muutmiseks"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Kinnita"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portide haldamine"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Kuulamisportide lubamine/keelamine"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Kuulamispordid"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Salvestatud lubatud pordid"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Lisa"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Kustuta <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Luba uus port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Sisestage uus pordi number"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Salvesta"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Tühista"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Sisestage number"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Sobimatu pordi number"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port on juba olemas"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal taotleb uue pordi avamist"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Taotletud port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Nõustu"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Keela"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Taastamine"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Sektsiooni taastevalikud"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Muutke algsele versioonile"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Eemaldage kõik"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Sektsiooni taastevalikud"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Algsele versioonile lähtestamine"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Kõigi andmete eemaldamine"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminali lähtestamine"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Andmed kustutatakse"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Kinnita"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Andmed eemaldatakse"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Lähtesta"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Tühista"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Varunda andmed asukohta <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Taastamine ebaõnnestus, kuna varundamine ebaõnnestus"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Taastamine ebaõnnestus varundamisvea tõttu"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Taastamine ebaõnnestus"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Ei saa varundusfaili eemaldada"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Varundatud andmete eemaldamine ebaõnnestus"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Varundusandmete eemaldamine"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Tühjenda <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Taastamatu viga"</string>
- <string name="error_desc" msgid="1939028888570920661">"Veast taastumine nurjus.\nVõite proovida rakenduse taaskäivitada või proovida üht taastamisvalikutest."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Tee <xliff:g id="PATH">/mnt/backup</xliff:g> eemaldamine"</string>
+ <string name="error_title" msgid="405150657301906598">"Taastamatu viga"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Veast taastumine ebaõnnestus.\nVõite proovida terminali taaskäivitada või proovida ühte taastevalikutest.\nKui kõik katsed ebaõnnestuvad, muutke kõik andmed loetamatuks, lülitades Linuxi terminali arendaja valikute kaudu sisse/välja."</string>
<string name="error_code" msgid="3585291676855383649">"Veakood: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Seaded"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal töötab"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klõpsake terminali avamiseks"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klõpsake terminali avamiseks"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Sule"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal suletakse"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Rakenda sulgemine"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> on lubatud"</string>
</resources>
diff --git a/android/TerminalApp/res/values-eu/strings.xml b/android/TerminalApp/res/values-eu/strings.xml
index 2601142..0cdcca5 100644
--- a/android/TerminalApp/res/values-eu/strings.xml
+++ b/android/TerminalApp/res/values-eu/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminala"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminalaren pantaila"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kurtsorea"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Lerro hutsa"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Sakatu birritan testua idazteko"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalatu Linux-en terminala"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux-en terminala exekutatzeko, gutxi gorabehera <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> datu deskargatu behar dituzu sarearen bidez.\nAurrera egin nahi duzu?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Deskargatu wifi-sare bat erabilgarri dagoenean"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux-en terminala exekutatzeko, gutxi gorabehera <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> datu deskargatu behar dituzu sarearen bidez.\nAurrera egin nahi duzu?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Deskargatu wifi bidez soilik"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalatu"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalatzen"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Sareko errorea. Egiaztatu konektatuta zaudela eta saiatu berriro."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Ezin izan da instalatu, sareko errore bat dela eta. Egiaztatu konektatuta zaudela eta saiatu berriro."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux-en terminala instalatzen"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Prozesua amaitu ondoren abiaraziko da Linux-en terminala"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Ezin izan da instalatu, sarean arazo bat dagoelako"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Ezin izan da instalatu. Saiatu berriro."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Instalazioa amaitzean abiaraziko da Linux-en terminala"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Ezin izan da instalatu, sarean arazo bat dagoelako"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Ezin izan da instalatu, wifi-sarerik erabilgarri ez dagoelako"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Ezin izan da instalatu. Saiatu berriro"</string>
<string name="action_settings" msgid="5729342767795123227">"Ezarpenak"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminala prestatzen"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminala geldiarazten"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminalak huts egin du"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Aldatu diskoaren tamaina"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Aldatu tamaina / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Aldatu diskoaren tamaina"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Aldatu erroko partizioaren tamaina"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Ezarri da diskoaren tamaina"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> esleituta"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Gehienez ere <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Utzi"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Aldaketak aplikatzeko, berrabiarazi"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Ataka-birbideratzU+2060ea"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfiguratu ataka-birbideratzea"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminala beste ataka bat irekitzen saiatzen ari da"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Ataka hau irekitzeko eskatu da: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplikatu"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Diskoaren tamaina aldatzeko, terminala berrabiaraziko da"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Berretsi"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ataka kontrolatzeko aukerak"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Onartu/Baztertu ataka aktiboak"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ataka aktiboak"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gorde dira onartutako atakak"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Gehitu"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Ezabatu <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Onartu beste ataka bat"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Idatzi beste ataka-zenbaki bat"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Gorde"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Utzi"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Idatzi zenbaki bat"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ataka-zenbakiak ez du balio"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Ataka jada badago"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalak beste ataka bat irekitzeko eskatu du"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Ataka hau eskatu da: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Onartu"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Ukatu"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Berreskuratzea"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Partizioa berreskuratzeko aukerak"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Aldatu hasierako bertsiora"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Kendu guztiak"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Partizioa berreskuratzeko aukerak"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Berrezarri hasierako bertsioa"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Kendu datu guztiak"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Berrezarri terminala"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Datuak ezabatu egingo dira"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Berretsi"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Datuak kenduko dira"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Berrezarri"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Utzi"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Egin datuen babeskopiak hemen: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Ezin izan da berreskuratu, babeskopiak huts egin duelako"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Ezin izan da leheneratu, babeskopien errore bat dela eta"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Ezin izan da berreskuratu"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Ezin da kendu babeskopia-fitxategia"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Ezin izan dira kendu babeskopien datuak"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Kendu babeskopien datuak"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Garbitu <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Leheneratu ezin den errorea"</string>
- <string name="error_desc" msgid="1939028888570920661">"Ezin izan da leheneratu errorea.\nBerrabiarazi aplikazioa edo probatu leheneratzeko aukeretako bat."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Kendu <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Leheneratu ezin den errorea"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Ezin izan da leheneratu errorea.\nBerrabiarazi terminala edo probatu leheneratzeko aukeretako bat.\nSaiakera guztiek huts egiten badute, xahutu datu guztiak garatzaileentzako aukeren bidez Linux-en terminala aktibatuta/desaktibatuta."</string>
<string name="error_code" msgid="3585291676855383649">"Errore-kodea: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Ezarpenak"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminala abian da"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Egin klik terminala irekitzeko"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Egin klik terminala irekitzeko"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Itxi"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal ixten ari da"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Behartu ixtera"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> gaituta dago"</string>
</resources>
diff --git a/android/TerminalApp/res/values-fa/strings.xml b/android/TerminalApp/res/values-fa/strings.xml
index ea7b9e1..4ec4d0a 100644
--- a/android/TerminalApp/res/values-fa/strings.xml
+++ b/android/TerminalApp/res/values-fa/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"پایانه"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"نمایشگر پایانه"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"مکاننما"</string>
+ <string name="empty_line" msgid="5012067143408427178">"خط خالی"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"برای تایپ کردن ورودی، دو تکضرب بزنید"</string>
<string name="installer_title_text" msgid="500663060973466805">"نصب پایانه Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"برای راهاندازی پایانه Linux، باید تقریباً <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> داده ازطریق شبکه بارگیری کنید.\nادامه میدهید؟"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"هنگام دسترسی به Wi-Fi بارگیری شود"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"برای راهاندازی پایانه Linux، باید تقریباً <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> داده ازطریق شبکه بارگیری کنید.\nادامه میدهید؟"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"بارگیری فقط با Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"نصب"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"درحال نصب"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"خطای شبکه. اتصال را بررسی و سپس دوباره امتحان کنید."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"بهدلیل خطای شبکه نصب نشد. اتصال را بررسی کنید و دوباره امتحان کنید."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"درحال نصب پایانه Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"پایانه Linux بعداز اتمام شروع خواهد شد"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"بهدلیل خطای شبکه نصب نشد"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"نصب نشد. دوباره امتحان کنید."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"پایانه Linux پساز تکمیل نصب، راهاندازی خواهد شد"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"بهدلیل مشکل در شبکه نصب نشد"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"نصب نشد چون Wi-Fi دردسترس نیست"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"نصب نشد. لطفاً دوباره امتحان کنید"</string>
<string name="action_settings" msgid="5729342767795123227">"تنظیمات"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"درحال آمادهسازی پایانه"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"پایانه درحال توقف است"</string>
<string name="vm_error_message" msgid="5231867246177661525">"پایانه ازکار افتاد"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"تغییر اندازه دیسک"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"تغییر اندازه / روت فایل سیستم"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"تغییر اندازه دیسک"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"تغییر اندازه پارتیشن ریشه"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"تنظیم اندازه دیسک"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> اختصاص یافته است"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"حداکثر <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"لغو"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"بازراهاندازی برای اعمال"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"بازارسال درگاه"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"پیکربندی بازارسال درگاه"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"پایانه میخواهد درگاه جدیدی باز کند"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"درگاهی که درخواست شده است باز شود: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"اعمال کردن"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"پایانه برای تغییر اندازه دیسک، بازراهاندازی خواهد شد"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"تأیید کردن"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"کنترل درگاه"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"مجاز/ رد کردن درگاههای گوش کردن"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"درگاههای گوش کردن"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"درگاههای مجاز ذخیره شدند"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"افزودن"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"حذف کردن <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"مجاز کردن درگاهی جدید"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"شماره درگاه جدیدی را وارد کنید"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"ذخیره"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"لغو"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"لطفاً شمارهای را وارد کنید"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"شماره درگاه نامعتبر است"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"درگاه ازقبل موجود است"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"پایانه میخواهد درگاه جدیدی باز کند"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"درگاه درخواستشده: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"پذیرفتن"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"رد کردن"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"بازیابی"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"گزینههای بازیابی پارتیشن"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"تغییر به نسخه ابتدایی"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"برداشتن همه"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"گزینههای بازیابی پارتیشن"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"بازنشانی به نسخه اولیه"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"حذف همه دادهها"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"بازنشانی پایانه"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"دادهها حذف خواهد شد"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"تأیید کردن"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"دادهها حذف خواهد شد"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"بازنشانی"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"لغو کردن"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"پشتیبانگیری از دادهها در <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"بازیابی انجام نشد چون فایل پشتیبان مشکل داشت"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"بهدلیل خطای نسخه پشتیبان بازیابی نشد"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"بازیابی انجام نشد"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"فایل پشتیبان حذف نشد"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"دادههای نسخه پشتیبان حذف نشد"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"حذف دادههای پشتیبان"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"پاکسازی <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"خطای غیرقابلبازیابی"</string>
- <string name="error_desc" msgid="1939028888570920661">"بازیابی از خطا ممکن نبود.\nمیتوانید برنامه را بازراهاندازی کنید یا یکی از گزینههای بازیابی را امتحان کنید."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"حذف <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"خطای غیرقابلبازیابی"</string>
+ <string name="error_desc" msgid="4588252235686826721">"بازیابی از خطا ممکن نبود.\nمیتوانید پایانه را بازراهاندازی کنید یا یکی از گزینههای بازیابی را امتحان کنید.\nاگر همه تلاشها ناموفق بود، همه دادهها را با روشن/خاموش کردن پایانه Linux از گزینههای توسعهدهندگان محو کنید."</string>
<string name="error_code" msgid="3585291676855383649">"کد خطا: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"تنظیمات"</string>
<string name="service_notification_title" msgid="2918088850910713393">"پایانه درحال اجرا است"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"برای باز کردن پایانه، کلیک کنید"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"برای باز کردن پایانه، کلیک کنید"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"بستن"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"پایانه درحال بسته شدن است"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"بستن اجباری"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> فعال شد"</string>
</resources>
diff --git a/android/TerminalApp/res/values-fi/strings.xml b/android/TerminalApp/res/values-fi/strings.xml
index 219a3fd..aec6a47 100644
--- a/android/TerminalApp/res/values-fi/strings.xml
+++ b/android/TerminalApp/res/values-fi/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Pääte"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminaalinäyttö"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kohdistin"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Tyhjä rivi"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Kirjoitussyötä kaksoisnapauttamalla"</string>
<string name="installer_title_text" msgid="500663060973466805">"Asenna Linux-pääte"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux-päätteen käynnistäminen edellyttää, että lataat noin <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dataa verkon kautta.\nHaluatko jatkaa?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Lataa, kun Wi-Fi on käytettävissä"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux-päätteen käynnistäminen edellyttää, että lataat noin <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dataa verkon kautta.\nHaluatko jatkaa?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Lataaminen vain Wi-Fi-yhteydellä"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Asenna"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Asennetaan"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Verkkovirhe. Tarkista yhteys ja yritä uudelleen."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Asennus epäonnistui verkkovirheen vuoksi. Tarkista verkkoyhteys ja yritä uudelleen."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux-päätettä asennetaan"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-pääte käynnistetään, kun se on valmis"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Asennus epäonnistui verkkovirheen vuoksi"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Asennus epäonnistui. Yritä uudelleen."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux-pääte käynnistyy, kun asennus on valmis"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Asennus epäonnistui verkkovirheen vuoksi"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Asennus epäonnistui, koska Wi-Fi ei ole käytettävissä"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Asennus epäonnistui. Yritä uudelleen"</string>
<string name="action_settings" msgid="5729342767795123227">"Asetukset"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Valmistellaan päätettä"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Pysäytetään terminaalia"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminaali kaatui"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Muuta levyn kokoa"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Muuta kokoa / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Muuta levyn kokoa"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Muuta juuriosiokoon kokoa"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Levyn koko asetettu"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> määritetty"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Enintään <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Peru"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Ota käyttöön uudelleenkäynnistämällä"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Porttiohjaus"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Määritä porttiohjaus"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Pääte yrittää avata uuden portin"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Avattavaksi pyydetty portti: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Käytä"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Levyn kokoa muutetaan uudelleenkäynnistyksen jälkeen"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Vahvista"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Porttien ohjaus"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Salli/kiellä kuunteluportit"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Kuunteluportit"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Tallennetut sallitut portit"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Lisää"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Poista <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Salli uusi portti"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Lisää uusi porttinumero"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Tallenna"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Peru"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Lisää numero"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Virheellinen portin numero"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Portti on jo olemassa"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Pääte yrittää avata uuden portin"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Pyydetty portti: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Hyväksy"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Hylkää"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Palautus"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Osion palautusvaihtoehdot"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Vaihda ensimmäiseen versioon"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Poista kaikki"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Osion palautusvaihtoehdot"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Palauta alkuperäinen versio"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Poista kaikki data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Nollaa terminaali"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data poistetaan"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Vahvista"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data poistetaan"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Nollaa"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Peru"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Varmuuskopioi data tänne: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Palautus epäonnistui, koska varmuuskopiointi epäonnistui"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Palautus epäonnistui varmuuskopiointivirheen vuoksi"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Palautus epäonnistui"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Varmuuskopiota ei voi poistaa"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Varmuuskopiodatan poistaminen epäonnistui"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Poista varmuuskopiodata"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Poista <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Peruuttamaton virhe"</string>
- <string name="error_desc" msgid="1939028888570920661">"Virheen korjaaminen epäonnistui.\nVoit yrittää käynnistää sovelluksen uudelleen tai kokeilla jotakin korjausvaihtoehtoa."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Poista <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Peruuttamaton virhe"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Virheen korjaaminen epäonnistui.\nVoit yrittää käynnistää päätelaitteen uudelleen tai kokeilla jotakin korjausvaihtoehtoa.\nJos kaikki yritykset epäonnistuvat, pyyhi kaikki data laittamalla Linux-päätelaite päälle ja pois päältä kehittäjäasetuksista."</string>
<string name="error_code" msgid="3585291676855383649">"Virhekoodi: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Asetukset"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Pääte on käynnissä"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Avaa pääte klikkaamalla"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Avaa pääte klikkaamalla"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Sulje"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal sulkeutuu"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Pakota sulkeutumaan"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> on käytössä"</string>
</resources>
diff --git a/android/TerminalApp/res/values-fr-rCA/strings.xml b/android/TerminalApp/res/values-fr-rCA/strings.xml
index ce5ffae..7d54372 100644
--- a/android/TerminalApp/res/values-fr-rCA/strings.xml
+++ b/android/TerminalApp/res/values-fr-rCA/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Écran du terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Curseur"</string>
+ <string name="empty_line" msgid="5012067143408427178">"La ligne est vide"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Toucher deux fois pour saisir une entrée"</string>
<string name="installer_title_text" msgid="500663060973466805">"Installer le terminal Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Pour lancer un terminal Linux, vous devez télécharger environ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de données sur le réseau.\nSouhaitez-vous continuer?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Télécharger lorsque le Wi-Fi est accessible"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Pour lancer un terminal Linux, vous devez télécharger environ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de données sur le réseau.\nSouhaitez-vous continuer?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Télécharger par Wi-Fi seulement"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installer"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installation…"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Erreur de réseau. Vérifiez la connexion et réessayez."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Échec de l\'installation en raison d\'une erreur de réseau. Vérifiez votre connexion, puis réessayez."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installation du terminal Linux en cours…"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Le terminal Linux démarrera une fois l\'installation terminée"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Échec de l\'installation en raison d\'un problème de réseau"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Échec de l\'installation. Réessayez."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Le terminal Linux démarrera une fois l\'installation terminée"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Échec de l\'installation en raison d\'un problème de réseau"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Échec de l\'installation parce que le Wi-Fi n\'est pas disponible"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Échec de l\'installation. Veuillez réessayer"</string>
<string name="action_settings" msgid="5729342767795123227">"Paramètres"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Préparation du terminal en cours…"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Arrêt du terminal en cours…"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Le terminal a planté"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Redimensionnement du disque"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Redimensionnement/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Redimensionnement du disque"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Redimensionnez la taille de la partition racine"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Taille du disque définie"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> attribués"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> maximum"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Annuler"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Redémarrer pour appliquer"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Redirection de port"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configurez la redirection de port"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Le terminal tente d\'ouvrir un nouveau port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port dont l\'ouverture est demandée : <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Appliquer"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Le terminal sera redémarré pour redimensionner le disque"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmer"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Contrôle du port"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Autoriser/Refuser les ports en mode Réception"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ports en mode Réception"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ports autorisés enregistrés"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ajouter"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Supprimer le port <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Autoriser un nouveau port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Entrez un nouveau numéro de port"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Enregistrer"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Annuler"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Veuillez entrer un numéro"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numéro de port incorrect"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Le port existe déjà"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Le terminal demande d\'ouvrir un nouveau port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port demandé : <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepter"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuser"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Récupération"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Options de récupération de partition"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Passer à la version initiale"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Tout retirer"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Options de récupération de partition"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Réinitialiser à la version initiale"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Retirez toutes les données"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Réinitialiser le terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Les données seront supprimées"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmer"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Les données seront retirées"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Réinitialiser"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Annuler"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sauvegarder les données sur <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Échec de la récupération en raison de l\'échec de la sauvegarde"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Échec de la récupération en raison d\'une erreur de sauvegarde"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Échec de la récupération"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Impossible de retirer le fichier de sauvegarde"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Échec du retrait des données de sauvegarde"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Retirer les données de sauvegarde"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Nettoyage de <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Erreur irrécupérable"</string>
- <string name="error_desc" msgid="1939028888570920661">"Échec de la récupération suite à une erreur.\nVous pouvez essayer de redémarrer l\'appli ou essayer l\'une des options de récupération."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Retirez <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Erreur irrécupérable"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Échec de la récupération suite à une erreur.\nVous pouvez essayer de redémarrer le terminal ou essayer l\'une des options de récupération.\nSi toutes les tentatives échouent, effacez toutes les données en activant/désactivant le terminal Linux à partir des options pour les développeurs."</string>
<string name="error_code" msgid="3585291676855383649">"Code d\'erreur : <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Paramètres"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Le terminal fonctionne"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Cliquez pour ouvrir le terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Cliquez pour ouvrir le terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Fermer"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Le terminal se fermera"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forcer la fermeture"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> est activé"</string>
</resources>
diff --git a/android/TerminalApp/res/values-fr/strings.xml b/android/TerminalApp/res/values-fr/strings.xml
index 412b98a..3fe8772 100644
--- a/android/TerminalApp/res/values-fr/strings.xml
+++ b/android/TerminalApp/res/values-fr/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Affichage du terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Curseur"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Ligne vide"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Appuyez deux fois pour saisir une entrée"</string>
<string name="installer_title_text" msgid="500663060973466805">"Installer le terminal Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Pour lancer le terminal Linux, vous devez télécharger environ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de données via le réseau.\nVoulez-vous continuer ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Télécharger lorsque le Wi-Fi sera disponible"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Pour lancer le terminal Linux, vous devez télécharger environ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de données via le réseau.\nVoulez-vous continuer ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Télécharger uniquement via le Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installer"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installation…"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Erreur réseau. Vérifiez la connexion et réessayez."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Échec de l\'installation en raison d\'une erreur réseau. Vérifiez la connexion, puis réessayez."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installation du terminal Linux…"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Le terminal Linux sera lancé une fois l\'opération terminée"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Échec de l\'installation en raison d\'un problème réseau"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Échec de l\'installation. Réessayez."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Le terminal Linux sera lancé une fois l\'installation terminée"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Échec de l\'installation en raison d\'un problème réseau"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Échec de l\'installation, car le Wi-Fi n\'est pas disponible"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Échec de l\'installation. Veuillez réessayer."</string>
<string name="action_settings" msgid="5729342767795123227">"Paramètres"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Préparation du terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Arrêt du terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Le terminal a planté"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Redimensionnement du disque"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Redimensionner/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Redimensionnement du disque"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Redimensionner la partition racine"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Taille du disque définie"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> attribués"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> maximum"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Annuler"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Redémarrer pour appliquer"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Transfert de port"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configurer le transfert de port"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Le terminal essaie d\'ouvrir un nouveau port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Demande d\'ouverture du port suivant : <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Appliquer"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Le terminal sera redémarré pour redimensionner le disque"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmer"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Contrôle de port"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Autoriser/refuser les ports d\'écoute"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ports d\'écoute"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ports autorisés enregistrés"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ajouter"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Supprimer <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Autoriser un nouveau port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Saisissez le numéro du nouveau port"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Enregistrer"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Annuler"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Veuillez saisir un numéro"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numéro de port incorrect"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Le port existe déjà"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Le terminal demande l\'ouverture d\'un nouveau port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port demandé : <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepter"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuser"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Récupération"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Options de récupération de la partition"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Revenir à la version initiale"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Tout supprimer"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Options de récupération de la partition"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Revenir à la version initiale"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Supprimer toutes les données"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Réinitialiser le terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Les données seront supprimées"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmer"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Les données seront supprimées"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Réinitialiser"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Annuler"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sauvegarder les données dans <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Récupération impossible en raison de l\'échec de la sauvegarde"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Échec de la récupération en raison d\'une erreur de sauvegarde"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Échec de la récupération"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Impossible de supprimer le fichier de sauvegarde"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Échec de la suppression des données de sauvegarde"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Supprimer les données de sauvegarde"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Libérer de l\'espace dans <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Supprimer <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Erreur irrécupérable"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Échec de la récupération après une erreur.\nVous pouvez essayer de redémarrer le terminal ou d\'utiliser l\'une des options de récupération.\nSi toutes les tentatives échouent, effacez toutes les données en activant/désactivant le terminal Linux à partir des options pour les développeurs."</string>
+ <string name="error_code" msgid="3585291676855383649">"Code d\'erreur : <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Paramètres"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal en cours d\'exécution"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Cliquez pour ouvrir le terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Cliquez pour ouvrir le terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Fermer"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal se ferme"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forcer la fermeture"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> est activé"</string>
</resources>
diff --git a/android/TerminalApp/res/values-gl/strings.xml b/android/TerminalApp/res/values-gl/strings.xml
index 61ffa17..ec98910 100644
--- a/android/TerminalApp/res/values-gl/strings.xml
+++ b/android/TerminalApp/res/values-gl/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Pantalla do terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Liña baleira"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Toca dúas veces para escribir texto"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalar o terminal de Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Para iniciar o terminal de Linux, tes que descargar uns <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de datos a través da rede.\nQueres continuar?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Descargar cando haxa wifi dispoñible"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Para iniciar o terminal de Linux, tes que descargar aproximadamente <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de datos a través da rede.\nQueres continuar?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Descargar só por wifi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalar"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalando"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Produciuse un erro da rede. Comproba a conexión e téntao de novo."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Non se puido completar a instalación por un erro da rede. Comproba a túa conexión e téntao de novo."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instalando terminal de Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"O terminal de Linux iniciarase en canto remate a instalación"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Produciuse un erro durante instalación por un problema coa rede"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Produciuse un erro durante a instalación. Téntao de novo."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"O terminal de Linux iniciarase en canto remate a instalación"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Produciuse un erro durante instalación por un problema coa rede"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Produciuse un erro durante a instalación porque non hai ningunha wifi dispoñible"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Produciuse un erro durante a instalación. Téntao de novo"</string>
<string name="action_settings" msgid="5729342767795123227">"Configuración"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparando terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Parando terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Produciuse un fallo no terminal"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Cambiar tamaño do disco"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Cambia o tamaño/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Cambiar o tamaño do disco"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Cambia o tamaño da partición raíz"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Definiuse o tamaño do disco"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Tamaño asignado: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> como máximo"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancelar"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Reiniciar e aplicar"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Encamiñamento de porto"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configura o encamiñamento de porto"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"O terminal está tentando abrir outro porto"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Porto que se solicitou abrir: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplicar"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"O terminal reiniciarase para cambiar o tamaño do disco"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmar"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control de portos"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir ou rexeitar portos de escoita"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portos de escoita"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gardáronse os portos permitidos"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Engadir"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eliminar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Permitir outro porto"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Mete outro número de porto"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Gardar"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancelar"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Pon un número"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"O número de porto non é válido"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Xa existe o porto"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"O terminal está solicitando que se abra outro porto"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Porto solicitado: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceptar"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Denegar"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recuperación"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opcións de recuperación da partición"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Cambiar á versión inicial"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Quita todo"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opcións de recuperación da partición"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Restablecer a versión inicial"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Elimina todos os datos"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Restablecer o terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Eliminaranse os datos"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmar"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Quitaranse os datos"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Restablecer"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancelar"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Facer unha copia de seguranza dos datos en <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Fallou a recuperación porque se produciu un erro na copia de seguranza"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Non se levou a cabo a recuperación debido a un erro coa copia de seguranza"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Produciuse un erro na recuperación"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Non se puido quitar o ficheiro da copia de seguranza"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Produciuse un erro ao quitar os datos da copia de seguranza"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Quitar datos da copia de seguranza"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Liberar espazo de <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Produciuse un erro que impide a recuperación"</string>
- <string name="error_desc" msgid="1939028888570920661">"Produciuse un fallo de recuperación despois dun erro.\nPodes probar a reiniciar a aplicación ou usar unha das opcións de recuperación."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Quita <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Produciuse un erro que impide a recuperación"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Non se puido recuperar a información despois dun erro.\nPodes probar a reiniciar o terminal ou tentar usar unha das opcións de recuperación.\nSe non se soluciona o problema, activa e desactiva o terminal de Linux nas opcións de programación para borrar todos os datos."</string>
<string name="error_code" msgid="3585291676855383649">"Código de erro: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Configuración"</string>
<string name="service_notification_title" msgid="2918088850910713393">"O terminal está en funcionamento"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Fai clic para abrir o terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Fai clic para abrir o terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Pechar"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"A aplicación Terminal estase pechando"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forzar peche"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Activouse <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-gu/strings.xml b/android/TerminalApp/res/values-gu/strings.xml
index 0d74ec0..d53d3eb 100644
--- a/android/TerminalApp/res/values-gu/strings.xml
+++ b/android/TerminalApp/res/values-gu/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ટર્મિનલ"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ટર્મિનલ ડિસ્પ્લે"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"કર્સર"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ખાલી લાઇન"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ઇનપુટ ટાઇપ કરવા માટે બે વાર ટૅપ કરો"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ટર્મિનલ ઇન્સ્ટૉલ કરો"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ટર્મિનલ લૉન્ચ કરવા માટે, તમારે નેટવર્ક પર આશરે <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ડેટા ડાઉનલોડ કરવાની જરૂર છે.\nશું તમારે આગળ વધવું છે?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"જ્યારે વાઇ-ફાઇ ઉપલબ્ધ હોય, ત્યારે ડાઉનલોડ કરો"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ટર્મિનલ લૉન્ચ કરવા માટે, તમારે નેટવર્ક પર આશરે <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ડેટા ડાઉનલોડ કરવાની જરૂર છે.\nશું તમે આગળ વધવા માગો છો?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"માત્ર વાઇ-ફાઇનો ઉપયોગ કરીને ડાઉનલોડ કરો"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ઇન્સ્ટૉલ કરો"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ઇન્સ્ટૉલ કરી રહ્યાં છીએ"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"નેટવર્ક ભૂલ. કનેક્શન ચેક કરો અને ફરી પ્રયાસ કરો."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"નેટવર્ક ભૂલને કારણે ઇન્સ્ટૉલ કરવામાં નિષ્ફળ રહ્યાં. તમારું ઇન્ટરનેટ કનેક્શન ચેક કરો અને ફરી પ્રયાસ કરો."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ટર્મિનલ ઇન્સ્ટૉલ કરી રહ્યાં છીએ"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"પ્રક્રિયા સમાપ્ત થયા પછી Linux ટર્મિનલ શરૂ થશે"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"નેટવર્કની સમસ્યાને કારણે ઇન્સ્ટૉલ કરવામાં નિષ્ફળ રહ્યાં"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ઇન્સ્ટૉલ કરવામાં નિષ્ફળ રહ્યાં. ફરી પ્રયાસ કરો."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ઇન્સ્ટૉલેશનની પ્રક્રિયા સમાપ્ત થયા પછી Linux ટર્મિનલ શરૂ થશે"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"નેટવર્ક સંબંધી કોઈ સમસ્યાને કારણે ઇન્સ્ટૉલ કરવામાં નિષ્ફળ રહ્યાં"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"વાઇ-ફાઇ ઉપલબ્ધ ન હોવાથી ઇન્સ્ટૉલ કરવામાં નિષ્ફળ રહ્યાં"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ઇન્સ્ટૉલ કરવામાં નિષ્ફળ રહ્યાં. કૃપા કરીને ફરી પ્રયાસ કરો"</string>
<string name="action_settings" msgid="5729342767795123227">"સેટિંગ"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ટર્મિનલ તૈયાર કરી રહ્યાં છીએ"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ટર્મિનલ બંધ કરી રહ્યાં છીએ"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ટર્મિનલ ક્રૅશ થયું"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ડિસ્કનું કદ બદલવું"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"કદ બદલો / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ડિસ્કનું કદ બદલવું"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"રૂટ પાર્ટિશનનું કદ બદલો"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ડિસ્કનું કદ સેટ કર્યું"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> સોંપ્યું છે"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"મહત્તમ <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"રદ કરો"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"લાગુ કરવા ફરી શરૂ કરો"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"પોર્ટ ફૉરવર્ડિંગ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"પોર્ટ ફૉરવર્ડિંગનું કન્ફિગ્યુરેશન કરો"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ટર્મિનલ નવું પોર્ટ ખોલવાનો પ્રયાસ કરી રહ્યું છે"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"પોર્ટને ખોલવાની વિનંતી કરવામાં આવી: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"લાગુ કરો"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ડિસ્કનું કદ બદલવા માટે ટર્મિનલને ફરી શરુ કરવામાં આવશે"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"કન્ફર્મ કરો"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"પોર્ટ નિયંત્રણ"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"સાંભળનાર પોર્ટને મંજૂરી આપો/નકારો"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"સાંભળનાર પોર્ટ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"સાચવેલા મંજૂરીપ્રાપ્ત પોર્ટ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ઉમેરો"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ડિલીટ કરો"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"નવા પોર્ટને મંજૂરી આપો"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"નવો પોર્ટ નંબર દાખલ કરો"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"સાચવો"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"રદ કરો"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"કૃપા કરીને કોઈ નંબર દાખલ કરો"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"પોર્ટ નંબર અમાન્ય છે"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"પોર્ટ પહેલેથી અસ્તિત્વમાં છે"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ટર્મિનલ નવું પોર્ટ ખોલવા માટે વિનંતી કરી રહ્યું છે"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"પોર્ટ કરવાની વિનંતી કરવામાં આવી: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"સ્વીકારો"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"નકારો"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"રિકવરી"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"પાર્ટિશન રિકવરીના વિકલ્પો"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"બદલીને પ્રારંભિક વર્ઝન કરો"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"તમામ કાઢી નાખો"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"પાર્ટિશન રિકવરીના વિકલ્પો"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"પ્રારંભિક વર્ઝન પર રીસેટ કરો"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"બધો ડેટા કાઢી નાખો"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ટર્મિનલ રીસેટ કરો"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ડેટા ડિલીટ કરવામાં આવશે"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"કન્ફર્મ કરો"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ડેટા કાઢી નાખવામાં આવશે"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"રીસેટ કરો"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"રદ કરો"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> પર ડેટાનું બૅકઅપ લો"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"બૅકઅપ નિષ્ફળ જવાને લીધે રિકવરી નિષ્ફળ રહી"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"બૅકઅપમાં ભૂલને કારણે રિકવર કરવામાં નિષ્ફળ રહ્યાં"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"રિકવરી નિષ્ફળ રહી"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"બૅકઅપ ફાઇલ કાઢી શકતા નથી"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"બૅકઅપ ડેટા કાઢી નાખવામાં નિષ્ફળ રહ્યાં"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"બૅકઅપ ડેટા કાઢી નાખો"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"ક્લિન અપ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> કાઢી નાખો"</string>
+ <string name="error_title" msgid="405150657301906598">"ભૂલને કારણે રિકવર કરવો અશક્ય"</string>
+ <string name="error_desc" msgid="4588252235686826721">"કોઈ ભૂલમાંથી રિકવર કરવામાં નિષ્ફળ રહ્યાં.\nતમે ટર્મિનલને ફરી શરૂ કરવાનો પ્રયાસ કરી શકો છો અથવા રિકવરીના વિકલ્પોમાંનો કોઈ એક વિકલ્પ અજમાવી શકો છો.\nજો બધા પ્રયાસો નિષ્ફળ જાય, તો ડેવલપરના વિકલ્પોમાંથી Linux ટર્મિનલને ચાલુ/બંધ કરીને બધો ડેટા વાઇપ કરો."</string>
+ <string name="error_code" msgid="3585291676855383649">"ભૂલનો કોડ: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"સેટિંગ"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ટર્મિનલ ચાલી રહ્યું છે"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ટર્મિનલ ખોલવા માટે ક્લિક કરો"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ટર્મિનલ ખોલવા માટે ક્લિક કરો"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"બંધ કરો"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ટર્મિનલ ઍપ બંધ થઈ રહી છે"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"ફરજિયાત બંધ કરો"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ચાલુ કરેલું છે"</string>
</resources>
diff --git a/android/TerminalApp/res/values-hi/strings.xml b/android/TerminalApp/res/values-hi/strings.xml
index 5fcc177..b644e1f 100644
--- a/android/TerminalApp/res/values-hi/strings.xml
+++ b/android/TerminalApp/res/values-hi/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"टर्मिनल डिसप्ले"</string>
<string name="terminal_input" msgid="4602512831433433551">"कर्सर."</string>
<string name="empty_line" msgid="5012067143408427178">"खाली लाइन"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"इनपुट टाइप करने के लिए, दो बार टैप करें"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux टर्मिनल ऐप्लिकेशन इंस्टॉल करें"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux टर्मिनल ऐप्लिकेशन को लॉन्च करने के लिए, आपको इंटरनेट से <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> डेटा डाउनलोड करना होगा.\nक्या आपको आगे बढ़ना है?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"वाई-फ़ाई उपलब्ध होने पर डाउनलोड करें"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux टर्मिनल ऐप्लिकेशन को लॉन्च करने के लिए, आपको इंटरनेट का इस्तेमाल करके <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> डेटा डाउनलोड करना होगा.\nक्या आपको आगे बढ़ना है?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"सिर्फ़ वाई-फ़ाई का इस्तेमाल करके डाउनलोड करें"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"इंस्टॉल करें"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"इंस्टॉल हो रहा"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"नेटवर्क की गड़बड़ी हुई. इंटरनेट कनेक्शन की जांच करें और फिर से कोशिश करें."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"नेटवर्क की किसी गड़बड़ी की वजह से, ऐप्लिकेशन को इंस्टॉल नहीं किया जा सका. अपने इंटरनेट कनेक्शन की जांच करें और दोबारा कोशिश करें."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux टर्मिनल ऐप्लिकेशन इंस्टॉल हो रहा है"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"प्रोसेस पूरी होने के बाद, Linux टर्मिनल ऐप्लिकेशन, इस्तेमाल किया जा सकेगा"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"नेटवर्क की समस्या की वजह से, इंस्टॉल नहीं किया जा सका"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"वाई-फ़ाई उपलब्ध न होने की वजह से, इंस्टॉल नहीं किया जा सका"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"इंस्टॉल नहीं किया जा सका. फिर से कोशिश करें."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"इंस्टॉल पूरा होने के बाद, Linux टर्मिनल चालू हो जाएगा"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"नेटवर्क की किसी समस्या की वजह से, इंस्टॉल नहीं किया जा सका"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"वाई-फ़ाई उपलब्ध न होने की वजह से, इंस्टॉल नहीं किया जा सका"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"इंस्टॉल नहीं किया जा सका. कृपया फिर से कोशिश करें"</string>
<string name="action_settings" msgid="5729342767795123227">"सेटिंग"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"टर्मिनल तैयार किया जा रहा है"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"टर्मिनल को रोका जा रहा है"</string>
<string name="vm_error_message" msgid="5231867246177661525">"टर्मिनल क्रैश हो गया"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"डिस्क का साइज़ बदलें"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"साइज़ बदलें / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"डिस्क का साइज़ बदलें"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"रूट पार्टिशन का साइज़ बदलें"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"डिस्क का साइज़ सेट किया गया"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> असाइन किया गया"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"मैक्सिमम <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"रद्द करें"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"रीस्टार्ट करें"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"पोर्ट फ़ॉरवर्डिंग"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"पोर्ट फ़ॉरवर्डिंग को कॉन्फ़िगर करें"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"टर्मिनल, एक नया पोर्ट खोलने की कोशिश कर रहा है"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"पोर्ट को खोलने का अनुरोध किया गया: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"लागू करें"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"डिस्क का साइज़ बदलने के लिए, टर्मिनल को रीस्टार्ट किया जाएगा"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"पुष्टि करें"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"पोर्ट कंट्रोल"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"लिसनिंग पोर्ट को अनुमति दें या अनुमति न दें"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"लिसनिंग पोर्ट"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"अनुमति पा चुके सभी पोर्ट को सेव किया गया"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"जोड़ें"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> को मिटाएं"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"नए पोर्ट को अनुमति दें"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"नया पोर्ट नंबर डालें"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"सेव करें"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"रद्द करें"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"कृपया कोई नंबर डालें"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"अमान्य पोर्ट संख्या"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"पोर्ट पहले से मौजूद है"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"टर्मिनल, एक नया पोर्ट खोलने का अनुरोध कर रहा है"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"पोर्ट खोलने का अनुरोध किया गया: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"स्वीकार करें"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"अस्वीकार करें"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"इमेज रिकवर करें"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"इमेज के हिस्से को रिकवर करने के विकल्प"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"शुरुआती वर्शन पर स्विच करें"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"सभी हटाएं"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"इमेज के हिस्से को रिकवर करने के विकल्प"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"रीसेट करके शुरुआती वर्शन पर जाएं"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"सारा डेटा हटाएं"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"टर्मिनल रीसेट करें"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"डेटा मिटा दिया जाएगा"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"पुष्टि करें"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"डेटा हटा दिया जाएगा"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"रीसेट करें"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"अभी नहीं"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> पर डेटा का बैक अप लें"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"बैकअप पूरा न होने की वजह से, रिकवर नहीं किया जा सका"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"बैकअप लेने में हुई गड़बड़ी की वजह से, डेटा वापस नहीं पाया जा सका"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"रिकवर नहीं किया जा सका"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"बैकअप फ़ाइल को हटाया नहीं जा सकता"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"बैकअप डेटा नहीं हटाया जा सका"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"बैकअप डेटा हटाएं"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> का बैकअप डेटा हटाएं"</string>
- <string name="error_title" msgid="7196464038692913778">"वह गड़बड़ी जिसकी वजह से डेटा वापस नहीं पाया जा सकता"</string>
- <string name="error_desc" msgid="1939028888570920661">"गड़बड़ी ठीक नहीं की जा सकी.\nऐप्लिकेशन को रीस्टार्ट करने की कोशिश करें या गड़बड़ी ठीक करने का कोई विकल्प आज़माएं."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> को हटाएं"</string>
+ <string name="error_title" msgid="405150657301906598">"ऐसी गड़बड़ी जिसकी वजह से डेटा वापस नहीं पाया जा सकता"</string>
+ <string name="error_desc" msgid="4588252235686826721">"किसी गड़बड़ी की वजह से डेटा वापस नहीं पाया जा सका.\nटर्मिनल को रीस्टार्ट करके देखें या डेटा वापस पाने के किसी एक विकल्प को आज़माएं.\nअगर सभी कोशिशें बेकार हो जाती हैं, तो \'डेवलपर के लिए सेटिंग और टूल\' से Linux टर्मिनल को चालू/बंद करके, सारा डेटा मिटा दें."</string>
<string name="error_code" msgid="3585291676855383649">"गड़बड़ी का कोड: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"सेटिंग"</string>
<string name="service_notification_title" msgid="2918088850910713393">"टर्मिनल चालू है"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"टर्मिनल खोलने के लिए क्लिक करें"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"टर्मिनल खोलने के लिए क्लिक करें"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"बंद करें"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"टर्मिनल ऐप्लिकेशन बंद हो रहा है"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"ज़बरदस्ती बंद करें"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> चालू है"</string>
</resources>
diff --git a/android/TerminalApp/res/values-hr/strings.xml b/android/TerminalApp/res/values-hr/strings.xml
index 686492c..8ce5af5 100644
--- a/android/TerminalApp/res/values-hr/strings.xml
+++ b/android/TerminalApp/res/values-hr/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Zaslon terminala"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Pokazivač"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Prazan redak"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dvaput dodirnite za unos"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalirajte Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Da biste pokrenuli Linux terminal, trebate preuzeti otprilike <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podataka putem mreže.\nŽelite li nastaviti?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Preuzmi kada Wi-Fi bude dostupan"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Da biste pokrenuli Linux terminal, trebate preuzeti oko <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podataka putem mreže.\nŽelite li nastaviti?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Preuzimanje samo putem Wi-Fi mreže"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instaliraj"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instaliranje"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Mrežna pogreška. Provjerite vezu i pokušajte ponovo."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Instaliranje nije uspjelo zbog mrežne pogreške. Provjerite vezu i pokušajte ponovo."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instaliranje Linux terminala"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal pokrenut će se nakon završetka"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Instalacija nije uspjela zbog problema s mrežom"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Instaliranje nije uspjelo. Pokušajte ponovo."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminal pokrenut će se nakon završetka instaliranja"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Instaliranje nije uspjelo zbog problema s mrežom"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Instaliranje nije uspjelo jer Wi-Fi nije dostupan"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Instaliranje nije uspjelo. Pokušajte ponovo"</string>
<string name="action_settings" msgid="5729342767795123227">"Postavke"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Priprema terminala"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Zaustavljanje terminala"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal se srušio"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Promjena veličine diska"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Promjena veličine/rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Promjena veličine diska"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Promjena veličine korijenske particije"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Veličina diska je postavljena"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Dodijeljeno: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maks. <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Odustani"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Ponovo pokrenite za primjenu"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Prosljeđivanje priključka"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfiguriranje prosljeđivanja priključka"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal pokušava otvoriti novi priključak"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Zatraženo je otvaranje priključka: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Primijeni"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal će se ponovo pokrenuti da bi se promijenila veličina diska"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Potvrdi"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrola priključka"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dopusti/odbij priključke za slušanje"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Priključci za slušanje"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Spremljeni dopušteni priključci"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Izbriši priključak <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Dopusti novi priključak"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Unesite novi broj priključka"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Spremi"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Odustani"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Unesite broj"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nevažeći broj priključka"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Priključak već postoji"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal zahtijeva da se otvori novi priključak"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Zatraženi priključak: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prihvati"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odbij"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Oporavak"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opcije oporavka particije"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Vrati na početnu verziju"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Ukloni sve"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opcije oporavka particije"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Vraćanje na početnu verziju"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Uklanjanje svih podataka"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Poništavanje terminala"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Podaci će se izbrisati"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Potvrdi"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Podaci će se ukloniti"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Poništi"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Odustani"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sigurnosno kopiranje podataka u <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Oporavak nije uspio jer sigurnosno kopiranje nije uspjelo"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Oporavak nije uspio zbog pogreške sigurnosnog kopiranja"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Oporavak nije uspio"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Datoteka sigurnosne kopije ne može se ukloniti"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Uklanjanje podataka sigurnosne kopije nije uspjelo"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Ukloni podatke sigurnosne kopije"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Izbriši <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Uklanjanje puta <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Nepopravljiva pogreška"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Oporavak od pogreške nije uspio.\nMožete pokušati ponovo pokrenuti terminal ili isprobajte jednu od opcija oporavka.\nAko nijedna metoda ne uspije, izbrišite sve podatke tako da uključite/isključite Linux terminal u opcijama za razvojne programere."</string>
+ <string name="error_code" msgid="3585291676855383649">"Kôd pogreške: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Postavke"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal je pokrenut"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliknite da biste otvorili terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliknite da biste otvorili terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Zatvori"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal se zatvara"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Prisilno zatvori"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Omogućeno je: <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-hu/strings.xml b/android/TerminalApp/res/values-hu/strings.xml
index 892de69..f3058d0 100644
--- a/android/TerminalApp/res/values-hu/strings.xml
+++ b/android/TerminalApp/res/values-hu/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"Terminálkijelző"</string>
<string name="terminal_input" msgid="4602512831433433551">"Kurzor"</string>
<string name="empty_line" msgid="5012067143408427178">"Üres sor"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"A bevitel beírásához koppintson duplán"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux-terminál telepítése"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"A Linux-terminál elindításához körülbelül <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> adatmennyiséget kell letöltenie a hálózaton keresztül.\nFolytatja?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Letöltés, ha rendelkezésre áll Wi-Fi-kapcsolat"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"A Linux-terminál elindításához körülbelül <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> adatmennyiséget kell letöltenie a hálózaton keresztül.\nFolytatja?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Letöltés csak Wi-Fi-kapcsolattal"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Telepítés"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Telepítés…"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Hálózati hiba. Ellenőrizze a kapcsolatot, majd próbálja újra."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Hálózati hiba miatt nem sikerült a telepítés. Ellenőrizze a kapcsolatot, majd próbálkozzon újra."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux-terminál telepítése…"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"A Linux-terminál a befejezés után indul el"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Hálózati probléma miatt nem sikerült a telepítés"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"Nem sikerült a telepítés, mert nincs Wi-Fi-kapcsolat"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"Nem sikerült a telepítés. Próbálkozzon újra."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"A Linux-terminál a telepítés befejezése után indul el"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Hálózati probléma miatt nem sikerült a telepítés"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Nem sikerült a telepítés, mert nincs Wi-Fi-kapcsolat"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Nem sikerült a telepítés. Próbálkozzon újra."</string>
<string name="action_settings" msgid="5729342767795123227">"Beállítások"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"A terminál előkészítése…"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"A terminál leállítása…"</string>
<string name="vm_error_message" msgid="5231867246177661525">"A terminál összeomlott"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Lemez átméretezése"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Átméretezés/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Lemez átméretezése"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"A gyökérpartíció átméretezése"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Lemezméret beállítva"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> hozzárendelve"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maximum: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Mégse"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Újraindítás az alkalmazáshoz"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Portátirányítás"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Portátirányítás konfigurálása"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"A Terminal új portot próbál megnyitni"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"A megnyitni kívánt port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Alkalmazás"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"A lemez átméretezése miatt a terminál újraindul"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Megerősítés"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portvezérlés"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Figyelő portok engedélyezése/letiltása"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Figyelő portok"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Mentett engedélyezett portok"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Hozzáadás"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> törlése"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Új port engedélyezése"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Adja meg az új portszámot"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Mentés"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Mégse"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Adjon meg egy számot"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Érvénytelen a portszám"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"A port már létezik"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"A terminál új port megnyitását kéri"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Kért port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Elfogadás"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Elutasítás"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Helyreállítás"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Partíció-helyreállítási lehetőségek"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Váltás az eredeti verzióra"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Az összes eltávolítása"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Partíció-helyreállítási lehetőségek"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Visszaállítás az eredeti verzióra"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Összes adat eltávolítása"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminál visszaállítása"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Az adatok törlődni fognak"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Megerősítés"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Az adatok el lesznek távolítva"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Visszaállítás"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Mégse"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Adatok biztonsági mentése ide: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"A helyreállítás sikertelen volt, mert a biztonsági mentés nem sikerült"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"A helyreállítás a biztonsági mentés hibája miatt sikertelen volt"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Sikertelen helyreállítás"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Nem sikerült eltávolítani a biztonságimentés-fájlt"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"A biztonsági másolat adatainak eltávolítása sikertelen volt"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Biztonsági másolat adatainak eltávolítása"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"A(z) <xliff:g id="PATH">/mnt/backup</xliff:g> útvonalon lévő adatok eltávolítása"</string>
- <string name="error_title" msgid="7196464038692913778">"Helyrehozhatatlan hiba"</string>
- <string name="error_desc" msgid="1939028888570920661">"Nem sikerült a hiba utáni helyreállítás.\nPróbálkozhat az alkalmazás újraindításával, vagy kipróbálhatja valamelyik helyreállítási lehetőséget."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> eltávolítása"</string>
+ <string name="error_title" msgid="405150657301906598">"Helyrehozhatatlan hiba"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Nem sikerült a hiba utáni helyreállítás.\nPróbálkozhat a terminál újraindításával, vagy kipróbálhatja valamelyik helyreállítási lehetőséget.\nHa minden próbálkozás sikertelen, a fejlesztői beállítások közötti Linux-terminál be-/kikapcsolásával visszaállíthatatlanul törölheti az összes adatot."</string>
<string name="error_code" msgid="3585291676855383649">"Hibakód: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Beállítások"</string>
<string name="service_notification_title" msgid="2918088850910713393">"A terminál fut"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kattintson a terminál megnyitásához"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kattintson a terminál megnyitásához"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Bezárás"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"A terminál bezárul"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Bezárás kényszerítése"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"A(z) <xliff:g id="ID_1">VirGL</xliff:g> engedélyezve van"</string>
</resources>
diff --git a/android/TerminalApp/res/values-hy/strings.xml b/android/TerminalApp/res/values-hy/strings.xml
index 5a2f90d..f11469b 100644
--- a/android/TerminalApp/res/values-hy/strings.xml
+++ b/android/TerminalApp/res/values-hy/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Տերմինալ"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Տերմինալի էկրան"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Նշորդ"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Դատարկ տող"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Կրկնակի հպեք մուտքագրելու համար"</string>
<string name="installer_title_text" msgid="500663060973466805">"Լինուքս տերմինալի տեղադրում"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Լինուքս տերմինալը գործարկելու համար անհրաժեշտ է ցանցի միջոցով ներբեռնել մոտ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> տվյալ։\nՇարունակե՞լ։"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Ներբեռնել, երբ սարքը միանա Wi-Fi-ին"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Լինուքս տերմինալը գործարկելու համար անհրաժեշտ է ցանցի միջոցով ներբեռնել մոտ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> տվյալ։\nՇարունակե՞լ։"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Ներբեռնել միայն Wi-Fi-ով"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Տեղադրել"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Տեղադրվում է"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Ցանցի սխալ։ Ստուգեք կապը և նորից փորձեք։"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Տեղադրումը ձախողվեց ցանցի սխալի պատճառով։ Ստուգեք կապը և նորից փորձեք։"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Լինուքս տերմինալը տեղադրվում է"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Ավարտից հետո Լինուքս տերմինալը կգործարկվի"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Տեղադրումը ձախողվեց ցանցի հետ կապված խնդրի պատճառով"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Չհաջողվեց տեղադրել: Նորից փորձեք։"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Լինուքս տերմինալը կգործարկվի տեղադրման ավարտից հետո"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Տեղադրումը ձախողվեց ցանցի հետ կապված խնդրի պատճառով"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Չհաջողվեց տեղադրել, քանի որ Wi-Fi ցանցը հասանելի չէ"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Չհաջողվեց տեղադրել: Նորից փորձեք"</string>
<string name="action_settings" msgid="5729342767795123227">"Կարգավորումներ"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Տերմինալի նախապատրաստում"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Տերմինալը կանգնեցվում է"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Տերմինալը խափանվել է"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Սկավառակի չափափոխում"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Չափափոխում / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Սկավառակի չափի փոխում"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Փոխել արմատային բաժնի չափը"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Սկավառակի չափսը սահմանված է"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Հատկացված է <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Առավելագույնը՝ <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Չեղարկել"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Կիրառելու համար վերագործարկեք"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Միացքի փոխանցում"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Միացքի փոխանցման կազմաձևում"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Տերմինալը փորձում է նոր միացք բացել"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Միացքը, որը պահանջվում է բացել՝ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Կիրառել"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Տերմինալը կվերագործարկվի սկավառակի չափը փոխելու համար"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Հաստատել"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Միացքների կառավարում"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Թույլատրել/մերժել ունկնդրման միացքները"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ունկնդրման միացքներ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Պահված թույլատրված միացքներ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ավելացնել"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Ջնջել <xliff:g id="PORT_NUMBER">%d</xliff:g> համարի միացքը"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Թույլատրել նոր միացք"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Մուտքագրեք նոր միացքի համարը"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Պահել"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Չեղարկել"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Մուտքագրեք համարը"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Միացքի անվավեր համար"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Միացքն արդեն գոյություն ունի"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Տերմինալը խնդրում է նոր միացք բացել"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Հարցված միացքը՝ <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Ընդունել"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Մերժել"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Վերականգնում"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Բաժնի վերականգնման տարբերակներ"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Նախնական տարբերակի վերականգնում"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Հեռացնել բոլորը"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Բաժնի վերականգնման տարբերակներ"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Վերականգնել նախնական տարբերակը"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Հեռացնել բոլոր տվյալները"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Տերմինալի վերակայում"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Տվյալները կջնջվեն"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Հաստատել"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Տվյալները կհեռացվեն"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Վերակայել"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Չեղարկել"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Պահուստավորել տվյալները այստեղ՝ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Պահուստավորման խափանման պատճառով չհաջողվեց վերականգնել"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Պահուստավորման խնդրի պատճառով չհաջողվեց վերականգնել"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Չհաջողվեց վերականգնել"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Հնարավոր չէ հեռացնել պահուստային կրկնօրինակի ֆայլը"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Չհաջողվեց հեռացնել պահուստավորված տվյալները"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Հեռացնել պահուստավորված տվյալները"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Մաքրել ուղին՝ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Հեռացնել <xliff:g id="PATH">/mnt/backup</xliff:g>ը"</string>
+ <string name="error_title" msgid="405150657301906598">"Հնարավոր չէ վերականգնել"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Չհաջողվեց վերացնել սխալը։\nՎերագործարկեք տերմինալը կամ փորձեք վերականգնման տարբերակներից մեկը։\nԵթե բոլոր փորձերը ձախողվեն, մաքրեք բոլոր տվյալները՝ միացնելով/անջատելով Լինուքս տերմինալը մշակողի ընտրանքներից։"</string>
+ <string name="error_code" msgid="3585291676855383649">"Սխալի կոդը՝ <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Կարգավորումներ"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Տերմինալն աշխատում է"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Սեղմեք՝ տերմինալը բացելու համար"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Սեղմեք՝ տերմինալը բացելու համար"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Փակել"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Տերմինալը փակվում է"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Ստիպողաբար փակել"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g>-ը միացված է"</string>
</resources>
diff --git a/android/TerminalApp/res/values-in/strings.xml b/android/TerminalApp/res/values-in/strings.xml
index 068a693..a2c4b01 100644
--- a/android/TerminalApp/res/values-in/strings.xml
+++ b/android/TerminalApp/res/values-in/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Tampilan terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Baris kosong"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Ketuk dua kali untuk mengetik input"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instal terminal Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Untuk meluncurkan terminal Linux, Anda perlu mendownload sekitar <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data melalui jaringan.\nApakah Anda ingin melanjutkan?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Download saat Wi-Fi tersedia"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Untuk meluncurkan terminal Linux, Anda perlu mendownload sekitar <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data melalui jaringan.\nApakah Anda ingin melanjutkan?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Hanya download melalui Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instal"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Menginstal"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Error jaringan. Periksa koneksi dan coba lagi."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Gagal menginstal karena ada error jaringan. Periksa koneksi dan coba lagi."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Menginstal terminal Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Terminal Linux akan dimulai setelah penginstalan selesai"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Gagal menginstal karena ada masalah jaringan"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Gagal menginstal. Coba lagi."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Terminal Linux akan dimulai setelah penginstalan selesai"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Gagal menginstal karena ada masalah jaringan"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Gagal menginstal karena Wi-Fi tidak tersedia"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Gagal menginstal. Coba lagi"</string>
<string name="action_settings" msgid="5729342767795123227">"Setelan"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Menyiapkan terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Menghentikan terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal error"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Ubah Ukuran Disk"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Ubah ukuran / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Ubah ukuran disk"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Mengubah ukuran partisi root"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Ukuran disk ditetapkan"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ditetapkan"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maks <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Batal"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Mulai ulang untuk menerapkan"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Penerusan Port"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurasi penerusan port"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal mencoba membuka port baru"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port yang diminta untuk dibuka: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Terapkan"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal akan dimulai ulang untuk mengubah ukuran disk"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Konfirmasi"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrol port"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Izinkan/tolak port yang sedang dalam proses"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Port yang sedang dalam proses"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Port yang diizinkan tersimpan"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Tambahkan"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Hapus <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Izinkan port baru"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Masukkan nomor port baru"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Simpan"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Batal"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Masukkan nomor"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nomor port tidak valid"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port sudah ada"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal meminta untuk membuka port baru"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port yang diminta: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Terima"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Tolak"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Pemulihan"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opsi Pemulihan Partisi"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Ubah ke Versi awal"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Hapus semua"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opsi pemulihan partisi"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Reset ke versi awal"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Hapus semua data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Reset terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data akan dihapus"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Konfirmasi"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data akan dihapus"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Reset"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Batal"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Cadangkan data ke <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Pemulihan gagal karena pencadangan gagal"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Gagal memulihkan karena ada error pencadangan"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Pemulihan gagal"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Tidak dapat menghapus file cadangan"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Gagal menghapus data cadangan"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Hapus data cadangan"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Membersihkan <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Error yang Tidak Dapat Dipulihkan"</string>
- <string name="error_desc" msgid="1939028888570920661">"Gagal memulihkan dari error.\nAnda dapat mencoba memulai ulang aplikasi, atau mencoba salah satu opsi pemulihan."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Hapus <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Error yang tidak dapat dipulihkan"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Gagal memulihkan dari error.\nAnda dapat mencoba memulai ulang terminal atau mencoba salah satu opsi pemulihan.\nJika semua upaya gagal, hapus semua data dengan mengaktifkan/menonaktifkan terminal Linux dari opsi developer."</string>
<string name="error_code" msgid="3585291676855383649">"Kode error: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Setelan"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal sedang berjalan"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klik untuk membuka terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klik untuk membuka terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Tutup"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal ditutup"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Tutup paksa"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> diaktifkan"</string>
</resources>
diff --git a/android/TerminalApp/res/values-is/strings.xml b/android/TerminalApp/res/values-is/strings.xml
index e50b1b6..2e97d0c 100644
--- a/android/TerminalApp/res/values-is/strings.xml
+++ b/android/TerminalApp/res/values-is/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Útstöð"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Skjár útstöðvar"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Bendill"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Auð lína"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Ýttu tvisvar til að slá inn ílag"</string>
<string name="installer_title_text" msgid="500663060973466805">"Setja upp Linux-útstöð"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Til að ræsa Linux-útstöð þarftu að sækja um <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> af gögnum yfir netkerfi.\nViltu halda áfram?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Sækja þegar Wi-Fi er tiltækt"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Þú þarft að sækja um <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> af gögnum í gegnum netið til að ræsa Linux-útstöð.\nViltu halda áfram?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Sækja með Wi-Fi eingöngu"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Setja upp"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Setur upp"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Netkerfisvilla. Athugaðu tenginguna og reyndu aftur."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Uppsetning tókst ekki sökum netkerfisvillu. Athugaðu tenginguna og reyndu aftur."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Setur upp Linux-útstöð"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-útstöð verður ræst þegar því lýkur"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Tókst ekki að setja upp vegna netkerfisvandamáls"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Tókst ekki að setja upp. Reyndu aftur."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux-útstöð ræsist að uppsetningu lokinni"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Uppsetning tókst ekki sökum netkerfisvillu"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Uppsetning tókst ekki vegna þess að Wi-Fi er ekki tiltækt"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Uppsetning tókst ekki. Reyndu aftur"</string>
<string name="action_settings" msgid="5729342767795123227">"Stillingar"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Undirbýr útstöð"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stöðvar tengi"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Tengi hrundi"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Breyta stærð disks"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Breyta stærð / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Breyta stærð disks"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Breyta stærð rótardeildar"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Stærð disks stillt"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> úthlutað"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> hámark"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Hætta við"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Endurræsa til að nota"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Framsending gáttar"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Stilla framsendingu gáttar"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Útstöð er að reyna að opna nýtt tengi"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Tengi sem beðið er um að sé opið: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Nota"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Útstöðin verður endurræst til að breyta stærk disks"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Staðfesta"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Gáttarstýring"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Leyfa hlustunargáttir/hafna hlustunargáttum"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Hlustunargáttir"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Vistaðar leyfðar gáttir"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Bæta við"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eyða <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Leyfa nýja gátt"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Slá inn nýtt gáttarnúmer"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Vista"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Hætta við"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Sláðu inn númer"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ógilt númer tengis"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Tengi er þegar til"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Útstöðin bað um að opna nýja gátt"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Gátt sem beðið var um: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Samþykkja"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Hafna"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Endurheimt"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Endurheimtarkostir deildar"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Breyta í upphaflega útgáfu"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Fjarlægja allt"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Endurheimtarkostir deildar"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Endurstilla í upprunalega útgáfu"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Fjarlægja öll gögn"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Endurstilla útstöð"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Gögnum verður eytt"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Staðfesta"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Gögn verða fjarlægð"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Endurstilla"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Hætta við"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Afrita gögn á <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Endurheimt mistókst vegna þess að öryggisafritun mistókst"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Endurheimt tókst ekki sökum afritunarvillu"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Endurheimt mistókst"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Ekki er hægt að fjarlægja öryggisafrit"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Ekki tókst að fjarlægja afrituð gögn"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Fjarlægja afrituð gögn"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Hreinsa <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Óleiðréttanleg villa"</string>
- <string name="error_desc" msgid="1939028888570920661">"Ekki tókst að endurheimta eftir villu.\nÞú getur reynt að endurræsa forritið eða prófað einn af endurheimtarkostunum."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Fjarlægja <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Óleiðréttanleg villa"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Ekki tókst að endurheimta eftir villu.\nÞú getur prófað að endurræsa útstöðina eða velja einn af endurheimtarkostunum.\nEf allar tilraunir mistakast skaltu hreinsa öll gögn með því að kveikja/slökkva á Linux-útstöð í forritunarvalkostum."</string>
<string name="error_code" msgid="3585291676855383649">"Villukóði: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Stillingar"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Útstöð er í gangi"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Smelltu til að opna útstöðina"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Smelltu til að opna útstöðina"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Loka"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal er að loka"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Þvinga fram lokun"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Kveikt er á <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-it/strings.xml b/android/TerminalApp/res/values-it/strings.xml
index 1f99326..1cfd2b5 100644
--- a/android/TerminalApp/res/values-it/strings.xml
+++ b/android/TerminalApp/res/values-it/strings.xml
@@ -20,58 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"Display terminale"</string>
<string name="terminal_input" msgid="4602512831433433551">"Cursore"</string>
<string name="empty_line" msgid="5012067143408427178">"Riga vuota"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Tocca due volte per digitare l\'input"</string>
<string name="installer_title_text" msgid="500663060973466805">"Installa terminale Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Per avviare il terminale Linux, devi scaricare circa <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> di dati tramite la rete.\nContinuare?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Scarica quando è disponibile una rete Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Per avviare il terminale Linux, devi scaricare circa <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> di dati tramite la rete.\nContinuare?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Scarica solo tramite Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installa"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installazione"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Errore di rete. Controlla la connessione e riprova."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Impossibile installare a causa di un errore di rete. Controlla la connessione e riprova."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installazione del terminale Linux in corso…"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Il terminale Linux verrà avviato al termine"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Installazione non riuscita a causa di un problema di rete"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"Impossibile installare: Wi-Fi non disponibile"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"Installazione non riuscita. Riprova."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Il terminale Linux verrà avviato al termine dell\'installazione"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Installazione non riuscita a causa di un problema di rete"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Impossibile installare: Wi-Fi non disponibile"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Installazione non riuscita. Riprova"</string>
<string name="action_settings" msgid="5729342767795123227">"Impostazioni"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparazione terminale in corso…"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Arresto del terminale in corso…"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Arresto anomalo del terminale"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Ridimensionamento disco"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Ridimensiona/rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Ridimensionamento disco"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Ridimensiona la partizione root"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Dimensioni disco impostate"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Assegnato: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Massimo: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Annulla"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Riavvia per applic."</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Port forwarding"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configura port forwarding"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Il terminale sta tentando di aprire una nuova porta"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Porta di cui è stata richiesta l\'apertura: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Applica"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Il terminale verrà riavviato per ridimensionare il disco"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Conferma"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controllo porte"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Consenti/rifiuta porte di ascolto"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porte di ascolto"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Porte consentite salvate"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Aggiungi"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Elimina <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Consenti una nuova porta"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Inserisci un nuovo numero di porta"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Salva"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Annulla"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Inserisci un numero"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numero di porta non valido"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"La porta esiste già"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Il terminale sta chiedendo di aprire una nuova porta"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Porta richiesta: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accetta"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rifiuta"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Ripristino"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opzioni ripristino partizione"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Torna alla versione iniziale"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Rimuovi tutto"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opzioni di recupero partizione"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Ripristina la versione iniziale"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Rimuovi tutti i dati"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Reimposta il terminale"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"I dati verranno eliminati"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Conferma"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"I dati verranno rimossi"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Reimposta"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Annulla"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Esegui il backup dei dati su <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Recupero non riuscito a causa di un errore di backup"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Impossibile recuperare a causa di un errore di backup"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Recupero non riuscito"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Impossibile rimuovere il file di backup"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Impossibile rimuovere i dati di backup"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Rimuovi i dati di backup"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Pulisci <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Rimuovi <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Errore irreversibile"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Impossibile recuperare da un errore.\nPuoi provare a riavviare il terminale o a utilizzare una delle opzioni di recupero.\nSe tutti i tentativi falliscono, cancella tutti i dati attivando/disattivando il terminale Linux dalle Opzioni sviluppatore."</string>
+ <string name="error_code" msgid="3585291676855383649">"Codice di errore: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Impostazioni"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Il terminale è in esecuzione"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Tocca per aprire il terminale"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Fai clic per aprire il terminale"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Chiudi"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Chiusura del terminale in corso…"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Termina"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> è abilitata"</string>
</resources>
diff --git a/android/TerminalApp/res/values-iw/strings.xml b/android/TerminalApp/res/values-iw/strings.xml
index 5c1037d..729b22b 100644
--- a/android/TerminalApp/res/values-iw/strings.xml
+++ b/android/TerminalApp/res/values-iw/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"טרמינל"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"תצוגת טרמינל"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"סמן"</string>
+ <string name="empty_line" msgid="5012067143408427178">"שורה ריקה"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"כדי להקליד טקסט צריך ללחוץ לחיצה כפולה"</string>
<string name="installer_title_text" msgid="500663060973466805">"התקנה של טרמינל Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"כדי להפעיל את טרמינל Linux, צריך להוריד נתונים בנפח של בערך <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> דרך הרשת.\nלהמשיך?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"הורדה כשיהיה חיבור ל-Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"כדי להפעיל את טרמינל Linux, צריך להוריד נתונים בנפח של בערך <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> דרך הרשת.\nלהמשיך?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"הורדה רק באמצעות Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"התקנה"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"בתהליך התקנה"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"שגיאה בחיבור לרשת. צריך לבדוק את החיבור ולנסות שוב."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ההתקנה נכשלה בגלל שגיאה בחיבור לרשת. מומלץ לבדוק את החיבור ולנסות שוב."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"מתבצעת התקנה של טרמינל Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"טרמינל Linux יופעל אחרי שההתקנה תסתיים"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ההתקנה נכשלה בגלל בעיה ברשת"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ההתקנה נכשלה. אפשר לנסות שוב."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"טרמינל Linux יופעל בסיום ההתקנה"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ההתקנה נכשלה בגלל בעיה ברשת"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ההתקנה נכשלה כי אין חיבור ל-Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ההתקנה נכשלה. אפשר לנסות שוב."</string>
<string name="action_settings" msgid="5729342767795123227">"הגדרות"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"הטרמינל בהכנה"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"המערכת עוצרת את הטרמינל"</string>
<string name="vm_error_message" msgid="5231867246177661525">"הטרמינל קרס"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"שינוי גודל הדיסק"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"שינוי הגודל / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"שינוי גודל הדיסק"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"שינוי גודל של מחיצת השורש"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"גודל הדיסק הוגדר"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"הוקצו <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"מקסימום <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ביטול"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"צריך להפעיל מחדש כדי להחיל את השינוי"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"העברה ליציאה אחרת"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"הגדרת העברה ליציאה אחרת"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"הטרמינל מנסה לפתוח יציאה חדשה"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"נשלחה בקשה לפתיחת היציאה: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"אישור"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"הטרמינל יופעל מחדש כדי שגודל הדיסק ישתנה"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"אישור"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"בקרת יציאות"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"אישור או דחייה של יציאות להאזנה"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"יציאות להאזנה"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"יציאות מורשות שנשמרו"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"הוספה"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"מחיקה של <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"אישור ליציאה חדשה"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"צריך להזין מספר של יציאה חדשה"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"שמירה"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ביטול"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"צריך להזין מספר"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"מספר היציאה לא תקין"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"היציאה כבר קיימת"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"הטרמינל מבקש לפתוח יציאה חדשה"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"נשלחה בקשה ליציאה: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"אישור"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"דחייה"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"שחזור"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"אפשרויות שחזור של המחיצה"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"שינוי לגרסה הראשונית"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"הסרת הכול"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"אפשרויות השחזור של המחיצה"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"איפוס לגרסה הראשונית"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"הסרת כל הנתונים"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"אתחול הטרמינל"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"הנתונים יימחקו"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"אישור"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"הנתונים יוסרו"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"איפוס"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ביטול"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"גיבוי הנתונים בנתיב <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"השחזור נכשל כי הגיבוי נכשל"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"השחזור נכשל בגלל שגיאה בגיבוי"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"השחזור נכשל"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"אי אפשר להסיר את קובץ הגיבוי"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ההסרה של נתוני הגיבוי נכשלה"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"הסרת נתוני הגיבוי"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"פינוי של <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"שגיאה שבעקבותיה אי אפשר לשחזר"</string>
- <string name="error_desc" msgid="1939028888570920661">"השחזור נכשל בגלל שגיאה.\nאפשר להפעיל מחדש את האפליקציה או לנסות אחת מאפשרויות השחזור."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"הסרה של <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"שגיאה שבעקבותיה אי אפשר לשחזר"</string>
+ <string name="error_desc" msgid="4588252235686826721">"השחזור נכשל בגלל שגיאה.\nאפשר להפעיל מחדש את הטרמינל או לנסות אחת מאפשרויות השחזור.\nאם כל הניסיונות נכשלו, אפשר לאפס את כל הנתונים על ידי הפעלה או השבתה של טרמינל Linux דרך האפשרויות למפתחים."</string>
<string name="error_code" msgid="3585291676855383649">"קוד שגיאה: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"הגדרות"</string>
<string name="service_notification_title" msgid="2918088850910713393">"הטרמינל פועל"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"צריך ללחוץ כדי לפתוח את הטרמינל"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"כדי לפתוח את הטרמינל, צריך ללחוץ כאן"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"סגירה"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"הטרמינל בתהליך סגירה"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"אילוץ סגירה"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> מופעל"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ja/strings.xml b/android/TerminalApp/res/values-ja/strings.xml
index e4a9cd7..19c4af8 100644
--- a/android/TerminalApp/res/values-ja/strings.xml
+++ b/android/TerminalApp/res/values-ja/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"ターミナルの表示"</string>
<string name="terminal_input" msgid="4602512831433433551">"カーソル"</string>
<string name="empty_line" msgid="5012067143408427178">"空の行"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ダブルタップしてタイプ入力します"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ターミナルをインストールする"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ターミナルを起動するには、ネットワーク経由で約 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> のデータのダウンロードが必要です。\n続行しますか?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi 接続時にダウンロード"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ターミナルを起動するには、ネットワーク経由で約 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> のデータのダウンロードが必要です。\n続行しますか?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fi 使用時にのみダウンロードする"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"インストール"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"インストール中"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ネットワーク エラーです。接続を確認し、もう一度お試しください。"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ネットワーク エラーが発生したため、インストールできませんでした。接続を確認してから、もう一度お試しください。"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ターミナルのインストール"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"完了後に Linux ターミナルが起動します"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ネットワークの問題によりインストールできませんでした"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"Wi-Fi が利用できないため、インストールできませんでした"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"インストールできませんでした。もう一度お試しください。"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"インストールが完了すると Linux ターミナルが起動します"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ネットワークの問題によりインストールできませんでした"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi が利用できないためインストールできませんでした"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"インストールできませんでした。もう一度お試しください"</string>
<string name="action_settings" msgid="5729342767795123227">"設定"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ターミナルを準備しています"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ターミナルを停止しています"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ターミナルがクラッシュしました"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ディスクサイズを変更"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"サイズ変更 / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ディスクサイズを変更"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ルート パーティションのサイズを変更"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ディスクサイズを設定しました"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> 割り当て済み"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"最大 <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"キャンセル"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"再起動して適用"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ポート転送"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ポート転送を設定する"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ターミナルが新しいポートを開こうとしています"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"開くようリクエストされたポート: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"適用"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ディスクのサイズを変更するためにターミナルが再起動します"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"確認"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ポートの管理"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"リスニング ポートの許可 / 拒否"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"リスニング ポート"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g>(<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"保存済みの許可ポート"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"追加"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> を削除"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"新しいポートを許可する"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"新しいポート番号を入力してください"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"保存"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"キャンセル"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"数字を入力してください"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ポート番号が無効です"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ポートはすでに存在します"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ターミナルが新しいポートを開くリクエストをしました"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"リクエストされたポート: <xliff:g id="PORT_NUMBER">%1$d</xliff:g>(<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"許可する"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"許可しない"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"リカバリ"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"パーティション復元オプション"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"最初のバージョンに変更"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"すべて削除"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"パーティション復元オプション"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"最初のバージョンにリセット"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"データをすべて削除"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ターミナルのリセット"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"データは削除されます"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"確認"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"データは削除されます"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"リセット"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"キャンセル"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> にデータをバックアップする"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"バックアップに失敗したため、復元できませんでした"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"バックアップ エラーのため復元できませんでした"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"復元できませんでした"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"バックアップ ファイルを削除できません"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"バックアップ データを削除できませんでした"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"バックアップ データの削除"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> をクリーンアップする"</string>
- <string name="error_title" msgid="7196464038692913778">"修復不可能なエラー"</string>
- <string name="error_desc" msgid="1939028888570920661">"エラーを修復できませんでした。\nアプリを再起動するか、いずれかの復元オプションをお試しください。"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> を削除"</string>
+ <string name="error_title" msgid="405150657301906598">"修復不可能なエラー"</string>
+ <string name="error_desc" msgid="4588252235686826721">"エラーを修復できませんでした。\nターミナルを再起動するか、いずれかの復元オプションをお試しください。\nそれでも修復できない場合は、開発者向けオプションで Linux ターミナルをオン / オフにして、すべてのデータをワイプしてください。"</string>
<string name="error_code" msgid="3585291676855383649">"エラーコード: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"設定"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ターミナルは実行中です"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"クリックするとターミナルが開きます"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"クリックするとターミナルが開きます"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"閉じる"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ターミナルを閉じています"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"強制終了"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g>は有効です"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ka/strings.xml b/android/TerminalApp/res/values-ka/strings.xml
index 44ad145..be79f8b 100644
--- a/android/TerminalApp/res/values-ka/strings.xml
+++ b/android/TerminalApp/res/values-ka/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ტერმინალი"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ტერმინალის წარმოჩენა"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"კურსორი"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ცარიელი სტრიქონი"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ორმაგად შეეხეთ ტექსტის ასაკრეფად"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ტერმინალის ინსტალაცია"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ტერმინალის გაშვებისთვის საჭიროა ქსელიდან ჩამოტვირთოთ დაახლოებით <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ზომის მონაცემები.\nგსურთ გაგრძელება?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ჩამოტვირთვა Wi-Fi კავშირის ხელმისაწვდომობისას"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ტერმინალის გაშვებისთვის საჭიროა ქსელიდან ჩამოტვირთოთ დაახლოებით <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ზომის მონაცემები.\nგსურთ გაგრძელება?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"ჩამოტვირთვა მხოლოდ Wi-Fi-ს გამოყენებით"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ინსტალაცია"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ინსტალირდება"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ქსელის შეცდომა. შეამოწმეთ კავშირი და ცადეთ ხელახლა."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ქსელის შეცდომის გამო ვერ მოხერხდა ინსტალაცია. შეამოწმეთ კავშირი და ცადეთ ხელახლა."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"მიმდინარეობს Linux ტერმინალის ინსტალაცია"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"დასრულების შემდეგ დაიწყება Linux ტერმინალის ინსტალაცია"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ქსელის შეცდომის გამო ვერ მოხერხდა ინსტალაცია"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ვერ მოახერხდა ინსტალაცია. ცადეთ ხელახლა."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ინსტალაციის დასრულების შემდეგ გაეშვება Linux ტერმინალი"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ქსელის პრობლემის გამო ვერ მოხერხდა ინსტალაცია"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi მიუწვდომელია, ამიტომ ინსტალაცია ვერ მოხერხდა"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ვერ მოახერხდა ინსტალაცია. გთხოვთ, ცადოთ ხელახლა"</string>
<string name="action_settings" msgid="5729342767795123227">"პარამეტრები"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"მიმდინარეობს ტერმინალის მომზადება"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"მიმდინარეობს ტერმინალის შეწყვეტა"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ტერმინალი გაჭედილია"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"დისკის ზომის შეცვლა"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ზომის შეცვლა / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"დისკის ზომის შეცვლა"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ძირეული დანაყოფის ზომის შეცვლა"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"დისკის ზომა დაყენებულია"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> მიმაგრებულია"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"მაქსიმალური ზომა: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"გაუქმება"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"ასამოქმედებლად გადატვირთეთ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"პორტის გადამისამართება"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"პორტის გადამისამართების კონფიგურაცია"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ტერმინალი ცდილობს ახალი პორტის გახსნას"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"პორტმა მოითხოვა, რომ იყოს გახსნილი: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"გამოყენება"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"დისკის ზომის შესაცვლელად გადაიტვირთება ტერმინალი"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"დადასტურება"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"პორტის მართვა"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"მოსმენის პორტების დაშვება/აკრძალვა"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"მოსმენის პორტები"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"შენახული დაშვებული პორტები"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"დამატება"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>-ის წაშლა"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"ახალი პორტის დაშვება"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"შეიყვანეთ ახალი პორტის ნომერი"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"შენახვა"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"გაუქმება"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"გთხოვთ, შეიყვანოთ ნომერი"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"პორტის არასწორი ნომერი"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"პორტი უკვე არსებობს"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ტერმინალი ითხოვს ახალი პორტის გახსნას"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"მოთხოვნილი პორტი: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"დათანხმება"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"უარყოფა"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"აღდგენა"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"დანაყოფის აღდგენის ვარიანტები"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"საწყის ვერსიაზე შეცვლა"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"ყველას ამოშლა"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"დანაყოფის აღდგენის ვარიანტები"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"საწყის ვერსიაზე გადაყენება"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ყველა მონაცემის ამოშლა"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ტერმინალის გადაყენება"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"მონაცემები წაიშლება"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"დადასტურება"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"მონაცემები ამოიშლება"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"გადაყენება"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"გაუქმება"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"მონაცემების სარეზერვო ასლის შექმნა <xliff:g id="PATH">/mnt/backup</xliff:g>-ზე"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"აღდგენა ვერ მოხერხდა, რადგან სარეზერვო კოპირება ვერ განხორციელდა"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"სარეზერვო ასლის შეცდომის გამო აღდგენა ვერ მოხერხდა"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"აღდგენა ვერ მოხერხდა"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"სარეზერვო ასლის ფაილის ამოშლა ვერ ხერხდება"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"სარეზერვო ასლის მონაცემების ამოშლა ვერ მოხერხდა"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"სარეზერვო ასლის მონაცემების ამოშლა"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g>-ის გასუფთავება"</string>
- <string name="error_title" msgid="7196464038692913778">"გამოუსწორებელი შეცდომა"</string>
- <string name="error_desc" msgid="1939028888570920661">"შეცდომა ვერ გამოსწორდა.\nშეგიძლიათ აპი გადატვირთოთ ან აღდგენის სხვა ვარიანტი ცადოთ."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g>-ის ამოშლა"</string>
+ <string name="error_title" msgid="405150657301906598">"გამოუსწორებელი შეცდომა"</string>
+ <string name="error_desc" msgid="4588252235686826721">"შეცდომა ვერ გამოსწორდა.\nშეგიძლიათ ცადოთ ტერმინალის გადატვირთვა ან აღდგენის ვარიანტებიდან ერთ-ერთი.\nთუ ყველა მცდელობა წარუმატებელი იქნება, ამოშალეთ ნებისმიერი მონაცემი დეველოპერთა პარამეტრებიდან Linux ტერმინალის ჩართვა/გამორთვის გზით."</string>
<string name="error_code" msgid="3585291676855383649">"შეცდომის კოდი: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"პარამეტრები"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ტერმინალი გაშვებულია"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"დააწკაპუნეთ ტერმინალის გასახსნელად"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ტერმინალის გასახსნელად დააწკაპუნეთ"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"დახურვა"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ტერმინალი იხურება"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"იძულებით დახურვა"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ჩართულია"</string>
</resources>
diff --git a/android/TerminalApp/res/values-kk/strings.xml b/android/TerminalApp/res/values-kk/strings.xml
index 2e906c3..5477c04 100644
--- a/android/TerminalApp/res/values-kk/strings.xml
+++ b/android/TerminalApp/res/values-kk/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Терминал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Терминал дисплейі"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Бос жол"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Теру үшін екі рет түртіңіз."</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux терминалын орнату"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux терминалын іске қосу үшін желі арқылы шамамен <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> деректі жүктеп алу қажет.\nЖалғастырасыз ба?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi желісі пайда болғанда жүктеп алу"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux терминалын іске қосу үшін желі арқылы шамамен <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> деректі жүктеп алу қажет.\nЖалғастырғыңыз келе ме?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Тек Wi-Fi арқылы жүктеп алу"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Орнату"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Орнатылып жатыр"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Желі қатесі орын алды. Байланысты тексеріңіз де, қайталап көріңіз."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Желі қатесіне байланысты орнату мүмкін болмады. Байланысты тексеріп, әрекетті қайталап көріңіз."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux терминалы орнатылып жатыр"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux терминалы орнату аяқталғаннан кейін іске қосылады."</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Желі мәселесіне байланысты орнату мүмкін болмады."</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Орнату мүмкін болмады. Қайталап көріңіз."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux терминалы орнату процесі аяқталған соң іске қосылады."</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Желі мәселесіне байланысты орнату мүмкін болмады."</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Орнатылмады, себебі Wi-Fi желісі жоқ."</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Орнату мүмкін болмады. Қайталап көріңіз."</string>
<string name="action_settings" msgid="5729342767795123227">"Параметрлер"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Терминал дайындалып жатыр."</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Терминал тоқтатылып жатыр."</string>
<string name="vm_error_message" msgid="5231867246177661525">"Терминал бұзылды."</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Диск көлемін өзгерту"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Көлемін өзгерту / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Диск өлшемін өзгерту"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Root бөлігінің өлшемін өзгерту"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Диск көлемі орнатылды."</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> тағайындалды"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Ең көбі <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Бас тарту"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Қолдану үшін қайта ашу"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Портты бағыттау"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Портты бағыттауды конфигурациялау"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Терминал жаңа порт ашайын деп жатыр"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Портты ашуға сұрау жіберілді: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Қолдану"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Диск өлшемін өзгерту үшін терминал өшіріліп қосылады."</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Растау"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Портты басқару"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Тыңдау порттарына рұқсат беру/тыйым салу"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Тыңдау порттары"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Рұқсат берілген порттар сақталды"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Қосу"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> портты жою"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Жаңа портқа рұқсат беру"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Жаңа порт нөмірін енгізіңіз."</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Сақтау"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Бас тарту"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Нөмірді енгізіңіз."</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Порт нөмірі жарамсыз."</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт бұрыннан бар."</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал жаңа порт ашуды сұрайды"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Қажетті порт: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Қабылдау"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Қабылдамау"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Қалпына келтіру"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Бөлікті қалпына келтіру опциялары"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Бастапқы нұсқаға өзгерту"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Барлығын өшіру"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Бөлікті қалпына келтіру опциялары"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Бастапқы нұсқаға қайта орнату"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Барлық деректі жою"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Терминалды бастапқы күйге қайтару"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Деректер жойылады."</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Растау"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Деректер өшіріледі."</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Қайта орнату"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Бас тарту"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Деректердің сақтық көшірмесін <xliff:g id="PATH">/mnt/backup</xliff:g> жолына сақтау"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Қалпына келтірілмеді, себебі сақтық көшірме жасалмады."</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Сақтық көшірме жасау қатесіне байланысты қалпына келтірілмеді."</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Қалпына келтірілмеді."</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Сақтық көшірме файлы өшірілмеді."</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Сақтық көшірмесі жасалған деректер өшірілмеді."</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Сақтық көшірме дерегін өшіру"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> дерегін тазалау"</string>
- <string name="error_title" msgid="7196464038692913778">"Қалпына келтіруге жол бермейтін қате"</string>
- <string name="error_desc" msgid="1939028888570920661">"Қатеден кейін қалпына келтіру мүмкін болмады.\nҚолданбаны жауып, қайтадан ашып көріңіз немесе қалпына келтіру опцияларының бірін пайдаланып көріңіз."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> жолын өшіру"</string>
+ <string name="error_title" msgid="405150657301906598">"Қалпына келтіруге жол бермейтін қате"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Қатеден кейін қалпына келтіру мүмкін болмады.\nТерминалды өшіріп қосып көріңіз немесе қалпына келтіру опцияларының бірін пайдаланып көріңіз.\nБарлық әрекет сәтсіз аяқталса, әзірлеуші опцияларынан Linux терминалын қосу/өшіру арқылы барлық деректі тазартыңыз."</string>
<string name="error_code" msgid="3585291676855383649">"Қате коды: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Параметрлер"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Терминал іске қосылып тұр"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Терминалды ашу үшін басыңыз."</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Терминалды ашу үшін түртіңіз."</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Жабу"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Терминал жабылып жатыр"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Қолмен жабу"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> қосылды."</string>
</resources>
diff --git a/android/TerminalApp/res/values-km/strings.xml b/android/TerminalApp/res/values-km/strings.xml
index 2513b4e..1ec9a0a 100644
--- a/android/TerminalApp/res/values-km/strings.xml
+++ b/android/TerminalApp/res/values-km/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ទែមីណាល់"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ផ្ទាំងអេក្រង់ទែមីណាល់"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"ទស្សន៍ទ្រនិច"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ជួរទទេ"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ចុចពីរដងដើម្បីវាយបញ្ចូលខ្លឹមសារ"</string>
<string name="installer_title_text" msgid="500663060973466805">"ដំឡើងទែមីណាល់ Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"ដើម្បីបើកដំណើរការទែមីណាល់ Linux អ្នកត្រូវទាញយកទិន្នន័យប្រហែលជា <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> នៅលើបណ្តាញ។\nតើអ្នកចង់បន្តដែរឬទេ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ទាញយកនៅពេលមាន Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"ដើម្បីបើកដំណើរការទែមីណាល់ Linux, អ្នកត្រូវទាញយកទិន្នន័យប្រហែលជា <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> នៅលើបណ្ដាញ។\nតើអ្នកចង់បន្តដែរឬទេ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"ទាញយកដោយប្រើតែ Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ដំឡើង"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"កំពុងដំឡើង"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"មានបញ្ហាបណ្ដាញ។ ពិនិត្យមើលការតភ្ជាប់ រួចព្យាយាមម្ដងទៀត។"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"មិនអាចដំឡើងបានទេ ដោយសារបញ្ហាបណ្ដាញ។ សូមពិនិត្យមើលការតភ្ជាប់របស់អ្នក រួចព្យាយាមម្ដងទៀត។"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"កំពុងដំឡើងទែមីណាល់ Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"ទែមីណាល់ Linux នឹងត្រូវបានចាប់ផ្ដើមបន្ទាប់ពីបញ្ចប់"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"មិនអាចដំឡើងបានទេ ដោយសារបញ្ហាបណ្ដាញ"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"មិនអាចដំឡើងបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ទែមីណាល់ Linux នឹងចាប់ផ្ដើមបន្ទាប់ពីការដំឡើងបានចប់"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"មិនអាចដំឡើងបានទេ ដោយសារបញ្ហាបណ្ដាញ"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"មិនអាចដំឡើងបានទេ ដោយសារមិនមាន Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"មិនអាចដំឡើងបានទេ។ សូមព្យាយាមម្ដងទៀត"</string>
<string name="action_settings" msgid="5729342767795123227">"ការកំណត់"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"កំពុងរៀបចំទែមីណាល់"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"កំពុងបញ្ឈប់ទែមីណាល់"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ទែមីណាល់បានគាំង"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ប្ដូរទំហំថាស"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ប្ដូរទំហំ / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ប្ដូរទំហំថាស"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ប្ដូរទំហំផ្នែកឫស"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"បានកំណត់ទំហំថាស"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"បានកំណត់ <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"អតិបរមា <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"បោះបង់"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"ចាប់ផ្ដើមឡើងវិញដើម្បីដាក់ប្រើ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ការបញ្ជូនច្រកបន្ត"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"កំណត់រចនាសម្ព័ន្ធការបញ្ជូនច្រកបន្ត"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ទែមីណាល់កំពុងព្យាយាមបើកច្រកថ្មី"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"បានស្នើសុំឱ្យបើកច្រក៖ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ដាក់ប្រើ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ទែមីណាល់នឹងត្រូវបានចាប់ផ្ដើមឡើងវិញ ដើម្បីប្ដូរទំហំថាស"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"បញ្ជាក់"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ការគ្រប់គ្រងច្រក"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"អនុញ្ញាត/បដិសេធច្រកស្ដាប់"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ច្រកស្ដាប់"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"បានរក្សាទុកច្រកដែលត្រូវបានអនុញ្ញាត"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"បញ្ចូល"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"លុប <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"អនុញ្ញាតច្រកថ្មី"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"បញ្ចូលលេខច្រកថ្មី"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"រក្សាទុក"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"បោះបង់"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"សូមបញ្ចូលលេខ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"លេខច្រកមិនត្រឹមត្រូវ"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"មានច្រករួចហើយ"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ទែមីណាល់កំពុងស្នើសុំបើកច្រកថ្មី"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"បានស្នើសុំច្រក៖ <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ទទួលយក"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"បដិសេធ"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"ស្ដារ"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"ជម្រើសស្ដារផ្នែក"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ប្ដូរទៅកំណែដំបូង"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"ដកចេញទាំងអស់"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"ជម្រើសស្ដារផ្នែក"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"កំណត់ឡើងវិញទៅកំណែដំបូង"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ដកទិន្នន័យទាំងអស់ចេញ"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"កំណត់ទែមីណាល់ឡើងវិញ"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ទិន្នន័យនឹងត្រូវបានលុប"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"បញ្ជាក់"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ទិន្នន័យនឹងត្រូវបានដកចេញ"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"កំណត់ឡើងវិញ"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"បោះបង់"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"បម្រុងទុកទិន្នន័យទៅ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ការស្ដារឡើងវិញមិនបានសម្រេច ដោយសារការបម្រុងទុកមិនបានសម្រេច"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"មិនអាចស្ដារឡើងវិញបានទេ ដោយសារបញ្ហាក្នុងការបម្រុងទុក"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"ការស្ដារឡើងវិញមិនបានសម្រេច"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"មិនអាចដកឯកសារបម្រុងទុកចេញបានទេ"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"មិនអាចដកទិន្នន័យបម្រុងទុកចេញបានទេ"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ដកទិន្នន័យបម្រុងទុកចេញ"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"សម្អាត <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"បញ្ហាដែលបណ្ដាលឱ្យមិនអាចស្ដារបាន"</string>
- <string name="error_desc" msgid="1939028888570920661">"មិនអាចស្ដារឡើងវិញពីបញ្ហាបានទេ។\nអ្នកអាចសាកល្បងចាប់ផ្ដើមកម្មវិធីឡើងវិញ ឬសាកល្បងប្រើជម្រើសមួយក្នុងចំណោមជម្រើសស្ដារ។"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"ដក <xliff:g id="PATH">/mnt/backup</xliff:g> ចេញ"</string>
+ <string name="error_title" msgid="405150657301906598">"បញ្ហាដែលបណ្ដាលឱ្យមិនអាចស្ដារបាន"</string>
+ <string name="error_desc" msgid="4588252235686826721">"មិនអាចស្ដារឡើងវិញពីបញ្ហាបានទេ។\nអ្នកអាចសាកល្បងចាប់ផ្ដើមទែមីណាល់ឡើងវិញ ឬសាកល្បងប្រើជម្រើសមួយក្នុងចំណោមជម្រើសស្ដារ។\nប្រសិនបើការព្យាយាមទាំងអស់មិនបានសម្រេច សូមឈូសទិន្នន័យទាំងអស់ដោយបើក/បិទទែមីណាល់ Linux ពីជម្រើសសម្រាប់អ្នកអភិវឌ្ឍន៍។"</string>
<string name="error_code" msgid="3585291676855383649">"លេខកូដបញ្ហា៖ <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ការកំណត់"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ទែមីណាល់កំពុងដំណើរការ"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ចុចដើម្បីបើកទែមីណាល់"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ចុចដើម្បីបើកទែមីណាល់"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"បិទ"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ទែមីណាល់កំពុងបិទ"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"បង្ខំឱ្យបិទ"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ត្រូវបានបើក"</string>
</resources>
diff --git a/android/TerminalApp/res/values-kn/strings.xml b/android/TerminalApp/res/values-kn/strings.xml
index 3fc63d2..3c53299 100644
--- a/android/TerminalApp/res/values-kn/strings.xml
+++ b/android/TerminalApp/res/values-kn/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ಟರ್ಮಿನಲ್"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ಟರ್ಮಿನಲ್ ಪ್ರದರ್ಶನ"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"ಕರ್ಸರ್"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ಖಾಲಿ ಸಾಲು"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ಇನ್ಪುಟ್ ಟೈಪ್ ಮಾಡಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲು, ನೀವು ನೆಟ್ವರ್ಕ್ನಲ್ಲಿ ಸುಮಾರು <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ಡೇಟಾವನ್ನು ಡೌನ್ಲೋಡ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.\nನೀವು ಮುಂದುವರಿಸಲು ಬಯಸುತ್ತೀರಾ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ವೈ-ಫೈ ಲಭ್ಯವಿದ್ದಾಗ ಡೌನ್ಲೋಡ್ ಮಾಡಿ"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲು, ನೀವು ನೆಟ್ವರ್ಕ್ನಲ್ಲಿ ಸುಮಾರು <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ಡೇಟಾವನ್ನು ಡೌನ್ಲೋಡ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.\nನೀವು ಮುಂದುವರಿಸಲು ಬಯಸುತ್ತೀರಾ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"ವೈ-ಫೈ ಅನ್ನು ಮಾತ್ರ ಬಳಸಿ ಡೌನ್ ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ಇನ್ಸ್ಟಾಲ್"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ನೆಟ್ವರ್ಕ್ ದೋಷ. ಕನೆಕ್ಷನ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ನೆಟ್ವರ್ಕ್ ದೋಷದಿಂದಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ. ನಿಮ್ಮ ಕನೆಕ್ಷನ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"ಮುಗಿದ ಮೇಲೆ Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತದೆ"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ನೆಟ್ವರ್ಕ್ ಸಮಸ್ಯೆಯಿಂದಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ಇನ್ಸ್ಟಾಲೇಶನ್ ಮುಗಿದ ನಂತರ Linux ಟರ್ಮಿನಲ್ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ನೆಟ್ವರ್ಕ್ ಸಮಸ್ಯೆಯಿಂದಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲದ ಕಾರಣ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="action_settings" msgid="5729342767795123227">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ಟರ್ಮಿನಲ್ ಅನ್ನು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ಟರ್ಮಿನಲ್ ಅನ್ನು ನಿಲ್ಲಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ಟರ್ಮಿನಲ್ ಕ್ರ್ಯಾಶ್ ಆಗಿದೆ"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ಡಿಸ್ಕ್ ಅನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ಮರುಗಾತ್ರಗೊಳಿಸಿ / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ಡಿಸ್ಕ್ ಅನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ರೂಟ್ ಪಾರ್ಟಿಶನ್ ಗಾತ್ರವನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ಡಿಸ್ಕ್ ಗಾತ್ರವನ್ನು ಸೆಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ನಿಯೋಜಿಸಲಾಗಿದೆ"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"ಗರಿಷ್ಠ <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ರದ್ದುಮಾಡಿ"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"ಅನ್ವಯಿಸಲು ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ಪೋರ್ಟ್ ಫಾರ್ವರ್ಡ್ ಮಾಡುವಿಕೆ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ಪೋರ್ಟ್ ಫಾರ್ವರ್ಡ್ ಮಾಡುವಿಕೆಯನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ಟರ್ಮಿನಲ್ ಹೊಸ ಪೋರ್ಟ್ ಅನ್ನು ತೆರೆಯಲು ಪ್ರಯತ್ನಿಸುತ್ತಿದೆ"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"ಪೋರ್ಟ್ ಅನ್ನು ತೆರೆಯಲು ವಿನಂತಿಸಲಾಗಿದೆ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ಅನ್ವಯಿಸಿ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ಡಿಸ್ಕ್ ಅನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಲು ಟರ್ಮಿನಲ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲಾಗುತ್ತದೆ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"ದೃಢೀಕರಿಸಿ"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ಪೋರ್ಟ್ ನಿಯಂತ್ರಣ"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ಆಲಿಸುವ ಪೋರ್ಟ್ಗಳನ್ನು ಅನುಮತಿಸಿ/ನಿರಾಕರಿಸಿ"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ಆಲಿಸುವ ಪೋರ್ಟ್ಗಳು"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ಅನುಮತಿಸಲಾದ ಪೋರ್ಟ್ಗಳನ್ನು ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ಸೇರಿಸಿ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ಅನ್ನು ಅಳಿಸಿ"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"ಹೊಸ ಪೋರ್ಟ್ ಅನ್ನು ಅನುಮತಿಸಿ"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"ಹೊಸ ಪೋರ್ಟ್ ಸಂಖ್ಯೆವೊಂದನ್ನು ನಮೂದಿಸಿ"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"ಸೇವ್ ಮಾಡಿ"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"ಸಂಖ್ಯೆಯನ್ನು ನಮೂದಿಸಿ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ಅಮಾನ್ಯ ಪೋರ್ಟ್ ಸಂಖ್ಯೆ"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ಪೋರ್ಟ್ ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ಟರ್ಮಿನಲ್ ಹೊಸ ಪೋರ್ಟ್ ಅನ್ನು ತೆರೆಯಲು ವಿನಂತಿಸುತ್ತಿದೆ"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"ಪೋರ್ಟ್ ಅನ್ನು ವಿನಂತಿಸಲಾಗಿದೆ: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ಸಮ್ಮತಿಸಿ"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ನಿರಾಕರಿಸಿ"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"ರಿಕವರಿ"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"ಪಾರ್ಟಿಶನ್ ರಿಕವರಿ ಆಯ್ಕೆಗಳು"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ಆರಂಭಿಕ ಆವೃತ್ತಿಗೆ ಬದಲಾಯಿಸಿ"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"ಎಲ್ಲವನ್ನೂ ತೆಗೆದುಹಾಕಿ"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"ಪಾರ್ಟಿಶನ್ ಮರುಪ್ರಾಪ್ತಿ ಆಯ್ಕೆಗಳು"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ಆರಂಭಿಕ ಆವೃತ್ತಿಗೆ ರೀಸೆಟ್ ಮಾಡಿ"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ಟರ್ಮಿನಲ್ ಅನ್ನು ರೀಸೆಟ್ ಮಾಡಿ"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"ದೃಢೀಕರಿಸಿ"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ಡೇಟಾವನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ರೀಸೆಟ್ ಮಾಡಿ"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ರದ್ದುಮಾಡಿ"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"ಡೇಟಾವನ್ನು <xliff:g id="PATH">/mnt/backup</xliff:g> ಗೆ ಬ್ಯಾಕಪ್ ಮಾಡಿ"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ಬ್ಯಾಕಪ್ ವಿಫಲವಾದ ಕಾರಣ ರಿಕವರಿ ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"ಬ್ಯಾಕಪ್ ದೋಷದಿಂದಾಗಿ ಚೇತರಿಸಿಕೊಳ್ಳಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"ರಿಕವರಿ ವಿಫಲವಾಗಿದೆ"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"ಬ್ಯಾಕಪ್ ಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ಬ್ಯಾಕಪ್ ಡೇಟಾವನ್ನು ತೆಗೆದುಹಾಕಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ಬ್ಯಾಕಪ್ ಡೇಟಾವನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> ಅನ್ನು ಕ್ಲೀನ್ ಅಪ್ ಮಾಡಿ"</string>
- <string name="error_title" msgid="7196464038692913778">"ಮರುಪಡೆಯಲಾಗದ ದೋಷ ಎದುರಾಗಿದೆ"</string>
- <string name="error_desc" msgid="1939028888570920661">"ದೋಷದಿಂದ ಚೇತರಿಸಿಕೊಳ್ಳಲು ವಿಫಲವಾಗಿದೆ.\nನೀವು ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಪ್ರಯತ್ನಿಸಬಹುದು ಅಥವಾ ಮರುಪ್ರಾಪ್ತಿ ಆಯ್ಕೆಗಳಲ್ಲಿ ಒಂದನ್ನು ಪ್ರಯತ್ನಿಸಬಹುದು."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> ತೆಗೆದುಹಾಕಿ"</string>
+ <string name="error_title" msgid="405150657301906598">"ಮರುಪಡೆಯಲಾಗದ ದೋಷ"</string>
+ <string name="error_desc" msgid="4588252235686826721">"ದೋಷದಿಂದ ಚೇತರಿಸಿಕೊಳ್ಳಲು ವಿಫಲವಾಗಿದೆ.\nನೀವು ಟರ್ಮಿನಲ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಪ್ರಯತ್ನಿಸಬಹುದು ಅಥವಾ ಮರುಪ್ರಾಪ್ತಿ ಆಯ್ಕೆಗಳಲ್ಲಿ ಒಂದನ್ನು ಪ್ರಯತ್ನಿಸಬಹುದು.\nಎಲ್ಲಾ ಪ್ರಯತ್ನಗಳು ವಿಫಲವಾದರೆ, ಡೆವಲಪರ್ ಆಯ್ಕೆಗಳಿಂದ Linux ಟರ್ಮಿನಲ್ ಅನ್ನು ಆನ್/ಆಫ್ ಮಾಡುವ ಮೂಲಕ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕು."</string>
<string name="error_code" msgid="3585291676855383649">"ದೋಷ ಕೋಡ್: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ಟರ್ಮಿನಲ್ ರನ್ ಆಗುತ್ತಿದೆ"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ಟರ್ಮಿನಲ್ ಅನ್ನು ತೆರೆಯಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ಟರ್ಮಿನಲ್ ಅನ್ನು ತೆರೆಯಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"ಮುಚ್ಚಿರಿ"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ಟರ್ಮಿನಲ್ ಮುಚ್ಚಲಾಗುತ್ತಿದೆ"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"ಬಲವಂತವಾಗಿ ಮುಚ್ಚಿ"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ko/strings.xml b/android/TerminalApp/res/values-ko/strings.xml
index 077fbcd..4ec1613 100644
--- a/android/TerminalApp/res/values-ko/strings.xml
+++ b/android/TerminalApp/res/values-ko/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"터미널"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"터미널 디스플레이"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"커서"</string>
+ <string name="empty_line" msgid="5012067143408427178">"빈 줄"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"두 번 탭하여 입력"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux 터미널 설치"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux 터미널을 실행하려면 네트워크를 통해 약 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g>의 데이터를 다운로드해야 합니다.\n계속하시겠습니까?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi 연결 시 다운로드"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux 터미널을 실행하려면 네트워크를 통해 약 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g>의 데이터를 다운로드해야 합니다.\n계속하시겠습니까?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fi를 통해서만 다운로드"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"설치"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"설치 중"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"네트워크 오류입니다. 연결을 확인한 후 다시 시도해 주세요."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"네트워크 오류로 인해 설치할 수 없습니다. 연결 상태를 확인한 후 다시 시도하세요."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux 터미널 설치 중"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"완료 후 Linux 터미널이 시작됩니다"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"네트워크 문제로 인해 설치할 수 없습니다"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"설치할 수 없습니다. 다시 시도하세요."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"설치가 완료되면 Linux 터미널이 시작됩니다."</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"네트워크 문제로 인해 설치할 수 없습니다."</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi를 사용할 수 없어 설치하지 못했습니다."</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"설치할 수 없습니다. 다시 시도해 보세요."</string>
<string name="action_settings" msgid="5729342767795123227">"설정"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"터미널 준비 중"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"터미널 중지 중"</string>
<string name="vm_error_message" msgid="5231867246177661525">"터미널 다운됨"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"디스크 크기 조정"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"크기 조정/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"디스크 크기 조절"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"루트 파티션 크기 조절"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"디스크 크기 설정됨"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> 할당됨"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"최대 <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"취소"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"다시 시작하여 적용"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"포트 전달"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"포트 전달 구성"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"터미널에서 새 포트를 열려고 합니다"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"포트 개방 요청: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"적용"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"디스크 크기를 조절하기 위해 터미널이 다시 시작됩니다."</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"확인"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"포트 제어"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"리스닝 포트 허용/거부"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"리스닝 포트"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g>(<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"저장된 허용 포트"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"추가"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> 삭제"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"새 포트 허용"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"새 포트 번호 입력"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"저장"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"취소"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"숫자를 입력하세요."</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"포트 번호가 잘못되었습니다."</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"포트가 이미 존재합니다."</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"터미널에서 새 포트를 열려고 합니다"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"요청된 포트: <xliff:g id="PORT_NUMBER">%1$d</xliff:g>(<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"수락"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"거부"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"복구"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"파티션 복구 옵션"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"최초 버전으로 변경"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"전체 삭제"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"파티션 복구 옵션"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"초기 버전으로 재설정"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"데이터 모두 삭제"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"터미널 재설정"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"데이터가 삭제됩니다."</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"확인"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"데이터가 삭제됩니다."</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"재설정"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"취소"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g>에 데이터 백업"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"백업에 실패하여 복구할 수 없음"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"백업 오류로 인해 복구할 수 없습니다."</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"복구 실패"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"백업 파일을 삭제할 수 없음"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"백업 데이터를 삭제할 수 없습니다."</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"백업 데이터 삭제"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> 지우기"</string>
- <string name="error_title" msgid="7196464038692913778">"복구 불가 오류"</string>
- <string name="error_desc" msgid="1939028888570920661">"오류에서 복구할 수 없습니다.\n앱을 다시 시작하거나 복구 옵션 중 하나를 사용해 보세요."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> 삭제"</string>
+ <string name="error_title" msgid="405150657301906598">"복구 불가 오류"</string>
+ <string name="error_desc" msgid="4588252235686826721">"오류에서 복구할 수 없습니다.\n터미널을 다시 시작하거나 복구 옵션을 시도해 보세요.\n모든 시도가 실패하면 개발자 옵션에서 Linux 터미널을 사용 설정/중지하여 모든 데이터를 삭제하세요."</string>
<string name="error_code" msgid="3585291676855383649">"오류 코드: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"설정"</string>
<string name="service_notification_title" msgid="2918088850910713393">"터미널이 실행 중입니다"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"터미널을 열려면 클릭하세요."</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"터미널을 열려면 클릭하세요."</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"닫기"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"터미널 앱 종료 중"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"강제 종료"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g>이(가) 사용 설정되었습니다."</string>
</resources>
diff --git a/android/TerminalApp/res/values-ky/strings.xml b/android/TerminalApp/res/values-ky/strings.xml
index 09fc0e1..17fc4ea 100644
--- a/android/TerminalApp/res/values-ky/strings.xml
+++ b/android/TerminalApp/res/values-ky/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Терминал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Терминалдын дисплейи"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Бош сап"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Терип киргизүү үчүн эки жолу таптаңыз"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux терминалын орнотуу"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux терминалын иштетүү үчүн болжол менен <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> жүктөп алышыңыз керек.\nУлантасызбы?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi жеткиликтүү болгондо жүктөп алуу"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux терминалын иштетүү үчүн болжол менен <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> маалыматты жүктөп алышыңыз керек.\nУлантасызбы?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fi аркылуу гана жүктөп алуу"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Орнотуу"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Орнотулууда"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Тармакта ката кетти. Байланышты текшерип, кайра аракет кылыңыз."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Тармак катасынан улам орнотулбай калды. Туташууңузду текшерип, кайталап көрүңүз."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux терминалы орнотулууда"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Бүткөндөн кийин Linux терминалы иштеп баштайт"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Тармактагы маселеден улам орнотулбай калды"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Орнотулган жок. Кайра аракет кылыңыз."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux терминалы орнотуу процесси аяктагандан кийин иштеп баштайт"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Тармактагы маселеден улам орнотулбай калды"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi жеткиликсиз болгондуктан, орнотулбай калды"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Орнотулган жок. Кайталап көрүңүз"</string>
<string name="action_settings" msgid="5729342767795123227">"Параметрлер"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Терминал даярдалууда"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Терминал токтотулууда"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Терминал бузулду"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Дисктин өлчөмүн өзгөртүү"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Өлчөмүн өзгөртүү / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Дисктин өлчөмүн өзгөртүү"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Катуу дисктин негизги бөлүгүнүн өлчөмүн өзгөртүү"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Дисктин өлчөмү коюлду"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> дайындалды"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Эң көп <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Жокко чыгаруу"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Колдонуу үчүн өчүрүп күйгүзүү"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Оюкчаны багыттоо"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Оюкчаны багыттоону конфигурациялоо"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Терминал жаңы портту ачканы жатат"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Төмөнкү портту ачуу сурамы жөнөтүлдү: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Колдонуу"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Дисктин өлчөмүн өзгөртүү үчүн терминал өчүрүлүп күйгүзүлөт"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Ырастоо"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Портту көзөмөлдөө"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Угуу портторуна уруксат берүү/тыюу салуу"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Угуу порттору"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Уруксат берилген порттор сакталды"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Кошуу"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Өчүрүү: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Жаңы портко уруксат берүү"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Жаңы порттун номерин киргизиңиз"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Сактоо"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Жокко чыгаруу"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Санды киргизиңиз"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Порттун номери жараксыз"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт бар"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал жаңы оюкчаны ачууну суранып жатат"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Оюкча суралды: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Кабыл алуу"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Четке кагуу"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Калыбына келтирүү"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Катуу диск бөлүгүн калыбына келтирүү параметрлери"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Баштапкы версияга өзгөртүү"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Баарын өчүрүү"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Катуу диск бөлүгүн калыбына келтирүү жолдору"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Баштапкы версияга кайтаруу"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Бардык маалыматты өчүрүү"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Терминалды баштапкы абалга келтирүү"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Маалымат өчүрүлөт"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Ырастоо"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Маалымат өчүрүлөт"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Кайра коюу"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Жокко чыгаруу"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Маалыматтын камдык көчүрмөсүн төмөнкүгө сактоо: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Камдык көчүрмө сакталбагандыктан калыбына келтирилген жок"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Камдык көчүрмөнү сактоо катасынан улам калыбына келтирилген жок"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Калыбына келтирилген жок"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Камдык көчүрмө файлы өчпөй жатат"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Маалыматтын камдык көчүрмөсү өчүрүлгөн жок"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Маалыматтын камдык көчүрмөсүн өчүрүү"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Тазалоо: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Оңдолбос ката"</string>
- <string name="error_desc" msgid="1939028888570920661">"Катадан кийин калыбына келтирилген жок.\nКолдонмону кайрадан ачып же аккаунтту калыбына келтирүү жолдорунун бирин колдонуп көрүңүз."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Өчүрүү: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Оңдолбос ката"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Катадан кийин калыбына келтирилген жок.\nТерминалды өчүрүп күйгүзүп же калыбына келтирүү жолдорунун бирин колдонуп көрүңүз.\nЭгер бардык аракеттер ишке ашпай калса, Linux терминалын иштеп чыгуучунун параметрлеринен күйгүзүп/өчүрүп, бардык маалыматты тазалаңыз."</string>
<string name="error_code" msgid="3585291676855383649">"Ката коду: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Параметрлер"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Терминал иштеп жатат"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Терминалды ачуу үчүн чыкылдатыңыз"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Терминалды ачуу үчүн басыңыз"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Жабуу"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Терминал жабылып жатат"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Мажбурлап жабуу"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> иштетилди"</string>
</resources>
diff --git a/android/TerminalApp/res/values-lo/strings.xml b/android/TerminalApp/res/values-lo/strings.xml
index 0b15498..cb8bc0c 100644
--- a/android/TerminalApp/res/values-lo/strings.xml
+++ b/android/TerminalApp/res/values-lo/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"ຈໍສະແດງຜົນ Terminal"</string>
<string name="terminal_input" msgid="4602512831433433551">"ເຄີເຊີ"</string>
<string name="empty_line" msgid="5012067143408427178">"ແຖວຫວ່າງເປົ່າ"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ແຕະສອງເທື່ອເພື່ອພິມການປ້ອນຂໍ້ມູນ"</string>
<string name="installer_title_text" msgid="500663060973466805">"ຕິດຕັ້ງເທີມິນອນ Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"ເພື່ອເປີດໃຊ້ເທີມິນອນ Linux, ທ່ານຕ້ອງດາວໂຫຼດຂໍ້ມູນປະມານ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ຜ່ານເຄືອຂ່າຍ.\nທ່ານຕ້ອງການດຳເນີນການຕໍ່ບໍ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ດາວໂຫຼດເມື່ອມີການເຊື່ອມຕໍ່ Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"ເພື່ອເປີດໃຊ້ເທີມິນອນ Linux, ທ່ານຈະຕ້ອງດາວໂຫຼດຂໍ້ມູນປະມານ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ຜ່ານເຄືອຂ່າຍ.\nທ່ານຕ້ອງການດຳເນີນການຕໍ່ບໍ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"ດາວໂຫຼດໂດຍໃຊ້ Wi-Fi ເທົ່ານັ້ນ"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ຕິດຕັ້ງ"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ກຳລັງຕິດຕັ້ງ"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ເຄືອຂ່າຍຜິດພາດ. ກວດສອບການເຊື່ອມຕໍ່ແລ້ວລອງໃໝ່."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ຕິດຕັ້ງບໍ່ສຳເລັດເນື່ອງຈາກເຄືອຂ່າຍຜິດພາດ. ກະລຸນາກວດເບິ່ງການເຊື່ອມຕໍ່ຂອງທ່ານແລ້ວລອງໃໝ່."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"ກຳລັງຕິດຕັ້ງເທີມິນອນ Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"ເທີມິນອນ Linux ຈະເລີ່ມຕົ້ນຫຼັງຈາກສຳເລັດ"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ຕິດຕັ້ງບໍ່ສຳເລັດເນື່ອງຈາກບັນຫາເຄືອຂ່າຍ"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"ຕິດຕັ້ງບໍ່ສຳເລັດຍ້ອນວ່າ Wi-Fi ບໍ່ມີໃຫ້"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"ຕິດຕັ້ງບໍ່ສໍາເລັດ. ກະລຸນາລອງໃໝ່."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ເທີມິນອນ Linux ຈະເລີ່ມຕົ້ນຫຼັງຈາກຕິດຕັ້ງສຳເລັດແລ້ວ"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ຕິດຕັ້ງບໍ່ສຳເລັດເນື່ອງຈາກມີບັນຫາເຄືອຂ່າຍ"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ຕິດຕັ້ງບໍ່ສຳເລັດເນື່ອງຈາກບໍ່ມີ Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ຕິດຕັ້ງບໍ່ສໍາເລັດ. ກະລຸນາລອງໃໝ່"</string>
<string name="action_settings" msgid="5729342767795123227">"ການຕັ້ງຄ່າ"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ກຳລັງກະກຽມເທີມິນອນ"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ກຳລັງຢຸດເທີມິນອນ"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ເທີມິນອນຫຼົ້ມ"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ປັບຂະໜາດດິສ"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ປັບຂະໜາດ / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ການປັບຂະໜາດດິສກ໌"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ປັບຂະໜາດ root ພາທິຊັນ"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ຕັ້ງຂະໜາດດິສ"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"ມອບໝາຍແລ້ວ <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"ສູງສຸດ <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ຍົກເລີກ"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"ຣີສະຕາດເພື່ອນຳໃຊ້"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ການສົ່ງຕໍ່ຜອດ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ຕັ້ງຄ່າການສົ່ງຕໍ່ຜອດ"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ເທີມິນອນກຳລັງພະຍາຍາມເປີດຜອດໃໝ່"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"ຮ້ອງຂໍໃຫ້ເປີດຜອດ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ນຳໃຊ້"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ລະບົບຈະຣີສະຕາດເທີມິນອນເພື່ອປັບຂະໜາດດິສກ໌"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"ຢືນຢັນ"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ການຄວບຄຸມຜອດ"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ອະນຸຍາດ/ປະຕິເສດຜອດການຟັງ"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ຜອດການຟັງ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ຜອດທີ່ອະນຸຍາດເຊິ່ງບັນທຶກໄວ້"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ເພີ່ມ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"ລຶບ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"ອະນຸຍາດຜອດໃໝ່"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"ໃສ່ໝາຍເລກຜອດໃໝ່"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"ບັນທຶກ"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ຍົກເລີກ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"ກະລຸນາໃສ່ໝາຍເລກ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ໝາຍເລກຜອດບໍ່ຖືກຕ້ອງ"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ມີຜອດຢູ່ກ່ອນແລ້ວ"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ເທີມິນອນກຳລັງສົ່ງຄຳຮ້ອງຂໍໃຫ້ເປີດຜອດໃໝ່"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"ຜອດທີ່ຮ້ອງຂໍ: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ຍອມຮັບ"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ປະຕິເສດ"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"ການກູ້ຄືນ"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"ຕົວເລືອກການກູ້ຄືນພາທິຊັນ"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ປ່ຽນເປັນເວີຊັນເລີ່ມຕົ້ນ"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"ລຶບທັງໝົດອອກ"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"ຕົວເລືອກການກູ້ຄືນພາທິຊັນ"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ຣີເຊັດເປັນເວີຊັນເລີ່ມຕົ້ນ"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ລຶບຂໍ້ມູນທັງໝົດອອກ"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ຣີເຊັດເທີມິນອນ"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ຂໍ້ມູນຈະຖືກລຶບ"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"ຢືນຢັນ"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ລະບົບຈະລຶບຂໍ້ມູນອອກ"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ຣີເຊັດ"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ຍົກເລີກ"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"ສຳຮອງຂໍ້ມູນໃສ່ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ການກູ້ຄືນບໍ່ສຳເລັດຍ້ອນການສຳຮອງຂໍ້ມູນບໍ່ສຳເລັດ"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"ກູ້ຄືນບໍ່ສຳເລັດເນື່ອງຈາກເກີດຂໍ້ຜິດພາດໃນການສຳຮອງຂໍ້ມູນ"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"ການກູ້ຄືນບໍ່ສຳເລັດ"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"ບໍ່ສາມາດລຶບໄຟລ໌ສຳຮອງຂໍ້ມູນອອກໄດ້"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ລຶບຂໍ້ມູນສຳຮອງອອກບໍ່ສຳເລັດ"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ລຶບການສຳຮອງຂໍ້ມູນອອກ"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"ອະນາໄມ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"ຂໍ້ຜິດພາດທີ່ບໍ່ສາມາດກູ້ຄືນມາໄດ້"</string>
- <string name="error_desc" msgid="1939028888570920661">"ການກູ້ຄືນຈາກຂໍ້ຜິດພາດບໍ່ສໍາເລັດ.\nທ່ານສາມາດລອງຣີສະຕາດແອັບ ຫຼື ລອງໜຶ່ງໃນຕົວເລືອກການກູ້ຄືນໄດ້."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"ລຶບ <xliff:g id="PATH">/mnt/backup</xliff:g> ອອກ"</string>
+ <string name="error_title" msgid="405150657301906598">"ຂໍ້ຜິດພາດທີ່ບໍ່ສາມາດກູ້ຄືນມາໄດ້"</string>
+ <string name="error_desc" msgid="4588252235686826721">"ກູ້ຄືນຈາກຂໍ້ຜິດພາດບໍ່ສຳເລັດ.\nທ່ານສາມາດລອງຣີສະຕາດເທີມິນອນ ຫຼື ລອງໃຊ້ໜຶ່ງໃນຕົວເລືອກການກູ້ຄືນໄດ້.\nຫາກພະຍາຍາມດຳເນີນການທຸກຢ່າງແລ້ວແຕ່ບໍ່ສຳເລັດ, ໃຫ້ລຶບລ້າງຂໍ້ມູນທັງໝົດໂດຍເປີດ/ປິດເທີມິນອນ Linux ຈາກຕົວເລືອກນັກພັດທະນາ."</string>
<string name="error_code" msgid="3585291676855383649">"ລະຫັດຂໍ້ຜິດພາດ: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ການຕັ້ງຄ່າ"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ເທີມິນອນກຳລັງເຮັດວຽກຢູ່"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ຄລິກເພື່ອເປີດເທີມິນອນ"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ຄລິກເພື່ອເປີດເທີມິນອນ"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"ປິດ"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ເທີມິນອນກຳລັງຈະປິດ"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"ບັງຄັບປິດ"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"ເປີດການນຳໃຊ້ <xliff:g id="ID_1">VirGL</xliff:g> ແລ້ວ"</string>
</resources>
diff --git a/android/TerminalApp/res/values-lt/strings.xml b/android/TerminalApp/res/values-lt/strings.xml
index 96c144b..76f5158 100644
--- a/android/TerminalApp/res/values-lt/strings.xml
+++ b/android/TerminalApp/res/values-lt/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminalas"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminalo ekranas"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Žymeklis"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Tuščia eilutė"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dukart palieskite, kad įvestumėte įvestį"</string>
<string name="installer_title_text" msgid="500663060973466805">"„Linux“ terminalo diegimas"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Norėdami paleisti „Linux“ terminalą, per tinklą turite atsisiųsti apytiksliai <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> duomenų.\nAr norite tęsti?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Atsisiųsti, kai pasiekiamas „Wi-Fi“"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Norėdami paleisti „Linux“ terminalą, per tinklą turite atsisiųsti apytiksliai <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> duomenų.\nAr norite tęsti?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Atsisiuntimas naudojant tik „Wi-Fi“"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Įdiegti"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Diegiama"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Tinklo klaida. Patikrinkite ryšį ir bandykite dar kartą."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Nepavyko įdiegti dėl tinklo klaidos. Patikrinkite ryšį ir bandykite dar kartą."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Diegiamas „Linux“ terminalas"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"„Linux“ terminalas bus paleistas pabaigus"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Nepavyko įdiegti dėl tinklo problemos"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Nepavyko įdiegti Bandykite dar kartą."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"„Linux“ terminalas bus paleistas, kai diegimas bus baigtas"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Nepavyko įdiegti dėl tinklo problemos"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Nepavyko įdiegti, nes „Wi-Fi“ nepasiekiamas"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Nepavyko įdiegti. Bandykite dar kartą"</string>
<string name="action_settings" msgid="5729342767795123227">"Nustatymai"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Ruošiamas terminalas"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminalas sustabdomas"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminalas užstrigo"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Disko dydžio keitimas"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Dydžio keitimas / „Rootfs“"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Disko dydžio keitimas"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Pakeisti šakninio skaidinio dydį"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disko dydis nustatytas"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Priskirta <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maks. <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Atšaukti"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"P. iš n., kad prit."</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Prievado numerio persiuntimas"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Prievado numerio persiuntimo konfigūravimas"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminalas bando atidaryti naują prievadą"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Prievadas, dėl kurio atidarymo pateikta užklausa: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Taikyti"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminalas bus paleistas iš naujo, kad būtų galima pakeisti disko dydį"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Patvirtinti"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Prievado valdymas"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Leisti klausymo prievadus / neleisti jų"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Klausymo prievadai"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Išsaugoti leidžiami prievadai"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Pridėti"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Ištrinti <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Leisti naują prievadą"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Įveskite naują prievado numerį"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Išsaugoti"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Atšaukti"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Įveskite skaičių"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Netinkamas prievado numeris"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Prievadas jau yra"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalas bando atidaryti naują prievadą"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Prievadas, kurio užklausa pateikta: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Sutikti"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Atmesti"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Atkūrimas"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Skaidinio atkūrimo parinktys"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Keitimas į pradinę versiją"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Pašalinti viską"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Skaidinio atkūrimo parinktys"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Iš naujo nustatyti pradinę versiją"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Pašalinti visus duomenis"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminalo nustatymas iš naujo"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Duomenys bus ištrinti"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Patvirtinti"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Duomenys bus pašalinti"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Nustatyti iš naujo"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Atšaukti"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sukurti atsarginę duomenų kopiją čia: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Nepavyko atkurti, nes nepavyko sukurti atsarginės kopijos"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Nepavyko atkurti dėl atsarginės kopijos klaidos"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Nepavyko atkurti"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Nepavyko pašalinti atsarginės kopijos failo"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Nepavyko pašalinti atsarginės kopijos duomenų"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Pašalinti atsarginės kopijos duomenis"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Išvalyti <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Nepataisoma klaida"</string>
- <string name="error_desc" msgid="1939028888570920661">"Nepavyko atkurti po klaidos.\nGalite bandyti iš naujo paleisti programą arba išbandyti vieną iš atkūrimo parinkčių."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Pašalinti <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Nepataisoma klaida"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Nepavyko atkurti po klaidos.\nGalite bandyti iš naujo paleisti terminalą arba išbandyti vieną iš atkūrimo parinkčių.\nJei nepavyksta atkurti, panaikinkite visus duomenis įjungę ir (arba) išjungę „Linux“ terminalą iš kūrėjo parinkčių."</string>
<string name="error_code" msgid="3585291676855383649">"Klaidos kodas: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Nustatymai"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminalas veikia"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Spustelėkite, kad atidarytumėte terminalą"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Spustelėkite, kad atidarytumėte terminalą"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Uždaryti"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminalas uždaromas"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Priverstinai uždaryti"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"„<xliff:g id="ID_1">VirGL</xliff:g>“ įgalinta"</string>
</resources>
diff --git a/android/TerminalApp/res/values-lv/strings.xml b/android/TerminalApp/res/values-lv/strings.xml
index 253da6d..a0730a1 100644
--- a/android/TerminalApp/res/values-lv/strings.xml
+++ b/android/TerminalApp/res/values-lv/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminālis"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Termināļa displejs"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursors"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Tukša rinda"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Veiciet dubultskārienu, lai ievadītu tekstu"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux termināļa instalēšana"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Lai palaistu Linux termināli, jums jālejupielādē aptuveni <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> datu, izmantojot tīklu.\nVai vēlaties turpināt?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Lejupielādēt, kad ir pieejams Wi-Fi savienojums"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Lai palaistu Linux termināli, jums jālejupielādē aptuveni <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> datu, izmantojot tīklu.\nVai vēlaties turpināt?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Lejupielāde, izmantojot tikai Wi‑Fi tīklu"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalēt"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalē"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Tīkla kļūda. Pārbaudiet savienojumu un mēģiniet vēlreiz."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Instalēšana neizdevās tīkla kļūdas dēļ. Pārbaudiet savienojumu un mēģiniet vēlreiz."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Notiek Linux termināļa instalēšana…"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminālis tiks palaists pēc pabeigšanas"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Tīkla problēmas dēļ neizdevās instalēt"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Neizdevās instalēt. Mēģiniet vēlreiz."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Kad instalēšana būs pabeigta, tiks palaists Linux terminālis"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Instalēšana neizdevās tīkla problēmas dēļ"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Instalēšana neizdevās, jo nav pieejams Wi‑Fi savienojums"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Neizdevās instalēt — mēģiniet vēlreiz"</string>
<string name="action_settings" msgid="5729342767795123227">"Iestatījumi"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Notiek termināļa sagatavošana."</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Notiek termināļa apturēšana."</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminālis avarēja."</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Diska lieluma mainīšana"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Mainīt lielumu / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Diska lieluma mainīšana"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Saknes nodalījuma lieluma mainīšana"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Diska lielums ir iestatīts."</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Piešķirtais lielums: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maksimālais lielums: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Atcelt"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Restartēt un lietot"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Porta pārsūtīšana"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurēt porta pārsūtīšanu"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminālis mēģina atvērt jaunu portu"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Ports, kura atvēršana pieprasīta: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Lietot"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Lai mainītu diska lielumu, terminālis tiks restartēts"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Apstiprināt"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portu kontrole"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Atļaut/aizliegt klausīšanās portus"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Klausīšanās porti"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saglabātie atļautie porti"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Pievienot"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Dzēst <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Atļaut jaunu portu"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Ievadiet jaunu porta numuru"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Saglabāt"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Atcelt"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Lūdzu, ievadiet numuru"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nederīgs porta numurs"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Ports jau pastāv"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminālis pieprasa jauna porta atvēršanu"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Pieprasītais ports: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Piekrist"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Noraidīt"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Atkopšana"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Nodalījuma atkopšanas opcijas"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Mainīšana uz sākotnējo versiju"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Noņemt visu"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Nodalījuma atkopšanas opcijas"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Atiestatīšana uz sākotnējo versiju"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Visu datu noņemšana"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Termināļa atiestatīšana"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Dati tiks izdzēsti"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Apstiprināt"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Dati tiks noņemti"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Atiestatīt"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Atcelt"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Dublēt datus ceļā <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Atkopšana neizdevās, jo neizdevās dublēšana"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Atkopšana neizdevās, jo radās dublēšanas kļūda"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Atkopšana neizdevās"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Nevar noņemt dublējuma failu"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Neizdevās noņemt dublējuma datus"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Dublējuma datu noņemšana"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Vietas atbrīvošana ceļā <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Neatkopjama kļūda"</string>
- <string name="error_desc" msgid="1939028888570920661">"Neizdevās veikt atkopšanu pēc kļūdas.\nVarat restartēt lietotni vai izmantot kādu no atkopšanas opcijām."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Datu noņemšana no ceļa <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Neatkopjama kļūda"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Neizdevās veikt atkopšanu pēc kļūdas.\nVarat restartēt termināli vai izmēģināt kādu no atkopšanas opcijām.\nJa neviens mēģinājums neizdodas, notīriet visus datus, izstrādātāju opcijās ieslēdzot/izslēdzot Linux termināli."</string>
<string name="error_code" msgid="3585291676855383649">"Kļūdas kods: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Iestatījumi"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminālis darbojas"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Noklikšķiniet, lai atvērtu termināli"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Lai atvērtu termināli, noklikšķiniet"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Aizvērt"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminālis tiek aizvērts"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Veikt piespiedu aizvēršanu"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ir iespējots"</string>
</resources>
diff --git a/android/TerminalApp/res/values-mk/strings.xml b/android/TerminalApp/res/values-mk/strings.xml
index 0fb2296..ac328d7 100644
--- a/android/TerminalApp/res/values-mk/strings.xml
+++ b/android/TerminalApp/res/values-mk/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Терминал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Екран на терминал"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Празен ред"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Допрете двапати за да внесете текст"</string>
<string name="installer_title_text" msgid="500663060973466805">"Инсталирајте го Linux-терминалот"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"За да го стартувате Linux-терминалот, треба да преземете податоци од приближно <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> преку мрежата.\nДали сакате да продолжите?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Преземете кога има Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"За да го стартувате Linux-терминалот, треба да преземете податоци од приближно <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> преку мрежата.\nДали сакате да продолжите?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Преземете само преку Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Инсталирај"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Се инсталира"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Грешка на мрежата. Проверете ја врската и обидете се повторно."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Не можеше да се инсталира поради грешка на мрежата. Проверете ја интернет-врската и обидете се повторно."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux-терминалот се инсталира"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-терминалот ќе се стартува по довршувањето"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Не можеше да се инсталира поради проблем со мрежата"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Не можеше да се инсталира. Обидете се повторно."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux-терминалот ќе се стартува откако ќе заврши инсталирањето"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Не можеше да се инсталира поради проблем со мрежата"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Не можеше да се инсталира бидејќи не е достапна Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Не можеше да се инсталира. Обидете се повторно"</string>
<string name="action_settings" msgid="5729342767795123227">"Поставки"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Терминалот се подготвува"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Терминалот се сопира"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Терминалот падна"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Променување на големината на дискот"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Променување големина/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Променување на големината на дискот"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Променете ја големината на главната партиција"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Големината на дискот е поставена"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Доделено: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Макс.: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Откажи"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Рестарт. за примена"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Проследување порти"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Конфигурирајте го проследувањето порти"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Терминалот се обидува да отвори нова порта"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Порта што е побарано да се отвори: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Примени"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Терминалот ќе се рестартира за да се промени големината на дискот"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Потврди"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Контрола на портите"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дозволете/одбијте порти за примање барања"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Порти за примање барања"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Дозволените порти се зачувани"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Додај"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Избриши <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Дозволете нова порта"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Внесете нов број на порта"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Зачувај"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Откажи"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Внесете број"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Неважечки број на порта"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Портата веќе постои"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминалот бара да отвори нова порта"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Побарана е порта: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прифати"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Одбиј"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Враќање"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Опции за враќање партиции"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Промени на првата верзија"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Отстрани ги сите"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Опции за враќање партиции"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Ресетирајте на почетната верзија"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Отстранете ги сите податоци"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Ресетирајте го терминалот"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Податоците ќе се избришат"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Потврди"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Податоците ќе се отстранат"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Ресетирај"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Откажи"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Направете бекап на податоците на <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Враќањето не успеа поради неуспешен бекап"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Не можеше да се поправи поради грешка при правење бекап"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Враќањето не успеа"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Не може да се отстрани датотеката со бекап"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Не можеше да се отстранат податоците со бекапот"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Отстранете ги податоците од бекапот"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Ослободете простор на <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Непоправлива грешка"</string>
- <string name="error_desc" msgid="1939028888570920661">"Грешката не можеше да се поправи.\nМоже да се обидете да ја рестартирате апликацијата или да испробате некоја од опциите за враќање."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Отстранете „<xliff:g id="PATH">/mnt/backup</xliff:g>“"</string>
+ <string name="error_title" msgid="405150657301906598">"Непоправлива грешка"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Грешката не можеше да се поправи.\nМоже да се обидете да го рестартирате терминалот или да испробате некоја од опциите за враќање.\nАко сите обиди се неуспешни, избришете ги сите податоци трајно со вклучување/исклучување на Linux-терминалот од „Програмерски опции“."</string>
<string name="error_code" msgid="3585291676855383649">"Код за грешка: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Поставки"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Терминалот е активен"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Кликнете за да го отворите терминалот"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Кликнете за да го отворите терминалот"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Затвори"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Терминалот се затвора"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Затвори присилно"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Овозможено: <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ml/strings.xml b/android/TerminalApp/res/values-ml/strings.xml
index 0911d01..1ff795d 100644
--- a/android/TerminalApp/res/values-ml/strings.xml
+++ b/android/TerminalApp/res/values-ml/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ടെർമിനൽ"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ടെർമിനൽ ഡിസ്പ്ലേ"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"കഴ്സർ"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ശൂന്യമായ ലൈൻ"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ഇൻപുട്ട് ടൈപ്പ് ചെയ്യാൻ ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ടെർമിനൽ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ടെർമിനൽ ലോഞ്ച് ചെയ്യാൻ, നിങ്ങൾക്ക് നെറ്റ്വർക്കിലൂടെ ഏകദേശം <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ഡാറ്റ ഡൗൺലോഡ് ചെയ്യേണ്ടതുണ്ട്.\nനിങ്ങൾക്ക് തുടരണോ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"വൈഫൈ ലഭ്യമാകുമ്പോൾ ഡൗൺലോഡ് ചെയ്യുക"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ടെർമിനൽ ലോഞ്ച് ചെയ്യാൻ, നിങ്ങൾക്ക് നെറ്റ്വർക്കിലൂടെ ഏകദേശം <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ഡാറ്റ ഡൗൺലോഡ് ചെയ്യേണ്ടതുണ്ട്.\nനിങ്ങൾക്ക് തുടരണമെന്നുണ്ടോ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"വൈഫൈ മാത്രം ഉപയോഗിച്ച് ഡൗൺലോഡ് ചെയ്യുക"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ഇൻസ്റ്റാൾ ചെയ്യുന്നു"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"നെറ്റ്വർക്ക് പിശക്. കണക്ഷൻ പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"നെറ്റ്വർക്ക് പിശക് കാരണം ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല. നിങ്ങളുടെ കണക്ഷൻ പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ടെർമിനൽ ഇൻസ്റ്റാൾ ചെയ്യുന്നു"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"പൂർത്തിയായിക്കഴിഞ്ഞാൽ, Linux ടെർമിനൽ ഇൻസ്റ്റാൾ ചെയ്യാൻ ആരംഭിക്കും"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"നെറ്റ്വർക്കുമായി ബന്ധപ്പെട്ട് പ്രശ്നമുണ്ടായതിനാൽ ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ഇൻസ്റ്റലേഷൻ പൂർത്തിയായതിന് ശേഷം Linux ടെർമിനൽ ആരംഭിക്കും"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"നെറ്റ്വർക്കുമായി ബന്ധപ്പെട്ട് പ്രശ്നമുണ്ടായതിനാൽ ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"വൈഫൈ ലഭ്യമല്ലാത്തതിനാൽ ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക"</string>
<string name="action_settings" msgid="5729342767795123227">"ക്രമീകരണം"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ടെർമിനൽ തയ്യാറാക്കുന്നു"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ടെർമിനൽ നിർത്തുന്നു"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ടെർമിനൽ ക്രാഷായി"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ഡിസ്ക് വലുപ്പം മാറ്റുക"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"വലുപ്പം മാറ്റുക / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ഡിസ്ക്കിന്റെ വലുപ്പം മാറ്റുക"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"റൂട്ട് പാർട്ടീഷൻ വലുപ്പം മാറ്റുക"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ഡിസ്ക് വലുപ്പം സജ്ജീകരിച്ചു"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> അസൈൻ ചെയ്തു"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"പരമാവധി <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"റദ്ദാക്കുക"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"പ്രയോഗിക്കാൻ റീസ്റ്റാർട്ട് ചെയ്യൂ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"പോർട്ട് ഫോർവേഡിങ്"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"പോർട്ട് ഫോർവേഡിങ് കോൺഫിഗർ ചെയ്യുക"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ഒരു പുതിയ പോർട്ട് തുറക്കാൻ ടെർമിനൽ ശ്രമിക്കുന്നു"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"പോർട്ട് തുറക്കാൻ അഭ്യർത്ഥിച്ചു: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ബാധകമാക്കുക"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ഡിസ്കിന്റെ വലുപ്പം മാറ്റുന്നതിനായി ടെർമിനൽ റീസ്റ്റാർട്ട് ചെയ്യും"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"സ്ഥിരീകരിക്കുക"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"പോർട്ട് നിയന്ത്രണം"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ശ്രവണ പോർട്ടുകൾ അനുവദിക്കുക/നിരസിക്കുക"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ശ്രവണ പോർട്ടുകൾ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"സംരക്ഷിച്ച അനുവദനീയമായ പോർട്ടുകൾ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ചേർക്കുക"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ഇല്ലാതാക്കുക"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"പുതിയ പോർട്ട് അനുവദിക്കുക"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"പുതിയ പോർട്ട് നമ്പർ നൽകുക"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"സംരക്ഷിക്കുക"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"റദ്ദാക്കുക"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"ഒരു നമ്പർ നൽകുക"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"പോർട്ട് നമ്പർ അസാധുവാണ്"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"പോർട്ട് ഇതിനകം നിലവിലുണ്ട്"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ഒരു പുതിയ പോർട്ട് തുറക്കാൻ ടെർമിനൽ അഭ്യർത്ഥിക്കുന്നു"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"അഭ്യർത്ഥിച്ച പോർട്ട്: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"അംഗീകരിക്കുക"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"നിരസിക്കുക"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"വീണ്ടെടുക്കുക"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"പാർട്ടീഷൻ വീണ്ടെടുക്കൽ ഓപ്ഷനുകൾ"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"പ്രാരംഭ പതിപ്പിലേക്ക് മാറ്റുക"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"എല്ലാം നീക്കം ചെയ്യുക"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"പാർട്ടീഷൻ വീണ്ടെടുക്കൽ ഓപ്ഷനുകൾ"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"പ്രാരംഭ പതിപ്പിലേക്ക് റീസെറ്റ് ചെയ്യുക"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യുക"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ടെർമിനൽ റീസെറ്റ് ചെയ്യുക"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ഡാറ്റ ഇല്ലാതാക്കും"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"സ്ഥിരീകരിക്കുക"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ഡാറ്റ നീക്കം ചെയ്യും"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"റീസെറ്റ് ചെയ്യുക"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"റദ്ദാക്കുക"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> എന്നതിലേക്ക് ഡാറ്റ ബാക്കപ്പെടുക്കുക"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ബാക്കപ്പ് ചെയ്യാനാകാത്തതിനാൽ വീണ്ടെടുക്കാനായില്ല"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"ബാക്കപ്പുമായി ബന്ധപ്പെട്ട പിശക് കാരണം വീണ്ടെടുക്കാനായില്ല"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"വീണ്ടെടുക്കാനായില്ല"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"ബാക്കപ്പ് ഫയൽ നീക്കം ചെയ്യാനാകില്ല"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ബാക്കപ്പ് ഡാറ്റ നീക്കം ചെയ്യാനായില്ല"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ബാക്കപ്പ് ഡാറ്റ നീക്കം ചെയ്യുക"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> ക്ലീനപ്പ് ചെയ്യുക"</string>
- <string name="error_title" msgid="7196464038692913778">"വീണ്ടെടുക്കാനാകാത്ത വിധത്തിലാക്കിയ പിശക്"</string>
- <string name="error_desc" msgid="1939028888570920661">"ഒരു പിശകിൽ നിന്ന് വീണ്ടെടുക്കാനായില്ല.\nനിങ്ങൾക്ക് ആപ്പ് റീസ്റ്റാർട്ട് ചെയ്യാൻ ശ്രമിക്കാം അല്ലെങ്കിൽ വീണ്ടെടുക്കൽ ഓപ്ഷനുകളിലൊന്ന് ശ്രമിച്ചുനോക്കാം."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> നീക്കം ചെയ്യുക"</string>
+ <string name="error_title" msgid="405150657301906598">"വീണ്ടെടുക്കാനാകാത്ത വിധത്തിലാക്കിയ പിശക്"</string>
+ <string name="error_desc" msgid="4588252235686826721">"ഒരു പിശകിൽ നിന്ന് വീണ്ടെടുക്കാനായില്ല.\nനിങ്ങൾക്ക് ടെർമിനൽ റീസ്റ്റാർട്ട് ചെയ്യാൻ ശ്രമിക്കാം അല്ലെങ്കിൽ വീണ്ടെടുക്കൽ ഓപ്ഷനുകളിലൊന്ന് ശ്രമിച്ചുനോക്കാം.\nഎല്ലാ ശ്രമങ്ങളും പരാജയപ്പെടുകയാണെങ്കിൽ, ഡെവലപ്പർ ഓപ്ഷനുകളിൽ നിന്ന് Linux ടെർമിനൽ ഓൺ/ഓഫ് ആക്കി എല്ലാ ഡാറ്റയും തുടച്ചുനീക്കുക."</string>
<string name="error_code" msgid="3585291676855383649">"പിശക് കോഡ്: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ക്രമീകരണം"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ടെർമിനൽ റൺ ചെയ്യുന്നു"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ടെർമിനൽ തുറക്കാൻ ക്ലിക്ക് ചെയ്യുക"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ടെർമിനൽ തുറക്കാൻ ക്ലിക്ക് ചെയ്യുക"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"അടയ്ക്കുക"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ടെർമിനൽ അടയ്ക്കുകയാണ്"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"നിർബന്ധിതമായി അടയ്ക്കുക"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> പ്രവർത്തനക്ഷമമാക്കി"</string>
</resources>
diff --git a/android/TerminalApp/res/values-mn/strings.xml b/android/TerminalApp/res/values-mn/strings.xml
index 23cb782..5b6ce4a 100644
--- a/android/TerminalApp/res/values-mn/strings.xml
+++ b/android/TerminalApp/res/values-mn/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Терминал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Терминалын дэлгэц"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Хоосон мөр"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Оролт бичихийн тулд хоёр товшино уу"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux terminal-г суулгах"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux терминалыг эхлүүлэхийн тулд та сүлжээгээр барагцаагаар <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g>-н өгөгдөл татах шаардлагатай.\nТа үргэлжлүүлэх үү?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi боломжтой үед татах"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux терминалыг эхлүүлэхийн тулд та барагцаагаар <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g>-н өгөгдлийг сүлжээгээр татах шаардлагатай.\nТа үргэлжлүүлэхийг хүсэж байна уу?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Зөвхөн Wi-Fi ашиглан татах"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Суулгах"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Суулгаж байна"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Сүлжээний алдаа гарлаа. Холболтыг шалгаж, дахин оролдоно уу."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Сүлжээний алдааны улмаас суулгаж чадсангүй. Холболтоо шалгаад, дахин оролдоно уу."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux терминалыг суулгаж байна"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Дууссаны дараа Linux терминал эхэлнэ"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Сүлжээний асуудлын улмаас суулгаж чадсангүй"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Суулгаж чадсангүй. Дахин оролдоно уу."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Суулгаж дууссаны дараа Linux терминалыг эхлүүлнэ"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Сүлжээний асуудлын улмаас суулгаж чадсангүй"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi боломжгүй тул суулгаж чадсангүй"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Суулгаж чадсангүй. Дахин оролдоно уу"</string>
<string name="action_settings" msgid="5729342767795123227">"Тохиргоо"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Терминалыг бэлтгэж байна"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Терминалыг зогсоож байна"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Терминал гэмтсэн"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Дискийн хэмжээг өөрчлөх"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Хэмжээг өөрчлөх / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Дискийн хэмжээг өөрчлөх"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Үндсэн хуваалтын хэмжээг өөрчлөх"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Дискийн хэмжээг тохируулсан"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> оноосон"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Дээд тал нь <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Цуцлах"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Дахин эхлүүлж ашигла"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Порт дамжуулах"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Порт дамжуулахыг тохируулах"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Терминал шинэ порт нээхээр оролдож байна"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Нээхийг хүссэн порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Оруулах"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Дискийн хэмжээг өөрчлөхийн тулд терминалыг дахин эхлүүлнэ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Баталгаажуулах"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Портын тохиргоо"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Сүлжээний хүсэлт хүлээж буй портуудыг зөвшөөрөх/татгалзах"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Сүлжээний хүсэлт хүлээж буй портууд"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Хадгалсан зөвшөөрөгдсөн портууд"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Нэмэх"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>-г устгах"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Шинэ портыг зөвшөөрөх"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Шинэ портын дугаар оруулах"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Хадгалах"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Цуцлах"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Дугаар оруулна уу"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Портын дугаар буруу байна"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт аль хэдийн байна"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал шинэ порт нээхийг хүсэж байна"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Хүссэн порт: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Зөвшөөрөх"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Татгалзах"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Сэргээх"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Хуваалтыг сэргээх сонголтууд"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Анхны хувилбар луу өөрчлөх"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Бүгдийг хасах"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Хуваалтыг сэргээх сонголтууд"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Анхны хувилбар луу шинэчлэх"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Бүх өгөгдлийг устгах"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Терминалыг шинэчлэх"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Өгөгдлийг устгана"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Баталгаажуулах"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Өгөгдлийг устгана"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Шинэчлэх"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Цуцлах"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Өгөгдлийг <xliff:g id="PATH">/mnt/backup</xliff:g>-д нөөцлөх"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Нөөцлөлт амжилтгүй болсон тул сэргээж чадсангүй"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Нөөцлөлтийн алдааны улмаас сэргээж чадсангүй"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Сэргээж чадсангүй"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Нөөц файлыг хасах боломжгүй"</string>
- <string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Нөөц өгөгдлийг хасах"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g>-г цэвэрлэх"</string>
- <string name="error_title" msgid="7196464038692913778">"Сэргээх боломжгүй алдаа"</string>
- <string name="error_desc" msgid="1939028888570920661">"Алдааны улмаас сэргээж чадсангүй.\nТа аппыг дахин эхлүүлэхээр оролдох эсвэл сэргээх сонголтуудын аль нэгийг туршиж үзэх боломжтой."</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Нөөц өгөгдлийг устгаж чадсангүй"</string>
+ <string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Нөөц өгөгдлийг устгах"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g>-г устгах"</string>
+ <string name="error_title" msgid="405150657301906598">"Сэргээх боломжгүй алдаа"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Алдааны улмаас сэргээж чадсангүй.\nТа терминалыг дахин эхлүүлэх эсвэл сэргээх сонголтуудын аль нэгийг туршиж үзэх боломжтой.\nХэрэв бүх оролдлого амжилтгүй болбол хөгжүүлэгчийн тохиргооноос Linux терминалыг асаах/унтраах замаар бүх өгөгдлийг арчина уу."</string>
<string name="error_code" msgid="3585291676855383649">"Алдааны код: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Тохиргоо"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Терминал ажиллаж байна"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Терминалыг нээхийн тулд товшино уу"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Терминалыг нээхийн тулд товшино уу"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Хаах"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Терминал хаагдаж байна"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Хүчээр хаах"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> идэвхэжсэн"</string>
</resources>
diff --git a/android/TerminalApp/res/values-mr/strings.xml b/android/TerminalApp/res/values-mr/strings.xml
index e084c1e..1701983 100644
--- a/android/TerminalApp/res/values-mr/strings.xml
+++ b/android/TerminalApp/res/values-mr/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"टर्मिनल"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"टर्मिनल डिस्प्ले"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"कर्सर"</string>
+ <string name="empty_line" msgid="5012067143408427178">"रिकामी ओळ"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"इनपुट टाइप करण्यासाठी दोनदा टॅप करा"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux टर्मिनल इंस्टॉल करा"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux टर्मिनल लाँच करण्यासाठी, तुम्ही नेटवर्कवरून अंदाजे <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> डेटा डाउनलोड करणे आवश्यक आहे.\nतुम्हाला पुढे सुरू ठेवायचे आहे का?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"वाय-फाय उपलब्ध असताना डाउनलोड करा"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux टर्मिनल लाँच करण्यासाठी, तुम्ही नेटवर्कवरून अंदाजे <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> डेटा डाउनलोड करणे आवश्यक आहे.\nतुम्हाला पुढे सुरू ठेवायचे आहे का?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"फक्त वाय-फाय वापरून डाउनलोड करा"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"इंस्टॉल करा"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"इंस्टॉल करत आहे"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"नेटवर्क एरर. कनेक्शन तपासून पुन्हा प्रयत्न करा."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"नेटवर्क एररमुळे इंस्टॉल करता आले नाही. तुमचे कनेक्शन तपासा आणि पुन्हा प्रयत्न करा."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux टर्मिनल इंस्टॉल करत आहे"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"पूर्ण झाल्यानंतर Linux टर्मिनल सुरू होईल"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"नेटवर्कच्या समस्येमुळे इंस्टॉल करता आले नाही"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"इंस्टॉल करता आले नाही. पुन्हा प्रयत्न करा."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"इंस्टॉलेशन पूर्ण झाल्यानंतर Linux टर्मिनल सुरू होईल"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"नेटवर्कच्या समस्येमुळे इंस्टॉल करता आले नाही"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"वाय-फाय उपलब्ध नसल्यामुळे इंस्टॉल करता आले नाही"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"इंस्टॉल करता आले नाही. कृपया पुन्हा प्रयत्न करा"</string>
<string name="action_settings" msgid="5729342767795123227">"सेटिंग्ज"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"टर्मिनल तयार करत आहे"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"टर्मिनल थांबवत आहे"</string>
<string name="vm_error_message" msgid="5231867246177661525">"टर्मिनल क्रॅश झाले आहे"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"डिस्कचा आकार बदला"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"आकार बदला / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"डिस्कचा आकार बदला"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"रूट पार्टिशनचा आकार बदला"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"डिस्कचा आकार सेट केला आहे"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> असाइन केले आहे"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"कमाल <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"रद्द करा"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"लागू करण्यासाठी रीस्टार्ट करा"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"पोर्ट फॉरवर्डिंग"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"पोर्ट फॉरवर्डिंग कॉन्फिगर करा"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"टर्मिनल नवीन पोर्ट उघडण्याचा प्रयत्न करत आहे"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"उघडण्याची विनंती केलेला पोर्ट: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"लागू करा"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"डिस्कचा आकार बदलण्यासाठी टर्मिनल पुन्हा सुरू केले जाईल"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"कन्फर्म करा"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"पोर्ट नियंत्रण"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ऐकण्याच्या पोर्टना अनुमती द्या/नाकारा"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ऐकण्याचे पोर्ट"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"सेव्ह केलेले व अनुमती असलेले पोर्ट"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"जोडा"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> हटवा"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"नवीन पोर्टला अनुमती द्या"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"नवीन पोर्ट नंबर एंटर करा"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"सेव्ह करा"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"रद्द करा"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"कृपया नंबर एंटर करा"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"पोर्ट नंबर चुकीचा आहे"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"पोर्ट आधीपासून अस्तित्वात आहे"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"टर्मिनल नवीन पोर्ट उघडण्याची विनंती करत आहे"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"पोर्टसंबंधित विनंती केली: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"स्वीकारा"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"नकार द्या"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"रिकव्हरी"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"पार्टिशनचे रिकव्हरी पर्याय"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"मूळ आवृत्तीवर बदला"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"सर्व काढून टाका"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"पार्टिशनचे रिकव्हरी पर्याय"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"मूळ आवृत्तीवर रीसेट करा"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"सर्व डेटा काढून टाका"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"टर्मिनल रीसेट करा"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"डेटा हटवला जाईल"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"कन्फर्म करा"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"डेटा काढून टाकला जाईल"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"रीसेट करा"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"रद्द करा"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> वर डेटाचा बॅकअप घ्या."</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"बॅकअप घेता आला नसल्यामुळे, रिकव्हरी करता आली नाही"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"बॅकअप एररमुळे रिकव्हर करता आले नाही"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"रिकव्हरी करता आली नाही"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"बॅकअप फाइल काढून टाकू शकत नाही"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"बॅकअप डेटा काढून टाकता आला नाही"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"बॅकअप डेटा काढून टाका"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"क्लीन अप करा <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> काढून टाका"</string>
+ <string name="error_title" msgid="405150657301906598">"रिकव्हर न करता येणारी एरर"</string>
+ <string name="error_desc" msgid="4588252235686826721">"एररमधून रिकव्हर करता आले नाही.\nतुम्ही टर्मिनल रीस्टार्ट करण्याचा प्रयत्न करू शकता किंवा रिकव्हरी पर्यायांपैकी एखादा पर्याय वापरून पाहू शकता.\nसर्व प्रयत्न अयशस्वी झाल्यास, डेव्हलपर पर्यायांमधून Linux टर्मिनल सुरू/बंद करून सर्व डेटा पुसून टाका."</string>
+ <string name="error_code" msgid="3585291676855383649">"एरर कोड: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"सेटिंग्ज"</string>
<string name="service_notification_title" msgid="2918088850910713393">"टर्मिनल रन होत आहे"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"टर्मिनल उघडण्यासाठी क्लिक करा"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"टर्मिनल उघडण्यासाठी क्लिक करा"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"बंद करा"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"टर्मिनल बंद होत आहे"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"सक्तीने बंद करा"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> सुरू केले आहे"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ms/strings.xml b/android/TerminalApp/res/values-ms/strings.xml
index b845724..1709e51 100644
--- a/android/TerminalApp/res/values-ms/strings.xml
+++ b/android/TerminalApp/res/values-ms/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Paparan terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Baris kosong"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Ketik dua kali untuk menaip input"</string>
<string name="installer_title_text" msgid="500663060973466805">"Pasang terminal Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Untuk melancarkan terminal Linux, anda perlu memuat turun anggaran <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data melalui rangkaian.\nAdakah anda mahu meneruskan proses?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Muat turun apabila Wi-Fi tersedia"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Untuk melancarkan terminal Linux, anda perlu memuat turun kira-kira <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data melalui rangkaian.\nAdakah anda mahu meneruskan proses?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Muat turun menggunakan Wi-Fi sahaja"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Pasang"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Memasang"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Ralat rangkaian. Semak sambungan dan cuba lagi."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Gagal melakukan pemasangan disebabkan oleh ralat rangkaian. Semak sambungan anda, kemudian cuba lagi."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Memasang terminal Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Terminal Linux akan dimulakan selepas selesai"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Gagal melakukan pemasangan disebabkan oleh masalah rangkaian"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Gagal melakukan pemasangan. Cuba lagi."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Terminal Linux akan dimulakan selepas pemasangan selesai"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Gagal melakukan pemasangan disebabkan oleh masalah rangkaian"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Gagal melakukan pemasangan kerana Wi-Fi tidak tersedia"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Gagal melakukan pemasangan. Sila cuba lagi"</string>
<string name="action_settings" msgid="5729342767795123227">"Tetapan"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Menyediakan terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Menghentikan terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal ranap"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Ubah Saiz Cakera"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Ubah saiz / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Ubah saiz cakera"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Ubah saiz pemetakan akar"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Set saiz cakera"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ditetapkan"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maksimum <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Batal"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Mulakan semula untuk gunakan"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Kiriman Semula Port"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurasikan kiriman semula port"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal sedang cuba membuka port baharu"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port diminta untuk dibuka : <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Guna"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal akan dimulakan semula untuk mengubah saiz cakera"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Sahkan"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kawalan port"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Benarkan/tolak port mendengar"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Port mendengar"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Port yang dibenarkan disimpan"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Tambah"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Padamkan <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Benarkan port baharu"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Masukkan nombor port baharu"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Simpan"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Batal"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Sila masukkan nombor"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nombor port tidak sah"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port sudah wujud"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal membuat permintaan untuk membuka port baharu"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port diminta: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Terima"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Tolak"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Pemulihan"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Pilihan pemulihan Pemetakan"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Tukar kepada Versi awal"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Alih keluar semua"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Pilihan pemulihan pemetakan"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Tetapkan semula kepada versi awal"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Alih keluar semua data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Tetapkan semula terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data akan dipadamkan"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Sahkan"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data akan dialih keluar"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Tetapkan semula"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Batal"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sandarkan data kepada <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Pemulihan gagal kerana sandaran telah gagal"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Gagal dipulihkan disebabkan oleh ralat sandaran"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Pemulihan gagal"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Tidak dapat mengalih keluar fail sandaran"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Gagal mengalih keluar data sandaran"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Alih keluar data sandaran"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Bersihkan <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Ralat yang Tidak dapat dipulihkan"</string>
- <string name="error_desc" msgid="1939028888570920661">"Gagal dipulihkan daripada ralat.\nAnda boleh cuba memulakan semula apl atau cuba salah satu pilihan pemulihan."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Alih keluar <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Ralat yang tidak dapat dipulihkan"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Gagal dipulihkan daripada ralat.\nAnda boleh cuba memulakan semula terminal atau cuba satu daripada pilihan pemulihan.\nJika semua percubaan gagal, hapuskan semua data dengan menghidupkan/mematikan terminal Linux daripada pilihan pembangun."</string>
<string name="error_code" msgid="3585291676855383649">"Kod ralat: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Tetapan"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal sedang dijalankan"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klik untuk membuka terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klik untuk membuka terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Tutup"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal ditutup"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Tutup paksa"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> didayakan"</string>
</resources>
diff --git a/android/TerminalApp/res/values-my/strings.xml b/android/TerminalApp/res/values-my/strings.xml
index d76b98d..dc3e555 100644
--- a/android/TerminalApp/res/values-my/strings.xml
+++ b/android/TerminalApp/res/values-my/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"တာမီနယ်"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"တာမီနယ် ပြကွက်"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"ကာဆာ"</string>
+ <string name="empty_line" msgid="5012067143408427178">"လိုင်းကို ရှင်းရန်"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"စာရိုက်ထည့်သွင်းရန် နှစ်ချက်တို့ပါ"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux တာမီနယ် ထည့်သွင်းခြင်း"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux တာမီနယ် စတင်ရန် ကွန်ရက်ပေါ်တွင် ဒေတာ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ခန့်ကို ဒေါင်းလုဒ်လုပ်ရမည်။\nရှေ့ဆက်လိုပါသလား။"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi ရသည့်အခါ ဒေါင်းလုဒ်လုပ်ရန်"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux တာမီနယ် စတင်ရန် ကွန်ရက်ပေါ်တွင် ဒေတာ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ခန့်ကို ဒေါင်းလုဒ်လုပ်ရမည်။\nရှေ့ဆက်လိုပါသလား။"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fi ဖြင့်သာ ဒေါင်းလုဒ်လုပ်ရန်"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ထည့်သွင်းရန်"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ထည့်သွင်းနေသည်"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ကွန်ရက် အမှားအယွင်း။ ချိတ်ဆက်မှုကို စစ်ဆေးပြီး ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ကွန်ရက် အမှားအယွင်းကြောင့် ထည့်သွင်း၍ မရလိုက်ပါ။ ချိတ်ဆက်မှုကို စစ်ဆေးပြီး ထပ်စမ်းကြည့်ပါ။"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux တာမီနယ်ကို ထည့်သွင်းနေသည်"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"ပြီးသွားပါက Linux တာမီနယ်ကို စတင်ပါမည်"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ကွန်ရက်ပြဿနာကြောင့် ထည့်သွင်း၍ မရလိုက်ပါ"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ထည့်သွင်း၍ မရလိုက်ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ထည့်သွင်းမှု ပြီးသည့်အခါ Linux တာမီနယ် စတင်မည်"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ကွန်ရက်ပြဿနာကြောင့် ထည့်သွင်း၍ မရလိုက်ပါ"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi မရနိုင်သောကြောင့် ထည့်သွင်း၍မရလိုက်ပါ"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ထည့်သွင်း၍ မရလိုက်ပါ။ ထပ်စမ်းကြည့်ပါ"</string>
<string name="action_settings" msgid="5729342767795123227">"ဆက်တင်များ"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"တာမီနယ်ကို ပြင်ဆင်နေသည်"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"တာမီနယ်ကို ရပ်နေသည်"</string>
<string name="vm_error_message" msgid="5231867246177661525">"တာမီနယ် ရပ်တန့်သွားသည်"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ဒစ်ခ်အရွယ်ပြင်ခြင်း"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"/ Rootfs အရွယ်ပြင်ရန်"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ဒစ်ခ်အရွယ်ပြင်ခြင်း"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ရုအကန့်အရွယ် ပြင်ရန်"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ဒစ်ခ်အရွယ်အစား သတ်မှတ်လိုက်သည်"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> သတ်မှတ်ထားသည်"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"အများဆုံး <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"မလုပ်တော့"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"သုံးရန် ပြန်စပါ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ပို့တ်ထပ်ဆင့်ပို့ခြင်း"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ပို့တ်ထပ်ဆင့်ပို့ခြင်းကို စီစဉ်သတ်မှတ်ပါ"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"တာမီနယ်က ပို့တ်အသစ်ကိုဖွင့်ရန် ကြိုးပမ်းနေသည်"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"ဖွင့်ရန်တောင်းဆိုထားသည့် ပို့တ်- <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"သုံးရန်"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ဒစ်ခ်ကို အရွယ်ပြင်ရန် တာမီနယ်ပြန်စပါမည်"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"အတည်ပြုရန်"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ပို့တ်ထိန်းချုပ်မှု"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"စောင့်နေသောပို့တ်များကို ခွင့်ပြုရန်/ငြင်းပယ်ရန်"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"စောင့်နေသောပို့တ်များ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ခွင့်ပြုထားသောပို့တ်များ သိမ်းပြီးပြီ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ထည့်ရန်"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ကို ဖျက်ရန်"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"ပို့တ်အသစ် ခွင့်ပြုခြင်း"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"ပို့တ်နံပါတ်အသစ် ထည့်ပါ"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"သိမ်းရန်"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"မလုပ်တော့"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"နံပါတ်တစ်ခု ရိုက်ထည့်ပါ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ပို့တ်နံပါတ် မမှန်ပါ"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ပို့တ်ရှိပြီးသားဖြစ်သည်"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"တာမီနယ်က ပို့တ်အသစ်ဖွင့်ရန် တောင်းဆိုနေသည်"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"တောင်းဆိုထားသော ပို့တ်- <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"လက်ခံရန်"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ငြင်းပယ်ရန်"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"ပြန်လည်ရယူခြင်း"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"အကန့်ပြန်ရယူရေး နည်းလမ်းများ"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ကနဦးဗားရှင်းသို့ ပြောင်းရန်"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"အားလုံး ဖယ်ရှားရန်"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"အကန့်ပြန်ရယူရေး နည်းလမ်းများ"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ကနဦးဗားရှင်းသို့ ပြင်ဆင်သတ်မှတ်ရန်"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ဒေတာအားလုံး ဖယ်ရှားရန်"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"တာမီနယ်ကို ပြင်ဆင်သတ်မှတ်ခြင်း"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ဒေတာကို ဖျက်ပါမည်"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"အတည်ပြုရန်"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ဒေတာကို ဖယ်ရှားပါမည်"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ပြန်သတ်မှတ်ရန်"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"မလုပ်တော့"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> တွင် ဒေတာအရန်သိမ်းရန်"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"အရန်သိမ်းခြင်း မအောင်မြင်သဖြင့် ပြန်လည်ရယူ၍ မရလိုက်ပါ"</string>
- <string name="settings_recovery_error" msgid="2451912941535666379">"ပြန်လည်ရယူ၍ မရလိုက်ပါ"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"မိတ္တူဖိုင်ကို ဖယ်ရှား၍မရပါ"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"အရန်သိမ်းခြင်းအမှားကြောင့် ပြန်လည်ရယူ၍ မရလိုက်ပါ"</string>
+ <string name="settings_recovery_error" msgid="2451912941535666379">"ပြန်လည်ရယူမှု မအောင်မြင်ပါ"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"အရန်ဒေတာကို ဖယ်ရှား၍ မရလိုက်ပါ"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"အရန်ဒေတာ ဖယ်ရှားခြင်း"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> ရှင်းထုတ်ဖယ်ရှားရန်"</string>
- <string name="error_title" msgid="7196464038692913778">"ပြန်ပြင်၍မရသော အမှား"</string>
- <string name="error_desc" msgid="1939028888570920661">"အမှားကို ပြန်ပြင်၍မရလိုက်ပါ။\nအက်ပ်ကို ပြန်စနိုင်သည် (သို့) ပြန်ရယူရေး နည်းလမ်းများထဲမှ တစ်ခုကို စမ်းကြည့်နိုင်သည်။"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> ကို ဖယ်ရှားရန်"</string>
+ <string name="error_title" msgid="405150657301906598">"ပြန်ပြင်၍မရသော အမှား"</string>
+ <string name="error_desc" msgid="4588252235686826721">"အမှားကို ပြန်ပြင်၍မရလိုက်ပါ။\nတာမီနယ်ကို ပြန်စနိုင်သည် (သို့) ပြန်ရယူရေး နည်းလမ်းများထဲမှ တစ်ခုကို စမ်းကြည့်နိုင်သည်။\nကြိုးပမ်းမှုအားလုံး အဆင်မပြေပါက ဆော့ဖ်ဝဲရေးသူအတွက် ရွေးစရာများမှနေ၍ Linux တာမီနယ်ကို ဖွင့်ခြင်း/ပိတ်ခြင်းဖြင့် ဒေတာအားလုံး ရှင်းလင်းပါ။"</string>
<string name="error_code" msgid="3585291676855383649">"အမှားကုဒ်- <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ဆက်တင်များ"</string>
<string name="service_notification_title" msgid="2918088850910713393">"တာမီနယ်ကို ဖွင့်ထားသည်"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"တာမီနယ်ဖွင့်ရန် နှိပ်ပါ"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"တာမီနယ်ဖွင့်ရန် နှိပ်ပါ"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"ပိတ်ရန်"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"တာမီနယ် ပိတ်နေသည်"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"မဖြစ်မနေပိတ်ရန်"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ဖွင့်ထားသည်"</string>
</resources>
diff --git a/android/TerminalApp/res/values-nb/strings.xml b/android/TerminalApp/res/values-nb/strings.xml
index d0adf2f..c0a84e5 100644
--- a/android/TerminalApp/res/values-nb/strings.xml
+++ b/android/TerminalApp/res/values-nb/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminalskjerm"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Markør"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Tom linje"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dobbelttrykk for å skrive inn tekst"</string>
<string name="installer_title_text" msgid="500663060973466805">"Installer Linux-terminalen"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"For å starte Linux-terminalen må du laste ned omtrent <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data via nettverket.\nVil du fortsette?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Last ned når wifi er tilgjengelig"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"For å starte Linux-terminalen må du laste ned omtrent <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data via nettverket.\nVil du fortsette?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Last ned bare via wifi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installer"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installerer"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Nettverksfeil. Sjekk tilkoblingen og prøv på nytt."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Kunne ikke installere på grunn av en nettverksfeil. Sjekk tilkoblingen, og prøv igjen."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installerer Linux-terminalen"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-terminalen startes når prosessen er ferdig"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Kunne ikke installere på grunn av et nettverksproblem"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Installasjonen mislyktes. Prøv på nytt."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux-terminalen startes når installasjonen er ferdig"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Kunne ikke installere på grunn av et nettverksproblem"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Kunne ikke installere fordi wifi ikke er tilgjengelig"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Installasjonen mislyktes. Prøv igjen"</string>
<string name="action_settings" msgid="5729342767795123227">"Innstillinger"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Forbereder terminalen"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stopper terminalen"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminalen krasjet"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Endre diskstørrelse"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Endre størrelse / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Endre diskstørrelse"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Endre størrelsen på rotpartisjonen"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Diskstørrelsen er angitt"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> er tildelt"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> maks"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Avbryt"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Omstart for å bruke"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Viderekobling av porter"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurer viderekobling av porter"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminalen prøver å åpne en ny port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Porten som er forespurt åpnet: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Bruk"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminalen starter på nytt for å endre størrelsen på disken"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Bekreft"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portkontroll"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Tillat/avslå lytteporter"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Lytteporter"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Lagrede tillatte porter"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Legg til"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Slett <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Tillat en ny port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Skriv inn et nytt portnummer"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Lagre"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Avbryt"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Legg inn et nummer"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ugyldig portnummer"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porten finnes allerede"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalen prøver å åpne en ny port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Ønsket port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Godta"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Avvis"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Gjenoppretting"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Gjenopprettingsalternativer for partisjoner"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Bytt til første versjon"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Fjern alle"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Gjenopprettingsalternativer for partisjoner"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Tilbakestill til den opprinnelige versjonen"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Fjern alle dataene"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Tilbakestill terminalen"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Dataene slettes"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Bekreft"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Dataene blir fjernet"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Tilbakestill"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Avbryt"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sikkerhetskopier data til <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Gjenopprettingen mislyktes fordi sikkerhetskopieringen mislyktes"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Kunne ikke gjenopprette på grunn av en sikkerhetskopieringsfeil"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Gjenopprettingen mislyktes"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Kan ikke fjerne sikkerhetskopifilen"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Kunne ikke fjerne sikkerhetskopierte data"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Fjern sikkerhetskopierte data"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Rydd opp <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Ugjenopprettelig feil"</string>
- <string name="error_desc" msgid="1939028888570920661">"Kunne ikke gjenopprette etter en feil.\nDu kan prøve å starte appen på nytt eller prøve et av gjenopprettingsalternativene."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Fjern <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Ugjenopprettelig feil"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Kunne ikke gjenopprette etter en feil.\nDu kan prøve å starte terminalen på nytt eller prøve et av gjenopprettingsalternativene.\nHvis alle forsøkene mislykkes, kan du slette alle dataene ved å slå på/av Linux-terminalen fra utvikleralternativene."</string>
<string name="error_code" msgid="3585291676855383649">"Feilkode: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Innstillinger"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminalen kjører"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klikk for å åpne terminalen"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klikk for å åpne terminalen"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Lukk"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminalen lukkes"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Tving avslutning"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> er aktivert"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ne/strings.xml b/android/TerminalApp/res/values-ne/strings.xml
index a7806a6..8cbda87 100644
--- a/android/TerminalApp/res/values-ne/strings.xml
+++ b/android/TerminalApp/res/values-ne/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"टर्मिनल"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"टर्मिनल डिस्प्ले"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"कर्सर"</string>
+ <string name="empty_line" msgid="5012067143408427178">"खाली लाइन"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"इनपुट टाइप गर्न डबल ट्याप गर्नुहोस्"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux टर्मिनल इन्स्टल गर्नुहोस्"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux टर्मिनल लन्च गर्नका निम्ति, तपाईंले नेटवर्क प्रयोग गरेर लगभग <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> जति डेटा डाउनलोड गर्नु पर्ने हुन्छ।\nतपाईं अघि बढ्नुहुन्छ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi उपलब्ध हुँदा डाउनलोड गर्नुहोस्"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux टर्मिनल सुरु गर्न तपाईंले नेटवर्क प्रयोग गरेर लगभग <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> जति डेटा डाउनलोड गर्नु पर्ने हुन्छ।\nतपाईं अघि बढ्नु चाहनुहुन्छ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fi मार्फत मात्र डाउनलोड गर्नुहोस्"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"इन्स्टल गर्नुहोस्"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"इन्स्टल गरिँदै छ"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"नेटवर्कसम्बन्धी त्रुटि। कनेक्सन जाँच गर्नुहोस् र फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"नेटवर्कसम्बन्धी त्रुटिका कारण इन्स्टल गर्न सकिएन। इन्टरनेट कनेक्सन जाँच्नुहोस् र फेरि प्रयास गर्नुहोस्।"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux टर्मिनल इन्स्टल गरिँदै छ"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"पूरा भइसकेपछि Linux टर्मिनल सुरु हुने छ"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"नेटवर्कसम्बन्धी समस्याका कारण इन्स्टल गर्न सकिएन"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"इन्स्टल गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"इन्स्टल गर्ने कार्य पूरा भएपछि Linux टर्मिनल सुरु हुने छ"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"नेटवर्कसम्बन्धी समस्याका कारण इन्स्टल गर्न सकिएन"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi उपलब्ध नभएकाले इन्स्टल गर्न सकिएन"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"इन्स्टल गर्न सकिएन। कृपया फेरि प्रयास गर्नुहोस्"</string>
<string name="action_settings" msgid="5729342767795123227">"सेटिङ"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"टर्मिनल तयार पारिँदै छ"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"टर्मिनल रोकिँदै छ"</string>
<string name="vm_error_message" msgid="5231867246177661525">"टर्मिनल क्र्यास भयो"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"डिस्कको आकार बदल्नुहोस्"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"आकार बदल्नुहोस् / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"डिस्कको आकार बदल्नुहोस्"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"मूल पार्टिसनको आकार बदल्नुहोस्"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"डिस्कको आकारको सेट गरियो"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"असाइन गरिएको: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"अधिकतम <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"रद्द गर्नुहोस्"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"परिवर्तन लागू गर्न रिस्टार्ट गर्नुहोस्"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"पोर्ट फर्वार्डिङ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"पोर्ट फर्वार्डिङ कन्फिगर गर्नुहोस्"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"टर्मिनलले एउटा नयाँ पोर्ट खोल्न खोजिरहेको छ"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"खोल्न अनुरोध गरिएको पोर्ट: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"लागू गर्नुहोस्"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"डिस्कको आकार बदल्न टर्मिनल रिस्टार्ट गरिने छ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"पुष्टि गर्नुहोस्"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"पोर्टसम्बन्धी कन्ट्रोल"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"लिसनिङ पोर्टहरू हाल्ने अनुमति दिनुहोस्/नदिनुहोस्"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"लिसनिङ पोर्टहरू"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"सेभ गरिएका अनुमति दिइएका पोर्टहरू"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"हाल्नुहोस्"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> मेटाउनुहोस्"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"नयाँ पोर्ट नम्बर हाल्ने अनुमति दिनुहोस्"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"नयाँ पोर्ट नम्बर हाल्नुहोस्"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"सेभ गर्नुहोस्"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"रद्द गर्नुहोस्"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"कृपया नम्बर हाल्नुहोस्"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"अवैध पोर्ट नम्बर"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"पोर्ट पहिल्यैदेखि छ"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"टर्मिनलले एउटा नयाँ पोर्ट खोल्न अनुरोध गरिरहेको छ"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"निम्न पोर्ट खोल्न अनुरोध गरिएको छ: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"स्वीकार गर्नुहोस्"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"अस्वीकार गर्नुहोस्"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"रिकभरी"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"पार्टिसन रिकभरीसम्बन्धी विकल्पहरू"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"यो संस्करण बदलेर सुरुको संस्करण बनाउनुहोस्"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"सबै हटाउनुहोस्"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"पार्टिसन रिकभर गर्ने विकल्पहरू"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"रिसेट गरी सुरुको संस्करण बनाउनुहोस्"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"सबै डेटा हटाउनुहोस्"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"टर्मिनल रिसेट गर्नुहोस्"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"डेटा मेटाइने छ"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"पुष्टि गर्नुहोस्"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"डेटा हटाइने छ"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"रिसेट गर्नुहोस्"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"रद्द गर्नुहोस्"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> मा डेटा ब्याकअप गर्नुहोस्"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ब्याकअप गर्न नसकिएकाले रिकभर गर्न सकिएन"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"ब्याकअपसम्बन्धी त्रुटिका कारण रिकभर गर्न सकिएन"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"रिकभर गर्न सकिएन"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"ब्याकअप फाइल हटाउन सकिएन"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ब्याकअप गरिएको डेटा हटाउन सकिएन"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ब्याकअप डेटा हटाउनुहोस्"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> हटाउनुहोस्"</string>
- <string name="error_title" msgid="7196464038692913778">"सच्याउन नमिल्ने त्रुटि"</string>
- <string name="error_desc" msgid="1939028888570920661">"कुनै त्रुटि सच्याउन सकिएन।\nतपाईं यो एप रिस्टार्ट गरी हेर्न वा त्रुटि सच्याउने यीमध्ये कुनै पनि एउटा तरिका अपनाई हेर्न सक्नुहुन्छ।"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> हटाउनुहोस्"</string>
+ <string name="error_title" msgid="405150657301906598">"रिकभर गर्न नदिने त्रुटि"</string>
+ <string name="error_desc" msgid="4588252235686826721">"कुनै त्रुटिका कारण रिकभर गर्न सकिएन।\nतपाईं टर्मिनल रिस्टार्ट गरी हेर्न वा रिकभर गर्ने विकल्पहरूमध्ये कुनै एउटा विकल्प अपनाई हेर्न सक्नुहुन्छ।\nसबै विकल्प अपनाउँदा पनि त्रुटि समाधान भएन भने विकासकर्ता मोडबाट Linux टर्मिनल अन/अफ गरी सबै डेटा मेटाउनुहोस्।"</string>
<string name="error_code" msgid="3585291676855383649">"त्रुटिको कोड: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"सेटिङ"</string>
<string name="service_notification_title" msgid="2918088850910713393">"टर्मिनल चलिरहेको छ"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"यो टर्मिनल खोल्न क्लिक गर्नुहोस्"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"टर्मिनल खोल्न क्लिक गर्नुहोस्"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"बन्द गर्नुहोस्"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"टर्मिनल एप बन्द हुँदै छ"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"बलपूर्वक बन्द गर्नुहोस्"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> अन गरिएको छ"</string>
</resources>
diff --git a/android/TerminalApp/res/values-nl/strings.xml b/android/TerminalApp/res/values-nl/strings.xml
index e012578..27fbc26 100644
--- a/android/TerminalApp/res/values-nl/strings.xml
+++ b/android/TerminalApp/res/values-nl/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"Terminalweergave"</string>
<string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
<string name="empty_line" msgid="5012067143408427178">"Lege regel"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dubbeltik om invoer te typen"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux-terminal installeren"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Als je Linux-terminal wilt starten, moet je ongeveer <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> aan data downloaden via het netwerk.\nWil je doorgaan?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Downloaden als wifi beschikbaar is"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Als je Linux-terminal wilt starten, moet je ongeveer <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> aan data downloaden via het netwerk.\nWil je doorgaan?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Alleen downloaden via wifi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installeren"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installeren"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Netwerkfout. Check de verbinding en probeer het opnieuw."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Kan niet installeren vanwege een netwerkfout. Check de verbinding en probeer het opnieuw."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux-terminal installeren"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-terminal wordt gestart na afronding"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Kan niet installeren vanwege het netwerkprobleem"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"Kan niet installeren omdat wifi niet beschikbaar is"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"Installatie mislukt. Probeer het opnieuw."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux-terminal wordt gestart nadat de installatie is afgerond"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Kan niet installeren vanwege een netwerkprobleem"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Kan niet installeren omdat wifi niet beschikbaar is"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Installatie mislukt. Probeer het opnieuw."</string>
<string name="action_settings" msgid="5729342767795123227">"Instellingen"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminal voorbereiden"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminal stoppen"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal gecrasht"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Formaat van schijf aanpassen"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Formaat aanpassen/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Formaat van schijf aanpassen"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"De grootte van de rootpartitie aanpassen"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Schijfgrootte ingesteld"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> toegewezen"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> max."</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Annuleren"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Opnieuw opstarten om toe te passen"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Poortdoorschakeling"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Poortdoorschakeling instellen"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal probeert een nieuwe poort te openen"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Poort die moet worden geopend: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Toepassen"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal wordt opnieuw opgestart om de schijfgrootte aan te passen"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Bevestigen"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Poortcontrole"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Luisterende poorten toestaan/weigeren"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Luisterende poorten"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Toegestane poorten opgeslagen"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Toevoegen"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> verwijderen"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Een nieuwe poort toestaan"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Voer een nieuw poortnummer in"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Opslaan"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Annuleren"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Voer een nummer in"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ongeldig poortnummer"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Poort bestaat al"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal verzoekt om een nieuwe poort te openen"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Poort aangevraagd: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepteren"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Weigeren"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Herstel"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Herstelopties voor partities"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Wijzigen naar eerste versie"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Alles verwijderen"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Herstelopties voor partities"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Resetten naar eerste versie"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Alle gegevens verwijderen"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminal resetten"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Gegevens worden verwijderd"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Bevestigen"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Gegevens worden verwijderd"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Resetten"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Annuleren"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Back-up van gegevens maken in <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Herstel is mislukt omdat de back-up is mislukt"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Herstel is mislukt vanwege een back-upfout"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Herstel is mislukt"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Kan back-upbestand niet verwijderen"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Kan back-upgegevens niet verwijderen"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Back-upgegevens verwijderen"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> opschonen"</string>
- <string name="error_title" msgid="7196464038692913778">"Onherstelbare fout"</string>
- <string name="error_desc" msgid="1939028888570920661">"Kan niet herstellen van een fout.\nJe kunt de app opnieuw opstarten of een van de herstelopties proberen."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> verwijderen"</string>
+ <string name="error_title" msgid="405150657301906598">"Onherstelbare fout"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Kan niet herstellen van een fout.\nJe kunt de terminal opnieuw opstarten of een van de herstelopties proberen.\nAls alle pogingen mislukken, wis je alle gegevens door de Linux-terminal aan/uit te zetten via de ontwikkelaarsopties."</string>
<string name="error_code" msgid="3585291676855383649">"Foutcode: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Instellingen"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal wordt uitgevoerd"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klik om de terminal te openen"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klik om terminal te openen"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Sluiten"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal wordt gesloten"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Geforceerd sluiten"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> staat aan"</string>
</resources>
diff --git a/android/TerminalApp/res/values-or/strings.xml b/android/TerminalApp/res/values-or/strings.xml
index 2324313..034849f 100644
--- a/android/TerminalApp/res/values-or/strings.xml
+++ b/android/TerminalApp/res/values-or/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ଟର୍ମିନାଲ"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ଟର୍ମିନାଲ ଡିସପ୍ଲେ"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"କର୍ସର"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ଖାଲି ଲାଇନ"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ଇନପୁଟ ଟାଇପ କରିବାକୁ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ଟର୍ମିନାଲକୁ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ଟର୍ମିନାଲ ଲଞ୍ଚ କରିବାକୁ ଆପଣଙ୍କୁ ନେଟୱାର୍କ ମାଧ୍ୟମରେ ପ୍ରାୟ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g>ର ଡାଟା ଡାଉନଲୋଡ କରିବାକୁ ହେବ।\nଆପଣ ଆଗକୁ ବଢ଼ିବେ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ହେଲେ ଡାଉନଲୋଡ କରନ୍ତୁ"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ଟର୍ମିନାଲ ଲଞ୍ଚ କରିବାକୁ ଆପଣଙ୍କୁ ନେଟୱାର୍କ ମାଧ୍ୟମରେ ପ୍ରାୟ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g>ର ଡାଟା ଡାଉନଲୋଡ କରିବାକୁ ହେବ।\nଆପଣ ଆଗକୁ ବଢ଼ିବା ପାଇଁ ଚାହିଁବେ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"କେବଳ ୱାଇ-ଫାଇ ବ୍ୟବହାର କରି ଡାଉନଲୋଡ କରନ୍ତୁ"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ଇନଷ୍ଟଲ କରାଯାଉଛି"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ନେଟୱାର୍କ ତ୍ରୁଟି। କନେକ୍ସନ ଯାଞ୍ଚ କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ଏକ ନେଟୱାର୍କ ତ୍ରୁଟି ଯୋଗୁଁ ଇନଷ୍ଟଲ କରିବାରେ ବିଫଳ ହୋଇଛି। ଆପଣଙ୍କ କନେକ୍ସନ ଯାଞ୍ଚ କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ଟର୍ମିନାଲକୁ ଇନଷ୍ଟଲ କରାଯାଉଛି"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"ପ୍ରକ୍ରିୟା ସମ୍ପୂର୍ଣ୍ଣ ହେବା ପରେ Linux ଟର୍ମିନାଲ ଆରମ୍ଭ ହେବ"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ନେଟୱାର୍କ ସମସ୍ୟା ଯୋଗୁଁ ଇନଷ୍ଟଲ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ଇନଷ୍ଟଲ କରିବାରେ ବିଫଳ ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ଇନଷ୍ଟଲେସନ ସମ୍ପୂର୍ଣ୍ଣ ହେବା ପରେ Linux ଟର୍ମିନାଲ ଷ୍ଟାର୍ଟ ହେବ"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ଏକ ନେଟୱାର୍କ ସମସ୍ୟା ଯୋଗୁଁ ଇନଷ୍ଟଲ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନଥିବା ଯୋଗୁଁ ଇନଷ୍ଟଲ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ଇନଷ୍ଟଲ କରିବାରେ ବିଫଳ ହୋଇଛି। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
<string name="action_settings" msgid="5729342767795123227">"ସେଟିଂସ"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ଟର୍ମିନାଲକୁ ପ୍ରସ୍ତୁତ କରାଯାଉଛି"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminalକୁ ବନ୍ଦ କରାଯାଉଛି"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ଟର୍ମିନାଲ କ୍ରାସ ହୋଇଛି"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ଡିସ୍କ ରିସାଇଜ କରନ୍ତୁ"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ରିସାଇଜ କରନ୍ତୁ / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ଡିସ୍କକୁ ରିସାଇଜ କରନ୍ତୁ"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ରୁଟ ପାର୍ଟିସନ ସାଇଜକୁ ରିସାଇଜ କରନ୍ତୁ"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ଡିସ୍କ ସାଇଜ ସେଟ ହୋଇଛି"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ଆସାଇନ କରାଯାଇଛି"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"ସର୍ବାଧିକ <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ବାତିଲ କରନ୍ତୁ"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"ଲାଗୁ ପାଇଁ ରିଷ୍ଟାର୍ଟ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ପୋର୍ଟ ଫରୱାର୍ଡିଂ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ପୋର୍ଟ ଫରୱାର୍ଡିଂକୁ କନଫିଗର କରନ୍ତୁ"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ଏକ ନୂଆ ପୋର୍ଟ ଖୋଲିବାକୁ ଟର୍ମିନାଲ ଅନୁରୋଧ କରୁଛି"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"ଏହି ପୋର୍ଟକୁ ଖୋଲା ରଖିବା ପାଇଁ ଅନୁରୋଧ କରାଯାଇଛି: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ଲାଗୁ କରନ୍ତୁ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ଡିସ୍କକୁ ରିସାଇଜ କରିବାକୁ ଟର୍ମିନାଲ ରିଷ୍ଟାର୍ଟ ହେବ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ପୋର୍ଟ ନିୟନ୍ତ୍ରଣ"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ଶୁଣିବା ପୋର୍ଟଗୁଡ଼ିକୁ ଅନୁମତି ଦିଅନ୍ତୁ/ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ଶୁଣିବା ପୋର୍ଟ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ଅନୁମତି ଦିଆଯାଇଥିବା ପୋର୍ଟଗୁଡ଼ିକୁ ସେଭ କରାଯାଇଛି"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>କୁ ଡିଲିଟ କରନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"ଏକ ନୂଆ ପୋର୍ଟକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"ଏକ ନୂଆ ପୋର୍ଟ ନମ୍ବର ଲେଖନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"ସେଭ କରନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ବାତିଲ କରନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"ଦୟାକରି ଗୋଟିଏ ନମ୍ବର ଲେଖନ୍ତୁ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ଅବୈଧ ପୋର୍ଟ ନମ୍ବର"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ପୋର୍ଟ ପୂର୍ବରୁ ଉପଲବ୍ଧ ଅଛି"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ଏକ ନୂଆ ପୋର୍ଟ ଖୋଲିବାକୁ ଟର୍ମିନାଲ ଅନୁରୋଧ କରୁଛି"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"ପୋର୍ଟ ପାଇଁ ଅନୁରୋଧ କରାଯାଇଛି: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ଗ୍ରହଣ କରନ୍ତୁ"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"ରିକଭରି"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"ପାର୍ଟିସନ ରିକଭରି ବିକଳ୍ପ"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ପ୍ରାରମ୍ଭିକ ଭର୍ସନକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"ସବୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"ପାର୍ଟିସନ ରିକଭରି ବିକଳ୍ପ"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ପ୍ରାରମ୍ଭିକ ଭର୍ସନରେ ରିସେଟ କରନ୍ତୁ"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ସମସ୍ତ ଡାଟାକୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ଟର୍ମିନାଲ ରିସେଟ କରନ୍ତୁ"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ଡାଟାକୁ ଡିଲିଟ କରାଯିବ"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ଡାଟାକୁ କାଢ଼ି ଦିଆଯିବ"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ରିସେଟ କରନ୍ତୁ"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ବାତିଲ କରନ୍ତୁ"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g>ରେ ଡାଟାର ବେକଅପ ନିଅନ୍ତୁ"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ବେକଅପ ବିଫଳ ହୋଇଥିବା ଯୋଗୁଁ ରିକଭରି ବିଫଳ ହୋଇଛି"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"ଏକ ବେକଅପ ତ୍ରୁଟି ଯୋଗୁଁ ରିକଭର କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"ରିକଭରି ବିଫଳ ହୋଇଛି"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"ବେକଅପ ଫାଇଲକୁ କାଢ଼ି ଦିଆଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ବେକଅପ ଡାଟାକୁ କାଢ଼ି ଦେବାରେ ବିଫଳ ହୋଇଛି"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ବେକଅପ ଡାଟାକୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> ଖାଲି କରନ୍ତୁ"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g>କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
+ <string name="error_title" msgid="405150657301906598">"ରିକଭର କରିହେଉନଥିବା ତ୍ରୁଟି"</string>
+ <string name="error_desc" msgid="4588252235686826721">"ଏକ ତ୍ରୁଟିରୁ ରିକଭର କରିବାରେ ବିଫଳ ହୋଇଛି।\nଆପଣ ଟର୍ମିନାଲ ରିଷ୍ଟାର୍ଟ କରିବାକୁ ଚେଷ୍ଟା କରିପାରିବେ କିମ୍ବା ରିକଭରି ବିକଳ୍ପଗୁଡ଼ିକ ମଧ୍ୟରୁ ଗୋଟିଏ ବିକଳ୍ପ ଚେଷ୍ଟା କରିପାରିବେ।\nଯଦି ସମସ୍ତ ପ୍ରଚେଷ୍ଟା ବିଫଳ ହୁଏ, ତେବେ ଡେଭେଲପର ବିକଳ୍ପରୁ Linux ଟର୍ମିନାଲକୁ ଚାଲୁ/ବନ୍ଦ କରି ସମସ୍ତ ଡାଟା ୱାଇପ କରନ୍ତୁ।"</string>
+ <string name="error_code" msgid="3585291676855383649">"ତ୍ରୁଟି କୋଡ: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ସେଟିଂସ"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ଟର୍ମିନାଲ ଚାଲୁ ଅଛି"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ଟର୍ମିନାଲ ଖୋଲିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ଟର୍ମିନାଲ ଖୋଲିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"ବନ୍ଦ କରନ୍ତୁ"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ଟର୍ମିନାଲ ବନ୍ଦ ହେବାକୁ ଯାଉଛି"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"ଫୋର୍ସ କ୍ଲୋଜ କରନ୍ତୁ"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g>କୁ ସକ୍ଷମ କରାଯାଇଛି"</string>
</resources>
diff --git a/android/TerminalApp/res/values-pa/strings.xml b/android/TerminalApp/res/values-pa/strings.xml
index 9d895cc..b6af472 100644
--- a/android/TerminalApp/res/values-pa/strings.xml
+++ b/android/TerminalApp/res/values-pa/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ਟਰਮੀਨਲ"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ਟਰਮੀਨਲ ਡਿਸਪਲੇ"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"ਕਰਸਰ"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ਖਾਲੀ ਲਾਈਨ"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ਇਨਪੁੱਟ ਟਾਈਪ ਕਰਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ਟਰਮੀਨਲ ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ਟਰਮੀਨਲ ਐਪ ਨੂੰ ਲਾਂਚ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਨੈੱਟਵਰਕ \'ਤੇ ਲਗਭਗ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ਡਾਟਾ ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।\nਕੀ ਅੱਗੇ ਵਧਣਾ ਹੈ?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ਵਾਈ-ਫਾਈ ਦੇ ਉਪਲਬਧ ਹੋਣ \'ਤੇ ਡਾਊਨਲੋਡ ਕਰੋ"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ਟਰਮੀਨਲ ਐਪ ਨੂੰ ਲਾਂਚ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਨੈੱਟਵਰਕ \'ਤੇ ਲਗਭਗ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ਡਾਟਾ ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।\nਕੀ ਤੁਸੀਂ ਅੱਗੇ ਵਧਣਾ ਚਾਹੋਗੇ?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"ਸਿਰਫ਼ ਵਾਈ-ਫਾਈ ਦੀ ਵਰਤੋਂ ਨਾਲ ਡਾਊਨਲੋਡ ਕਰੋ"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ਸਥਾਪਤ ਕਰੋ"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ਸਥਾਪਤ ਹੋ ਰਹੀ ਹੈ"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ਨੈੱਟਵਰਕ ਗੜਬੜ। ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰ ਕੇ ਮੁੜ-ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ਨੈੱਟਵਰਕ ਗੜਬੜ ਕਰਕੇ ਸਥਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ। ਆਪਣੇ ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ਟਰਮੀਨਲ ਐਪ ਸਥਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"ਪ੍ਰਕਿਰਿਆ ਪੂਰੀ ਹੋਣ ਤੋਂ ਬਾਅਦ, Linux ਟਰਮੀਨਲ ਐਪ ਸ਼ੁਰੂ ਹੋ ਜਾਵੇਗੀ"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ਨੈੱਟਵਰਕ ਸੰਬੰਧੀ ਸਮੱਸਿਆ ਕਾਰਨ ਸਥਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ਸਥਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ਸਥਾਪਤ ਕਰਨ ਦੀ ਪ੍ਰਕਿਰਿਆ ਸਮਾਪਤ ਹੋਣ ਤੋਂ ਬਾਅਦ, Linux ਟਰਮੀਨਲ ਸ਼ੁਰੂ ਹੋ ਜਾਵੇਗਾ"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ਨੈੱਟਵਰਕ ਸੰਬੰਧੀ ਸਮੱਸਿਆ ਕਰਕੇ ਸਥਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਾ ਹੋਣ ਕਰਕੇ ਸਥਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ਸਥਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="action_settings" msgid="5729342767795123227">"ਸੈਟਿੰਗਾਂ"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ਟਰਮੀਨਲ ਨੂੰ ਤਿਆਰ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ਟਰਮੀਨਲ ਨੂੰ ਬੰਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ਟਰਮੀਨਲ ਕ੍ਰੈਸ਼ ਹੋ ਗਿਆ"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ਡਿਸਕ ਦਾ ਆਕਾਰ ਬਦਲੋ"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ਆਕਾਰ ਬਦਲੋ / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ਡਿਸਕ ਦਾ ਆਕਾਰ ਬਦਲੋ"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ਰੂਟ ਪਾਰਟੀਸ਼ਨ ਦਾ ਆਕਾਰ ਬਦਲੋ"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ਡਿਸਕ ਸਾਈਜ਼ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ਜ਼ਿੰਮੇ ਲਗਾਇਆ ਗਿਆ"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"ਵੱਧੋ-ਵੱਧ <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ਰੱਦ ਕਰੋ"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"ਲਾਗੂ ਕਰਨ ਲਈ ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"ਪੋਰਟ ਫਾਰਵਰਡਿੰਗ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"ਪੋਰਟ ਫਾਰਵਰਡਿੰਗ ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ਟਰਮੀਨਲ ਇੱਕ ਨਵੇਂ ਪੋਰਟ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਿਹਾ ਹੈ"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"ਪੋਰਟ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਗਈ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ਲਾਗੂ ਕਰੋ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ਡਿਸਕ ਦਾ ਆਕਾਰ ਬਦਲਣ ਲਈ ਟਰਮੀਨਲ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"ਤਸਦੀਕ ਕਰੋ"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ਪੋਰਟ ਕੰਟਰੋਲ"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ਲਿਸਨਿੰਗ ਪੋਰਟਾਂ ਨੂੰ ਆਗਿਆ ਦਿਓ/ਅਸਵੀਕਾਰ ਕਰੋ"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ਲਿਸਨਿੰਗ ਪੋਰਟ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ਮਨਜ਼ੂਰਸ਼ੁਦਾ ਪੋਰਟ ਰੱਖਿਅਤ ਕੀਤੇ ਗਏ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ਨੂੰ ਮਿਟਾਓ"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"ਨਵੇਂ ਪੋਰਟ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"ਇੱਕ ਨਵਾਂ ਪੋਰਟ ਨੰਬਰ ਦਾਖਲ ਕਰੋ"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"ਰੱਖਿਅਤ ਕਰੋ"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ਰੱਦ ਕਰੋ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"ਕਿਰਪਾ ਕਰਕੇ ਕੋਈ ਨੰਬਰ ਦਾਖਲ ਕਰੋ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ਅਵੈਧ ਪੋਰਟ ਨੰਬਰ"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ਪੋਰਟ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ਟਰਮੀਨਲ ਇੱਕ ਨਵੇਂ ਪੋਰਟ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਬੇਨਤੀ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"ਪੋਰਟ ਸੰਬੰਧੀ ਬੇਨਤੀ ਕੀਤੀ ਗਈ: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"ਰਿਕਵਰੀ"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"ਪਾਰਟੀਸ਼ਨ ਰਿਕਵਰੀ ਦੇ ਵਿਕਲਪ"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ਸ਼ੁਰੂਆਤੀ ਵਰਜਨ \'ਤੇ ਬਦਲੋ"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"ਸਭ ਹਟਾਓ"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"ਪਾਰਟੀਸ਼ਨ ਰਿਕਵਰੀ ਦੇ ਵਿਕਲਪ"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ਸ਼ੁਰੂਆਤੀ ਵਰਜਨ \'ਤੇ ਰੀਸੈੱਟ ਕਰੋ"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"ਸਾਰਾ ਡਾਟਾ ਹਟਾਓ"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ਟਰਮੀਨਲ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"ਤਸਦੀਕ ਕਰੋ"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ਡਾਟਾ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ਰੀਸੈੱਟ ਕਰੋ"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ਰੱਦ ਕਰੋ"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> \'ਤੇ ਡਾਟੇ ਦਾ ਬੈਕਅੱਪ ਲਓ"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"ਮੁੜ-ਹਾਸਲ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ, ਕਿਉਂਕਿ ਬੈਕਅੱਪ ਅਸਫਲ ਰਿਹਾ"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"ਬੈਕਅੱਪ ਸੰਬੰਧੀ ਗੜਬੜ ਕਰਕੇ ਮੁੜ-ਹਾਸਲ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"ਮੁੜ-ਹਾਸਲ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"ਬੈਕਅੱਪ ਫ਼ਾਈਲ ਹਟਾਈ ਨਹੀਂ ਜਾ ਸਕਦੀ"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"ਬੈਕਅੱਪ ਡਾਟਾ ਹਟਾਉਣਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"ਬੈਕਅੱਪ ਡਾਟਾ ਹਟਾਓ"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> ਨੂੰ ਕਲੀਨ ਅੱਪ ਕਰੋ"</string>
- <string name="error_title" msgid="7196464038692913778">"ਮੁੜ-ਹਾਸਲ ਨਾ ਹੋਣਯੋਗ ਡਾਟੇ ਸੰਬੰਧੀ ਗੜਬੜ"</string>
- <string name="error_desc" msgid="1939028888570920661">"ਗੜਬੜ ਨੂੰ ਠੀਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।\nਤੁਸੀਂ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਸਕਦੇ ਹੋ ਜਾਂ ਰਿਕਵਰੀ ਦੇ ਵਿਕਲਪ ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਨੂੰ ਅਜ਼ਮਾ ਕੇ ਦੇਖ ਸਕਦੇ ਹੋ।"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> ਨੂੰ ਹਟਾਓ"</string>
+ <string name="error_title" msgid="405150657301906598">"ਮੁੜ-ਹਾਸਲ ਨਾ ਹੋਣਯੋਗ ਡਾਟੇ ਸੰਬੰਧੀ ਗੜਬੜ"</string>
+ <string name="error_desc" msgid="4588252235686826721">"ਗੜਬੜ ਨੂੰ ਠੀਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।\nਤੁਸੀਂ ਟਰਮੀਨਲ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਸਕਦੇ ਹੋ ਜਾਂ ਰਿਕਵਰੀ ਦੇ ਵਿਕਲਪਾਂ ਵਿੱਚੋਂ ਕਿਸੇ ਇੱਕ ਨੂੰ ਅਜ਼ਮਾ ਕੇ ਦੇਖ ਸਕਦੇ ਹੋ।\nਜੇ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ ਅਸਫਲ ਹੋ ਜਾਂਦੀਆਂ ਹਨ, ਤਾਂ ਵਿਕਾਸਕਾਰ ਵਿਕਲਪਾਂ ਤੋਂ Linux ਟਰਮੀਨਲ ਨੂੰ ਚਾਲੂ/ਬੰਦ ਕਰ ਕੇ ਸਾਰਾ ਡਾਟਾ ਸਾਫ਼ ਕਰੋ।"</string>
<string name="error_code" msgid="3585291676855383649">"ਗੜਬੜ ਕੋਡ: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ਸੈਟਿੰਗਾਂ"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ਟਰਮੀਨਲ ਚਾਲੂ ਹੈ"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ਟਰਮੀਨਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਕਲਿੱਕ ਕਰੋ"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ਟਰਮੀਨਲ ਖੋਲ੍ਹਣ ਲਈ ਕਲਿੱਕ ਕਰੋ"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"ਬੰਦ ਕਰੋ"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ਟਰਮੀਨਲ ਬੰਦ ਹੋ ਰਿਹਾ ਹੈ"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"ਜ਼ਬਰਦਸਤੀ ਬੰਦ ਕਰੋ"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ਚਾਲੂ ਹੈ"</string>
</resources>
diff --git a/android/TerminalApp/res/values-pl/strings.xml b/android/TerminalApp/res/values-pl/strings.xml
index 2124dac..92a6dea 100644
--- a/android/TerminalApp/res/values-pl/strings.xml
+++ b/android/TerminalApp/res/values-pl/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Ekran terminala"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Pusty wiersz"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Kliknij dwukrotnie, aby wpisać"</string>
<string name="installer_title_text" msgid="500663060973466805">"Zainstaluj terminal Linuxa"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Aby uruchomić terminal Linuxa, musisz pobrać przez sieć około <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> danych.\nChcesz kontynuować?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Pobierz, gdy będzie dostępna sieć Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Aby uruchomić terminal Linuxa, musisz pobrać przez sieć około <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> danych.\nChcesz kontynuować?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Pobieraj tylko przez Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Zainstaluj"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instaluję"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Błąd sieci. Sprawdź połączenie i spróbuj ponownie."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Nie udało się zainstalować z powodu błędu sieci. Sprawdź połączenie i spróbuj jeszcze raz."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instaluję terminal Linuxa"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Po zakończeniu zostanie uruchomiony terminal Linuxa"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Nie udało się zainstalować z powodu problemu z siecią"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Nie udało się zainstalować. Spróbuj ponownie."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Po zakończeniu instalacji uruchomi się terminal Linuxa"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Nie udało się zainstalować z powodu problemu z siecią"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Nie udało się zainstalować, ponieważ Wi-Fi jest niedostępne"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Nie udało się zainstalować. Spróbuj jeszcze raz"</string>
<string name="action_settings" msgid="5729342767795123227">"Ustawienia"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Przygotowuję terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Zatrzymuję terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal uległ awarii"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Zmień rozmiar dysku"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Zmień rozmiar / rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Zmiana rozmiaru dysku"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Zmień rozmiar partycji poziomu głównego"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Rozmiar dysku został ustawiony"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Przypisano <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maksymalny rozmiar <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Anuluj"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Uruchom ponownie"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Przekierowanie portów"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Skonfiguruj przekierowanie portów"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal próbuje otworzyć nowy port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port, który ma być otwarty: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Zastosuj"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Aby zmienić rozmiar dysku, terminal zostanie uruchomiony ponownie"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Potwierdź"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrola portów"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Zezwalaj/odrzucaj porty nasłuchujące"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porty nasłuchujące"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Zapisane dozwolone porty"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Usuń port <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Zezwól na nowy port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Wpisz nowy numer portu"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Zapisz"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Anuluj"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Podaj numer"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nieprawidłowy numer portu"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port już istnieje"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal wysłał żądanie otwarcia nowego portu"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Żądany port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Zaakceptuj"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odrzuć"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Odzyskiwanie"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opcje odzyskiwania partycji"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Zmień na wersję początkową"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Usuń wszystko"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opcje odzyskiwania partycji"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Przywróć wersję początkową"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Usuń wszystkie dane"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Zresetuj terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Dane zostaną usunięte"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Potwierdź"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Dane zostaną usunięte"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Resetuj"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Anuluj"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Utwórz kopię zapasową w lokalizacji <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Nie udało się przywrócić danych z powodu błędu kopii zapasowej"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Nie udało się przywrócić z powodu błędu kopii zapasowej"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Nie udało się przywrócić"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Nie udało się usunąć pliku kopii zapasowej"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Nie udało się usunąć danych kopii zapasowej"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Usuń dane kopii zapasowej"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Zwolnij miejsce w lokalizacji <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Nieodwracalny błąd"</string>
- <string name="error_desc" msgid="1939028888570920661">"Nie udało się przywrócić aplikacji po błędzie.\nMożesz spróbować ponownie ją uruchomić lub skorzystać z jednej z opcji odzyskiwania."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Usuń: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Nieodwracalny błąd"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Nie udało się przywrócić aplikacji po błędzie.\nMożesz spróbować ponownie uruchomić terminal lub skorzystać z jednej z opcji odzyskiwania.\nJeśli wszystkie próby zawiodą, wyczyść dane, włączając/wyłączając terminal Linuxa w opcjach dla programistów."</string>
<string name="error_code" msgid="3585291676855383649">"Kod błędu: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Ustawienia"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal jest uruchomiony"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliknij, aby otworzyć terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliknij, aby otworzyć terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Zamknij"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal się zamyka"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Wymuś zamknięcie"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Układ <xliff:g id="ID_1">VirGL</xliff:g> jest włączony"</string>
</resources>
diff --git a/android/TerminalApp/res/values-pt-rPT/strings.xml b/android/TerminalApp/res/values-pt-rPT/strings.xml
index a221586..337e355 100644
--- a/android/TerminalApp/res/values-pt-rPT/strings.xml
+++ b/android/TerminalApp/res/values-pt-rPT/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Ecrã do terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Linha vazia"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Toque duas vezes para introduzir o texto"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instale o terminal do Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Para iniciar o terminal do Linux, tem de transferir cerca de <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de dados através da rede.\nQuer continuar?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Transferir quando estiver disponível uma rede Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Para iniciar o terminal do Linux, tem de transferir cerca de <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de dados através da rede.\nQuer continuar?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Transferir apenas através de Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalar"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"A instalar…"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Erro de rede. Verifique a ligação e tente novamente."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Falha ao instalar devido a um erro de rede. Verifique a ligação e tente novamente."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"A instalar o terminal do Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"O terminal do Linux vai ser iniciado após a conclusão"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Falha ao instalar devido a um problema de rede"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Falha ao instalar. Tente novamente."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"O terminal do Linux vai ser iniciado após a conclusão da instalação"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Falha ao instalar devido a um problema de rede"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Falha ao instalar porque o Wi-Fi não está disponível"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Falha ao instalar. Tente novamente"</string>
<string name="action_settings" msgid="5729342767795123227">"Definições"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"A preparar o terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"A parar o terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"O terminal falhou"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Redimensionamento do disco"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Redimensionamento/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Redimensionamento do disco"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Redimensione o tamanho da partição de raiz"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Tamanho do disco definido"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Tamanho atribuído: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Tamanho máx.: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancelar"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Reiniciar p/ aplicar"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Encaminhamento de portas"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configure o encaminhamento de portas"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"O terminal está a tentar abrir uma nova porta"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Porta com pedido de abertura: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplicar"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"O terminal vai ser reiniciado para redimensionar o disco"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmar"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controlo de portas"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir/negar portas de audição"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portas de audição"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Portas permitidas guardadas"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Adicionar"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eliminar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Permitir uma nova porta"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Introduza um novo número de porta"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Guardar"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancelar"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Introduza um número"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Número de porta inválido"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"A porta já existe"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"O terminal está a pedir para abrir uma nova porta"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Porta pedida: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceitar"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Recusar"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recuperação"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opções de recuperação de partições"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Altere para a versão inicial"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Remova tudo"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opções de recuperação de partições"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Reponha para a versão inicial"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Remova todos os dados"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Reponha o terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Os dados vão ser eliminados"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmar"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Os dados vão ser removidos"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Repor"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancelar"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Fazer uma cópia de segurança dos dados para <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"A recuperação falhou porque ocorreu uma falha na cópia de segurança"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Falha ao recuperar devido a um erro de cópia de segurança"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Falha na recuperação"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Não é possível remover o ficheiro da cópia de segurança"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Falha ao remover os dados da cópia de segurança"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Remova os dados da cópia de segurança"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Limpe <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Erro irrecuperável"</string>
- <string name="error_desc" msgid="1939028888570920661">"Falha ao recuperar de um erro.\nPode tentar reiniciar a app ou experimentar uma das opções de recuperação."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Remova <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Erro irrecuperável"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Falha ao recuperar de um erro.\nPode tentar reiniciar o terminal ou experimentar uma das opções de recuperação.\nSe todas as tentativas falharem, limpe todos os dados ativando/desativando o terminal do Linux nas opções de programador."</string>
<string name="error_code" msgid="3585291676855383649">"Código de erro: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Definições"</string>
<string name="service_notification_title" msgid="2918088850910713393">"O terminal está em execução"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Clique para abrir o terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Clique para abrir o terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Fechar"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"A app Terminal está a ser fechada"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forçar fecho"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"A <xliff:g id="ID_1">VirGL</xliff:g> está ativada"</string>
</resources>
diff --git a/android/TerminalApp/res/values-pt/strings.xml b/android/TerminalApp/res/values-pt/strings.xml
index 52523a7..b223c9f 100644
--- a/android/TerminalApp/res/values-pt/strings.xml
+++ b/android/TerminalApp/res/values-pt/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Tela do terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Linha vazia"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Toque duas vezes para digitar"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalar terminal Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Para iniciar o terminal Linux, é necessário baixar cerca de <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de dados pela rede.\nVocê quer continuar?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Baixar quando o Wi-Fi estiver disponível"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Para iniciar o terminal Linux, é necessário baixar cerca de <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de dados pela rede.\nQuer continuar?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Baixar somente com Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalar"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Instalando"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Erro de rede. Verifique a conexão e tente de novo."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Falha ao instalar devido a um erro de rede. Verifique sua conexão e tente de novo."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Instalando terminal Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"O terminal Linux será iniciado após a instalação"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Falha ao instalar devido a um problema de rede"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Falha ao instalar. Tente de novo."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"O terminal Linux será iniciado após a instalação"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Falha ao instalar devido a um problema de rede"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Falha ao instalar porque o Wi-Fi não está disponível"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Falha ao instalar. Tente de novo"</string>
<string name="action_settings" msgid="5729342767795123227">"Configurações"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Preparando o terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Interrompendo o terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"O terminal falhou"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Redimensionamento de disco"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Redimensionar / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Redimensionamento de disco"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Redimensionar o tamanho da partição raiz"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Tamanho do disco definido"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Atribuído: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Máximo: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Cancelar"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Reiniciar para aplicar"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Encaminhamento de portas"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configurar o encaminhamento de portas"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"O terminal está tentando abrir uma nova porta"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Porta a ser aberta: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplicar"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"O terminal será reiniciado para redimensionar o disco"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmar"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controle de portas"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir/negar portas de detecção"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portas de detecção"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"As portas permitidas foram salvas"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Adicionar"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Excluir <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Permitir uma nova porta"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Digite o número de uma nova porta"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Salvar"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Cancelar"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Insira um número"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Número de porta inválido"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"A porta já existe"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"O terminal está pedindo para abrir uma nova porta"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Porta solicitada: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceitar"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Negar"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recuperação"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opções de recuperação da partição"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Mudar para a versão inicial"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Remover tudo"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opções de recuperação da partição"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Redefinir para a versão inicial"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Remover todos os dados"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Redefinir terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Os dados serão excluídos"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmar"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Os dados serão removidos"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Redefinir"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Cancelar"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Fazer backup dos dados em <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"A recuperação falhou porque o backup falhou"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Falha ao recuperar devido a um erro de backup"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Falha na recuperação"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Não é possível remover o arquivo de backup"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Falha ao remover os dados de backup"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Remover dados de backup"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Limpar <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Remover <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Erro irrecuperável"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Falha ao recuperar o terminal de um erro.\nTente reiniciar o terminal ou usar uma das opções de recuperação.\nSe todas as tentativas falharem, exclua permanentemente os dados ativando/desativando o terminal Linux nas Opções do desenvolvedor."</string>
+ <string name="error_code" msgid="3585291676855383649">"Código do erro: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Configurações"</string>
<string name="service_notification_title" msgid="2918088850910713393">"O terminal está em execução"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Clique para abrir o terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Clique para abrir o terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Fechar"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"O terminal está fechando"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forçar fechamento"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"O <xliff:g id="ID_1">VirGL</xliff:g> está ativado"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ro/strings.xml b/android/TerminalApp/res/values-ro/strings.xml
index 1d015a8..9cfa4bc 100644
--- a/android/TerminalApp/res/values-ro/strings.xml
+++ b/android/TerminalApp/res/values-ro/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Afișaj terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Linie goală"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Atinge de două ori pentru a introduce text"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalează terminalul Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Pentru a lansa terminalul Linux, trebuie să descarci aproximativ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de date prin rețea.\nVrei să continui?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Descarcă atunci când este disponibilă o conexiune Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Pentru a lansa terminalul Linux, trebuie să descarci aproximativ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> de date prin rețea.\nVrei să continui?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Descarcă numai prin Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalează"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Se instalează"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Eroare de rețea. Verifică-ți conexiunea și încearcă din nou."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Nu s-a putut instala din cauza unei erori de rețea. Verifică-ți conexiunea și încearcă din nou."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Se instalează terminalul Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Terminalul Linux va porni după încheiere"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Nu s-a putut instala din cauza unei probleme de rețea"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Nu s-a instalat. Încearcă din nou."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Terminalul Linux va porni după finalizarea instalării"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Nu s-a putut instala din cauza unei probleme legate de rețea"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Nu s-a putut instala deoarece nu este disponibilă o conexiune Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Nu s-a instalat. Încearcă din nou."</string>
<string name="action_settings" msgid="5729342767795123227">"Setări"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Se pregătește terminalul"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Se oprește terminalul"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminalul s-a blocat"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Redimensionarea discului"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Redimensionează / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Redimensionarea discului"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Redimensionează mărimea partiției root"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Dimensiunea discului este setată"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"S-au alocat <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> max."</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Anulează"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Repornește să aplici"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Redirecționare de port"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Configurează redirecționarea de port"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminalul încearcă să deschidă un nou port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Portul solicitat să fie deschis: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Aplică"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminalul va fi repornit pentru a redimensiona discul"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Confirmă"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controlul porturilor"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permite / refuză porturile active"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porturi active"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Porturi permise salvate"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Adaugă"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Șterge <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Acceptă un port nou"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Introdu un număr de port nou"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Salvează"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Anulează"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Introdu un număr"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Număr de port nevalid"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Portul există deja"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalul solicită să deschidă un nou port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Portul solicitat: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Acceptă"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuză"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Recuperare"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opțiuni de recuperare a partițiilor"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Schimbă la versiunea inițială"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Elimină-le pe toate"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opțiuni de recuperare a partiției"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Resetează la versiunea inițială"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Elimină toate datele"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Resetează terminalul"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Datele se vor șterge"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Confirmă"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Datele vor fi eliminate"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Resetează"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Anulează"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Fă backup datelor în <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Nu s-a putut recupera deoarece backupul nu a reușit"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Nu s-a putut recupera din cauza unei erori de backup"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Nu s-a putut recupera"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Nu se poate elimina fișierul de backup"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Nu s-au putut elimina datele din backup"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Elimină datele din backup"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Curăță <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Eroare ireversibilă"</string>
- <string name="error_desc" msgid="1939028888570920661">"Nu s-a putut recupera în urma unei erori.\nRepornește aplicația sau încearcă una dintre opțiunile de recuperare."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Elimină <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Eroare ireversibilă"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Nu s-a putut recupera în urma unei erori.\nRepornește terminalul sau încearcă una dintre opțiunile de recuperare.\nDacă toate încercările eșuează, șterge toate datele activând sau dezactivând terminalul Linux din opțiunile pentru dezvoltatori."</string>
<string name="error_code" msgid="3585291676855383649">"Cod de eroare: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Setări"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminalul rulează"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Dă clic pentru a deschide terminalul"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Dă clic pentru a deschide terminalul"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Închide"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminalul se închide"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Forțează închiderea"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> este activat"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ru/strings.xml b/android/TerminalApp/res/values-ru/strings.xml
index f14c59d..c3dfec3 100644
--- a/android/TerminalApp/res/values-ru/strings.xml
+++ b/android/TerminalApp/res/values-ru/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Терминал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Экран терминала"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Пустая строка"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Нажмите дважды, чтобы начать вводить текст"</string>
<string name="installer_title_text" msgid="500663060973466805">"Установка терминала Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Для запуска терминала Linux нужно скачать примерно <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> данных по сети.\nПродолжить?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Скачать только через Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Для запуска терминала Linux нужно скачать примерно <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> данных по сети.\nПродолжить?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Скачивать только по Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Установить"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Установка"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Ошибка сети. Проверьте подключение и повторите попытку."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Не удалось выполнить установку из-за ошибки сети. Проверьте подключение и повторите попытку."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Установка терминала Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"После окончания будет запущен терминал Linux."</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Не удалось выполнить установку из-за ошибки сети."</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Сбой установки. Повторите попытку."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Терминал Linux запустится после завершения установки."</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Не удалось выполнить установку из-за проблемы с сетью."</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Не удалось выполнить установку, так как сеть Wi-Fi недоступна."</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Сбой установки. Повторите попытку."</string>
<string name="action_settings" msgid="5729342767795123227">"Настройки"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Терминал подготавливается."</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Работа терминала останавливается."</string>
<string name="vm_error_message" msgid="5231867246177661525">"Произошел сбой терминала."</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Изменение размера диска"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Rootfs и изменение размера"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Изменить размер диска"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Изменить размер корневого раздела"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Размер диска задан."</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Выделено <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Максимум <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Отмена"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Перезапуск и примен."</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Переадресация портов"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Настроить переадресацию портов"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Терминал пытается открыть новый порт"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Запрашивается разрешение открыть порт <xliff:g id="PORT_NUMBER">%d</xliff:g>."</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Применить"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Для изменения размера диска терминал будет перезапущен."</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Подтвердить"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Управление портами"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Открыть/закрыть доступ к портам прослушивания"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Порты прослушивания"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Сохраненные порты с открытым доступом"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Добавить"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Удалить <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Открыть доступ к новому порту"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Введите номер нового порта"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Сохранить"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Отмена"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Введите номер."</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Неверный номер порта."</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт уже существует."</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал просит открыть новый порт"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Запрашиваемый порт: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Разрешить"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Не разрешать"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Восстановление"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Варианты восстановления разделов"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Перейти к исходной версии"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Удалить все"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Варианты восстановления разделов"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Восстановить исходную версию"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Удалить все данные"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Сброс настроек терминала"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Данные будут удалены."</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Подтвердить"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Данные будут удалены."</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Сбросить"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Отмена"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Сохранить резервную копию в <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Не удается восстановить данные из-за ошибки резервного копирования."</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Не удалось выполнить восстановление из-за ошибки резервного копирования."</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Ошибка восстановления."</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Не получается удалить файл резервной копии."</string>
- <string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Удалить резервную копию"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Удалить из <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Не получилось удалить резервную копию данных."</string>
+ <string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Удалить данные резервного копирования"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Удалить <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Неустранимая ошибка"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Не удалось исправить ошибку.\nПопробуйте перезапустить терминал или воспользуйтесь одним из вариантов восстановления.\nЕсли ни один из способов не поможет, включите или отключите режим \"Для разработчиков\" на терминале Linux."</string>
+ <string name="error_code" msgid="3585291676855383649">"Код ошибки: <xliff:g id="ERROR_CODE">%s</xliff:g>."</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Настройки"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Терминал запущен"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Нажмите, чтобы открыть его."</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Нажмите, чтобы открыть терминал."</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Закрыть"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Терминал закрывается"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Закрыть принудительно"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g>: включено."</string>
</resources>
diff --git a/android/TerminalApp/res/values-si/strings.xml b/android/TerminalApp/res/values-si/strings.xml
index e864cd2..1b4ffc3 100644
--- a/android/TerminalApp/res/values-si/strings.xml
+++ b/android/TerminalApp/res/values-si/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ටර්මිනලය"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ටර්මිනල සංදර්ශකය"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"කර්සරය"</string>
+ <string name="empty_line" msgid="5012067143408427178">"හිස් රේඛාව"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ආදානය ටයිප් කිරීමට දෙවරක් තට්ටු කරන්න"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ටර්මිනලය ස්ථාපනය කරන්න"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ටර්මිනලය දියත් කිරීමට, ඔබට ජාලය හරහා දත්ත <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> පමණ බාගත කිරීමට අවශ්ය වේ.\nඔබ ඉදිරියට යනවා ද?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi ලබා ගත හැකි විට බාගන්න"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ටර්මිනලය දියත් කිරීමට, ඔබට ජාලය හරහා දත්ත <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> පමණ බාගැනීමට අවශ්ය වේ.\nඔබ ඉදිරියට යාමට කැමති ද?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fi පමණක් භාවිතා කරමින් බාගන්න"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ස්ථාපනය කරන්න"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ස්ථාපනය කරමින්"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ජාල දෝෂයකි. සම්බන්ධතාවය පරීක්ෂා කර යළි උත්සාහ කරන්න."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ජාල දෝෂයක් හේතුවෙන් ස්ථාපනය කිරීමට අසමත් විය. ඔබේ සබැඳුම පරීක්ෂා කර නැවත උත්සාහ කරන්න."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ටර්මිනලය ස්ථාපනය කරමින්"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux ටර්මිනලය අවසන් වූ පසු ආරම්භ වනු ඇත"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ජාල ගැටලුවක් හේතුවෙන් ස්ථාපනය කිරීමට අසමත් විය"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ස්ථාපනය කිරීමට අසමත් විය. නැවත උත්සාහ කරන්න."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ස්ථාපනය අවසන් වූ පසු Linux ටර්මිනලය ආරම්භ වනු ඇත"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ජාල ගැටලුවක් හේතුවෙන් ස්ථාපනය කිරීමට අසමත් විය"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi නොමැති නිසා ස්ථාපනය කිරීමට අසමත් විය"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ස්ථාපනය කිරීමට අසමත් විය. නැවත උත්සාහ කරන්න"</string>
<string name="action_settings" msgid="5729342767795123227">"සැකසීම්"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ටර්මිනලය සූදානම් කිරීම"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ටර්මිනලය නතර කිරීම"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ටර්මිනලය බිඳ වැටුණි"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"තැටි ප්රමාණය වෙනස් කිරීම"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ප්රතිප්රමාණ කරන්න / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"තැටි ප්රමාණය වෙනස් කිරීම"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"මූල කොටස් ප්රමාණය ප්රතිප්රමාණ කරන්න"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"තැටි ප්රමාණය සැකසිණි"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> පවරන ලදි"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> උපරිමය"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"අවලංගු කරන්න"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"යෙදීමට යළි අරඹන්න"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"පෝටය යොමු කිරීම"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"පෝටය යොමු කිරීම වින්යාස කරන්න"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ටර්මිනලය නව පෝටයක් විවෘත කිරීමට උත්සාහ කරයි"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"පෝටය විවෘත කිරීමට ඉල්ලා ඇත: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"යොදන්න"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"තැටියේ ප්රමාණය වෙනස් කිරීමට ටර්මිනලය යළි ඇරඹෙනු ඇත"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"තහවුරු කරන්න"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"පෝටය පාලනය"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"සවන්දීමේ පෝටයන්ට ඉඩ දෙන්න/ප්රතික්ෂේප කරන්න"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"සවන්දීමේ පෝටයන්"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> <xliff:g id="PROCESS_NAME">%2$s</xliff:g>"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"සුරකින ලද ඉඩ දුන් පෝටයන්"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"එක් කරන්න"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> මකන්න"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"නව පෝටයකට ඉඩ දෙන්න"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"නව පෝට අංකයක් ඇතුළු කරන්න"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"සුරකින්න"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"අවලංගු කරන්න"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"අංකයක් ඇතුළු කරන්න"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"වලංගු නොවන පෝට අංකය"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"පෝටය දැනටමත් පවතී"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ටර්මිනලය නව පෝටයක් විවෘත කිරීමට ඉල්ලීම් කරයි"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"පෝටය ඉල්ලා ඇත: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"පිළිගන්න"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ප්රතික්ෂේප කරන්න"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"ප්රතිසාධනය"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"කොටස් ප්රතිසාන විකල්ප"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ආරම්භක අනුවාදයට වෙනස් කරන්න"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"සියල්ල ඉවත් කරන්න"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"කොටස් ප්රතිසාන විකල්ප"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ආරම්භක අනුවාදයට යළි සකසන්න"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"සියලු දත්ත ඉවත් කරන්න"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ටර්මිනලය යළි සකසන්න"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"දත්ත මකනු ඇත"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"තහවුරු කරන්න"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"දත්ත ඉවත් කරනු ලැබේ"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"යළි සකසන්න"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"අවලංගු කරන්න"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> වෙත දත්ත උපස්ථ කරන්න"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"උපස්ථය අසමත් වූ නිසා ප්රතිසාධනය අසමත් විය"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"උපස්ථ දෝෂයක් හේතුවෙන් ප්රතිසාධනය කිරීමට අසමත් විය"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"ප්රතිසාධනය අසමත් විය"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"උපස්ථ ගොනුව ඉවත් කළ නොහැක"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"උපස්ථ දත්ත ඉවත් කිරීමට අසමත් විය"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"උපස්ථ දත්ත ඉවත් කරන්න"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> පිරිසිදු කරන්න"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> ඉවත් කරන්න"</string>
+ <string name="error_title" msgid="405150657301906598">"ප්රතිසාධනය කළ නොහැකි දෝෂය"</string>
+ <string name="error_desc" msgid="4588252235686826721">"දෝෂයකින් ප්රතිසාධනය කිරීමට අසමත් විය.\nඔබට ටර්මිනලය නැවත ආරම්භ කිරීමට උත්සාහ කළ හැක, නැතහොත් ප්රතිසාධන විකල්ප වලින් එකක් උත්සාහ කරන්න.\nසියලු උත්සාහයන් අසමත් වුවහොත්, සංවර්ධක විකල්ප වලින් Linux පර්යන්තය ක්රියාත්මක/ක්රියාවිරහිත කිරීමෙන් සියලු දත්ත පිස දමන්න."</string>
+ <string name="error_code" msgid="3585291676855383649">"දෝෂ කේතය: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"සැකසීම්"</string>
<string name="service_notification_title" msgid="2918088850910713393">"පර්යන්තය ධාවනය වේ"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ටර්මිනලය විවෘත කිරීමට ක්ලික් කරන්න"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ටර්මිනලය විවෘත කිරීමට ක්ලික් කරන්න"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"වසන්න"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ටර්මිනලය වැසෙමින් පවතී"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"බලෙන් වසන්න"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> සබලයි"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sk/strings.xml b/android/TerminalApp/res/values-sk/strings.xml
index ad48c26..d77433e 100644
--- a/android/TerminalApp/res/values-sk/strings.xml
+++ b/android/TerminalApp/res/values-sk/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminál"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Zobrazenie terminálu"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kurzor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Prázdny riadok"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dvakrát klepnite a zadajte vstup"</string>
<string name="installer_title_text" msgid="500663060973466805">"Inštalácia terminálu systému Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Ak chcete spustiť terminál systému Linux, musíte cez sieť stiahnuť približne <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dát.\nChcete pokračovať?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Stiahnuť, keď bude k dispozícii Wi‑Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Ak chcete spustiť terminál Linux, musíte cez sieť stiahnuť približne <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dát.\nChcete pokračovať?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Sťahovať iba cez Wi‑Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Inštalovať"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Inštaluje sa"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Chyba siete. Skontrolujte pripojenie a skúste to znova."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Nepodarilo sa nainštalovať pre chybu siete. Skontrolujte pripojenie a skúste to znova."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Inštaluje sa terminál systému Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Terminál systému Linux sa spustí po dokončení"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Nepodarilo sa nainštalovať pre problém so sieťou"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Nepodarilo sa nainštalovať. Skúste to znova."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Terminál Linux sa spustí po dokončení inštalácie"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Nepodarilo sa nainštalovať pre problém so sieťou"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Inštalácia sa nepodarila, pretože nie je k dispozícii Wi‑Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Nepodarilo sa nainštalovať. Skúste to znova."</string>
<string name="action_settings" msgid="5729342767795123227">"Nastavenia"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminál sa pripravuje"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminál sa zastavuje"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminál spadol"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Zmena veľkosti disku"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Zmeniť veľkosť / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Zmena veľkosti disku"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Zmena veľkosti koreňového oddielu"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Veľkosť disku je nastavená"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Pridelené <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Max. <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Zrušiť"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Vyžaduje sa reštart"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Presmerovanie portov"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Nakonfigurovať presmerovanie portov"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminál sa pokúša otvoriť nový port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Vyžaduje sa otvorenie portu: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Použiť"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminál sa reštartuje, aby sa zmenila veľkosť disku"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Potvrdiť"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ovládanie portov"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Povoliť alebo zakázať porty počúvania"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porty počúvania"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Uložené povolené porty"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Pridať"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Odstrániť <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Povoľte nový port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Zadajte nové číslo portu"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Uložiť"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Zrušiť"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Zadajte číslo"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Neplatné číslo portu"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port už existuje"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminál požaduje otvoriť nový port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Požadovaný port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prijať"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Zamietnuť"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Obnovenie"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Možnosti obnovenia oddielu"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Zmena na pôvodnú verziu"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Odstrániť všetko"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Možnosti obnovenia oddielu"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Reset na pôvodnú verziu"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Odstránenie všetkých údajov"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Resetovanie terminálu"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Údaje budú odstránené"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Potvrdiť"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Údaje budú odstránené"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Resetovať"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Zrušiť"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Zálohovať údaje do <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Obnovenie sa nepodarilo, pretože sa nepodarilo zálohovať"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Nepodarilo sa obnoviť pre chybu zálohy"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Obnovenie sa nepodarilo"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Súbor zálohy sa nepodarilo odstrániť"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Údaje zálohy sa nepodarilo odstrániť"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Odstrániť údaje zálohy"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Vyčistiť <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Odstránenie cesty <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Neopraviteľná chyba"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Nepodarilo sa obnoviť z chybového stavu.\nSkúste terminál reštartovať alebo vyskúšajte jednu z možností obnovenia.\nAk všetky pokusy zlyhajú, trvale vymažte všetky údaje tým, že v sekcii Pre vývojárov zapnete alebo vypnete terminál Linux."</string>
+ <string name="error_code" msgid="3585291676855383649">"Kód chyby: <xliff:g id="ERROR_CODE">%s</xliff:g>."</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Nastavenia"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminál je spustený"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliknutím otvorte terminál"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliknutím otvorte terminál"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Zavrieť"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminál sa zatvára"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Vynútiť zavretie"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Procesor <xliff:g id="ID_1">VirGL</xliff:g> je aktivovaný"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sl/strings.xml b/android/TerminalApp/res/values-sl/strings.xml
index 74b3f6d..0583a0f 100644
--- a/android/TerminalApp/res/values-sl/strings.xml
+++ b/android/TerminalApp/res/values-sl/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Prikaz terminala"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kazalec"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Prazna vrstica"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Dvakrat se dotaknite za tipkanje vnosa"</string>
<string name="installer_title_text" msgid="500663060973466805">"Namestitev terminala Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Če želite zagnati terminal Linux, morate prek omrežja prenesti približno <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podatkov.\nAli želite nadaljevati?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Prenesi, ko bo na voljo Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Če želite zagnati terminal Linux, morate prek omrežja prenesti približno <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> podatkov.\nAli želite nadaljevati?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Prenos samo z uporabo povezave Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Namesti"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Nameščanje"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Omrežna napaka. Preverite povezavo in poskusite znova."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Namestitev ni uspela zaradi omrežne napake. Preverite povezavo in poskusite znova."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Nameščanje terminala Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Terminal Linux se bo zagnal po končani namestitvi"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Namestitev ni uspela zaradi težave z omrežjem"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Namestitev ni uspela. Poskusite znova."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Terminal Linux se bo zagnal po končani namestitvi"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Namestitev ni uspela zaradi težave z omrežjem"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Namestitev ni uspela, ker Wi-Fi ni na voljo"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Namestitev ni uspela. Poskusite znova."</string>
<string name="action_settings" msgid="5729342767795123227">"Nastavitve"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Pripravljanje terminala"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Ustavljanje terminala"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal se je zrušil"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Spreminjanje velikosti diska"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Spreminjanje velikosti/korenski datotečni sistem"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Spreminjanje velikosti diska"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Spreminjanje velikosti korenske particije"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Velikost diska je nastavljena"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Dodeljeno: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Največja velikost: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Prekliči"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Znova zaženi za uporabo"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Posredovanje vrat"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfiguriranje posredovanja vrat"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal poskuša odpreti nova vrata"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Zahtevano je odprtje teh vrat: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Uporabi"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal se bo znova zagnal, da se bo izvedla sprememba velikosti diska"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Potrdi"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Nadzor vrat"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dovoli/zavrni vrata za poslušanje"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Vrata za poslušanje"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Shranjena dovoljena vrata"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Izbriši <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Dovoli nova vrata"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Vnesite številko novih vrat"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Shrani"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Prekliči"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Vnesite številko"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Neveljavna številka vrat"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Vrata že obstajajo"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal zahteva odpiranje novih vrat"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Zahtevana vrata: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Sprejmi"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Zavrni"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Obnovitev"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Možnosti obnovitve particije"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Spremeni v začetno različico"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Odstrani vse"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Možnosti obnovitve particije"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Ponastavitev na začetno različico"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Odstranitev vseh podatkov"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Ponastavitev terminala"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Podatki bodo izbrisani"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Potrdi"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Podatki bodo odstranjeni"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Ponastavi"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Prekliči"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Varnostno kopiranje podatkov v <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Obnovitev ni uspela zaradi neuspešnega varnostnega kopiranja"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Obnovitev ni uspela zaradi napake varnostne kopije"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Obnovitev ni uspela"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Datoteke z varnostno kopijo ni mogoče odstraniti"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Varnostno kopiranih podatkov ni bilo mogoče odstraniti"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Odstranitev varnostno kopiranih podatkov"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Počiščenje poti <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Nepopravljiva napaka"</string>
- <string name="error_desc" msgid="1939028888570920661">"Obnovitev po napaki ni uspela.\nPoskusite znova zagnati aplikacijo ali uporabiti eno od možnosti obnovitve."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Odstrani <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Nepopravljiva napaka"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Obnovitev po napaki ni uspela.\nPoskusite znova zagnati terminal ali uporabiti eno od možnosti obnovitve.\nČe noben poskus ne uspe, izbrišite vse podatke tako, da v možnostih za razvijalce vklopite/izklopite terminal Linux."</string>
<string name="error_code" msgid="3585291676855383649">"Koda napake: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Nastavitve"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal se izvaja"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliknite, če želite odpreti terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliknite, če želite odpreti terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Zapri"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal se zapira"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Vsili zapiranje"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> je omogočen"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sq/strings.xml b/android/TerminalApp/res/values-sq/strings.xml
index ee42f8a..3bac355 100644
--- a/android/TerminalApp/res/values-sq/strings.xml
+++ b/android/TerminalApp/res/values-sq/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminali"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Ekrani i terminalit"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursori"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Rresht bosh"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Trokit dy herë për të shkruar të dhëna"</string>
<string name="installer_title_text" msgid="500663060973466805">"Instalo terminalin e Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Për të hapur terminalin e Linux, duhet të shkarkosh afërsisht <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> të dhëna nëpërmjet rrjetit.\nDëshiron të vazhdosh?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Shkarko kur të ofrohet Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Për të hapur terminalin e Linux, duhet të shkarkosh afërsisht <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> të dhëna nëpërmjet rrjetit.\nDëshiron të vazhdosh?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Shkarko duke përdorur vetëm Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Instalo"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Po instalohet"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Gabim në rrjet. Kontrollo lidhjen dhe provo përsëri."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Instalimi dështoi për shkak të një problemi të rrjetit. Kontrollo lidhjen tënde dhe provo përsëri."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Terminali i Linux po instalohet"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Terminali i Linux do të niset pas përfundimit"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Instalimi dështoi për shkak të një problemi të rrjetit"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Instalimi dështoi. Provo përsëri."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Terminali i Linux do të niset pas përfundimit të instalimit"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Instalimi dështoi për shkak të një problemi të rrjetit"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Instalimi dështoi për shkak se Wi-Fi nuk ofrohet"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Instalimi dështoi. Provo përsëri"</string>
<string name="action_settings" msgid="5729342767795123227">"Cilësimet"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminali po përgatitet"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminali po ndalohet"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminali u ndërpre aksidentalisht"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Ndryshimi i përmasave të diskut"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Ndrysho përmasat / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Ndryshimi i përmasave të diskut"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Ndrysho madhësinë e ndarjes rrënjë"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Madhësia e diskut u caktua"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Caktuar: <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maksimumi: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Anulo"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Rinis për të zbatuar"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Transferimi i portës"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfiguro transferimin e portës"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminali po përpiqet të hapë një portë të re"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Porta që kërkohet të hapet: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Zbato"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminali do të riniset për të ndryshuar përmasat e diskut"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Konfirmo"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrolli i portës"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Lejo/refuzo portat e dëgjimit"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portat e dëgjimit"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Portat e lejuara të ruajtura"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Shto"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Fshi <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Lejo një portë të re"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Fut një numër të një porte të re"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Ruaj"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Anulo"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Fut një numër"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numër i pavlefshëm i portës"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porta ekziston tashmë"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminali po përpiqet të hapë një portë të re"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Porta e kërkuar: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prano"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuzo"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Rikuperimi"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Opsionet e rikuperimit të ndarjes"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Ndrysho në versionin fillestar"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Hiqi të gjitha"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Opsionet e rikuperimit të ndarjes"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Rivendos në versionin fillestar"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Hiq të gjitha të dhënat"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Rivendos terminalin"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Të dhënat do të fshihen"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Konfirmo"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Të dhënat do të hiqen"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Rivendos"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Anulo"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Rezervo të dhënat te <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Rikuperimi dështoi për shkak se rezervimi dështoi"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Rikuperimi dështoi për shkak të një gabimi të rezervimit"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Rikuperimi dështoi"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Skedari i rezervimit nuk mund të hiqet"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Heqja e të dhënave të rezervimit dështoi"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Hiq të dhënat e rezervimit"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Pastro <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Hiq <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Gabim i parikuperueshëm"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Rikuperimi nga një gabim dështoi.\nMund të provosh ta rinisësh terminalin ose provo një nga opsionet e rikuperimit.\nNëse dështojnë të gjitha përpjekjet, pastro të gjitha të dhënat duke aktivizuar/çaktivizuar terminalin e Linux nga opsionet e zhvilluesit."</string>
+ <string name="error_code" msgid="3585291676855383649">"Kodi i gabimit: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Cilësimet"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminali po ekzekutohet"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Kliko për të hapur terminalin"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Kliko për të hapur terminalin"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Mbyll"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"\"Terminali\" po mbyllet"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Ndalo me forcë"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> është aktivizuar"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sr/strings.xml b/android/TerminalApp/res/values-sr/strings.xml
index a1d4005..97a2e4b 100644
--- a/android/TerminalApp/res/values-sr/strings.xml
+++ b/android/TerminalApp/res/values-sr/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Терминал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Приказ терминала"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Празан ред"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Двапут додирните да бисте унели текст"</string>
<string name="installer_title_text" msgid="500663060973466805">"Инсталирајте Linux терминал"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Да бисте покренули Linux терминал, треба да преузмете око <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> података преко мреже.\nЖелите да наставите?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Преузми када WiFi буде доступан"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Да бисте покренули Linux терминал, треба да преузмете око <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> података преко мреже.\nЖелите ли да наставите?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Преузимај само преко WiFi мреже"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Инсталирај"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Инсталира се"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Грешка на мрежи. Проверите везу и пробајте поново."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Инсталирање није успело због грешке на мрежи. Проверите везу и пробајте поново."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Инсталира се Linux терминал"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux терминал ће се покренути после завршетка"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Инсталирање није успело због проблема са мрежом"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Инсталирање није успело. Пробајте поново."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux терминал ће се покренути када се инсталација заврши"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Инсталирање није успело због проблема са мрежом"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Инсталирање није успело јер WiFi није доступан"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Инсталирање није успело. Пробајте поново"</string>
<string name="action_settings" msgid="5729342767795123227">"Подешавања"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Терминал се припрема"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Терминал се зауставља"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Терминал је отказао"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Промена величине диска"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Промените величину / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Промена величине диска"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Промените величину основне партиције"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Величина диска је подешена"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Додељено <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Макс. <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Откажи"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Рестартуј и примени"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Прослеђивање порта"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Конфигуришите прослеђивање порта"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Терминал покушава да отвори нови порт"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Порт чије је отварање тражено: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Примени"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Терминал ће се рестартовати да би се променила величина диска"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Потврди"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Контрола порта"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дозволите или забраните портове за слушање"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Портови за слушање"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Сачувани дозвољени портови"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Додај"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Избриши <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Дозволите нови порт"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Унесите нови број порта"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Сачувај"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Откажи"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Унесите број"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Неважећи број порта"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт већ постоји"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал тражи да отвори нови порт"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Обавезан порт: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прихвати"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Одбиј"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Опоравак"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Опције опоравка партиција"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Промени на почетну верзију"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Уклоните све"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Опције опоравка партиција"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Вратите на почетну верзију"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Уклоните све податке"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Ресетујте терминал"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Подаци ће бити избрисани"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Потврди"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Подаци ће бити уклоњени"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Ресетуј"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Откажи"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Направи резервну копију података на <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Опоравак није успео јер прављење резервне копије није успело"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Опоравак није успео због грешке при прављењу резервне копије"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Опоравак није успео"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Уклањање фајла резервне копије није успело"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Уклањање резервне копије података није успело"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Уклоните резервну копију"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Обришите <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Непоправљива грешка"</string>
- <string name="error_desc" msgid="1939028888570920661">"Опоравак од грешке није успео.\nПробајте да рестартујете апликацију или пробајте једну од опција за враћање."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Уклоните <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Непоправљива грешка"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Опоравак од грешке није успео.\nПокушајте да рестартујете терминал или испробајте једну од опција за враћање.\nАко ниједан покушај не успе, обришите све податке тако што ћете укључити или искључити Linux терминал у опцијама за програмере."</string>
<string name="error_code" msgid="3585291676855383649">"Кôд грешке: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Подешавања"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Терминал је активан"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Кликните да бисте отворили терминал"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Кликните да бисте отворили терминал"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Затвори"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Терминал се затвара"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Принудно затвори"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> је омогућен"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sv/strings.xml b/android/TerminalApp/res/values-sv/strings.xml
index 692f89c..3b1b4f0 100644
--- a/android/TerminalApp/res/values-sv/strings.xml
+++ b/android/TerminalApp/res/values-sv/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminalskärm"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Markör"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Tom rad"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Tryck snabbt två gånger för att skriva in data"</string>
<string name="installer_title_text" msgid="500663060973466805">"Installera Linux-terminalen"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Om du vill starta Linux-terminalen måste du ladda ned ungefär <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data via nätverket.\nVill du fortsätta?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Ladda ned när wifi är tillgängligt"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Om du vill starta Linux-terminalen måste du ladda ned ungefär <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> data via nätverket.\nVill du fortsätta?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Ladda endast ned via wifi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Installera"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Installerar"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Nätverksfel. Kontrollera anslutningen och försök igen."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Det gick inte att installera på grund av ett nätverksfel. Kontrollera anslutningen och försök igen."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Installerar Linux-terminalen"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux-terminalen startas när processen är klar"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Det gick inte att installera på grund av nätverksproblemet"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Installationen misslyckades. Försök igen."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux-terminalen startas när installationen har slutförts"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Det gick inte att installera på grund av ett nätverksproblem"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Det gick inte att installera eftersom att wifi inte är tillgängligt"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Installationen misslyckades. Försök igen"</string>
<string name="action_settings" msgid="5729342767795123227">"Inställningar"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminalen förbereds"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Stoppar terminalen"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminalen kraschade"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Ändra diskstorlek"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Ändra storlek/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Ändra diskstorlek"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Ändra storlek på rotpartitionen"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Diskstorlek har angetts"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> har tilldelats"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Max <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Avbryt"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Starta om för att tillämpa"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Portvidarebefordran"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Konfigurera portvidarebefordran"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminalen försöker öppna en ny port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port som begärs att öppnas: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Tillämpa"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminalen startas om för att ändra storlek på disken"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Bekräfta"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portkontroll"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Tillåt/neka lyssningsportar"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Lyssningsportar"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Sparade tillåtna portar"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Lägg till"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Radera <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Tillåt en ny port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Ange ett nytt portnummer"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Spara"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Avbryt"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Ange ett nummer"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ogiltigt portnummer"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porten finns redan"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalen begär att öppna en ny port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port som begärs: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Godkänn"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Neka"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Återställning"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Återställningsalternativ för partition"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Ändra till ursprunglig version"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Ta bort alla"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Återställningsalternativ för partition"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Återställ till ursprunglig version"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Ta bort all data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Återställ terminalen"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data raderas"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Bekräfta"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data kommer att tas bort"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Återställ"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Avbryt"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Säkerhetskopiera data till <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Återställningen misslyckades eftersom säkerhetskopieringen misslyckades"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Det gick inte att återställa på grund av ett säkerhetskopieringsfel"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Återställningen misslyckades"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Det går inte att ta bort säkerhetskopian"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Det gick inte att ta bort säkerhetskopierad data"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Ta bort säkerhetskopierad data"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Rensa <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Ta bort <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Allvarligt fel"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Det gick inte att återställa på grund av ett fel.\nDu kan försöka starta om terminalen eller prova ett av återställningsalternativen.\nOm alla försök misslyckas kan du radera all data genom att aktivera/inaktivera Linux-terminalen i utvecklaralternativen."</string>
+ <string name="error_code" msgid="3585291676855383649">"Felkod: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Inställningar"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminalen körs"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Klicka för att öppna terminalen"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Klicka för att öppna terminalen"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Stäng"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminalen stängs av"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Tvinga avstängning"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> har aktiverats"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sw/strings.xml b/android/TerminalApp/res/values-sw/strings.xml
index ca79457..c8ffd12 100644
--- a/android/TerminalApp/res/values-sw/strings.xml
+++ b/android/TerminalApp/res/values-sw/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Temino"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Skrini ya kituo"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kiteuzi"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Mstari usio na chochote"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Gusa mara mbili ili uweke data kwa kuandika"</string>
<string name="installer_title_text" msgid="500663060973466805">"Weka temino ya Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Unahitaji kupakua takribani <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ya data kwenye mtandao ili uwashe temino ya Linux.\nUngependa kuendelea?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Pakua wakati Wi-Fi inapatikana"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Unahitaji kupakua takribani <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ya data kupitia mtandao ili uwashe temino ya Linux.\nUngependa kuendelea?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Pakua ukitumia Wi-Fi pekee"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Weka"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Inaweka"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Hitilafu ya mtandao. Angalia muunganisho kisha ujaribu tena."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Imeshindwa kuweka kwenye kifaa kutokana na hitilafu ya mtandao. Kagua muunganisho wako kisha ujaribu tena."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Inaweka temino ya Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Temino ya Linux itawashwa baada ya kumaliza"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Imeshindwa kuweka kwenye kifaa kwa sababu ya tatizo la mtandao"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Imeshindwa kuweka kwenye kifaa. Jaribu tena."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Temino ya Linux itafunguka baada ya kumaliza kuweka kwenye kifaa"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Imeshindwa kuweka kwenye kifaa kutokana na tatizo la mtandao"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Imeshindwa kuweka kwenye kifaa kwa sababu Wi-Fi haipatikani"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Imeshindwa kuweka kwenye kifaa. Tafadhali jaribu tena"</string>
<string name="action_settings" msgid="5729342767795123227">"Mipangilio"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Inaandaa temino"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Inafunga temino"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Temino imeacha kufanya kazi"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Kubadilisha Ukubwa wa Diski"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Badilisha ukubwa / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Kubadilisha ukubwa wa diski"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Kubadilisha ukubwa wa sehemu yenye idhini maalum ya kudhibiti"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Ukubwa wa diski umewekwa"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> zimekabidhiwa"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Kikomo cha <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Acha"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Zima na uwashe utumie"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Kusambaza Mlango Kwingine"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Weka mipangilio ya kusambaza mlango kwingine"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Kituo kinajaribu kufungua mlango mpya"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Umeomba mlango ufunguliwe: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Tekeleza"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Temino itafungwa kisha ifunguliwe ili kubadilisha ukubwa wa diski"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Thibitisha"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Udhibiti wa mlango"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Ruhusu au kataa milango ya usikilizaji"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Milango ya usikilizaji"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Umehifadhi milango inayoruhusiwa"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Weka"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Futa <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Ruhusu mlango mpya"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Weka namba ya mlango mpya"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Hifadhi"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Acha"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Tafadhali weka namba"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Namba ya mlango si sahihi"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Tayari mlango upo"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Temino inatuma ombi la kufungua mlango mpya"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Ombi la mlango: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Kubali"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Kataa"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Kurejesha"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Chaguo za kurejesha data ya sehemu"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Rudi kwenye Toleo la awali"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Ondoa yote"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Chaguo za kurejesha data ya sehemu"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Kurejesha mipangilio ya toleo la awali"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Ondoa data yako yote"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Badilisha temino"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Data itafutwa"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Thibitisha"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Data itaondolewa"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Weka upya"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Acha"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Hifadhi nakala ya data kwenye <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Haikurejesha kwa sababu imeshindwa kuhifadhi nakala"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Imeshindwa kurejesha kutokana na hitilafu ya kuhifadhi nakala"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Haikurejesha"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Imeshindwa kuondoa faili yenye hifadhi nakala"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Imeshindwa kuondoa data ya kuhifadhi nakala"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Ondoa data ya nakala"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Safisha <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Hitilafu Inayozuia Kurejesha"</string>
- <string name="error_desc" msgid="1939028888570920661">"Imeshindwa kurejea kutoka hali ya hitilafu.\nUnaweza kujaribu kufungua programu upya au ujaribu mojawapo ya chaguo za urejeshaji."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Ondoa <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Hitilafu inayozuia kurejesha"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Imeshindwa kurejesha data kutokana na hitilafu.\nUnaweza kujaribu kufunga kisha ufungue kifaa au ujaribu mojawapo ya chaguo za kurejesha.\nIwapo utashindwa, ondoa kabisa data yote kwa kuwasha au kuzima kifaa cha Linux katika chaguo za wasanidi programu."</string>
<string name="error_code" msgid="3585291676855383649">"Msimbo wa hitilafu: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Mipangilio"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Temino inatumika"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Bofya ili ufungue temino"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Bofya ili ufungue temino"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Funga"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Kituo kinafungwa"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Lazimisha kufunga"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> imewashwa"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ta/strings.xml b/android/TerminalApp/res/values-ta/strings.xml
index e99b837..44d0fad 100644
--- a/android/TerminalApp/res/values-ta/strings.xml
+++ b/android/TerminalApp/res/values-ta/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"டெர்மினல் டிஸ்ப்ளே"</string>
<string name="terminal_input" msgid="4602512831433433551">"கர்சர்"</string>
<string name="empty_line" msgid="5012067143408427178">"வெற்று வரி"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"உள்ளீட்டை டைப் செய்ய இருமுறை தட்டுங்கள்"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux டெர்மினலை நிறுவுதல்"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux டெர்மினலைத் தொடங்க, நெட்வொர்க் மூலம் நீங்கள் சுமார் <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> தரவைப் பதிவிறக்க வேண்டும்.\nதொடர விரும்புகிறீர்களா?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"வைஃபை கிடைக்கும்போது பதிவிறக்கு"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux டெர்மினலைத் தொடங்க, நெட்வொர்க் மூலம் நீங்கள் சுமார் <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> தரவைப் பதிவிறக்க வேண்டும்.\nதொடர விரும்புகிறீர்களா?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"வைஃபையைப் பயன்படுத்தி மட்டும் பதிவிறக்கு"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"நிறுவு"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"நிறுவுகிறது"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"நெட்வொர்க் பிழை. இணைப்பைச் சரிபார்த்து மீண்டும் முயலவும்."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"நெட்வொர்க்கில் பிழை காரணமாக நிறுவ முடியவில்லை. இணைய இணைப்பைச் சரிபார்த்துவிட்டு மீண்டும் முயலவும்."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux டெர்மினலை நிறுவுகிறது"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"நிறைவடைந்ததும் Linux டெர்மினல் தொடங்கப்படும்"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"நெட்வொர்க் சிக்கல் இருப்பதால் நிறுவ முடியவில்லை"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"வைஃபை கிடைக்காததால் நிறுவ முடியவில்லை"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"நிறுவ முடியவில்லை. மீண்டும் முயலவும்."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"நிறுவப்பட்டதும் Linux டெர்மினல் தொடங்கும்"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"நெட்வொர்க் சிக்கல் காரணமாக நிறுவ முடியவில்லை"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"வைஃபை கிடைக்காததால் நிறுவ முடியவில்லை"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"நிறுவ முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="action_settings" msgid="5729342767795123227">"அமைப்புகள்"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"டெர்மினலைத் தயார்செய்கிறது"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"டெர்மினல் நிறுத்தப்படுகிறது"</string>
<string name="vm_error_message" msgid="5231867246177661525">"டெர்மினல் சிதைவடைந்தது"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"டிஸ்க் அளவை மாற்றுதல்"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"அளவை மாற்று / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"டிஸ்க் அளவை மாற்றுதல்"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ரூட் பார்டிஷன் அளவை மாற்றுதல்"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"டிஸ்க் அளவு அமைக்கப்பட்டது"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ஒதுக்கப்பட்டது"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"அதிகபட்சம் <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ரத்துசெய்"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"பயன்படுத்த தொடங்குக"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"போர்ட் அனுப்புதல்"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"போர்ட் அனுப்புதலை உள்ளமைத்தல்"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"டெர்மினல் புதிய போர்ட்டைத் திறக்க முயல்கிறது"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"திறக்கும்படி கேட்கப்பட்டுள்ள போர்ட்: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"பயன்படுத்து"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"டிஸ்க் அளவை மாற்ற டெர்மினல் மீண்டும் தொடங்கப்படும்"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"உறுதிசெய்"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"போர்ட் கட்டுப்பாடு"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"லிஸனிங் போர்ட்டுகளை அனுமதித்தல்/நிராகரித்தல்"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"லிஸனிங் போர்ட்டுகள்"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"சேமித்த அனுமதிக்கப்பட்ட போர்ட்டுகள்"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"சேர்க்கும்"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ஐ நீக்கும்"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"புதிய போர்ட்டை அனுமதித்தல்"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"புதிய போர்ட் எண்ணை டைப் செய்யுங்கள்"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"சேமி"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ரத்துசெய்"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"எண்ணை டைப் செய்யவும்"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"தவறான போர்ட் எண்"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"போர்ட் ஏற்கெனவே உள்ளது"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"டெர்மினல் புதிய போர்ட்டைத் திறக்குமாறு கேட்கிறது"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"போர்ட் கேட்கப்பட்டுள்ளது: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ஏற்கிறேன்"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"நிராகரி"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"மீட்டெடுத்தல்"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"பார்டிஷன் மீட்டெடுப்பு விருப்பங்கள்"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"முதல் பதிப்பிற்கு மாற்று"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"அனைத்தையும் அகற்றும்"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"பார்டிஷன் மீட்டெடுப்பு விருப்பங்கள்"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"தொடக்கப் பதிப்பிற்கு மீட்டமைத்தல்"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"அனைத்துத் தரவையும் அகற்றுதல்"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"டெர்மினலை மீட்டமைத்தல்"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"தரவு நீக்கப்படும்"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"உறுதிசெய்"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"தரவு அகற்றப்படும்"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"மீட்டமை"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ரத்துசெய்"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> இல் உள்ள தரவைக் காப்புப் பிரதி எடுத்தல்"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"காப்புப் பிரதி எடுத்தல் தோல்வியடைந்ததால் மீட்டெடுக்க முடியவில்லை"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"காப்புப் பிரதி எடுப்பதில் பிழை ஏற்பட்டதால் மீட்டெடுக்க முடியவில்லை"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"மீட்டெடுக்க முடியவில்லை"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"காப்புப் பிரதி ஃபைலை அகற்ற முடியவில்லை"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"காப்புப் பிரதி எடுக்கப்பட்ட தரவை அகற்ற முடியவில்லை"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"காப்புப் பிரதித் தரவை அகற்றுதல்"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> ஐக் காலியாக்குதல்"</string>
- <string name="error_title" msgid="7196464038692913778">"சரிசெய்ய முடியாத பிழை"</string>
- <string name="error_desc" msgid="1939028888570920661">"பிழையைச் சரிசெய்ய முடியவில்லை.\nநீங்கள் ஆப்ஸை மீண்டும் தொடங்க முயலலாம் அல்லது மீட்டெடுப்பு விருப்பங்களில் ஒன்றைப் பயன்படுத்திப் பார்க்கலாம்."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> ஐ அகற்றுதல்"</string>
+ <string name="error_title" msgid="405150657301906598">"சரிசெய்ய முடியாத பிழை"</string>
+ <string name="error_desc" msgid="4588252235686826721">"பிழையில் இருந்து மீட்டெடுக்க முடியவில்லை.\nநீங்கள் டெர்மினலை மீண்டும் தொடங்கியோ மீட்டெடுப்பு விருப்பங்களில் ஒன்றைப் பயன்படுத்தியோ பார்க்கலாம்.\nஅனைத்து முயற்சிகளும் தோல்வி அடைந்தால் டெவெலப்பர் விருப்பங்களில் Linux டெர்மினலை ஆன்/ஆஃப் செய்து அனைத்துத் தரவையும் அழிக்கவும்."</string>
<string name="error_code" msgid="3585291676855383649">"பிழைக் குறியீடு: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"அமைப்புகள்"</string>
<string name="service_notification_title" msgid="2918088850910713393">"டெர்மினல் இயக்கத்தில் உள்ளது"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"டெர்மினலைத் திறக்க கிளிக் செய்யுங்கள்"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"டெர்மினலைத் திறக்க கிளிக் செய்யுங்கள்"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"மூடு"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"டெர்மினல் மூடப்படுகிறது"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"உடனே மூடு"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> இயக்கப்பட்டது"</string>
</resources>
diff --git a/android/TerminalApp/res/values-te/strings.xml b/android/TerminalApp/res/values-te/strings.xml
index e13f2dc..6a3d646 100644
--- a/android/TerminalApp/res/values-te/strings.xml
+++ b/android/TerminalApp/res/values-te/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"టెర్మినల్"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminal డిస్ప్లే"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"కర్సర్"</string>
+ <string name="empty_line" msgid="5012067143408427178">"ఖాళీ లైన్"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"డబుల్-ట్యాప్ చేసి ఇన్పుట్ను టైప్ చేయండి"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux టెర్మినల్ను ఇన్స్టాల్ చేయండి"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux టెర్మినల్ను ప్రారంభించడానికి, మీరు నెట్వర్క్ ద్వారా దాదాపు <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> డేటాను డౌన్లోడ్ చేసుకోవాలి.\nమీరు కొనసాగిస్తారా?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi అందుబాటులో ఉన్నప్పుడు డౌన్లోడ్ చేయండి"</string>
- <string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ఇన్స్టాల్ చేయి"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux టెర్మినల్ను ప్రారంభించడానికి, మీరు నెట్వర్క్ ద్వారా దాదాపు <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> డేటాను డౌన్లోడ్ చేసుకోవాలి.\nమీరు కొనసాగించాలనుకుంటున్నారా?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Wi-Fiని ఉపయోగించి మాత్రమే డౌన్లోడ్ చేయండి"</string>
+ <string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ఇన్స్టాల్"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"ఇన్స్టాల్ చేస్తోంది"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"నెట్వర్క్ ఎర్రర్. కనెక్షన్ను చెక్ చేసి, మళ్లీ ట్రై చేయండి."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"నెట్వర్క్ ఎర్రర్ కారణంగా ఇన్స్టాల్ చేయడం విఫలమైంది. మీ కనెక్షన్ను చెక్ చేసి మళ్లీ ట్రై చేయండి."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux టెర్మినల్ను ఇన్స్టాల్ చేస్తోంది"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"పూర్తయిన తర్వాత Linux టెర్మినల్ ప్రారంభమవుతుంది"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"నెట్వర్క్ సమస్య కారణంగా ఇన్స్టాల్ చేయడం విఫలమైంది"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"ఇన్స్టాల్ చేయడం విఫలమైంది. మళ్లీ ట్రై చేయండి."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"ఇన్స్టాలేషన్ పూర్తయిన తర్వాత Linux టెర్మినల్ ప్రారంభమవుతుంది"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"నెట్వర్క్ సమస్య కారణంగా ఇన్స్టాల్ చేయడం విఫలమైంది"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi అందుబాటులో లేని కారణంగా ఇన్స్టాల్ చేయడం విఫలమైంది"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ఇన్స్టాల్ చేయడం విఫలమైంది. దయచేసి మళ్లీ ట్రై చేయండి"</string>
<string name="action_settings" msgid="5729342767795123227">"సెట్టింగ్లు"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"టెర్మినల్ను సిద్ధం చేస్తోంది"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"టెర్మినల్ను ఆపివేస్తోంది"</string>
<string name="vm_error_message" msgid="5231867246177661525">"టెర్మినల్ క్రాష్ అయింది"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"డిస్క్ సైజ్ మార్చడం"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"సైజ్ మార్చండి / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"డిస్క్ సైజ్ మార్చడం"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"రూట్ పార్టిషన్ సైజ్ను మార్చండి"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"డిస్క్ సైజ్ సెట్ చేయబడింది"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> కేటాయించబడింది"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"గరిష్ఠంగా <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"రద్దు చేయండి"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"వర్తించేందుకు రీస్టార్ట్ చేయండి"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"పోర్ట్ ఫార్వర్డింగ్"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"పోర్ట్ ఫార్వర్డింగ్ను కాన్ఫిగర్ చేయండి"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"టెర్మినల్ ఒక కొత్త పోర్ట్ను తెరవడానికి ట్రై చేస్తోంది"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"పోర్ట్ తెరవాలని రిక్వెస్ట్ చేశారు: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"వర్తింపజేయండి"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"డిస్క్ సైజ్ను మార్చడానికి టెర్మినల్ రీస్టార్ట్ అవుతుంది"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"నిర్ధారించండి"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"పోర్ట్ కంట్రోల్"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"వినే పోర్ట్లకు అనుమతినివ్వండి/తిరస్కరించండి"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"వినే పోర్ట్లు"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"సేవ్ చేసిన, అనుమతి ఉన్న పోర్ట్లు"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"జోడించండి"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>ను తొలగించండి"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"కొత్త పోర్ట్కు అనుమతినివ్వండి"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"కొత్త పోర్ట్ నంబర్ను ఎంటర్ చేయండి"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"సేవ్ చేయండి"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"రద్దు చేయండి"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"దయచేసి నంబర్ను ఎంటర్ చేయండి."</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"చెల్లుబాటు కాని పోర్ట్ నంబర్"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"పోర్ట్ ఇప్పటికే ఉంది"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"టెర్మినల్ ఒక కొత్త పోర్ట్ను తెరవడానికి రిక్వెస్ట్ చేస్తోంది"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"రిక్వెస్ట్ చేయబడిన పోర్ట్: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ఆమోదించండి"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"తిరస్కరించండి"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"రికవరీ"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"పార్టిషన్ రికవరీ ఆప్షన్లు"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"మొదటి వెర్షన్కు మార్చండి"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"అన్నీ తీసివేయండి"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"పార్టిషన్ రికవరీ ఆప్షన్లు"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"మొదటి వెర్షన్కు రీసెట్ చేయండి"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"మొత్తం డేటాను తీసివేయండి"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"టెర్మినల్ను రీసెట్ చేయండి"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"డేటా తొలగించబడుతుంది"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"నిర్ధారించండి"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"డేటా తీసివేయబడుతుంది"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"రీసెట్ చేయండి"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"రద్దు చేయండి"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g>లో డేటాను బ్యాకప్ చేయండి"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"బ్యాకప్ విఫలమైనందున రికవరీ విఫలమైంది"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"బ్యాకప్ ఎర్రర్ కారణంగా రికవర్ చేయడం విఫలమైంది"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"రికవరీ విఫలమైంది"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"బ్యాకప్ ఫైల్ను తీసివేయడం సాధ్యపడదు"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"బ్యాకప్ డేటాను తీసివేయడం విఫలమైంది"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"బ్యాకప్ డేటాను తీసివేయండి"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"క్లీనప్ <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"రికవరీని అసాధ్యం చేసే ఎర్రర్"</string>
- <string name="error_desc" msgid="1939028888570920661">"ఎర్రర్ను రికవర్ చేయడంలో విఫలమైంది.\nమీరు యాప్ను రీస్టార్ట్ చేసి ట్రై చేయవచ్చు లేదా రికవరీ ఆప్షన్లలో ఒకదాన్ని ట్రై చేయవచ్చు."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g>ను తీసివేయండి"</string>
+ <string name="error_title" msgid="405150657301906598">"రికవరీని అసాధ్యం చేసే ఎర్రర్"</string>
+ <string name="error_desc" msgid="4588252235686826721">"ఎర్రర్ను రికవర్ చేయడంలో విఫలమైంది.\nమీరు టెర్మినల్ను రీస్టార్ట్ చేసి ట్రై చేయవచ్చు లేదా రికవరీ ఆప్షన్లలో ఒకదాన్ని ట్రై చేయవచ్చు.\nఅన్ని ప్రయత్నాలు విఫలమైతే, డెవలపర్ ఆప్షన్ల నుండి Linux టెర్మినల్ను ఆన్/ఆఫ్ చేయడం ద్వారా మొత్తం డేటాను పూర్తిగా తొలగించండి."</string>
<string name="error_code" msgid="3585291676855383649">"ఎర్రర్ కోడ్: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"సెట్టింగ్లు"</string>
<string name="service_notification_title" msgid="2918088850910713393">"టెర్మినల్ రన్ అవుతోంది"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"టెర్మినల్ను తెరవడానికి క్లిక్ చేయండి"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"టెర్మినల్ను తెరవడానికి క్లిక్ చేయండి"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"మూసివేయండి"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal మూసివేయబడుతోంది"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"బలవంతంగా మూసివేయండి"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ప్రారంభించబడింది"</string>
</resources>
diff --git a/android/TerminalApp/res/values-th/strings.xml b/android/TerminalApp/res/values-th/strings.xml
index 0a96ca3..66716ec 100644
--- a/android/TerminalApp/res/values-th/strings.xml
+++ b/android/TerminalApp/res/values-th/strings.xml
@@ -20,55 +20,71 @@
<string name="terminal_display" msgid="4810127497644015237">"จอแสดงผลของเทอร์มินัล"</string>
<string name="terminal_input" msgid="4602512831433433551">"เคอร์เซอร์"</string>
<string name="empty_line" msgid="5012067143408427178">"บรรทัดว่างเปล่า"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"แตะสองครั้งเพื่อพิมพ์ข้อความ"</string>
<string name="installer_title_text" msgid="500663060973466805">"ติดตั้งเทอร์มินัล Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"หากต้องการเปิดเทอร์มินัล Linux คุณจะต้องดาวน์โหลดข้อมูลประมาณ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ผ่านเครือข่าย\nคุณต้องการดำเนินการต่อไหม"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"ดาวน์โหลดเมื่อมีการเชื่อมต่อ Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"หากต้องการเปิดเทอร์มินัล Linux คุณจะต้องดาวน์โหลดข้อมูลประมาณ <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ผ่านเครือข่าย\nคุณต้องการดำเนินการต่อไหม"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"ดาวน์โหลดโดยใช้ Wi-Fi เท่านั้น"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"ติดตั้ง"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"กำลังติดตั้ง"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"ข้อผิดพลาดเกี่ยวกับเครือข่าย ตรวจสอบการเชื่อมต่อแล้วลองอีกครั้ง"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"ติดตั้งไม่สำเร็จเนื่องจากมีข้อผิดพลาดเกี่ยวกับเครือข่าย โปรดตรวจสอบการเชื่อมต่อแล้วลองอีกครั้ง"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"กำลังติดตั้งเทอร์มินัล Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"เทอร์มินัล Linux จะเริ่มต้นหลังจากติดตั้งเสร็จ"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"ติดตั้งไม่สำเร็จเนื่องจากมีปัญหาเครือข่าย"</string>
- <string name="installer_error_no_wifi" msgid="8631584648989718121">"ติดตั้งไม่สำเร็จเนื่องจากไม่มี Wi-Fi"</string>
- <string name="installer_error_unknown" msgid="1991780204241177455">"ติดตั้งไม่สำเร็จ โปรดลองอีกครั้ง"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"เทอร์มินัล Linux จะเริ่มต้นหลังจากติดตั้งเสร็จแล้ว"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"ติดตั้งไม่สำเร็จเนื่องจากมีปัญหาเครือข่าย"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"ติดตั้งไม่สำเร็จเนื่องจากไม่มี Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"ติดตั้งไม่สำเร็จ โปรดลองอีกครั้ง"</string>
<string name="action_settings" msgid="5729342767795123227">"การตั้งค่า"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"กำลังเตรียมเทอร์มินัล"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"กำลังหยุดเทอร์มินัล"</string>
<string name="vm_error_message" msgid="5231867246177661525">"เทอร์มินัลขัดข้อง"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"การปรับขนาดดิสก์"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"ปรับขนาด/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"การปรับขนาดดิสก์"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"ปรับขนาดรูทพาร์ติชัน"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ตั้งค่าขนาดดิสก์แล้ว"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"กำหนดขนาด <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> แล้ว"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"สูงสุด <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"ยกเลิก"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"รีสตาร์ทเพื่อใช้"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"การส่งต่อพอร์ต"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"กำหนดค่าการส่งต่อพอร์ต"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"เทอร์มินัลกำลังพยายามเปิดพอร์ตใหม่"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"พอร์ตที่ขอให้เปิด: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"ใช้"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ระบบจะรีสตาร์ทเทอร์มินัลเพื่อปรับขนาดดิสก์"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"ยืนยัน"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"การควบคุมพอร์ต"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"อนุญาต/ปฏิเสธพอร์ตที่กำลังรอการเชื่อมต่อ"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"พอร์ตที่กำลังรอการเชื่อมต่อ"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"บันทึกพอร์ตที่อนุญาตแล้ว"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"เพิ่ม"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"ลบ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"อนุญาตพอร์ตใหม่"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"ป้อนหมายเลขพอร์ตใหม่"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"บันทึก"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"ยกเลิก"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"โปรดป้อนหมายเลข"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"หมายเลขพอร์ตไม่ถูกต้อง"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"มีพอร์ตอยู่แล้ว"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"เทอร์มินัลกำลังส่งคำขอเปิดพอร์ตใหม่"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"พอร์ตที่ขอ: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ยอมรับ"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ปฏิเสธ"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"การกู้คืน"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"ตัวเลือกการกู้คืนพาร์ติชัน"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"เปลี่ยนเป็นเวอร์ชันเริ่มต้น"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"นำออกทั้งหมด"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"ตัวเลือกการกู้คืนพาร์ติชัน"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"รีเซ็ตเป็นเวอร์ชันเริ่มต้น"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"นำข้อมูลทั้งหมดออก"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"รีเซ็ตเทอร์มินัล"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ระบบจะลบข้อมูล"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"ยืนยัน"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ระบบจะนําข้อมูลออก"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"รีเซ็ต"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"ยกเลิก"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"สำรองข้อมูลไปยัง <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"กู้คืนไม่สำเร็จเนื่องจากสำรองข้อมูลไม่สำเร็จ"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"กู้คืนไม่สำเร็จเนื่องจากเกิดข้อผิดพลาดในการสำรองข้อมูล"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"การกู้คืนไม่สำเร็จ"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"นำไฟล์ข้อมูลสำรองออกไม่ได้"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"นําข้อมูลสํารองออกไม่สําเร็จ"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"นําข้อมูลสํารองออก"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"ล้าง <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"ข้อผิดพลาดที่กู้คืนไม่ได้"</string>
- <string name="error_desc" msgid="1939028888570920661">"กู้คืนจากข้อผิดพลาดไม่สำเร็จ\nคุณสามารถลองรีสตาร์ทแอปหรือลองใช้ตัวเลือกการกู้คืนได้"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"นำ <xliff:g id="PATH">/mnt/backup</xliff:g> ออก"</string>
+ <string name="error_title" msgid="405150657301906598">"ข้อผิดพลาดที่กู้คืนไม่ได้"</string>
+ <string name="error_desc" msgid="4588252235686826721">"กู้คืนจากข้อผิดพลาดไม่สำเร็จ\nคุณสามารถลองรีสตาร์ทเทอร์มินัลหรือลองใช้ตัวเลือกการกู้คืนได้\nหากพยายามดำเนินการทุกอย่างแล้วแต่ไม่สำเร็จ ให้ล้างข้อมูลทั้งหมดโดยเปิด/ปิดเทอร์มินัล Linux จากตัวเลือกสำหรับนักพัฒนาแอป"</string>
<string name="error_code" msgid="3585291676855383649">"รหัสข้อผิดพลาด: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"การตั้งค่า"</string>
<string name="service_notification_title" msgid="2918088850910713393">"เทอร์มินัลกำลังทำงาน"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"คลิกเพื่อเปิดเทอร์มินัล"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"คลิกเพื่อเปิดเทอร์มินัล"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"ปิด"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"เทอร์มินัลกำลังจะปิด"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"บังคับปิด"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"เปิดใช้งาน <xliff:g id="ID_1">VirGL</xliff:g> แล้ว"</string>
</resources>
diff --git a/android/TerminalApp/res/values-tl/strings.xml b/android/TerminalApp/res/values-tl/strings.xml
index 29f316e..56b2679 100644
--- a/android/TerminalApp/res/values-tl/strings.xml
+++ b/android/TerminalApp/res/values-tl/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Display ng terminal"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Cursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Walang lamang linya"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Mag-double tap para mag-type ng input"</string>
<string name="installer_title_text" msgid="500663060973466805">"I-install ang terminal ng Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Para ilunsad ang terminal ng Linux, kailangan mong mag-download ng humigit-kumulang <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> na data sa network.\nGusto mo bang magpatuloy?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"I-download kapag available ang Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Para ilunsad ang terminal ng Linux, kailangan mong mag-download ng humigit-kumulang <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> na data sa network.\nGusto mo bang magpatuloy?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Mag-download sa pamamagitan lang ng Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"I-install"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Ini-install"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Error sa network. Tingnan ang koneksyon at subukan ulit."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Hindi na-install dahil sa error sa network. Suriin ang iyong koneksyon at subukan ulit."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Ini-install ang terminal ng Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Magsisimula ang terminal ng Linux pagkatapos mag-install"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Hindi na-install dahil sa isyu sa network"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Hindi na-install. Subukan ulit."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Magsisimula ang terminal ng Linux pagkatapos ng pag-install"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Hindi na-install dahil sa isyu sa network"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Hindi na-install dahil walang Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Hindi na-install. Pakisubukan ulit"</string>
<string name="action_settings" msgid="5729342767795123227">"Mga Setting"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Inihahanda ang terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Hinihinto ang terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Nag-crash ang terminal"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"I-resize ang Disk"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"I-resize / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Pag-resize ng disk"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"I-resize ang laki ng root partition"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Nakatakda na ang laki ng disk"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ang nakatalaga"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> ang max"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Kanselahin"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"I-restart para gawin"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Pag-forward ng Port"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"I-configure ang pag-forward ng port"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Sinusubukan ng terminal na magbukas ng bagong port"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port na na-request na maging bukas: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Ilapat"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Ire-restart ang terminal para i-resize ang disk"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Kumpirmahin"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrol ng port"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Payagan/tanggihan ang mga port ng pakikinig"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Mga port sa pakikinig"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"I-save ang mga pinayagang port"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Magdagdag"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"I-delete ang <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Payagan ang bagong port"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Maglagay ng bagong port number"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"I-save"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Kanselahin"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Maglagay ng numero"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid na numero ng port"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Mayroon na ng port na ito"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Nag-request ang terminal na magbukas ng bagong port"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Ni-request na port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Tanggapin"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Tanggihan"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Pag-recover"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Mga opsyon sa Pag-recover ng Partition"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Baguhin sa inisyal na bersyon"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Alisin lahat"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Mga opsyon sa pag-recover ng partition"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"I-reset sa inisyal na bersyon"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Alisin ang lahat ng data"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"I-reset ang terminal"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Made-delete ang data"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Kumpirmahin"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Aalisin ang data"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"I-reset"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Kanselahin"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Mag-back up ng data sa <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Hindi na-recover dahil hindi gumana ang backup"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Hindi na-recover dahil sa error sa backup"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Hindi na-recover"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Hindi maalis ang backup file"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Hindi naalis ang backup na data"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Alisin ang backup data"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"I-clean up ang <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Hindi nare-recover na error"</string>
- <string name="error_desc" msgid="1939028888570920661">"Hindi naka-recover mula sa isang error.\nPuwede mong subukang i-restart ang app, o subukan ang isa sa mga opsyon sa pag-recover."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Alisin ang <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Hindi nare-recover na error"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Hindi naka-recover mula sa isang error.\nPuwede mong subukang i-restart ang terminal o subukan ang isa sa mga opsyon sa pag-recover.\nKung mabigo ang lahat ng pagtatangka, i-wipe ang lahat ng data sa pamamagitan ng pag-on/off sa terminal ng Linux mula sa mga opsyon ng developer."</string>
<string name="error_code" msgid="3585291676855383649">"Code ng error: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Mga Setting"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Gumagana ang terminal"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"I-click para buksan ang terminal"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"I-click para buksan ang terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Isara"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Nagsasara ang terminal"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Sapilitang isara"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"Na-enable ang <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-tr/strings.xml b/android/TerminalApp/res/values-tr/strings.xml
index 5ad93ae..4374923 100644
--- a/android/TerminalApp/res/values-tr/strings.xml
+++ b/android/TerminalApp/res/values-tr/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminal ekranı"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"İmleç"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Boş satır"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Yazarak giriş yapmak için iki kez dokunun"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux terminalini yükleyin"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux terminalini başlatmak için ağ üzerinden yaklaşık <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> veri indirmeniz gerekir.\nDevam etmek istiyor musunuz?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Kablosuz bağlantı olduğunda indir"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux terminalini başlatmak için ağ üzerinden yaklaşık <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> veri indirmeniz gerekir.\nDevam etmek istiyor musunuz?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Yalnızca kablosuz bağlantıyla indir"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Yükle"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Yükleniyor"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Ağ hatası. Bağlantıyı kontrol edip tekrar deneyin."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Bir ağ hatası nedeniyle yüklenemedi. Bağlantınızı kontrol edip tekrar deneyin."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux terminali yükleniyor"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminali, işlem tamamlandıktan sonra başlatılacak"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Ağ sorunu nedeniyle yüklenemedi."</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Yüklenemedi. Tekrar deneyin."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Linux terminali, yükleme işlemi tamamlandıktan sonra başlatılacak"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Ağ sorunu nedeniyle yüklenemedi"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Kablosuz bağlantı olmadığından yükleme işlemi başarısız oldu"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Yüklenemedi. Lütfen tekrar deneyin"</string>
<string name="action_settings" msgid="5729342767795123227">"Ayarlar"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminal hazırlanıyor"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminal durduruluyor"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal kilitlendi"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Diski yeniden boyutlandır"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Yeniden boyutlandır/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Diski yeniden boyutlandır"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Kök bölüm boyutunu yeniden ayarlayın"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disk boyutu ayarlandı"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> atandı"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"<xliff:g id="MAX_SIZE">%1$s</xliff:g> maks."</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"İptal"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Uygulamak için yeniden başlatın"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Bağlantı noktası yönlendirme"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Bağlantı noktası yönlendirmeyi yapılandır"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal yeni bir bağlantı noktası açmaya çalışıyor"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Açılması istenen bağlantı noktası: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Uygula"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Terminal, diski yeniden boyutlandırmak için yeniden başlatılacak"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Onayla"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Bağlantı noktası kontrolü"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dinelenen bağlantı noktalarına izin ver/izin verme"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Dinlenen bağlantı noktaları"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"İzin verilen kayıtlı bağlantı noktaları"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ekle"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Sil: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Yeni bir bağlantı noktasına izin verme"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Yeni bir bağlantı noktası numarası girin"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Kaydet"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"İptal"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Lütfen bir telefon numarası girin"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Bağlantı noktası numarası geçersiz"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Bağlantı noktası zaten mevcut"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal yeni bir bağlantı noktası açmak istiyor"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"İstenilen bağlantı noktası: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Kabul et"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Reddet"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Kurtarma"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Bölüm kurtarma seçenekleri"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"İlk sürüme geç"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Tümünü kaldır"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Bölüm kurtarma seçenekleri"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"İlk sürüme sıfırla"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Verilerin tümünü kaldır"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminali sıfırla"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Veriler silinecek"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Onayla"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Veriler kaldırılacak"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Sıfırla"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"İptal"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Verileri <xliff:g id="PATH">/mnt/backup</xliff:g> konumuna yedekle"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Yedekleme işlemi başarısız olduğu için kurtarma işlemi tamamlanamadı"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Yedekleme hatası nedeniyle kurtarılamadı"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Kurtarma işlemi başarısız oldu"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Yedek dosyası kaldırılamıyor"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Yedek veriler kaldırılamadı"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Yedek verileri kaldır"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> konumundaki verileri temizle"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> etiketini kaldır"</string>
+ <string name="error_title" msgid="405150657301906598">"Düzeltilemeyen hata"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Bir hatayı düzeltme işlemi başarısız oldu.\nTerminali yeniden başlatmayı veya kurtarma seçeneklerinden birini uygulamayı deneyebilirsiniz.\nTüm denemeler başarısız olursa geliştirici seçeneklerinden Linux terminalini açıp kapatarak tüm verileri temizleyin."</string>
+ <string name="error_code" msgid="3585291676855383649">"Hata kodu: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Ayarlar"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal çalışıyor"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Terminali açmak için tıklayın"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Terminali açmak için tıklayın"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Kapat"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal kapanıyor"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Uygulamayı kapat"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> etkinleştirildi"</string>
</resources>
diff --git a/android/TerminalApp/res/values-uk/strings.xml b/android/TerminalApp/res/values-uk/strings.xml
index c883d3a..bd2d574 100644
--- a/android/TerminalApp/res/values-uk/strings.xml
+++ b/android/TerminalApp/res/values-uk/strings.xml
@@ -17,65 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Термінал"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Дисплей термінала"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Курсор"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Пустий рядок"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Двічі торкніться, щоб ввести текст"</string>
<string name="installer_title_text" msgid="500663060973466805">"Установити термінал Linux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Щоб запустити термінал Linux, потрібно завантажити приблизно <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> даних через мережу.\nПродовжити?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Завантажити через Wi-Fi, коли буде доступно"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Щоб запустити термінал Linux, потрібно завантажити приблизно <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> даних через мережу.\nПродовжити?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Завантажувати лише через Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Установити"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Встановлення"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Помилка мережі. Перевірте з’єднання й повторіть спробу."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Не вдалося встановити через помилку мережі. Перевірте з’єднання й повторіть спробу."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Встановлення термінала Linux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Після завершення буде запущено термінал Linux"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Не вдалося встановити через проблему з мережею"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Не вдалося встановити. Повторіть спробу."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Термінал Linux запуститься після встановлення"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Не вдалося встановити через проблему з мережею"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Не вдалося встановити, оскільки немає Wi-Fi-з’єднання"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Не вдалося встановити. Повторіть спробу."</string>
<string name="action_settings" msgid="5729342767795123227">"Налаштування"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Підготовка термінала"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Зупинка термінала"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Збій термінала"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Зміна розміру диска"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Змінити розмір/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Зміна розміру диска"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Змінити розмір кореневого розділу"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Розмір диска вказано"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Виділено <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Максимальний розмір: <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Скасувати"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Перезапустити, щоб застосувати"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Переадресація порту"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Налаштувати переадресацію порту"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Термінал намагається відкрити новий порт"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Порт, який потрібно відкрити: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Застосувати"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Термінал буде перезапущено, щоб змінити розмір диска"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Підтвердити"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Керування портами"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дозволити/заборонити порти прослуховування"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Порти прослуховування"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Збережені дозволені порти"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Додати"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Видалити <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Дозволити новий порт"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Введіть новий номер порту"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Зберегти"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Скасувати"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Введіть номер"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Недійсний номер порту"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт уже існує"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Термінал просить відкрити новий порт"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Порт, указаний у запиті: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прийняти"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Відхилити"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Відновлення"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Способи відновлення розділів"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Змінити на початкову версію"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Видалити все"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Способи відновлення розділів"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Відновити початкову версію"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Видалити всі дані"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Скинути налаштування термінала"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Дані буде видалено"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Підтвердити"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Дані буде видалено"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Скинути"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Скасувати"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Створити резервну копію даних у <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Не вдалося відновити, оскільки резервну копію не створено"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Не вдалося відновити через помилку резервного копіювання"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Не вдалося відновити"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Не вдалося вилучити файл резервної копії"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Не вдалося видалити резервну копію даних"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Видалити резервну копію даних"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Очистити <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <!-- no translation found for error_title (7196464038692913778) -->
- <skip />
- <!-- no translation found for error_desc (1939028888570920661) -->
- <skip />
- <!-- no translation found for error_code (3585291676855383649) -->
- <skip />
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Видалити <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Помилка з неможливістю відновлення"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Не вдалося виконати відновлення після помилки.\nСпробуйте перезапустити термінал або скористатись одним зі способів відновлення.\nЯкщо це не допоможе, очистьте всі дані, увімкнувши або вимкнувши термінал Linux у параметрах розробника."</string>
+ <string name="error_code" msgid="3585291676855383649">"Код помилки: <xliff:g id="ERROR_CODE">%s</xliff:g>."</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Налаштування"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Термінал запущено"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Натисніть, щоб відкрити термінал"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Натисніть, щоб відкрити термінал"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Закрити"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Термінал закривається"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Примусово закрити"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> увімкнено"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ur/strings.xml b/android/TerminalApp/res/values-ur/strings.xml
index 81c051f..3ad7c39 100644
--- a/android/TerminalApp/res/values-ur/strings.xml
+++ b/android/TerminalApp/res/values-ur/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"ٹرمینل"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"ٹرمینل ڈسپلے"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"کرسر"</string>
+ <string name="empty_line" msgid="5012067143408427178">"خالی لائن"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"ان پٹ ٹائپ کرنے کے لیے دو بار تھپتھپائیں"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux ٹرمینل انسٹال کریں"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux ٹرمینل کو شروع کرنے کے لیے، آپ کو نیٹ ورک پر تقریباً <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ڈیٹا ڈاؤن لوڈ کرنا ہوگا۔\nکیا آپ آگے بڑھیں گے؟"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi دستیاب ہونے پر ڈاؤن لوڈ کریں"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux ٹرمینل شروع کرنے کے لیے، آپ کو نیٹ ورک پر تقریباً <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> ڈیٹا ڈاؤن لوڈ کرنا ہوگا۔\nکیا آپ آگے بڑھنا چاہیں گے؟"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"صرف Wi-Fi کا استعمال کر کے ڈاؤن لوڈ کریں"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"انسٹال کریں"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"انسٹال کیا جا رہا ہے"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"نیٹ ورک کی خرابی۔ کنکشن چیک کریں اور دوبارہ کوشش کریں۔"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"نیٹ ورک کی خرابی کی وجہ سے انسٹال نہیں کیا جا سکا۔ اپنا کنکشن چیک کریں اور دوبارہ کوشش کریں۔"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux ٹرمینل انسٹال ہو رہا ہے"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"مکمل ہونے کے بعد Linux ٹرمینل شروع کیا جا سکے گا"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"نیٹ ورک میں خرابی کی وجہ سے انسٹال نہیں کیا جا سکا"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"انسٹال نہیں کیا جا سکا۔ دوبارہ کوشش کریں۔"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"انسٹالیشن مکمل ہونے کے بعد Linux ٹرمینل شروع ہو جائے گا"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"نیٹ ورک کے مسئلے کی وجہ سے انسٹال نہیں کیا جا سکا"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi دستیاب نہ ہونے کی وجہ سے انسٹال نہیں کیا جا سکا"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"انسٹال نہیں کیا جا سکا۔ براہ کرم دوبارہ کوشش کریں"</string>
<string name="action_settings" msgid="5729342767795123227">"ترتیبات"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"ٹرمینل تیار ہو رہا ہے"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"ٹرمینل کو روکا جا رہا ہے"</string>
<string name="vm_error_message" msgid="5231867246177661525">"ٹرمینل کریش ہو گیا"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"ڈسک کا سائز تبدیل کریں"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"سائز تبدیل کریں / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"ڈسک کا سائز تبدیل کریں"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"روٹ پارٹیشن کا سائز تبدیل کریں"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"ڈسک کے سائز کا سیٹ"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> تفویض کردہ"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"زیادہ سے زیادہ <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"منسوخ کریں"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"لاگو کرنے کے لیے ری سٹارٹ کریں"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"پورٹ فارورڈنگ"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"پورٹ فارورڈنگ کو کنفیگر کریں"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"ٹرمینل ایک نیا پورٹ کھولنے کی کوشش کر رہا ہے"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"پورٹ کو کھولنے کی درخواست کی گئی ہے: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"لاگو کریں"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"ڈسک کا سائز تبدیل کرنے کے لیے ٹرمینل کو ری سٹارٹ کیا جائے گا"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"تصدیق کریں"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"پورٹ کنٹرول"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"لسننگ پورٹس کو اجازت دیں/مسترد کریں"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"لسننگ پورٹس"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"اجازت یافتہ پورٹس کو محفوظ کیا گیا"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"شامل کریں"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> حذف کریں"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"نئے پورٹ کی اجازت دی"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"نیا پورٹ نمبر درج کریں"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"محفوظ کریں"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"منسوخ کریں"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"براہ کرم ایک نمبر درج کریں"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"غلط پورٹ نمبر"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"پورٹ پہلے سے موجود ہے"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ٹرمینل ایک نیا پورٹ کھولنے کی درخواست کر رہا ہے"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"پورٹ کی درخواست کی گئی: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"قبول کریں"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"مسترد کریں"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"بازیابی"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"پارٹیشن کی بازیابی کے اختیارات"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"ابتدائی ورژن میں تبدیلی"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"سبھی ہٹائیں"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"پارٹیشن کی بازیابی کے اختیارات"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"ابتدائی ورژن پر ری سیٹ کریں"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"سبھی ڈیٹا ہٹائیں"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"ٹرمینل ری سیٹ کریں"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"ڈیٹا حذف کر دیا جائے گا"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"تصدیق کریں"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"ڈیٹا ہٹا دیا جائے گا"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"ری سیٹ کریں"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"منسوخ کریں"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"<xliff:g id="PATH">/mnt/backup</xliff:g> پر ڈیٹا کا بیک اپ لیں"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"بیک اپ ناکام ہونے کی وجہ سے بازیابی ناکام ہو گئی"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"بیک اپ کی خرابی کی وجہ سے بازیاب نہیں کیا جا سکا"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"بازیابی ناکام ہو گئی"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"بیک اپ فائل کو ہٹایا نہیں جا سکتا"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"بیک اپ ڈیٹا نہیں ہٹایا جا سکا"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"بیک اپ ڈیٹا ہٹائیں"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"<xliff:g id="PATH">/mnt/backup</xliff:g> کو ہٹائیں"</string>
- <string name="error_title" msgid="7196464038692913778">"نا قابل بازیابی کی خرابی"</string>
- <string name="error_desc" msgid="1939028888570920661">"ایک خرابی سے بازیافت کرنے میں ناکام۔\nآپ ایپ کو ری اسٹارٹ کرنے کی کوشش کر سکتے ہیں یا بازیابی کے اختیارات میں سے ایک کو آزما سکتے ہیں۔"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"<xliff:g id="PATH">/mnt/backup</xliff:g> ہٹائیں"</string>
+ <string name="error_title" msgid="405150657301906598">"نا قابل بازیابی کی خرابی"</string>
+ <string name="error_desc" msgid="4588252235686826721">"کسی خرابی سے بازیاب کرنے میں ناکام۔\nآپ ٹرمینل کو ری اسٹارٹ کرنے کی کوشش کر سکتے ہیں یا بازیابی کے اختیارات میں سے ایک اختیار آزما سکتے ہیں۔\nاگر تمام کوششیں ناکام ہوتی ہیں تو ڈویلپر کے اختیارات سے Linux ٹرمینل کو آن/آف کر کے تمام ڈیٹا صاف کریں۔"</string>
<string name="error_code" msgid="3585291676855383649">"خرابی کا کوڈ: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"ترتیبات"</string>
<string name="service_notification_title" msgid="2918088850910713393">"ٹرمینل چل رہا ہے"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"ٹرمینل کھولنے کے لیے کلک کریں"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"ٹرمینل کھولنے کے لیے کلک کریں"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"بند کریں"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"ٹرمینل بند ہو رہا ہے"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"زبردستی بند کریں"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> فعال ہے"</string>
</resources>
diff --git a/android/TerminalApp/res/values-uz/strings.xml b/android/TerminalApp/res/values-uz/strings.xml
index 8093ef1..159d04c 100644
--- a/android/TerminalApp/res/values-uz/strings.xml
+++ b/android/TerminalApp/res/values-uz/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Terminal displeyi"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Kursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Boʻsh qator"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Matn kiritish uchun ikki marta bosing"</string>
<string name="installer_title_text" msgid="500663060973466805">"Linux terminalini oʻrnatish"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Linux terminalini ishga tushirish uchun tarmoq orqali taxminan <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> axborot yuklab olish kerak.\nDavom etilsinmi?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Wi-Fi tarmoqqa ulanganda yuklab olish"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Linux terminalini ishga tushirish uchun tarmoq orqali taxminan <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> axborot yuklab olish kerak.\nDavom etilsinmi?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Faqat Wi-Fi orqali yuklab olish"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Oʻrnatish"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Oʻrnatilmoqda"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Tarmoq xatosi. Aloqani tekshirib, qayta urining."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Tarmoq xatosi tufayli oʻrnatilmadi. Ulanishni tekshirib, qaytadan urining."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Linux terminali oʻrnatilmoqda"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminali oʻrnatilganidan keyin ishga tushadi"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Tarmoq xatosi sababli oʻrnatilmadi"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Oʻrnatilmadi. Qayta urining."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Oʻrnatish yakunlangach, Linux terminali ishga tushadi"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Tarmoq xatosi sababli oʻrnatilmadi"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Wi-Fi mavjud emasligi sababli oʻrnatilmadi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Oʻrnatilmadi. Qayta urining"</string>
<string name="action_settings" msgid="5729342767795123227">"Sozlamalar"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Terminal tayyorlanmoqda"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Terminal toʻxtatilmoqda"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal ishdan chiqdi"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Disk hajmini oʻzgartirish"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Hajmini oʻzgartirish / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Disk hajmini oʻzgartirish"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Root boʻlimi hajmini oʻzgartirish"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Disk hajmi belgilandi"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> ajratilgan"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Maks <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Bekor qilish"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Qoʻllash uchun qayta yoqing"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Portni uzatish"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Portni uzatish sozlamalari"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal yangi port ochishga urinmoqda"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Port ochishga ruxsat soʻraldi: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Tatbiq etish"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Disk hajmini oʻzgartirish uchun terminal qayta ishga tushiriladi"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Tasdiqlash"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portlar boshqaruvi"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Uzatish portlariga ruxsat berish/ularni taqiqlash"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Uzatish postlari"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ruxsat etilgan portlar saqlandi"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Qoʻshish"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> hisobini oʻchirish"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Yangi portga ruxsat bering"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Yangi port raqamini kiriting"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Saqlash"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Bekor qilish"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Raqamni kiriting"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Port raqami yaroqsiz"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port allaqachon mavjud"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal yangi port ochishni talab qilmoqda"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Talab qilingan port: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Qabul qilish"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rad etish"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Tiklash"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Disk boʻlimini tiklash opsiyalari"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Dastlabki versiyaga oʻzgartirish"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Hammasini tozalash"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Disk boʻlimini tiklash usullari"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Dastlabki versiyaga qaytarish"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Barcha maʼlumotlarni tozalash"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Terminalni asliga qaytarish"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Maʼlumotlar oʻchib ketadi"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Tasdiqlash"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Maʼlumotlar olib tashlanadi"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Tiklash"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Bekor qilish"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Maʼlumotlarni bu yerga zaxiralash: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Zaxiralash amalga oshmagani uchun tiklanmadi"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Zaxiralash xatosi tufayli tiklanmadi"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Tiklanmadi"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Zaxira fayli olib tashlanmadi"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Zaxira maʼlumotlari olib tashlanmadi"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Zaxira maʼlumotlarini olib tashlash"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Tozalash: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Qayta tiklanmaydigan xato"</string>
- <string name="error_desc" msgid="1939028888570920661">"Xatolikdan tiklanmadi.\nIlovani qayta ishga tushirishingiz yoki tiklash usullaridan birini sinashingiz mumkin."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Olib tashlash: <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Qayta tiklanmaydigan xato"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Xatolikdan tiklanmadi.\nTerminalni qayta ishga tushirishingiz yoki tiklash variantlaridan birini bajarishingiz mumkin.\nAgar barcha urinishlar muvaffaqiyatsiz chiqsa, dasturchi parametrlaridan Linux terminalini yoqish/oʻchirish orqali barcha maʼlumotlarni oʻchirib tashlang."</string>
<string name="error_code" msgid="3585291676855383649">"Xatolik kodi: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Sozlamalar"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal ishga tushgan"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Terminalni ochish uchun bosing"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Terminalni ochish uchun bosing"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Yopish"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal yopilmoqda"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Majburiy yopish"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> yoniq"</string>
</resources>
diff --git a/android/TerminalApp/res/values-vi/strings.xml b/android/TerminalApp/res/values-vi/strings.xml
index dd6c5f5..d7d6c93 100644
--- a/android/TerminalApp/res/values-vi/strings.xml
+++ b/android/TerminalApp/res/values-vi/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Terminal"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Màn hình cửa sổ dòng lệnh"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Con trỏ"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Dòng trống"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Nhấn đúp để nhập nội dung"</string>
<string name="installer_title_text" msgid="500663060973466805">"Cài đặt Linux terminal"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Để chạy Linux terminal, bạn cần tải khoảng <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dữ liệu xuống qua mạng.\nBạn có muốn tiếp tục không?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Tải xuống khi có Wi-Fi"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Để chạy ứng dụng Terminal trên Linux, bạn cần tải khoảng <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> dữ liệu xuống qua mạng.\nBạn có muốn tiếp tục không?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Chỉ tải xuống qua Wi-Fi"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Cài đặt"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Đang cài đặt"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Lỗi mạng. Hãy kiểm tra trạng thái kết nối rồi thử lại."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Không cài đặt được do lỗi mạng. Hãy kiểm tra kết nối của bạn rồi thử lại."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Đang cài đặt Linux terminal"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux terminal sẽ khởi động sau khi cài đặt xong"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Không cài đặt được do sự cố mạng"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Không cài đặt được. Hãy thử lại."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Ứng dụng Terminal trên Linux sẽ khởi động sau khi quá trình cài đặt hoàn tất"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Không cài đặt được do sự cố mạng"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Không cài đặt được do không có Wi-Fi"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Không cài đặt được. Vui lòng thử lại"</string>
<string name="action_settings" msgid="5729342767795123227">"Cài đặt"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Đang chuẩn bị Terminal"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Đang dừng Terminal"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Terminal gặp sự cố"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Đổi kích thước ổ đĩa"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Đổi kích thước/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Đổi kích thước ổ đĩa"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Đổi kích thước phân vùng gốc"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Đã đặt dung lượng ổ đĩa"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"Ðã phân bổ <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Tối đa <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Huỷ"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Chạy lại để áp dụng"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Chuyển tiếp cổng"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Định cấu hình tính năng chuyển tiếp cổng"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Terminal đang cố mở một cổng mới"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Cổng được yêu cầu mở: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Áp dụng"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Ứng dụng Terminal sẽ khởi động lại để đổi kích thước ổ đĩa"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Xác nhận"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kiểm soát cổng"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Cho phép/từ chối cổng nghe"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Cổng nghe"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Đã lưu các cổng được cho phép"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Thêm"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Xoá <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Cho phép một cổng mới"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Nhập số cổng mới"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Lưu"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Huỷ"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Vui lòng nhập một số"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Số cổng không hợp lệ"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Cổng đã tồn tại"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Ứng dụng Terminal đang yêu cầu mở một cổng mới"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Cổng được yêu cầu: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Chấp nhận"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Từ chối"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Khôi phục"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Tuỳ chọn khôi phục phân vùng"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Chuyển về phiên bản ban đầu"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Xoá tất cả"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Tuỳ chọn khôi phục phân vùng"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Đặt lại về phiên bản ban đầu"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Xoá mọi dữ liệu"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Đặt lại cửa sổ dòng lệnh"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Dữ liệu sẽ bị xoá"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Xác nhận"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Dữ liệu sẽ bị xoá"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Đặt lại"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Huỷ"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Sao lưu dữ liệu vào <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Không khôi phục được vì không sao lưu được"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Không khôi phục được do lỗi sao lưu"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Không khôi phục được"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Không xoá được tệp sao lưu"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Không xoá được dữ liệu sao lưu"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Xoá dữ liệu sao lưu"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Dọn dẹp <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Lỗi không thể khôi phục"</string>
- <string name="error_desc" msgid="1939028888570920661">"Không khôi phục được dữ liệu sau khi xảy ra lỗi.\nBạn có thể thử khởi động lại ứng dụng hoặc thử một trong các tuỳ chọn khôi phục."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Xoá <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Lỗi không thể khôi phục"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Không khôi phục được dữ liệu sau khi xảy ra lỗi.\nBạn có thể thử khởi động lại ứng dụng Terminal hoặc thử một trong các tuỳ chọn khôi phục.\nNếu tất cả các cách đều không hiệu quả, hãy xoá sạch mọi dữ liệu bằng cách bật/tắt ứng dụng Terminal trên Linux trong phần tuỳ chọn cho nhà phát triển."</string>
<string name="error_code" msgid="3585291676855383649">"Mã lỗi: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Cài đặt"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Terminal đang chạy"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Nhấp để mở cửa sổ dòng lệnh"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Nhấp để mở ứng dụng Terminal"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Đóng"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Terminal đang đóng"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Buộc đóng"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> đã được bật"</string>
</resources>
diff --git a/android/TerminalApp/res/values-zh-rCN/strings.xml b/android/TerminalApp/res/values-zh-rCN/strings.xml
index 266e4b5..31cf746 100644
--- a/android/TerminalApp/res/values-zh-rCN/strings.xml
+++ b/android/TerminalApp/res/values-zh-rCN/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"终端"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"终端显示内容"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"光标"</string>
+ <string name="empty_line" msgid="5012067143408427178">"空行"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"点按两次即可输入"</string>
<string name="installer_title_text" msgid="500663060973466805">"安装 Linux 终端"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"如需启动 Linux 终端,您需要联网下载大约 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> 的数据。\n要继续吗?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"连接到 WLAN 时下载"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"如需启动 Linux 终端,您需要联网下载大约 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> 的数据。\n要继续吗?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"仅通过 WLAN 下载"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"安装"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"正在安装"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"网络错误。请检查网络连接,然后重试。"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"由于网络连接错误,安装失败。请检查网络连接状态,然后重试。"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"正在安装 Linux 终端"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"完成后将启动 Linux 终端"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"由于网络问题,安装失败"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"安装失败。请重试。"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"安装完成后将启动 Linux 终端"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"由于网络问题,安装失败"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"由于 WLAN 不可用,安装失败"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"安装失败,请重试"</string>
<string name="action_settings" msgid="5729342767795123227">"设置"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"正在准备终端"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"正在停止终端"</string>
<string name="vm_error_message" msgid="5231867246177661525">"终端已崩溃"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"调整磁盘大小"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"调整大小/Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"调整磁盘大小"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"调整根分区的大小"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"已设置磁盘大小"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"已分配 <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"最大为 <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"取消"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"重启以应用"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"端口转发"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"配置端口转发"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"终端正在尝试打开新端口"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"请求打开的端口:<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"应用"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"终端将重启以调整磁盘大小"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"确认"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"端口控制"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"允许/拒绝使用监听端口"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"监听端口"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g>(<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"已保存的获准端口"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"添加"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"删除“<xliff:g id="PORT_NUMBER">%d</xliff:g>”"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"允许使用新端口"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"输入新端口号"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"保存"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"取消"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"请输入数字"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"端口号无效"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"端口已存在"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"终端正在请求打开新端口"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"请求的端口:<xliff:g id="PORT_NUMBER">%1$d</xliff:g>(<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"接受"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"拒绝"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"恢复"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"分区恢复选项"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"更改为初始版本"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"全部移除"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"分区恢复选项"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"重置为初始版本"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"移除所有数据"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"重置终端"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"数据将被删除"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"确认"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"数据将被移除"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"重置"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"取消"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"将数据备份到 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"备份失败,因此无法恢复"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"由于备份错误,无法恢复"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"恢复失败"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"无法移除备份文件"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"未能移除备份数据"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"移除备份数据"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"清理 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"不可恢复的错误"</string>
- <string name="error_desc" msgid="1939028888570920661">"未能从错误中恢复。\n您可以尝试重新启动该应用,或尝试某一恢复选项。"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"移除 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"不可恢复的错误"</string>
+ <string name="error_desc" msgid="4588252235686826721">"未能从错误中恢复。\n您可以尝试重启终端,或尝试某一恢复选项。\n如果所有尝试都失败,请通过在“开发者选项”中开启/关闭 Linux 终端来擦除所有数据。"</string>
<string name="error_code" msgid="3585291676855383649">"错误代码:<xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"设置"</string>
<string name="service_notification_title" msgid="2918088850910713393">"终端正在运行"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"点按即可打开终端"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"点击即可打开终端"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"关闭"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"终端即将关闭"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"强行关闭"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> 已启用"</string>
</resources>
diff --git a/android/TerminalApp/res/values-zh-rHK/strings.xml b/android/TerminalApp/res/values-zh-rHK/strings.xml
index 463b221..1284ecc 100644
--- a/android/TerminalApp/res/values-zh-rHK/strings.xml
+++ b/android/TerminalApp/res/values-zh-rHK/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"終端機"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"終端機顯示畫面"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"游標"</string>
+ <string name="empty_line" msgid="5012067143408427178">"空白行"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"㩒兩下就可以將文字轉語音"</string>
<string name="installer_title_text" msgid="500663060973466805">"安裝 Linux 終端機"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"如要啟動 Linux 終端機,你需要透過網絡下載約 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> 資料。\n要繼續嗎?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"連接 Wi-Fi 時下載"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"如要啟動 Linux 終端機,你需要透過網絡下載約 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> 資料。\n要繼續嗎?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"只透過 Wi-Fi 下載"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"安裝"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"正在安裝"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"網絡錯誤。請檢查網絡連線,然後重試。"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"發生網絡錯誤,因此無法安裝。請檢查連線,然後再試一次。"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"正在安裝 Linux 終端機"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Linux 將於安裝完成後開啟"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"由於網絡發生問題,因此無法安裝"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"無法安裝,請再試一次。"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"安裝完成後,Linux 終端機將會啟動"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"由於網絡發生問題,因此無法安裝"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"由於沒有可用的 Wi-Fi,因此無法安裝"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"無法安裝,請再試一次"</string>
<string name="action_settings" msgid="5729342767795123227">"設定"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"正在準備終端機"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"正在停止終端機"</string>
<string name="vm_error_message" msgid="5231867246177661525">"終端機當機"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"調整磁碟大小"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"調整大小 / Rootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"調整磁碟大小"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"調整 root 分區大小"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"已設定磁碟大小"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"已指派 <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"最多 <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"取消"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"重新啟動即可套用"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"連接埠轉送"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"設定連接埠轉送"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"終端機正在嘗試開啟新的連接埠"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"要求開啟的連接埠:<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"套用"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"終端機將會重新開機以調整磁碟大小"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"確認"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"連接埠控制項"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"允許/拒絕聆聽連接埠"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"聆聽連接埠"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"已儲存許可的連接埠"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"新增"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"刪除 <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"允許存取新的連接埠"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"輸入新的連接埠號碼"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"儲存"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"取消"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"請輸入數字"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"連接埠號碼無效"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"連接埠已存在"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"終端機正在要求開啟新的連接埠"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"已要求連接埠:<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"接受"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"拒絕"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"復原"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"分區復原選項"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"變更至初始版本"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"全部移除"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"分區復原選項"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"重設至初始版本"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"移除所有資料"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"重設終端機"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"資料將被刪除"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"確認"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"系統將會移除資料"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"重設"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"取消"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"將資料備份至 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"由於備份失敗,因此無法復原"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"由於出現備份錯誤,因此無法復原"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"無法復原"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"無法移除備份檔案"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"無法移除備份資料"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"移除備份資料"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"清理 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"無法復原的錯誤"</string>
- <string name="error_desc" msgid="1939028888570920661">"無法從錯誤中復原。\n你可嘗試重新啟動應用程式,或使用其中一個復原選項。"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"移除 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"無法復原的錯誤"</string>
+ <string name="error_desc" msgid="4588252235686826721">"無法從錯誤中復原。\n你可嘗試重新啟動終端機,或使用其中一個復原選項。\n如果各種嘗試皆失敗,前往開發人員選項開啟/關閉 Linux 終端機即可抹除所有資料。"</string>
<string name="error_code" msgid="3585291676855383649">"錯誤代碼:<xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"設定"</string>
<string name="service_notification_title" msgid="2918088850910713393">"終端機執行中"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"按一下即可開啟終端機"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"按一下以開啟終端機"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"關閉"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"終端機正在關閉"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"強制關閉"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"已啟用 <xliff:g id="ID_1">VirGL</xliff:g>"</string>
</resources>
diff --git a/android/TerminalApp/res/values-zh-rTW/strings.xml b/android/TerminalApp/res/values-zh-rTW/strings.xml
index 83a667b..7391300 100644
--- a/android/TerminalApp/res/values-zh-rTW/strings.xml
+++ b/android/TerminalApp/res/values-zh-rTW/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"終端機"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"終端機顯示畫面"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"游標"</string>
+ <string name="empty_line" msgid="5012067143408427178">"空白行"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"輕觸兩下即可輸入"</string>
<string name="installer_title_text" msgid="500663060973466805">"安裝 Linux 終端機"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"如要啟動 Linux 終端機,必須透過網路下載大約 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> 的資料。\n要繼續嗎?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"連上 Wi-Fi 網路時下載"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"如要啟動 Linux 終端機,必須透過網路下載大約 <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> 的資料。\n要繼續嗎?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"僅透過 Wi-Fi 下載"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"安裝"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"安裝中"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"網路發生錯誤。請檢查連線狀況,然後再試一次。"</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"網路發生錯誤,因此無法安裝。請檢查連線狀態,然後再試一次。"</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"正在安裝 Linux 終端機"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"完成後將啟動 Linux 終端機"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"網路發生問題,因此無法安裝"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"無法安裝,請再試一次。"</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"安裝完成後將啟動 Linux 終端機"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"網路發生問題,因此無法安裝"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"無法連上 Wi-Fi,因此無法安裝"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"無法安裝,請再試一次"</string>
<string name="action_settings" msgid="5729342767795123227">"設定"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"正在準備終端機"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"正在停止終端機"</string>
<string name="vm_error_message" msgid="5231867246177661525">"終端機當機"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"調整磁碟大小"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"調整 Rootfs 大小"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"調整磁碟大小"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"調整根分區大小"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"已設定磁碟大小"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"已指派 <xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"最多 <xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"取消"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"重新啟動即可套用"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"通訊埠轉送"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"設定通訊埠轉送"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"終端機正在嘗試開啟新的通訊埠"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"要求開啟的通訊埠:<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"套用"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"終端機將重新啟動,以調整磁碟大小"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"確認"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"通訊埠控制"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"允許/拒絕監聽通訊埠"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"監聽通訊埠"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"已儲存允許的通訊埠"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"新增"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"刪除 <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"允許的新通訊埠"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"輸入新的通訊埠號碼"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"儲存"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"取消"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"請輸入數字"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"通訊埠號碼無效"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"已有這個通訊埠"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"終端機正在要求開啟新的通訊埠"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"要求的通訊埠:<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"接受"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"拒絕"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"復原"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"分區復原選項"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"變更為初始版本"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"全部移除"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"分區復原選項"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"重設為初始版本"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"移除所有資料"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"重設終端機"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"資料將刪除"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"確認"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"資料將移除"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"重設"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"取消"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"將資料備份至 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"備份失敗,因此無法復原"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"備份發生錯誤,因此無法復原"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"無法復原"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"無法移除備份檔案"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"無法移除備份資料"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"移除備份資料"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"清除 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"無法復原的錯誤"</string>
- <string name="error_desc" msgid="1939028888570920661">"無法從錯誤中復原。\n你可以嘗試重新啟動應用程式,或使用其中一個復原選項。"</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"移除 <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"無法復原的錯誤"</string>
+ <string name="error_desc" msgid="4588252235686826721">"無法從錯誤中復原。\n你可以試著重新啟動終端機,也可以使用其中一個復原選項。\n如果都無法解決問題,請使用開發人員選項開啟/關閉 Linux 終端機,抹除所有資料。"</string>
<string name="error_code" msgid="3585291676855383649">"錯誤代碼:<xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"設定"</string>
<string name="service_notification_title" msgid="2918088850910713393">"終端機運作中"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"點選即可開啟終端機"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"點選即可開啟終端機"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"關閉"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"終端機正在關閉"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"強制關閉"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> 已啟用"</string>
</resources>
diff --git a/android/TerminalApp/res/values-zu/strings.xml b/android/TerminalApp/res/values-zu/strings.xml
index a15dcda..4036ec1 100644
--- a/android/TerminalApp/res/values-zu/strings.xml
+++ b/android/TerminalApp/res/values-zu/strings.xml
@@ -17,62 +17,74 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="5597111707986572208">"Itheminali"</string>
- <!-- no translation found for terminal_display (4810127497644015237) -->
- <skip />
- <!-- no translation found for terminal_input (4602512831433433551) -->
- <skip />
- <!-- no translation found for empty_line (5012067143408427178) -->
- <skip />
+ <string name="terminal_display" msgid="4810127497644015237">"Isibonisi setheminali"</string>
+ <string name="terminal_input" msgid="4602512831433433551">"Icursor"</string>
+ <string name="empty_line" msgid="5012067143408427178">"Umugqa ongenalutho"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"Thepha kabili ukuze uthayiphe okokufaka"</string>
<string name="installer_title_text" msgid="500663060973466805">"Faka itheminali yeLinux"</string>
- <string name="installer_desc_text_format" msgid="2734224805682171826">"Ukuze uqalise itheminali yeLinux, udinga ukudawuniloda cishe idatha u-<xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> kunethiwekhi.\nUngathanda ukuqhubeka?"</string>
- <string name="installer_wait_for_wifi_checkbox_text" msgid="487720664098014506">"Dawuniloda lapho i-Wi-Fi itholakala"</string>
+ <string name="installer_desc_text_format" msgid="5935117404303982823">"Ukuze uqalise itheminali yeLinux, udinga ukudawuniloda cishe idatha engaba ngu-<xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> kunethiwekhi.\nUngathanda yini ukuqhubeka?"</string>
+ <string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"Dawuniloda usebenzisa i-Wi-Fi kuphela"</string>
<string name="installer_install_button_enabled_text" msgid="6142090640081511103">"Faka"</string>
<string name="installer_install_button_disabled_text" msgid="8651445004125422467">"Iyafaka"</string>
- <string name="installer_install_network_error_message" msgid="2450409107529774410">"Iphutha lenethiwekhi. Hlola uxhumo bese uyazama futhi."</string>
+ <string name="installer_install_network_error_message" msgid="6483202005746623398">"Yehlulekile ukufaka ngenxa yephutha lenethiwekhi. Hlola uxhumo lwakho uphinde uzame futhi."</string>
<string name="installer_notif_title_text" msgid="471160690081159042">"Ifaka itheminali yeLinux"</string>
- <string name="installer_notif_desc_text" msgid="6746098106305899060">"Itheminali yeLinux izoqalwa ngemva kokuqeda"</string>
- <string name="installer_error_network" msgid="3265100678310833813">"Yehlulekile ukufaka ngenxa yenkinga yenethiwekhi"</string>
- <!-- no translation found for installer_error_no_wifi (8631584648989718121) -->
- <skip />
- <string name="installer_error_unknown" msgid="1991780204241177455">"Yehlulekile ukufaka. Zama futhi."</string>
+ <string name="installer_notif_desc_text" msgid="2353770076549425837">"Itheminali yeLinux izoqala ngemva kokuqedwa kokufakwa"</string>
+ <string name="installer_error_network" msgid="5627330072955876676">"Yehlulekile ukufaka ngenxa yenkinga yenethiwekhi"</string>
+ <string name="installer_error_no_wifi" msgid="1180164894845030969">"Yehlulekile ukufaka ngoba i-Wi-Fi ayitholakali"</string>
+ <string name="installer_error_unknown" msgid="5657920711470180224">"Yehlulekile ukufaka. Sicela uzame futhi"</string>
<string name="action_settings" msgid="5729342767795123227">"Amasethingi"</string>
<string name="vm_creation_message" msgid="6594953532721367502">"Ilungiselela itheminali"</string>
<string name="vm_stop_message" msgid="3978349856095529255">"Itheminali yokumisa"</string>
<string name="vm_error_message" msgid="5231867246177661525">"Itheminali iphahlazekile"</string>
- <string name="settings_disk_resize_title" msgid="1545791169419914600">"Shintsha Usayizi Wediski"</string>
- <string name="settings_disk_resize_sub_title" msgid="149418971610906138">"Shintsha usayizi / IRootfs"</string>
+ <string name="settings_disk_resize_title" msgid="8648082439414122069">"Shintsha usayizi wediski"</string>
+ <string name="settings_disk_resize_sub_title" msgid="568100064927028058">"Shintsha usayizi kasayizi wokuhlukanisa umsuka"</string>
<string name="settings_disk_resize_resize_message" msgid="5990475712303845087">"Usayizi wediski usethiwe"</string>
<string name="settings_disk_resize_resize_gb_assigned_format" msgid="109301857555401579">"U-<xliff:g id="ASSIGNED_SIZE">%1$s</xliff:g> wabiwe"</string>
<string name="settings_disk_resize_resize_gb_max_format" msgid="6221210151688630371">"Umkhawulo ka-<xliff:g id="MAX_SIZE">%1$s</xliff:g>"</string>
<string name="settings_disk_resize_resize_cancel" msgid="2182388126941686562">"Khansela"</string>
- <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="83303619015991908">"Qala kabusha ukusebenzisa"</string>
- <string name="settings_port_forwarding_title" msgid="4867439149919324784">"Ukudlulisela Ngembobo"</string>
- <string name="settings_port_forwarding_sub_title" msgid="6848040752531535488">"Lungiselela ukudlulisela ngembobo"</string>
- <string name="settings_port_forwarding_notification_title" msgid="2822798067500254704">"Itheminali izama ukuvula imbobo entsha"</string>
- <string name="settings_port_forwarding_notification_content" msgid="2167103177775323330">"Imbobo icelwe ukuba ivulwe: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply" msgid="6651018335906339973">"Faka"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_message" msgid="6906352501525496328">"Itheminali izoqalwa kabusha ukuze ishintshe usayizi wediski"</string>
+ <string name="settings_disk_resize_resize_confirm_dialog_confirm" msgid="7347432999245803583">"Qinisekisa"</string>
+ <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ulawulo lwembobo"</string>
+ <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Vumela/nqabela izimbobo zokulalela"</string>
+ <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Izimbobo zokulalela"</string>
+ <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
+ <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Izimbobo ezivunyelwe ezilondoloziwe"</string>
+ <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Engeza"</string>
+ <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Sula i-<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+ <string name="settings_port_forwarding_dialog_title" msgid="2734992099990516463">"Vumela imbobo entsha"</string>
+ <string name="settings_port_forwarding_dialog_textview_hint" msgid="3514035855169269600">"Faka inombolo yembobo entsha"</string>
+ <string name="settings_port_forwarding_dialog_save" msgid="1097831033824718393">"Londoloza"</string>
+ <string name="settings_port_forwarding_dialog_cancel" msgid="1972597831318470889">"Khansela"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_input" msgid="7589299096002468249">"Sicela ufake inombolo"</string>
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Inombolo engasebenzi yembobo"</string>
+ <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Imbobo isikhona"</string>
+ <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Itheminali icela ukuvula imbobo entsha"</string>
+ <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Imbobo iceliwe: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
<string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Yamukela"</string>
<string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Yenqaba"</string>
<string name="settings_recovery_title" msgid="6586840079226383285">"Ukuthola"</string>
- <string name="settings_recovery_sub_title" msgid="1067782421529340576">"Okukhethwa kukho kokubuyisela ukwahlukanisa"</string>
- <string name="settings_recovery_reset_title" msgid="8785305518694186025">"Shintshela Ohlotsheni lokuqala"</string>
- <string name="settings_recovery_reset_sub_title" msgid="5656572074090728544">"Susa konke"</string>
+ <string name="settings_recovery_sub_title" msgid="3906996270508262595">"Okungakhethwa kukho kokutakula ukwahlukanisa"</string>
+ <string name="settings_recovery_reset_title" msgid="5388842560910568731">"Setha kabusha ohlotsheni lokuqala"</string>
+ <string name="settings_recovery_reset_sub_title" msgid="1079896907344675995">"Susa yonke idatha"</string>
<string name="settings_recovery_reset_dialog_title" msgid="874946981716251094">"Setha kabusha itheminali"</string>
- <string name="settings_recovery_reset_dialog_message" msgid="6392681199895696206">"Idatha izosulwa"</string>
- <string name="settings_recovery_reset_dialog_confirm" msgid="431718610013947861">"Qinisekisa"</string>
+ <string name="settings_recovery_reset_dialog_message" msgid="851530339815113000">"Idatha izosuswa"</string>
+ <string name="settings_recovery_reset_dialog_confirm" msgid="6916237820754131902">"Setha kabusha"</string>
<string name="settings_recovery_reset_dialog_cancel" msgid="1666264288208459725">"Khansela"</string>
<string name="settings_recovery_reset_dialog_backup_option" msgid="2079431035205584614">"Yenza ikhophi yedatha ku-<xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="settings_recovery_error_due_to_backup" msgid="2129959464075410607">"Ukuthola kuhlulekile ngoba ukwenza isipele kuhlulekile"</string>
+ <string name="settings_recovery_error_due_to_backup" msgid="9034741074141274096">"Yehlulekile ukuphinda ithole ngenxa yephutha lesipele"</string>
<string name="settings_recovery_error" msgid="2451912941535666379">"Ukuthola kwehlulekile"</string>
- <string name="settings_recovery_error_during_removing_backup" msgid="6515615177661212463">"Ayikwazi ukususa ifayela eliyisipele"</string>
+ <string name="settings_recovery_error_during_removing_backup" msgid="2447990797766248691">"Yehlulekile ukususa isipele"</string>
<string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Susa idatha eyisipele"</string>
- <string name="settings_recovery_remove_backup_sub_title" msgid="212161719832573475">"Hlanza i-<xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
- <string name="error_title" msgid="7196464038692913778">"Iphutha Elingabuyiseki"</string>
- <string name="error_desc" msgid="1939028888570920661">"Yehlulekile ukutakula ephutheni.\nUngazama ukuqala kabusha i-app, noma uzame okungakhethwa kukho kokukodwa kokutakula."</string>
+ <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Susa i-<xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
+ <string name="error_title" msgid="405150657301906598">"Iphutha elingabuyiseki"</string>
+ <string name="error_desc" msgid="4588252235686826721">"Kuhlulekile ukutholakala ngemva kwephutha. \nUngazama ukuqala kabusha itheminali noma uzame okunye kokungakhethwa kukho kokutakula. \nUma yonke imizamo ihluleka, sula yonke idatha ngokuvula/ngokuvala itheminali yeLinux kokungakhethwa kukho konjiniyela."</string>
<string name="error_code" msgid="3585291676855383649">"Ikhodi yephutha: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
<string name="service_notification_settings" msgid="1437365721184401135">"Amasethingi"</string>
<string name="service_notification_title" msgid="2918088850910713393">"Itheminali iyasebenza"</string>
- <string name="service_notification_content" msgid="3579923802797824545">"Chofoza ukuze uvule itheminali"</string>
+ <string name="service_notification_content" msgid="5772901142342308273">"Chofoza ukuze uvule itheminali"</string>
<string name="service_notification_quit_action" msgid="4888327875869277455">"Vala"</string>
- <!-- no translation found for virgl_enabled (5466273280705345122) -->
- <skip />
+ <string name="service_notification_close_title" msgid="1442526433361428844">"Itheminali iyavalwa"</string>
+ <string name="service_notification_force_quit_action" msgid="3462226330416157775">"Phoqelela ukuvala"</string>
+ <string name="virgl_enabled" msgid="5242525588039698086">"I-<xliff:g id="ID_1">VirGL</xliff:g> inikwe amandla."</string>
</resources>
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index 40c354e..bdebb83 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -87,6 +87,8 @@
<string name="settings_port_forwarding_sub_title">Allow/deny listening ports</string>
<!-- Title for active ports setting in port forwarding [CHAR LIMIT=none] -->
<string name="settings_port_forwarding_active_ports_title">Listening ports</string>
+ <!-- Text content for active ports setting in port forwarding [CHAR LIMIT=none] -->
+ <string name="settings_port_forwarding_active_ports_content"><xliff:g id="port_number" example="8000">%1$d</xliff:g> (<xliff:g id="process_name" example="undefined">%2$s</xliff:g>)</string>
<!-- Title for other enabled ports setting in port forwarding [CHAR LIMIT=none] -->
<string name="settings_port_forwarding_other_enabled_ports_title">Saved allowed ports</string>
<!-- Description of add button for other enabled ports. Used for talkback. [CHAR LIMIT=16] -->
@@ -112,7 +114,7 @@
<!-- Notification title for a new active port [CHAR LIMIT=none] -->
<string name="settings_port_forwarding_notification_title">Terminal is requesting to open a new port</string>
<!-- Notification content for a new active port [CHAR LIMIT=none] -->
- <string name="settings_port_forwarding_notification_content">Port requested: <xliff:g id="port_number" example="8080">%d</xliff:g></string>
+ <string name="settings_port_forwarding_notification_content">Port requested: <xliff:g id="port_number" example="8000">%1$d</xliff:g> (<xliff:g id="process_name" example="undefined">%2$s</xliff:g>)</string>
<!-- Notification action accept [CHAR LIMIT=16] -->
<string name="settings_port_forwarding_notification_accept">Accept</string>
<!-- Notification action deny [CHAR LIMIT=16] -->
@@ -170,4 +172,10 @@
<!-- This string is for toast message to notify that VirGL is enabled. [CHAR LIMIT=40] -->
<string name="virgl_enabled"><xliff:g>VirGL</xliff:g> is enabled</string>
+
+ <!-- This is the name of the notification channel for long-runnint tasks [CHAR LIMIT=none] -->
+ <string name="notification_channel_long_running_name">Long running tasks</string>
+
+ <!-- This is the name of the notification channel for system events [CHAR LIMIT=none] -->
+ <string name="notification_channel_system_events_name">System events</string>
</resources>
diff --git a/android/VmAttestationDemoApp/src/main.rs b/android/VmAttestationDemoApp/src/main.rs
index 26df52c..bcc056d 100644
--- a/android/VmAttestationDemoApp/src/main.rs
+++ b/android/VmAttestationDemoApp/src/main.rs
@@ -16,7 +16,6 @@
use anyhow::{ensure, Context, Result};
use log::{error, info};
-use std::panic;
use vm_payload::AttestationError;
vm_payload::main!(main);
@@ -28,10 +27,6 @@
.with_tag("service_vm_client")
.with_max_level(log::LevelFilter::Debug),
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- error!("{}", panic_info);
- }));
if let Err(e) = try_main() {
error!("failed with {:?}", e);
std::process::exit(1);
diff --git a/android/compos_verify/verify.rs b/android/compos_verify/verify.rs
index b94ebbc..a88d00c 100644
--- a/android/compos_verify/verify.rs
+++ b/android/compos_verify/verify.rs
@@ -34,7 +34,6 @@
use std::fs;
use std::fs::File;
use std::io::Read;
-use std::panic;
use std::path::Path;
const MAX_FILE_SIZE_BYTES: u64 = 100 * 1024;
@@ -65,11 +64,6 @@
.with_log_buffer(LogId::System), // Needed to log successfully early in boot
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- error!("{}", panic_info);
- }));
-
if let Err(e) = try_main() {
error!("{:?}", e);
std::process::exit(1)
diff --git a/android/composd/src/composd_main.rs b/android/composd/src/composd_main.rs
index e5d6c75..0b142f2 100644
--- a/android/composd/src/composd_main.rs
+++ b/android/composd/src/composd_main.rs
@@ -28,7 +28,6 @@
use anyhow::{Context, Result};
use binder::{register_lazy_service, ProcessState};
use log::{error, info};
-use std::panic;
use std::sync::Arc;
#[allow(clippy::eq_op)]
@@ -39,11 +38,6 @@
android_logger::Config::default().with_tag("composd").with_max_level(log_level),
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- log::error!("{}", panic_info);
- }));
-
ProcessState::start_thread_pool();
let virtmgr =
diff --git a/android/virtmgr/Android.bp b/android/virtmgr/Android.bp
index ad63995..c2d67cf 100644
--- a/android/virtmgr/Android.bp
+++ b/android/virtmgr/Android.bp
@@ -38,7 +38,6 @@
"libcfg_if",
"libclap",
"libcrosvm_control_static",
- "libcstr",
"libcommand_fds",
"libdisk",
"libglob",
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 15a80a6..57779bf 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -20,7 +20,7 @@
use crate::crosvm::{AudioConfig, CrosvmConfig, DiskFile, SharedPathConfig, DisplayConfig, GpuConfig, InputDeviceOption, PayloadState, UsbConfig, VmContext, VmInstance, VmState};
use crate::debug_config::{DebugConfig, DebugPolicy};
use crate::dt_overlay::{create_device_tree_overlay, VM_DT_OVERLAY_MAX_SIZE, VM_DT_OVERLAY_PATH};
-use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images, add_microdroid_vendor_image};
+use crate::payload::{ApexInfoList, add_microdroid_payload_images, add_microdroid_system_images, add_microdroid_vendor_image};
use crate::selinux::{check_tee_service_permission, getfilecon, getprevcon, SeContext};
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::{
@@ -29,6 +29,7 @@
ErrorCode::ErrorCode,
};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
+ AssignedDevices::AssignedDevices,
AssignableDevice::AssignableDevice,
CpuTopology::CpuTopology,
DiskImage::DiskImage,
@@ -67,7 +68,6 @@
self, wait_for_interface, Accessor, BinderFeatures, ConnectionInfo, ExceptionCode, Interface, ParcelFileDescriptor,
SpIBinder, Status, StatusCode, Strong, IntoBinderResult,
};
-use cstr::cstr;
use glob::glob;
use libc::{AF_VSOCK, sa_family_t, sockaddr_vm};
use log::{debug, error, info, warn};
@@ -137,6 +137,21 @@
static SUPPORTED_OS_NAMES: LazyLock<HashSet<String>> =
LazyLock::new(|| get_supported_os_names().expect("Failed to get list of supported os names"));
+static CALLING_EXE_PATH: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
+ let calling_exe_link = format!("/proc/{}/exe", get_calling_pid());
+ match fs::read_link(&calling_exe_link) {
+ Ok(calling_exe_path) => Some(calling_exe_path),
+ Err(e) => {
+ // virtmgr forked from apps fails to read /proc probably due to hidepid=2. As we
+ // discourage vendor apps, regarding such cases as system is safer.
+ // TODO(b/383969737): determine if this is okay. Or find a way how to track origins of
+ // apps.
+ warn!("can't read_link '{calling_exe_link}': {e:?}; regarding as system");
+ None
+ }
+ }
+});
+
fn create_or_update_idsig_file(
input_fd: &ParcelFileDescriptor,
idsig_fd: &ParcelFileDescriptor,
@@ -406,10 +421,38 @@
}
}
-fn find_partition(path: &Path) -> binder::Result<String> {
- match path.components().nth(1) {
+fn find_partition(path: Option<&Path>) -> binder::Result<String> {
+ let path = match path {
+ Some(path) => path,
+ None => return Ok("system".to_owned()),
+ };
+ let mut components = path.components();
+ match components.nth(1) {
Some(std::path::Component::Normal(partition)) => {
- Ok(partition.to_string_lossy().into_owned())
+ if partition != "apex" {
+ return Ok(partition.to_string_lossy().into_owned());
+ }
+
+ // If path is under /apex, find a partition of the preinstalled .apex path
+ let apex_name = match components.next() {
+ Some(std::path::Component::Normal(name)) => name.to_string_lossy(),
+ _ => {
+ return Err(anyhow!("Can't find apex name for '{}'", path.display()))
+ .or_service_specific_exception(-1)
+ }
+ };
+
+ let apex_info_list = ApexInfoList::load()
+ .context("Failed to get apex info list")
+ .or_service_specific_exception(-1)?;
+
+ for apex_info in apex_info_list.list.iter() {
+ if apex_info.name == apex_name {
+ return Ok(apex_info.partition.to_lowercase());
+ }
+ }
+
+ Err(anyhow!("Can't find apex info for '{apex_name}'")).or_service_specific_exception(-1)
}
_ => Err(anyhow!("Can't find partition in '{}'", path.display()))
.or_service_specific_exception(-1),
@@ -424,24 +467,27 @@
fn create_early_vm_context(
&self,
config: &VirtualMachineConfig,
+ calling_exe_path: Option<&Path>,
) -> binder::Result<(VmContext, Cid, PathBuf)> {
- let calling_exe_path = format!("/proc/{}/exe", get_calling_pid());
- let link = fs::read_link(&calling_exe_path)
- .context(format!("can't read_link '{calling_exe_path}'"))
- .or_service_specific_exception(-1)?;
- let partition = find_partition(&link)?;
-
let name = match config {
VirtualMachineConfig::RawConfig(config) => &config.name,
VirtualMachineConfig::AppConfig(config) => &config.name,
};
- let early_vm =
- find_early_vm_for_partition(&partition, name).or_service_specific_exception(-1)?;
- if Path::new(&early_vm.path) != link {
+ let calling_partition = find_partition(calling_exe_path)?;
+ let early_vm = find_early_vm_for_partition(&calling_partition, name)
+ .or_service_specific_exception(-1)?;
+ let calling_exe_path = match calling_exe_path {
+ Some(path) => path,
+ None => {
+ return Err(anyhow!("Can't verify the path of PID {}", get_calling_pid()))
+ .or_service_specific_exception(-1)
+ }
+ };
+ if Path::new(&early_vm.path) != calling_exe_path {
return Err(anyhow!(
- "VM '{name}' in partition '{partition}' must be created with '{}', not '{}'",
+ "VM '{name}' in partition '{calling_partition}' must be created with '{}', not '{}'",
&early_vm.path,
- link.display()
+ calling_exe_path.display()
))
.or_service_specific_exception(-1);
}
@@ -525,7 +571,7 @@
// Allocating VM context checks the MANAGE_VIRTUAL_MACHINE permission.
let (vm_context, cid, temporary_directory) = if cfg!(early) {
- self.create_early_vm_context(config)?
+ self.create_early_vm_context(config, CALLING_EXE_PATH.as_deref())?
} else {
self.create_vm_context(requester_debug_pid, config)?
};
@@ -541,7 +587,22 @@
check_gdb_allowed(config)?;
}
- let device_tree_overlay = maybe_create_device_tree_overlay(config, &temporary_directory)?;
+ let instance_id = extract_instance_id(config);
+ let mut device_tree_overlays = vec![];
+ if let Some(dt_overlay) =
+ maybe_create_reference_dt_overlay(config, &instance_id, &temporary_directory)?
+ {
+ device_tree_overlays.push(dt_overlay);
+ }
+ if let Some(dtbo) = get_dtbo(config) {
+ let dtbo = File::from(
+ dtbo.as_ref()
+ .try_clone()
+ .context("Failed to create VM DTBO from ParcelFileDescriptor")
+ .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?,
+ );
+ device_tree_overlays.push(dtbo);
+ }
let debug_config = DebugConfig::new(config);
let ramdump = if !uses_gki_kernel(config) && debug_config.is_ramdump_needed() {
@@ -625,7 +686,8 @@
// Check if files for payloads and bases are NOT coming from /vendor and /odm, as they may
// have unstable interfaces.
// TODO(b/316431494): remove once Treble interfaces are stabilized.
- check_partitions_for_files(config).or_service_specific_exception(-1)?;
+ check_partitions_for_files(config, &find_partition(CALLING_EXE_PATH.as_deref())?)
+ .or_service_specific_exception(-1)?;
let zero_filler_path = temporary_directory.join("zero.img");
write_zero_filler(&zero_filler_path)
@@ -668,29 +730,30 @@
}
};
- let (vfio_devices, dtbo) = if !config.devices.is_empty() {
- let mut set = HashSet::new();
- for device in config.devices.iter() {
- let path = canonicalize(device)
- .with_context(|| format!("can't canonicalize {device}"))
- .or_service_specific_exception(-1)?;
- if !set.insert(path) {
- return Err(anyhow!("duplicated device {device}"))
- .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT);
+ let (vfio_devices, dtbo) = match &config.devices {
+ AssignedDevices::Devices(devices) if !devices.is_empty() => {
+ let mut set = HashSet::new();
+ for device in devices.iter() {
+ let path = canonicalize(device)
+ .with_context(|| format!("can't canonicalize {device}"))
+ .or_service_specific_exception(-1)?;
+ if !set.insert(path) {
+ return Err(anyhow!("duplicated device {device}"))
+ .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT);
+ }
}
+ let devices = GLOBAL_SERVICE.bindDevicesToVfioDriver(devices)?;
+ let dtbo_file = File::from(
+ GLOBAL_SERVICE
+ .getDtboFile()?
+ .as_ref()
+ .try_clone()
+ .context("Failed to create VM DTBO from ParcelFileDescriptor")
+ .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?,
+ );
+ (devices, Some(dtbo_file))
}
- let devices = GLOBAL_SERVICE.bindDevicesToVfioDriver(&config.devices)?;
- let dtbo_file = File::from(
- GLOBAL_SERVICE
- .getDtboFile()?
- .as_ref()
- .try_clone()
- .context("Failed to create VM DTBO from ParcelFileDescriptor")
- .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?,
- );
- (devices, Some(dtbo_file))
- } else {
- (vec![], None)
+ _ => (vec![], None),
};
let display_config = if cfg!(paravirtualized_devices) {
config
@@ -756,6 +819,8 @@
.unwrap_or(Ok(UsbConfig { controller: false }))
.or_binder_exception(ExceptionCode::BAD_PARCELABLE)?;
+ let detect_hangup = is_app_config && gdb_port.is_none();
+
// Actually start the VM.
let crosvm_config = CrosvmConfig {
cid,
@@ -774,6 +839,7 @@
.ok()
.and_then(NonZeroU32::new)
.unwrap_or(NonZeroU32::new(256).unwrap()),
+ swiotlb_mib: config.swiotlbMib.try_into().ok().and_then(NonZeroU32::new),
cpus,
host_cpu_topology,
console_out_fd,
@@ -782,11 +848,11 @@
ramdump,
indirect_files,
platform_version: parse_platform_version_req(&config.platformVersion)?,
- detect_hangup: is_app_config,
+ detect_hangup,
gdb_port,
vfio_devices,
dtbo,
- device_tree_overlay,
+ device_tree_overlays,
display_config,
input_device_options,
hugepages: config.hugePages,
@@ -798,6 +864,8 @@
balloon: config.balloon,
usb_config,
dump_dt_fd,
+ enable_hypervisor_specific_auth_method: config.enableHypervisorSpecificAuthMethod,
+ instance_id,
};
let instance = Arc::new(
VmInstance::new(
@@ -883,8 +951,9 @@
Err(anyhow!("No hashtree digest is extracted from microdroid vendor image"))
}
-fn maybe_create_device_tree_overlay(
+fn maybe_create_reference_dt_overlay(
config: &VirtualMachineConfig,
+ instance_id: &[u8; 64],
temporary_directory: &Path,
) -> binder::Result<Option<File>> {
// Currently, VirtMgr adds the host copy of reference DT & untrusted properties
@@ -908,28 +977,26 @@
"Passing vendor hashtree digest to pvmfw. This will be rejected if it doesn't \
match the trusted digest in the pvmfw config, causing the VM to fail to start."
);
- vec![(cstr!("vendor_hashtree_descriptor_root_digest"), vendor_hashtree_digest.as_slice())]
+ vec![(c"vendor_hashtree_descriptor_root_digest", vendor_hashtree_digest.as_slice())]
} else {
vec![]
};
- let instance_id;
let key_material;
let mut untrusted_props = Vec::with_capacity(2);
if cfg!(llpvm_changes) {
- instance_id = extract_instance_id(config);
- untrusted_props.push((cstr!("instance-id"), &instance_id[..]));
+ untrusted_props.push((c"instance-id", &instance_id[..]));
let want_updatable = extract_want_updatable(config);
if want_updatable && is_secretkeeper_supported() {
// Let guest know that it can defer rollback protection to Secretkeeper by setting
// an empty property in untrusted node in DT. This enables Updatable VMs.
- untrusted_props.push((cstr!("defer-rollback-protection"), &[]));
+ untrusted_props.push((c"defer-rollback-protection", &[]));
let sk: Strong<dyn ISecretkeeper> =
binder::wait_for_interface(SECRETKEEPER_IDENTIFIER)?;
if sk.getInterfaceVersion()? >= 2 {
let PublicKey { keyMaterial } = sk.getSecretkeeperIdentity()?;
key_material = keyMaterial;
- trusted_props.push((cstr!("secretkeeper_public_key"), key_material.as_slice()));
+ trusted_props.push((c"secretkeeper_public_key", key_material.as_slice()));
}
}
}
@@ -952,6 +1019,16 @@
Ok(device_tree_overlay)
}
+fn get_dtbo(config: &VirtualMachineConfig) -> Option<&ParcelFileDescriptor> {
+ let VirtualMachineConfig::RawConfig(config) = config else {
+ return None;
+ };
+ match &config.devices {
+ AssignedDevices::Dtbo(dtbo) => dtbo.as_ref(),
+ _ => None,
+ }
+}
+
fn write_zero_filler(zero_filler_path: &Path) -> Result<()> {
let file = OpenOptions::new()
.create_new(true)
@@ -1212,7 +1289,7 @@
append_kernel_param("androidboot.microdroid.mount_vendor=1", &mut vm_config)
}
- vm_config.devices.clone_from(&custom_config.devices);
+ vm_config.devices = AssignedDevices::Devices(custom_config.devices.clone());
vm_config.networkSupported = custom_config.networkSupported;
for param in custom_config.extraKernelCmdlineParams.iter() {
@@ -1260,7 +1337,7 @@
Ok(vm_config)
}
-fn check_partition_for_file(fd: &ParcelFileDescriptor) -> Result<()> {
+fn check_partition_for_file(fd: &ParcelFileDescriptor, calling_partition: &str) -> Result<()> {
let path = format!("/proc/self/fd/{}", fd.as_raw_fd());
let link = fs::read_link(&path).context(format!("can't read_link {path}"))?;
@@ -1270,24 +1347,39 @@
return Ok(());
}
- if link.starts_with("/vendor") || link.starts_with("/odm") {
- bail!("vendor or odm file {} can't be used for VM", link.display());
+ let is_fd_vendor = link.starts_with("/vendor") || link.starts_with("/odm");
+ let is_caller_vendor = calling_partition == "vendor" || calling_partition == "odm";
+
+ if is_fd_vendor != is_caller_vendor {
+ bail!("{} can't be used for VM client in {calling_partition}", link.display());
}
Ok(())
}
-fn check_partitions_for_files(config: &VirtualMachineRawConfig) -> Result<()> {
+fn check_partitions_for_files(
+ config: &VirtualMachineRawConfig,
+ calling_partition: &str,
+) -> Result<()> {
config
.disks
.iter()
.flat_map(|disk| disk.partitions.iter())
.filter_map(|partition| partition.image.as_ref())
- .try_for_each(check_partition_for_file)?;
+ .try_for_each(|fd| check_partition_for_file(fd, calling_partition))?;
- config.kernel.as_ref().map_or(Ok(()), check_partition_for_file)?;
- config.initrd.as_ref().map_or(Ok(()), check_partition_for_file)?;
- config.bootloader.as_ref().map_or(Ok(()), check_partition_for_file)?;
+ config
+ .disks
+ .iter()
+ .filter_map(|disk| disk.image.as_ref())
+ .try_for_each(|fd| check_partition_for_file(fd, calling_partition))?;
+
+ config.kernel.as_ref().map_or(Ok(()), |fd| check_partition_for_file(fd, calling_partition))?;
+ config.initrd.as_ref().map_or(Ok(()), |fd| check_partition_for_file(fd, calling_partition))?;
+ config
+ .bootloader
+ .as_ref()
+ .map_or(Ok(()), |fd| check_partition_for_file(fd, calling_partition))?;
Ok(())
}
@@ -2138,6 +2230,7 @@
match partition {
"system" => Ok(100..200),
"system_ext" | "product" => Ok(200..300),
+ "vendor" | "odm" => Ok(300..400),
_ => Err(anyhow!("Early VMs are not supported for {partition}")),
}
}
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index 2bfa4e1..096d3b5 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -112,6 +112,7 @@
pub protected: bool,
pub debug_config: DebugConfig,
pub memory_mib: NonZeroU32,
+ pub swiotlb_mib: Option<NonZeroU32>,
pub cpus: Option<NonZeroU32>,
pub host_cpu_topology: bool,
pub console_out_fd: Option<File>,
@@ -124,7 +125,7 @@
pub gdb_port: Option<NonZeroU16>,
pub vfio_devices: Vec<VfioDevice>,
pub dtbo: Option<File>,
- pub device_tree_overlay: Option<File>,
+ pub device_tree_overlays: Vec<File>,
pub display_config: Option<DisplayConfig>,
pub input_device_options: Vec<InputDeviceOption>,
pub hugepages: bool,
@@ -136,6 +137,8 @@
pub balloon: bool,
pub usb_config: UsbConfig,
pub dump_dt_fd: Option<File>,
+ pub enable_hypervisor_specific_auth_method: bool,
+ pub instance_id: [u8; 64],
}
#[derive(Debug)]
@@ -321,7 +324,7 @@
let tap =
if let Some(tap_file) = &config.tap { Some(tap_file.try_clone()?) } else { None };
- run_virtiofs(&config)?;
+ let vhost_fs_devices = run_virtiofs(&config)?;
// If this fails and returns an error, `self` will be left in the `Failed` state.
let child =
@@ -336,7 +339,13 @@
let child_clone = child.clone();
let instance_clone = instance.clone();
let monitor_vm_exit_thread = Some(thread::spawn(move || {
- instance_clone.monitor_vm_exit(child_clone, failure_pipe_read, vfio_devices, tap);
+ instance_clone.monitor_vm_exit(
+ child_clone,
+ failure_pipe_read,
+ vfio_devices,
+ tap,
+ vhost_fs_devices,
+ );
}));
if detect_hangup {
@@ -483,6 +492,7 @@
failure_pipe_read: File,
vfio_devices: Vec<VfioDevice>,
tap: Option<File>,
+ vhost_user_devices: Vec<SharedChild>,
) {
let failure_reason_thread = std::thread::spawn(move || {
// Read the pipe to see if any failure reason is written
@@ -510,6 +520,34 @@
}
}
+ // In crosvm, when vhost_user frontend is dead, vhost_user backend device will detect and
+ // exit. We can safely wait() for vhost user device after waiting crosvm main
+ // process.
+ for device in vhost_user_devices {
+ match device.wait() {
+ Ok(status) => {
+ info!("Vhost user device({}) exited with status {}", device.id(), status);
+ if !status.success() {
+ if let Some(code) = status.code() {
+ // vhost_user backend device exit with error code
+ error!(
+ "vhost user device({}) exited with error code: {}",
+ device.id(),
+ code
+ );
+ } else {
+ // The spawned child process of vhost_user backend device is
+ // killed by signal
+ error!("vhost user device({}) killed by signal", device.id());
+ }
+ }
+ }
+ Err(e) => {
+ error!("Error waiting for vhost user device({}) to die: {}", device.id(), e);
+ }
+ }
+ }
+
let failure_reason = failure_reason_thread.join().expect("failure_reason_thread panic'd");
let mut vm_state = self.vm_state.lock().unwrap();
@@ -912,7 +950,8 @@
}
}
-fn run_virtiofs(config: &CrosvmConfig) -> io::Result<()> {
+fn run_virtiofs(config: &CrosvmConfig) -> io::Result<Vec<SharedChild>> {
+ let mut devices: Vec<SharedChild> = Vec::new();
for shared_path in &config.shared_paths {
if shared_path.app_domain {
continue;
@@ -944,9 +983,10 @@
let result = SharedChild::spawn(&mut command)?;
info!("Spawned virtiofs crosvm({})", result.id());
+ devices.push(result);
}
- Ok(())
+ Ok(devices)
}
/// Starts an instance of `crosvm` to manage a new VM.
@@ -988,7 +1028,29 @@
let mut memory_mib = config.memory_mib;
+ if config.enable_hypervisor_specific_auth_method && !config.protected {
+ bail!("hypervisor specific auth method only supported for protected VMs");
+ }
if config.protected {
+ if config.enable_hypervisor_specific_auth_method {
+ if !hypervisor_props::is_gunyah()? {
+ bail!("hypervisor specific auth method not supported for current hypervisor");
+ }
+ // "QCOM Trusted VM" compatibility mode.
+ //
+ // When this mode is enabled, two hypervisor specific IDs are expected to be packed
+ // into the instance ID. We extract them here and pass along to crosvm so they can be
+ // given to the hypervisor driver via an ioctl.
+ let vm_id = u32::from_le_bytes(config.instance_id[60..64].try_into().unwrap());
+ let pas_id = u16::from_le_bytes(config.instance_id[58..60].try_into().unwrap());
+ command.arg("--hypervisor").arg(
+ format!("gunyah[device=/dev/gunyah,qcom_trusted_vm_id={vm_id},qcom_trusted_vm_pas_id={pas_id}]"),
+ );
+ // Put the FDT close to the payload (default is end of RAM) to so that CMA can be used
+ // without bloating memory usage.
+ command.arg("--fdt-position").arg("after-payload");
+ }
+
match system_properties::read(SYSPROP_CUSTOM_PVMFW_PATH)? {
Some(pvmfw_path) if !pvmfw_path.is_empty() => {
if pvmfw_path == "none" {
@@ -1000,11 +1062,18 @@
_ => command.arg("--protected-vm"),
};
- // 3 virtio-console devices + vsock = 4.
- let virtio_pci_device_count = 4 + config.disks.len();
- // crosvm virtio queue has 256 entries, so 2 MiB per device (2 pages per entry) should be
- // enough.
- let swiotlb_size_mib = 2 * virtio_pci_device_count as u32;
+ let swiotlb_size_mib = config.swiotlb_mib.map(u32::from).unwrap_or({
+ // 3 virtio-console devices + vsock = 4.
+ // TODO: Count more device types, like balloon, input, and sound.
+ let virtio_pci_device_count = 4 + config.disks.len();
+ // crosvm virtio queue has 256 entries, so 2 MiB per device (2 pages per entry) should
+ // be enough.
+ // NOTE: The above explanation isn't completely accurate, e.g., circa 2024q4, each
+ // virtio-block has 16 queues with 256 entries each and each virito-console has 2
+ // queues of 256 entries each. So, it is allocating less than 2 pages per entry, but
+ // seems to work well enough in practice.
+ 2 * virtio_pci_device_count as u32
+ });
command.arg("--swiotlb").arg(swiotlb_size_mib.to_string());
// b/346770542 for consistent "usable" memory across protected and non-protected VMs.
@@ -1149,9 +1218,10 @@
.context("failed to create control listener")?;
command.arg("--socket").arg(add_preserved_fd(&mut preserved_fds, control_sock));
- if let Some(dt_overlay) = config.device_tree_overlay {
- command.arg("--device-tree-overlay").arg(add_preserved_fd(&mut preserved_fds, dt_overlay));
- }
+ config.device_tree_overlays.into_iter().for_each(|dt_overlay| {
+ let arg = add_preserved_fd(&mut preserved_fds, dt_overlay);
+ command.arg("--device-tree-overlay").arg(arg);
+ });
if cfg!(paravirtualized_devices) {
if let Some(gpu_config) = &config.gpu_config {
diff --git a/android/virtmgr/src/dt_overlay.rs b/android/virtmgr/src/dt_overlay.rs
index 108ed61..fe2a419 100644
--- a/android/virtmgr/src/dt_overlay.rs
+++ b/android/virtmgr/src/dt_overlay.rs
@@ -15,14 +15,13 @@
//! This module support creating AFV related overlays, that can then be appended to DT by VM.
use anyhow::{anyhow, Result};
-use cstr::cstr;
use fsfdt::FsFdt;
use libfdt::Fdt;
use std::ffi::CStr;
use std::path::Path;
-pub(crate) const AVF_NODE_NAME: &CStr = cstr!("avf");
-pub(crate) const UNTRUSTED_NODE_NAME: &CStr = cstr!("untrusted");
+pub(crate) const AVF_NODE_NAME: &CStr = c"avf";
+pub(crate) const UNTRUSTED_NODE_NAME: &CStr = c"untrusted";
pub(crate) const VM_DT_OVERLAY_PATH: &str = "vm_dt_overlay.dtbo";
pub(crate) const VM_DT_OVERLAY_MAX_SIZE: usize = 2000;
@@ -63,13 +62,13 @@
Fdt::create_empty_tree(buffer).map_err(|e| anyhow!("Failed to create empty Fdt: {e:?}"))?;
let mut fragment = fdt
.root_mut()
- .add_subnode(cstr!("fragment@0"))
+ .add_subnode(c"fragment@0")
.map_err(|e| anyhow!("Failed to add fragment node: {e:?}"))?;
fragment
- .setprop(cstr!("target-path"), b"/\0")
+ .setprop(c"target-path", b"/\0")
.map_err(|e| anyhow!("Failed to set target-path property: {e:?}"))?;
let overlay = fragment
- .add_subnode(cstr!("__overlay__"))
+ .add_subnode(c"__overlay__")
.map_err(|e| anyhow!("Failed to add __overlay__ node: {e:?}"))?;
let avf =
overlay.add_subnode(AVF_NODE_NAME).map_err(|e| anyhow!("Failed to add avf node: {e:?}"))?;
@@ -87,12 +86,12 @@
// Read dt_path from host DT and overlay onto fdt.
if let Some(path) = dt_path {
- fdt.overlay_onto(cstr!("/fragment@0/__overlay__"), path)?;
+ fdt.overlay_onto(c"/fragment@0/__overlay__", path)?;
}
if !trusted_props.is_empty() {
let mut avf = fdt
- .node_mut(cstr!("/fragment@0/__overlay__/avf"))
+ .node_mut(c"/fragment@0/__overlay__/avf")
.map_err(|e| anyhow!("Failed to search avf node: {e:?}"))?
.ok_or(anyhow!("Failed to get avf node"))?;
for (name, value) in trusted_props {
@@ -120,14 +119,14 @@
#[test]
fn untrusted_prop_test() {
let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
- let prop_name = cstr!("XOXO");
+ let prop_name = c"XOXO";
let prop_val_input = b"OXOX";
let fdt =
create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)], &[])
.unwrap();
let prop_value_dt = fdt
- .node(cstr!("/fragment@0/__overlay__/avf/untrusted"))
+ .node(c"/fragment@0/__overlay__/avf/untrusted")
.unwrap()
.expect("/avf/untrusted node doesn't exist")
.getprop(prop_name)
@@ -139,14 +138,14 @@
#[test]
fn trusted_prop_test() {
let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
- let prop_name = cstr!("XOXOXO");
+ let prop_name = c"XOXOXO";
let prop_val_input = b"OXOXOX";
let fdt =
create_device_tree_overlay(&mut buffer, None, &[], &[(prop_name, prop_val_input)])
.unwrap();
let prop_value_dt = fdt
- .node(cstr!("/fragment@0/__overlay__/avf"))
+ .node(c"/fragment@0/__overlay__/avf")
.unwrap()
.expect("/avf node doesn't exist")
.getprop(prop_name)
diff --git a/android/virtmgr/src/payload.rs b/android/virtmgr/src/payload.rs
index 5811314..bd6bf10 100644
--- a/android/virtmgr/src/payload.rs
+++ b/android/virtmgr/src/payload.rs
@@ -48,15 +48,19 @@
/// Represents the list of APEXes
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
-struct ApexInfoList {
+pub(crate) struct ApexInfoList {
+ /// The list of APEXes
#[serde(rename = "apex-info")]
- list: Vec<ApexInfo>,
+ pub(crate) list: Vec<ApexInfo>,
}
+/// Represents info of an APEX
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
-struct ApexInfo {
+pub(crate) struct ApexInfo {
+ /// Name of APEX
#[serde(rename = "moduleName")]
- name: String,
+ pub(crate) name: String,
+
#[serde(rename = "versionCode")]
version: u64,
#[serde(rename = "modulePath")]
@@ -80,11 +84,15 @@
#[serde(rename = "preinstalledModulePath")]
preinstalled_path: PathBuf,
+
+ /// Partition of APEX
+ #[serde(default)]
+ pub(crate) partition: String,
}
impl ApexInfoList {
/// Loads ApexInfoList
- fn load() -> Result<&'static ApexInfoList> {
+ pub(crate) fn load() -> Result<&'static ApexInfoList> {
static INSTANCE: OnceCell<ApexInfoList> = OnceCell::new();
INSTANCE.get_or_try_init(|| {
let apex_info_list = File::open(APEX_INFO_LIST_PATH)
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/AssignedDevices.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/AssignedDevices.aidl
new file mode 100644
index 0000000..984f596
--- /dev/null
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/AssignedDevices.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.system.virtualizationservice;
+
+/** Assigned devices */
+union AssignedDevices {
+ /** List of SysFS nodes of devices to be assigned for VFIO */
+ String[] devices = {};
+
+ /** Device tree overlay for non-VFIO case */
+ ParcelFileDescriptor dtbo;
+}
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index d98fdcc..b6eff64 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -15,6 +15,7 @@
*/
package android.system.virtualizationservice;
+import android.system.virtualizationservice.AssignedDevices;
import android.system.virtualizationservice.AudioConfig;
import android.system.virtualizationservice.CpuTopology;
import android.system.virtualizationservice.DiskImage;
@@ -62,6 +63,9 @@
/** The amount of RAM to give the VM, in MiB. 0 or negative to use the default. */
int memoryMib;
+ /** The amount of swiotlb to give the VM, in MiB. 0 or negative to use the default. */
+ int swiotlbMib;
+
/** The vCPU topology that will be generated for the VM. Default to 1 vCPU. */
CpuTopology cpuTopology = CpuTopology.ONE_CPU;
@@ -88,8 +92,8 @@
*/
boolean hugePages;
- /** List of SysFS nodes of devices to be assigned */
- String[] devices;
+ /** Assigned devices */
+ AssignedDevices devices;
@nullable DisplayConfig displayConfig;
@@ -116,4 +120,10 @@
/** List of tee services this VM wants to access */
String[] teeServices;
+
+ /**
+ * Set whether to use an alternate, hypervisor-specific authentication method for protected
+ * VMs.
+ */
+ boolean enableHypervisorSpecificAuthMethod;
}
diff --git a/build/avf_flags.aconfig b/build/avf_flags.aconfig
index 9815c60..921c374 100644
--- a/build/avf_flags.aconfig
+++ b/build/avf_flags.aconfig
@@ -9,3 +9,11 @@
bug: "383347947"
is_fixed_read_only: true
}
+
+flag {
+ name: "terminal_gui_support"
+ is_exported: true
+ namespace: "virtualization"
+ description: "Flag for GUI support in terminal"
+ bug: "386296118"
+}
\ No newline at end of file
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 9bb1481..a426d22 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -57,18 +57,16 @@
;;
esac
if [[ "${*:$OPTIND:1}" ]]; then
- built_image="${*:$OPTIND:1}"
+ output="${*:$OPTIND:1}"
fi
}
prepare_build_id() {
- local filename=build_id
if [ -z "${KOKORO_BUILD_NUMBER}" ]; then
- echo eng-$(hostname)-$(date --utc) > ${filename}
+ echo eng-$(hostname)-$(date --utc)
else
- echo ${KOKORO_BUILD_NUMBER} > ${filename}
+ echo ${KOKORO_BUILD_NUMBER}
fi
- echo ${filename}
}
install_prerequisites() {
@@ -158,6 +156,7 @@
source "$HOME"/.cargo/env
rustup target add "${arch}"-unknown-linux-gnu
cargo install cargo-license
+ cargo install cargo-deb
}
download_debian_cloud_image() {
@@ -170,23 +169,11 @@
wget -O - "${url}" | tar xz -C "${outdir}" --strip-components=1
}
-build_rust_binary_and_copy() {
+build_rust_as_deb() {
pushd "$(dirname "$0")/../../guest/$1" > /dev/null
- local release_flag=
- local artifact_mode=debug
- if [[ "$mode" == "release" ]]; then
- release_flag="--release"
- artifact_mode=release
- fi
- RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
+ cargo deb \
--target "${arch}-unknown-linux-gnu" \
- --target-dir "${workdir}/$1" ${release_flag}
- mkdir -p "${dst}/files/usr/local/bin/$1"
- cp "${workdir}/$1/${arch}-unknown-linux-gnu/${artifact_mode}/$1" "${dst}/files/usr/local/bin/$1/AVF"
- chmod 777 "${dst}/files/usr/local/bin/$1/AVF"
-
- mkdir -p "${dst}/files/usr/share/doc/$1"
- cargo license > "${dst}/files/usr/share/doc/$1/copyright"
+ --output "${debian_cloud_image}/localdebs"
popd > /dev/null
}
@@ -220,10 +207,9 @@
cp -R "$(dirname "$0")/localdebs/" "${debian_cloud_image}/"
build_ttyd
- build_rust_binary_and_copy forwarder_guest
- build_rust_binary_and_copy forwarder_guest_launcher
- build_rust_binary_and_copy ip_addr_reporter
- build_rust_binary_and_copy shutdown_runner
+ build_rust_as_deb forwarder_guest
+ build_rust_as_deb forwarder_guest_launcher
+ build_rust_as_deb shutdown_runner
}
package_custom_kernel() {
@@ -303,17 +289,23 @@
}
run_fai() {
- local out="${built_image}"
+ local out="${raw_disk_image}"
make -C "${debian_cloud_image}" "image_bookworm_nocloud_${debian_arch}"
mv "${debian_cloud_image}/image_bookworm_nocloud_${debian_arch}.raw" "${out}"
}
-extract_partitions() {
- root_partition_num=1
- bios_partition_num=14
- efi_partition_num=15
+generate_output_package() {
+ fdisk -l "${raw_disk_image}"
+ local vm_config="$(realpath $(dirname "$0"))/vm_config.json.${arch}"
+ local root_partition_num=1
+ local bios_partition_num=14
+ local efi_partition_num=15
- loop=$(losetup -f --show --partscan $built_image)
+ pushd ${workdir} > /dev/null
+
+ echo ${build_id} > build_id
+
+ loop=$(losetup -f --show --partscan $raw_disk_image)
dd if="${loop}p$root_partition_num" of=root_part
if [[ "$arch" == "x86_64" ]]; then
dd if="${loop}p$bios_partition_num" of=bios_part
@@ -321,11 +313,38 @@
dd if="${loop}p$efi_partition_num" of=efi_part
losetup -d "${loop}"
- sed -i "s/{root_part_guid}/$(sfdisk --part-uuid $built_image $root_partition_num)/g" vm_config.json
+ cp ${vm_config} vm_config.json
+ sed -i "s/{root_part_guid}/$(sfdisk --part-uuid $raw_disk_image $root_partition_num)/g" vm_config.json
if [[ "$arch" == "x86_64" ]]; then
- sed -i "s/{bios_part_guid}/$(sfdisk --part-uuid $built_image $bios_partition_num)/g" vm_config.json
+ sed -i "s/{bios_part_guid}/$(sfdisk --part-uuid $raw_disk_image $bios_partition_num)/g" vm_config.json
fi
- sed -i "s/{efi_part_guid}/$(sfdisk --part-uuid $built_image $efi_partition_num)/g" vm_config.json
+ sed -i "s/{efi_part_guid}/$(sfdisk --part-uuid $raw_disk_image $efi_partition_num)/g" vm_config.json
+
+ images=()
+ if [[ "$arch" == "aarch64" ]]; then
+ images+=(
+ root_part
+ efi_part
+ )
+ # TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
+ elif [[ "$arch" == "x86_64" ]]; then
+ rm -f vmlinuz initrd.img
+ virt-get-kernel -a "${raw_disk_image}"
+ mv vmlinuz* vmlinuz
+ mv initrd.img* initrd.img
+ images+=(
+ bios_part
+ root_part
+ efi_part
+ vmlinuz
+ initrd.img
+ )
+ fi
+
+ popd > /dev/null
+
+ # --sparse option isn't supported in apache-commons-compress
+ tar czv -f ${output} -C ${workdir} build_id "${images[@]}" vm_config.json
}
clean_up() {
@@ -335,8 +354,9 @@
set -e
trap clean_up EXIT
-built_image=image.raw
+output=images.tar.gz
workdir=$(mktemp -d)
+raw_disk_image=${workdir}/image.raw
build_id=$(prepare_build_id)
debian_cloud_image=${workdir}/debian_cloud_image
debian_version=bookworm
@@ -354,32 +374,4 @@
copy_android_config
package_custom_kernel
run_fai
-fdisk -l "${built_image}"
-images=()
-
-cp "$(dirname "$0")/vm_config.json.${arch}" vm_config.json
-
-extract_partitions
-
-if [[ "$arch" == "aarch64" ]]; then
- images+=(
- root_part
- efi_part
- )
-# TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
-elif [[ "$arch" == "x86_64" ]]; then
- rm -f vmlinuz initrd.img
- virt-get-kernel -a "${built_image}"
- mv vmlinuz* vmlinuz
- mv initrd.img* initrd.img
- images+=(
- bios_part
- root_part
- efi_part
- vmlinuz
- initrd.img
- )
-fi
-
-# --sparse option isn't supported in apache-commons-compress
-tar czv -f images.tar.gz ${build_id} "${images[@]}" vm_config.json
+generate_output_package
diff --git a/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF b/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF
deleted file mode 100644
index b9f3193..0000000
--- a/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit]
-Description=ip report service
-After=syslog.target
-After=network.target
-Requires=ttyd.service
-After=virtiofs_internal.service
-[Service]
-ExecStart=/usr/bin/bash -c '/usr/local/bin/ip_addr_reporter --grpc_port $(cat /mnt/internal/debian_service_port)'
-Type=simple
-Restart=on-failure
-User=root
-Group=root
-[Install]
-WantedBy=multi-user.target
diff --git a/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF b/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF
deleted file mode 100644
index bfb8afb..0000000
--- a/build/debian/fai_config/files/etc/systemd/system/shutdown_runner.service/AVF
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-After=syslog.target
-After=network.target
-After=virtiofs_internal.service
-[Service]
-ExecStart=/usr/bin/bash -c '/usr/local/bin/shutdown_runner --grpc_port $(cat /mnt/internal/debian_service_port)'
-Type=simple
-User=root
-Group=root
-[Install]
-WantedBy=multi-user.target
diff --git a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
index 4a32f2b..d86bab0 100644
--- a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
+++ b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
@@ -3,11 +3,14 @@
After=syslog.target
After=network.target
After=virtiofs_internal.service
+
[Service]
ExecStart=/usr/local/bin/ttyd --ssl --ssl-cert /etc/ttyd/server.crt --ssl-key /etc/ttyd/server.key --ssl-ca /mnt/internal/ca.crt -t disableLeaveAlert=true -W login -f droid
+ExecStartPost=/usr/bin/avahi-publish-service ttyd _http._tcp 7681
Type=simple
Restart=always
User=root
Group=root
+
[Install]
WantedBy=multi-user.target
diff --git a/build/debian/fai_config/package_config/AVF b/build/debian/fai_config/package_config/AVF
index a91c354..98b558b 100644
--- a/build/debian/fai_config/package_config/AVF
+++ b/build/debian/fai_config/package_config/AVF
@@ -1,4 +1,10 @@
PACKAGES install
+avahi-daemon
+avahi-utils
bpfcc-tools
+libnss-mdns
procps
+forwarder-guest
+forwarder-guest-launcher
+shutdown-runner
diff --git a/build/debian/fai_config/scripts/AVF/10-systemd b/build/debian/fai_config/scripts/AVF/10-systemd
index 119bec7..121acc5 100755
--- a/build/debian/fai_config/scripts/AVF/10-systemd
+++ b/build/debian/fai_config/scripts/AVF/10-systemd
@@ -1,16 +1,9 @@
#!/bin/bash
-chmod +x $target/usr/local/bin/forwarder_guest
-chmod +x $target/usr/local/bin/forwarder_guest_launcher
-chmod +x $target/usr/local/bin/ip_addr_reporter
-chmod +x $target/usr/local/bin/shutdown_runner
chmod +x $target/usr/local/bin/ttyd
ln -s /etc/systemd/system/ttyd.service $target/etc/systemd/system/multi-user.target.wants/ttyd.service
-ln -s /etc/systemd/system/ip_addr_reporter.service $target/etc/systemd/system/multi-user.target.wants/ip_addr_reporter.service
ln -s /etc/systemd/system/virtiofs.service $target/etc/systemd/system/multi-user.target.wants/virtiofs.service
-ln -s /etc/systemd/system/forwarder_guest_launcher.service $target/etc/systemd/system/multi-user.target.wants/forwarder_guest_launcher.service
ln -s /etc/systemd/system/virtiofs_internal.service $target/etc/systemd/system/multi-user.target.wants/virtiofs_internal.service
ln -s /etc/systemd/system/backup_mount.service $target/etc/systemd/system/multi-user.target.wants/backup_mount.service
-ln -s /etc/systemd/system/shutdown_runner.service $target/etc/systemd/system/multi-user.target.wants/shutdown_runner.service
sed -i 's/#LLMNR=yes/LLMNR=no/' $target/etc/systemd/resolved.conf
diff --git a/docs/custom_vm.md b/docs/custom_vm.md
index 7597131..2815bbf 100644
--- a/docs/custom_vm.md
+++ b/docs/custom_vm.md
@@ -44,6 +44,6 @@
`weston` with VNC backend might be another option, but it isn't available in
Debian package repository for bookworm.
-## Hardware accelration
+## Hardware acceleration
If the file `/sdcard/linux/virglrenderer` exists on the device, it enables VirGL for VM.
This requires enabling ANGLE for the Terminal app. (https://chromium.googlesource.com/angle/angle.git/+/HEAD/doc/DevSetupAndroid.md)
diff --git a/docs/getting_started.md b/docs/getting_started.md
index 0a7cca6..03657ed 100644
--- a/docs/getting_started.md
+++ b/docs/getting_started.md
@@ -9,7 +9,7 @@
* aosp\_oriole (Pixel 6)
* aosp\_raven (Pixel 6 Pro)
* aosp\_felix (Pixel Fold)
-* aosp\_tangopro (Pixel Tablet)
+* aosp\_tangorpro (Pixel Tablet)
* aosp\_cf\_x86\_64\_phone (Cuttlefish a.k.a. Cloud Android). Follow [this
instruction](https://source.android.com/docs/setup/create/cuttlefish-use) to
use.
diff --git a/guest/compsvc/src/compsvc_main.rs b/guest/compsvc/src/compsvc_main.rs
index 9bc522c..a8202e1 100644
--- a/guest/compsvc/src/compsvc_main.rs
+++ b/guest/compsvc/src/compsvc_main.rs
@@ -25,7 +25,6 @@
use anyhow::Result;
use compos_common::COMPOS_VSOCK_PORT;
use log::{debug, error};
-use std::panic;
fn main() {
if let Err(e) = try_main() {
@@ -40,10 +39,6 @@
.with_tag("compsvc")
.with_max_level(log::LevelFilter::Debug),
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- error!("{}", panic_info);
- }));
debug!("compsvc is starting as a rpc service.");
vm_payload::run_single_vsock_service(compsvc::new_binder()?, COMPOS_VSOCK_PORT)
diff --git a/guest/derive_microdroid_vendor_dice_node/Android.bp b/guest/derive_microdroid_vendor_dice_node/Android.bp
index 8b79aad..7a3ccbe 100644
--- a/guest/derive_microdroid_vendor_dice_node/Android.bp
+++ b/guest/derive_microdroid_vendor_dice_node/Android.bp
@@ -10,7 +10,6 @@
rustlibs: [
"libanyhow",
"libclap",
- "libcstr",
"libdice_driver",
"libdiced_open_dice",
"libdm_rust",
diff --git a/guest/derive_microdroid_vendor_dice_node/src/main.rs b/guest/derive_microdroid_vendor_dice_node/src/main.rs
index 0f0631e..4ec91ad 100644
--- a/guest/derive_microdroid_vendor_dice_node/src/main.rs
+++ b/guest/derive_microdroid_vendor_dice_node/src/main.rs
@@ -16,7 +16,6 @@
use anyhow::{bail, Context, Result};
use clap::Parser;
-use cstr::cstr;
use dice_driver::DiceDriver;
use diced_open_dice::{
hash, retry_bcc_format_config_descriptor, DiceConfigValues, OwnedDiceArtifacts, HIDDEN_SIZE,
@@ -50,7 +49,7 @@
// See dice_for_avf_guest.cddl for CDDL of Configuration Descriptor of VM components.
fn build_descriptor(vbmeta: &VbMetaImage) -> Result<Vec<u8>> {
let values = DiceConfigValues {
- component_name: Some(cstr!("Microdroid vendor")),
+ component_name: Some(c"Microdroid vendor"),
security_version: Some(vbmeta.rollback_index()),
..Default::default()
};
diff --git a/guest/forwarder_guest/.cargo/config.toml b/guest/forwarder_guest/.cargo/config.toml
new file mode 100644
index 0000000..a451cda
--- /dev/null
+++ b/guest/forwarder_guest/.cargo/config.toml
@@ -0,0 +1,6 @@
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+rustflags = ["-C", "target-feature=+crt-static"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "target-feature=+crt-static"]
diff --git a/guest/forwarder_guest/Cargo.toml b/guest/forwarder_guest/Cargo.toml
index ce50e4c..bb9b826 100644
--- a/guest/forwarder_guest/Cargo.toml
+++ b/guest/forwarder_guest/Cargo.toml
@@ -10,3 +10,8 @@
poll_token_derive = "0.1.0"
remain = "0.2.14"
vmm-sys-util = "0.12.1"
+
+[package.metadata.deb]
+maintainer = "ferrochrome-dev@google.com"
+copyright = "2024, The Android Open Source Project"
+depends = "$auto"
diff --git a/guest/forwarder_guest_launcher/.cargo/config.toml b/guest/forwarder_guest_launcher/.cargo/config.toml
new file mode 100644
index 0000000..a451cda
--- /dev/null
+++ b/guest/forwarder_guest_launcher/.cargo/config.toml
@@ -0,0 +1,6 @@
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+rustflags = ["-C", "target-feature=+crt-static"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "target-feature=+crt-static"]
diff --git a/guest/forwarder_guest_launcher/Cargo.toml b/guest/forwarder_guest_launcher/Cargo.toml
index c875484..9c4d7e3 100644
--- a/guest/forwarder_guest_launcher/Cargo.toml
+++ b/guest/forwarder_guest_launcher/Cargo.toml
@@ -12,6 +12,7 @@
futures = "0.3.31"
listeners = "0.2.1"
log = "0.4.22"
+netdev = "0.31.0"
prost = "0.13.3"
serde = { version = "1.0.215", features = ["derive"] }
tokio = { version = "1.40.0", features = ["process", "rt-multi-thread"] }
@@ -20,3 +21,10 @@
[build-dependencies]
tonic-build = "0.12.3"
+
+[package.metadata.deb]
+maintainer = "ferrochrome-dev@google.com"
+copyright = "2024, The Android Open Source Project"
+depends = "$auto"
+maintainer-scripts = "debian/"
+systemd-units = { }
diff --git a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF b/guest/forwarder_guest_launcher/debian/service
similarity index 62%
rename from build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
rename to guest/forwarder_guest_launcher/debian/service
index f4c2a24..6824c70 100644
--- a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
+++ b/guest/forwarder_guest_launcher/debian/service
@@ -3,12 +3,14 @@
After=syslog.target
After=network.target
After=virtiofs_internal.service
+
[Service]
-ExecStart=/usr/bin/bash -c '/usr/local/bin/forwarder_guest_launcher --host 192.168.0.1 --grpc_port $(cat /mnt/internal/debian_service_port)'
+ExecStart=/usr/bin/bash -c '/usr/bin/forwarder_guest_launcher --grpc_port $(cat /mnt/internal/debian_service_port)'
Type=simple
Restart=on-failure
RestartSec=1
User=root
Group=root
+
[Install]
WantedBy=multi-user.target
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
index f6944d6..963a531 100644
--- a/guest/forwarder_guest_launcher/src/main.rs
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -18,11 +18,11 @@
use clap::Parser;
use csv_async::AsyncReader;
use debian_service::debian_service_client::DebianServiceClient;
-use debian_service::{QueueOpeningRequest, ReportVmActivePortsRequest};
+use debian_service::{ActivePort, QueueOpeningRequest, ReportVmActivePortsRequest};
use futures::stream::StreamExt;
use log::{debug, error};
use serde::Deserialize;
-use std::collections::HashSet;
+use std::collections::HashMap;
use std::process::Stdio;
use tokio::io::BufReader;
use tokio::process::Command;
@@ -46,16 +46,14 @@
ip: i8,
lport: i32,
rport: i32,
+ #[serde(alias = "C-COMM")]
+ c_comm: String,
newstate: String,
}
#[derive(Parser)]
/// Flags for running command
pub struct Args {
- /// Host IP address
- #[arg(long)]
- #[arg(alias = "host")]
- host_addr: String,
/// grpc port number
#[arg(long)]
#[arg(alias = "grpc_port")]
@@ -92,12 +90,12 @@
}
async fn send_active_ports_report(
- listening_ports: HashSet<i32>,
+ listening_ports: HashMap<i32, ActivePort>,
client: &mut DebianServiceClient<Channel>,
) -> Result<(), Box<dyn std::error::Error>> {
let res = client
.report_vm_active_ports(Request::new(ReportVmActivePortsRequest {
- ports: listening_ports.into_iter().collect(),
+ ports: listening_ports.values().cloned().collect(),
}))
.await?
.into_inner();
@@ -130,12 +128,16 @@
// TODO(b/340126051): Consider using NETLINK_SOCK_DIAG for the optimization.
let listeners = listeners::get_all()?;
// TODO(b/340126051): Support distinguished port forwarding for ipv6 as well.
- let mut listening_ports: HashSet<_> = listeners
+ let mut listening_ports: HashMap<_, _> = listeners
.iter()
- .map(|x| x.socket)
- .filter(|x| x.is_ipv4())
- .map(|x| x.port().into())
- .filter(|x| is_forwardable_port(*x))
+ .filter(|x| x.socket.is_ipv4())
+ .map(|x| {
+ (
+ x.socket.port().into(),
+ ActivePort { port: x.socket.port().into(), comm: x.process.name.to_string() },
+ )
+ })
+ .filter(|(x, _)| is_forwardable_port(*x))
.collect();
send_active_ports_report(listening_ports.clone(), &mut client).await?;
@@ -153,7 +155,7 @@
}
match row.newstate.as_str() {
TCPSTATES_STATE_LISTEN => {
- listening_ports.insert(row.lport);
+ listening_ports.insert(row.lport, ActivePort { port: row.lport, comm: row.c_comm });
}
TCPSTATES_STATE_CLOSE => {
listening_ports.remove(&row.lport);
@@ -171,7 +173,8 @@
env_logger::init();
debug!("Starting forwarder_guest_launcher");
let args = Args::parse();
- let addr = format!("https://{}:{}", args.host_addr, args.grpc_port);
+ let gateway_ip_addr = netdev::get_default_gateway()?.ipv4[0];
+ let addr = format!("https://{}:{}", gateway_ip_addr.to_string(), args.grpc_port);
let channel = Endpoint::from_shared(addr)?.connect().await?;
let client = DebianServiceClient::new(channel);
diff --git a/guest/ip_addr_reporter/.gitignore b/guest/ip_addr_reporter/.gitignore
deleted file mode 100644
index ea8c4bf..0000000
--- a/guest/ip_addr_reporter/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target
diff --git a/guest/ip_addr_reporter/Cargo.toml b/guest/ip_addr_reporter/Cargo.toml
deleted file mode 100644
index 7592e3f..0000000
--- a/guest/ip_addr_reporter/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[package]
-name = "ip_addr_reporter"
-version = "0.1.0"
-edition = "2021"
-license = "Apache-2.0"
-
-[dependencies]
-clap = { version = "4.5.20", features = ["derive"] }
-netdev = "0.31.0"
-prost = "0.13.3"
-tokio = { version = "1.40.0", features = ["rt-multi-thread"] }
-tonic = "0.12.3"
-
-[build-dependencies]
-tonic-build = "0.12.3"
diff --git a/guest/ip_addr_reporter/build.rs b/guest/ip_addr_reporter/build.rs
deleted file mode 100644
index e3939d4..0000000
--- a/guest/ip_addr_reporter/build.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() -> Result<(), Box<dyn std::error::Error>> {
- let proto_file = "../../libs/debian_service/proto/DebianService.proto";
-
- tonic_build::compile_protos(proto_file).unwrap();
-
- Ok(())
-}
diff --git a/guest/ip_addr_reporter/src/main.rs b/guest/ip_addr_reporter/src/main.rs
deleted file mode 100644
index 62a7aef..0000000
--- a/guest/ip_addr_reporter/src/main.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use api::debian_service_client::DebianServiceClient;
-use api::IpAddr;
-
-use clap::Parser;
-pub mod api {
- tonic::include_proto!("com.android.virtualization.terminal.proto");
-}
-
-#[derive(Parser)]
-/// Flags for running command
-pub struct Args {
- /// grpc port number
- #[arg(long)]
- #[arg(alias = "grpc_port")]
- grpc_port: String,
-}
-
-#[tokio::main]
-async fn main() -> Result<(), String> {
- let args = Args::parse();
- let gateway_ip_addr = netdev::get_default_gateway()?.ipv4[0];
- let ip_addr = netdev::get_default_interface()?.ipv4[0].addr();
-
- let server_addr = format!("http://{}:{}", gateway_ip_addr.to_string(), args.grpc_port);
-
- println!("local ip addr: {}", ip_addr.to_string());
- println!("coonect to grpc server {}", server_addr);
-
- let mut client = DebianServiceClient::connect(server_addr).await.map_err(|e| e.to_string())?;
-
- let request = tonic::Request::new(IpAddr { addr: ip_addr.to_string() });
-
- let response = client.report_vm_ip_addr(request).await.map_err(|e| e.to_string())?;
- println!("response from server: {:?}", response);
- Ok(())
-}
diff --git a/guest/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl b/guest/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
index b7a539b..8d02d97 100644
--- a/guest/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
+++ b/guest/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
@@ -78,6 +78,20 @@
byte[] getVmInstanceSecret(in byte[] identifier, int size);
/**
+ * Write `data`, on behalf of the client, to Secretkeeper.
+ * This is confidential to the pVM and protected via appropriate DICE policy
+ * on the payload's DICE chain.
+ */
+ void writePayloadRpData(in byte[32] data);
+
+ /**
+ * Read payload's `data` written on behalf of the payload in Secretkeeper.
+ * The returned value can be null either due to no value written or because
+ * Android maliciously deleted the value - Secretkeeper deletion are not authenticated.
+ */
+ @nullable byte[32] readPayloadRpData();
+
+ /**
* Gets the DICE attestation chain for the VM.
*
* The DICE chain must not be made available to all VMs as it contains privacy breaking
@@ -116,4 +130,13 @@
* certification chain.
*/
AttestationResult requestAttestation(in byte[] challenge, in boolean testMode);
+
+ /**
+ * Checks whether the VM instance is new - i.e., if this is the first run of an instance.
+ * This is an indication of fresh new VM secrets. Payload can use this to setup the fresh
+ * instance if needed.
+ *
+ * @return true on the first boot of the instance & false on subsequent boot.
+ */
+ boolean isNewInstance();
}
diff --git a/guest/microdroid_manager/microdroid_manager.rc b/guest/microdroid_manager/microdroid_manager.rc
index da38564..9fa8a9d 100644
--- a/guest/microdroid_manager/microdroid_manager.rc
+++ b/guest/microdroid_manager/microdroid_manager.rc
@@ -2,8 +2,6 @@
disabled
# print android log to kmsg
file /dev/kmsg w
- # redirect stdout/stderr to kmsg_debug
- stdio_to_kmsg
setenv RUST_LOG info
# TODO(jooyung) remove this when microdroid_manager becomes a daemon
oneshot
diff --git a/guest/microdroid_manager/src/dice.rs b/guest/microdroid_manager/src/dice.rs
index edc4d63..bf89358 100644
--- a/guest/microdroid_manager/src/dice.rs
+++ b/guest/microdroid_manager/src/dice.rs
@@ -153,7 +153,8 @@
subcomponents.into_iter().map(Subcomponent::into_value).collect::<Result<Vec<_>>>()?;
map.push((cbor!(-71002)?, cbor!(values)?));
}
-
+ // Add a placeholder security version as it is required by the open-dice profile "Android.16"
+ map.push((cbor!(-70005)?, cbor!(0)?));
Ok(Value::Map(map).to_vec()?)
}
@@ -180,10 +181,10 @@
let config_descriptor =
format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
- 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
+ 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
- 0x68,
+ 0x68, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
];
assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Ok(())
@@ -199,10 +200,10 @@
let config_descriptor =
format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
- 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
+ 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
- 0x69, 0x6e, 0x61, 0x72, 0x79,
+ 0x69, 0x6e, 0x61, 0x72, 0x79, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
];
assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Ok(())
@@ -228,13 +229,13 @@
let config_descriptor = format_payload_config_descriptor(&payload_metadata, subcomponents)?;
// Verified using cbor.me.
static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
- 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
+ 0xa4, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
0x68, 0x3a, 0x00, 0x01, 0x15, 0x59, 0x82, 0xa4, 0x01, 0x64, 0x61, 0x70, 0x6b, 0x31,
0x02, 0x01, 0x03, 0x42, 0x2a, 0x2b, 0x04, 0x41, 0x11, 0xa4, 0x01, 0x64, 0x61, 0x70,
0x6b, 0x32, 0x02, 0x1b, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x41,
- 0x2b, 0x04, 0x42, 0x13, 0x14,
+ 0x2b, 0x04, 0x42, 0x13, 0x14, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
];
assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Ok(())
diff --git a/guest/microdroid_manager/src/main.rs b/guest/microdroid_manager/src/main.rs
index 4b261c4..57ad35d 100644
--- a/guest/microdroid_manager/src/main.rs
+++ b/guest/microdroid_manager/src/main.rs
@@ -250,7 +250,7 @@
if is_strict_boot() {
// Provisioning must happen on the first boot and never again.
- if is_new_instance() {
+ if is_new_instance_legacy() {
ensure!(
saved_data.is_none(),
MicrodroidError::PayloadInvalidConfig(
@@ -297,6 +297,17 @@
Ok(instance_data)
}
+// The VM instance run can be
+// 1. Either Newly created - which can happen if this is really a new VM instance (or a malicious
+// Android has deleted relevant secrets)
+// 2. Or Re-run from an already seen VM instance.
+#[derive(PartialEq, Eq)]
+enum VmInstanceState {
+ Unknown,
+ NewlyCreated,
+ PreviouslySeen,
+}
+
fn try_run_payload(
service: &Strong<dyn IVirtualMachineService>,
vm_payload_service_fd: OwnedFd,
@@ -326,8 +337,25 @@
// To minimize the exposure to untrusted data, derive dice profile as soon as possible.
info!("DICE derivation for payload");
let dice_artifacts = dice_derivation(dice, &instance_data, &payload_metadata)?;
- let vm_secret =
- VmSecret::new(dice_artifacts, service).context("Failed to create VM secrets")?;
+ let mut state = VmInstanceState::Unknown;
+ let vm_secret = VmSecret::new(dice_artifacts, service, &mut state)
+ .context("Failed to create VM secrets")?;
+
+ let is_new_instance = match state {
+ VmInstanceState::NewlyCreated => true,
+ VmInstanceState::PreviouslySeen => false,
+ VmInstanceState::Unknown => {
+ // VmSecret instantiation was not able to determine the state. This should only happen
+ // for legacy secret mechanism (V1) - in which case fallback to legacy
+ // instance.img based determination of state.
+ ensure!(
+ !should_defer_rollback_protection(),
+ "VmInstanceState is Unknown whilst guest is expected to use V2 based secrets.
+ This should've never happened"
+ );
+ is_new_instance_legacy()
+ }
+ };
if cfg!(dice_changes) {
// Now that the DICE derivation is done, it's ok to allow payload code to run.
@@ -387,6 +415,7 @@
service.clone(),
vm_secret,
vm_payload_service_fd,
+ is_new_instance,
)?;
// Set export_tombstones if enabled
@@ -488,7 +517,7 @@
Path::new(AVF_STRICT_BOOT).exists()
}
-fn is_new_instance() -> bool {
+fn is_new_instance_legacy() -> bool {
Path::new(AVF_NEW_INSTANCE).exists()
}
@@ -670,9 +699,20 @@
});
}
- if !is_debuggable()? {
- command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
- }
+ // Never accept input from outside
+ command.stdin(Stdio::null());
+
+ // If the VM is debuggable, let stdout/stderr go outside via /dev/kmsg to ease the debugging
+ let (stdout, stderr) = if is_debuggable()? {
+ use std::os::fd::FromRawFd;
+ let kmsg_fd = env::var("ANDROID_FILE__dev_kmsg").unwrap().parse::<i32>().unwrap();
+ // SAFETY: no one closes kmsg_fd
+ unsafe { (Stdio::from_raw_fd(kmsg_fd), Stdio::from_raw_fd(kmsg_fd)) }
+ } else {
+ (Stdio::null(), Stdio::null())
+ };
+ command.stdout(stdout);
+ command.stderr(stderr);
info!("notifying payload started");
service.notifyPayloadStarted()?;
diff --git a/guest/microdroid_manager/src/vm_payload_service.rs b/guest/microdroid_manager/src/vm_payload_service.rs
index 7f4317b..fb57812 100644
--- a/guest/microdroid_manager/src/vm_payload_service.rs
+++ b/guest/microdroid_manager/src/vm_payload_service.rs
@@ -33,6 +33,7 @@
allow_restricted_apis: bool,
virtual_machine_service: Strong<dyn IVirtualMachineService>,
secret: VmSecret,
+ is_new_instance: bool,
}
impl IVmPayloadService for VmPayloadService {
@@ -97,6 +98,29 @@
certificateChain: cert_chain,
})
}
+
+ fn readPayloadRpData(&self) -> binder::Result<Option<[u8; 32]>> {
+ let data = self
+ .secret
+ .read_payload_data_rp()
+ .context("Failed to read payload's rollback protected data")
+ .with_log()
+ .or_service_specific_exception(-1)?;
+ Ok(data)
+ }
+
+ fn writePayloadRpData(&self, data: &[u8; 32]) -> binder::Result<()> {
+ self.secret
+ .write_payload_data_rp(data)
+ .context("Failed to write payload's rollback protected data")
+ .with_log()
+ .or_service_specific_exception(-1)?;
+ Ok(())
+ }
+
+ fn isNewInstance(&self) -> binder::Result<bool> {
+ Ok(self.is_new_instance)
+ }
}
impl Interface for VmPayloadService {}
@@ -107,8 +131,9 @@
allow_restricted_apis: bool,
vm_service: Strong<dyn IVirtualMachineService>,
secret: VmSecret,
+ is_new_instance: bool,
) -> VmPayloadService {
- Self { allow_restricted_apis, virtual_machine_service: vm_service, secret }
+ Self { allow_restricted_apis, virtual_machine_service: vm_service, secret, is_new_instance }
}
fn check_restricted_apis_allowed(&self) -> binder::Result<()> {
@@ -128,9 +153,10 @@
vm_service: Strong<dyn IVirtualMachineService>,
secret: VmSecret,
vm_payload_service_fd: OwnedFd,
+ is_new_instance: bool,
) -> Result<()> {
let vm_payload_binder = BnVmPayloadService::new_binder(
- VmPayloadService::new(allow_restricted_apis, vm_service, secret),
+ VmPayloadService::new(allow_restricted_apis, vm_service, secret, is_new_instance),
BinderFeatures::default(),
);
diff --git a/guest/microdroid_manager/src/vm_secret.rs b/guest/microdroid_manager/src/vm_secret.rs
index 5cc90ff..56b3482 100644
--- a/guest/microdroid_manager/src/vm_secret.rs
+++ b/guest/microdroid_manager/src/vm_secret.rs
@@ -38,6 +38,7 @@
use zeroize::Zeroizing;
use std::sync::Mutex;
use std::sync::Arc;
+use crate::VmInstanceState;
const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
const AUTHORITY_HASH: i64 = -4670549;
@@ -71,13 +72,20 @@
// with downgraded images will not have access to VM's secret.
// V2 secrets require hardware support - Secretkeeper HAL, which (among other things)
// is backed by tamper-evident storage, providing rollback protection to these secrets.
- V2 { dice_artifacts: OwnedDiceArtifactsWithExplicitKey, skp_secret: ZVec },
+ V2 {
+ instance_id: [u8; ID_SIZE],
+ dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
+ skp_secret: ZVec,
+ secretkeeper_session: SkVmSession,
+ },
// V1 secrets are not protected against rollback of boot images.
// They are reliable only if rollback of images was prevented by verified boot ie,
// each stage (including pvmfw/Microdroid/Microdroid Manager) prevents downgrade of next
// stage. These are now legacy secrets & used only when Secretkeeper HAL is not supported
// by device.
- V1 { dice_artifacts: OwnedDiceArtifacts },
+ V1 {
+ dice_artifacts: OwnedDiceArtifacts,
+ },
}
// For supporting V2 secrets, guest expects the public key to be present in the Linux device tree.
@@ -92,6 +100,7 @@
pub fn new(
dice_artifacts: OwnedDiceArtifacts,
vm_service: &Strong<dyn IVirtualMachineService>,
+ state: &mut VmInstanceState,
) -> Result<Self> {
ensure!(dice_artifacts.bcc().is_some(), "Dice chain missing");
if !crate::should_defer_rollback_protection() {
@@ -100,24 +109,28 @@
let explicit_dice = OwnedDiceArtifactsWithExplicitKey::from_owned_artifacts(dice_artifacts)
.context("Failed to get Dice artifacts in explicit key format")?;
- let session = SkVmSession::new(vm_service, &explicit_dice)?;
let id = super::get_instance_id()?.ok_or(anyhow!("Missing instance_id"))?;
let explicit_dice_chain = explicit_dice
.explicit_key_dice_chain()
.ok_or(anyhow!("Missing explicit dice chain, this is unusual"))?;
let policy = sealing_policy(explicit_dice_chain)
.map_err(|e| anyhow!("Failed to build a sealing_policy: {e}"))?;
+ let session = SkVmSession::new(vm_service, &explicit_dice, policy)?;
let mut skp_secret = Zeroizing::new([0u8; SECRET_SIZE]);
- if let Some(secret) = session.get_secret(id, Some(policy.clone()))? {
- *skp_secret = secret
+ if let Some(secret) = session.get_secret(id)? {
+ *skp_secret = secret;
+ *state = VmInstanceState::PreviouslySeen;
} else {
log::warn!("No entry found in Secretkeeper for this VM instance, creating new secret.");
*skp_secret = rand::random();
- session.store_secret(id, skp_secret.clone(), policy)?;
+ session.store_secret(id, skp_secret.clone())?;
+ *state = VmInstanceState::NewlyCreated;
}
Ok(Self::V2 {
+ instance_id: id,
dice_artifacts: explicit_dice,
skp_secret: ZVec::try_from(skp_secret.to_vec())?,
+ secretkeeper_session: session,
})
}
@@ -130,7 +143,7 @@
fn get_vm_secret(&self, salt: &[u8], identifier: &[u8], key: &mut [u8]) -> Result<()> {
match self {
- Self::V2 { dice_artifacts, skp_secret } => {
+ Self::V2 { dice_artifacts, skp_secret, .. } => {
let mut hasher = sha::Sha256::new();
hasher.update(dice_artifacts.cdi_seal());
hasher.update(skp_secret);
@@ -152,6 +165,23 @@
pub fn derive_encryptedstore_key(&self, key: &mut [u8]) -> Result<()> {
self.get_vm_secret(SALT_ENCRYPTED_STORE, ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(), key)
}
+
+ pub fn read_payload_data_rp(&self) -> Result<Option<[u8; SECRET_SIZE]>> {
+ let Self::V2 { instance_id, secretkeeper_session, .. } = self else {
+ return Err(anyhow!("Rollback protected data is not available with V1 secrets"));
+ };
+ let payload_id = sha::sha512(instance_id);
+ secretkeeper_session.get_secret(payload_id)
+ }
+
+ pub fn write_payload_data_rp(&self, data: &[u8; SECRET_SIZE]) -> Result<()> {
+ let data = Zeroizing::new(*data);
+ let Self::V2 { instance_id, secretkeeper_session, .. } = self else {
+ return Err(anyhow!("Rollback protected data is not available with V1 secrets"));
+ };
+ let payload_id = sha::sha512(instance_id);
+ secretkeeper_session.store_secret(payload_id, data)
+ }
}
// Construct a sealing policy on the dice chain. VMs uses the following set of constraint for
@@ -227,31 +257,35 @@
}
// The secure session between VM & Secretkeeper
-struct SkVmSession(Arc<Mutex<SkSession>>);
+pub(crate) struct SkVmSession {
+ session: Arc<Mutex<SkSession>>,
+ sealing_policy: Vec<u8>,
+}
+
+// TODO(b/378911776): This get_secret/store_secret fails on expired session.
+// Introduce retry after refreshing the session
impl SkVmSession {
fn new(
vm_service: &Strong<dyn IVirtualMachineService>,
dice: &OwnedDiceArtifactsWithExplicitKey,
+ sealing_policy: Vec<u8>,
) -> Result<Self> {
let secretkeeper_proxy = get_secretkeeper_service(vm_service)?;
- let secure_session =
- SkSession::new(secretkeeper_proxy, dice, Some(get_secretkeeper_identity()?))?;
- let secure_session = Arc::new(Mutex::new(secure_session));
- Ok(Self(secure_session))
+ let session = SkSession::new(secretkeeper_proxy, dice, Some(get_secretkeeper_identity()?))?;
+ let session = Arc::new(Mutex::new(session));
+ Ok(Self { session, sealing_policy })
}
- fn store_secret(
- &self,
- id: [u8; ID_SIZE],
- secret: Zeroizing<[u8; SECRET_SIZE]>,
- sealing_policy: Vec<u8>,
- ) -> Result<()> {
- let store_request =
- StoreSecretRequest { id: Id(id), secret: Secret(*secret), sealing_policy };
+ fn store_secret(&self, id: [u8; ID_SIZE], secret: Zeroizing<[u8; SECRET_SIZE]>) -> Result<()> {
+ let store_request = StoreSecretRequest {
+ id: Id(id),
+ secret: Secret(*secret),
+ sealing_policy: self.sealing_policy.clone(),
+ };
log::info!("Secretkeeper operation: {:?}", store_request);
let store_request = store_request.serialize_to_packet().to_vec().map_err(anyhow_err)?;
- let session = &mut *self.0.lock().unwrap();
+ let session = &mut *self.session.lock().unwrap();
let store_response = session.secret_management_request(&store_request)?;
let store_response = ResponsePacket::from_slice(&store_response).map_err(anyhow_err)?;
let response_type = store_response.response_type().map_err(anyhow_err)?;
@@ -263,15 +297,14 @@
Ok(())
}
- fn get_secret(
- &self,
- id: [u8; ID_SIZE],
- updated_sealing_policy: Option<Vec<u8>>,
- ) -> Result<Option<[u8; SECRET_SIZE]>> {
- let get_request = GetSecretRequest { id: Id(id), updated_sealing_policy };
+ fn get_secret(&self, id: [u8; ID_SIZE]) -> Result<Option<[u8; SECRET_SIZE]>> {
+ let get_request = GetSecretRequest {
+ id: Id(id),
+ updated_sealing_policy: Some(self.sealing_policy.clone()),
+ };
log::info!("Secretkeeper operation: {:?}", get_request);
let get_request = get_request.serialize_to_packet().to_vec().map_err(anyhow_err)?;
- let session = &mut *self.0.lock().unwrap();
+ let session = &mut *self.session.lock().unwrap();
let get_response = session.secret_management_request(&get_request)?;
let get_response = ResponsePacket::from_slice(&get_response).map_err(anyhow_err)?;
let response_type = get_response.response_type().map_err(anyhow_err)?;
diff --git a/guest/pvmfw/Android.bp b/guest/pvmfw/Android.bp
index 51f7802..4ef57a6 100644
--- a/guest/pvmfw/Android.bp
+++ b/guest/pvmfw/Android.bp
@@ -17,7 +17,6 @@
"libciborium_nostd",
"libciborium_io_nostd",
"libcoset_nostd",
- "libcstr",
"libdiced_open_dice_nostd",
"libhypervisor_backends",
"liblibfdt_nostd",
@@ -52,9 +51,6 @@
unit_test: true,
},
prefer_rlib: true,
- rustlibs: [
- "libcstr",
- ],
}
rust_test {
@@ -117,6 +113,7 @@
"libcbor_util",
"libciborium",
"libdiced_open_dice_nostd",
+ "libhwtrust",
"libpvmfw_avb_nostd",
"libdiced_sample_inputs_nostd",
"libzerocopy_nostd",
@@ -384,6 +381,8 @@
"-E",
"-P",
"-xassembler-with-cpp", // allow C preprocessor directives
+ // Suppress an error about the unused -c that precedes -S.
+ "-Wno-unused-command-line-argument",
],
visibility: ["//visibility:private"],
}
diff --git a/guest/pvmfw/avb/tests/api_test.rs b/guest/pvmfw/avb/tests/api_test.rs
index 0ed0279..23e05d4 100644
--- a/guest/pvmfw/avb/tests/api_test.rs
+++ b/guest/pvmfw/avb/tests/api_test.rs
@@ -190,7 +190,7 @@
&load_latest_signed_kernel()?,
&load_latest_initrd_normal()?,
/* trusted_public_key= */ &[0u8; 0],
- SlotVerifyError::PublicKeyRejected.into(),
+ SlotVerifyError::PublicKeyRejected(None).into(),
)
}
@@ -200,7 +200,7 @@
&load_latest_signed_kernel()?,
&load_latest_initrd_normal()?,
/* trusted_public_key= */ &[0u8; 512],
- SlotVerifyError::PublicKeyRejected.into(),
+ SlotVerifyError::PublicKeyRejected(None).into(),
)
}
@@ -210,7 +210,7 @@
&load_latest_signed_kernel()?,
&load_latest_initrd_normal()?,
&fs::read(PUBLIC_KEY_RSA2048_PATH)?,
- SlotVerifyError::PublicKeyRejected.into(),
+ SlotVerifyError::PublicKeyRejected(None).into(),
)
}
diff --git a/guest/pvmfw/avb/tests/utils.rs b/guest/pvmfw/avb/tests/utils.rs
index 79552b5..e8590ac 100644
--- a/guest/pvmfw/avb/tests/utils.rs
+++ b/guest/pvmfw/avb/tests/utils.rs
@@ -124,8 +124,7 @@
let footer = extract_avb_footer(&kernel)?;
let kernel_digest =
hash(&[&hash(&[b"bootloader"]), &kernel[..usize::try_from(footer.original_image_size)?]]);
- let capabilities =
- if cfg!(llpvm_changes) { vec![Capability::SecretkeeperProtection] } else { vec![] };
+ let capabilities = vec![Capability::SecretkeeperProtection];
let initrd_digest = Some(hash(&[&hash(&[initrd_salt]), initrd]));
let expected_boot_data = VerifiedBootData {
debug_level: expected_debug_level,
@@ -133,7 +132,7 @@
initrd_digest,
public_key: &public_key,
capabilities,
- rollback_index: if cfg!(llpvm_changes) { 1 } else { 0 },
+ rollback_index: 1,
page_size,
};
assert_eq!(expected_boot_data, verified_boot_data);
diff --git a/guest/pvmfw/src/bootargs.rs b/guest/pvmfw/src/bootargs.rs
index aacd8e0..0a5697f 100644
--- a/guest/pvmfw/src/bootargs.rs
+++ b/guest/pvmfw/src/bootargs.rs
@@ -108,7 +108,6 @@
#[cfg(test)]
mod tests {
use super::*;
- use cstr::cstr;
fn check(raw: &CStr, expected: Result<&[(&str, Option<&str>)], ()>) {
let actual = BootArgsIterator::new(raw);
@@ -136,35 +135,35 @@
#[test]
fn empty() {
- check(cstr!(""), Ok(&[]));
- check(cstr!(" "), Ok(&[]));
- check(cstr!(" \n "), Ok(&[]));
+ check(c"", Ok(&[]));
+ check(c" ", Ok(&[]));
+ check(c" \n ", Ok(&[]));
}
#[test]
fn single() {
- check(cstr!("foo"), Ok(&[("foo", None)]));
- check(cstr!(" foo"), Ok(&[("foo", None)]));
- check(cstr!("foo "), Ok(&[("foo", None)]));
- check(cstr!(" foo "), Ok(&[("foo", None)]));
+ check(c"foo", Ok(&[("foo", None)]));
+ check(c" foo", Ok(&[("foo", None)]));
+ check(c"foo ", Ok(&[("foo", None)]));
+ check(c" foo ", Ok(&[("foo", None)]));
}
#[test]
fn single_with_value() {
- check(cstr!("foo=bar"), Ok(&[("foo", Some("=bar"))]));
- check(cstr!(" foo=bar"), Ok(&[("foo", Some("=bar"))]));
- check(cstr!("foo=bar "), Ok(&[("foo", Some("=bar"))]));
- check(cstr!(" foo=bar "), Ok(&[("foo", Some("=bar"))]));
+ check(c"foo=bar", Ok(&[("foo", Some("=bar"))]));
+ check(c" foo=bar", Ok(&[("foo", Some("=bar"))]));
+ check(c"foo=bar ", Ok(&[("foo", Some("=bar"))]));
+ check(c" foo=bar ", Ok(&[("foo", Some("=bar"))]));
- check(cstr!("foo="), Ok(&[("foo", Some("="))]));
- check(cstr!(" foo="), Ok(&[("foo", Some("="))]));
- check(cstr!("foo= "), Ok(&[("foo", Some("="))]));
- check(cstr!(" foo= "), Ok(&[("foo", Some("="))]));
+ check(c"foo=", Ok(&[("foo", Some("="))]));
+ check(c" foo=", Ok(&[("foo", Some("="))]));
+ check(c"foo= ", Ok(&[("foo", Some("="))]));
+ check(c" foo= ", Ok(&[("foo", Some("="))]));
}
#[test]
fn single_with_quote() {
- check(cstr!("foo=hello\" \"world"), Ok(&[("foo", Some("=hello\" \"world"))]));
+ check(c"foo=hello\" \"world", Ok(&[("foo", Some("=hello\" \"world"))]));
}
#[test]
@@ -175,32 +174,32 @@
#[test]
fn multiple() {
check(
- cstr!(" a=b c=d e= f g "),
+ c" a=b c=d e= f g ",
Ok(&[("a", Some("=b")), ("c", Some("=d")), ("e", Some("=")), ("f", None), ("g", None)]),
);
check(
- cstr!(" a=b \n c=d e= f g"),
+ c" a=b \n c=d e= f g",
Ok(&[("a", Some("=b")), ("c", Some("=d")), ("e", Some("=")), ("f", None), ("g", None)]),
);
}
#[test]
fn incomplete_quote() {
- check(
- cstr!("foo=incomplete\" quote bar=y"),
- Ok(&[("foo", Some("=incomplete\" quote bar=y"))]),
- );
+ check(c"foo=incomplete\" quote bar=y", Ok(&[("foo", Some("=incomplete\" quote bar=y"))]));
}
#[test]
fn complex() {
- check(cstr!(" a a1= b=c d=e,f,g x=\"value with quote\" y=val\"ue with \"multiple\" quo\"te "), Ok(&[
- ("a", None),
- ("a1", Some("=")),
- ("b", Some("=c")),
- ("d", Some("=e,f,g")),
- ("x", Some("=\"value with quote\"")),
- ("y", Some("=val\"ue with \"multiple\" quo\"te")),
- ]));
+ check(
+ c" a a1= b=c d=e,f,g x=\"value with quote\" y=val\"ue with \"multiple\" quo\"te ",
+ Ok(&[
+ ("a", None),
+ ("a1", Some("=")),
+ ("b", Some("=c")),
+ ("d", Some("=e,f,g")),
+ ("x", Some("=\"value with quote\"")),
+ ("y", Some("=val\"ue with \"multiple\" quo\"te")),
+ ]),
+ );
}
}
diff --git a/guest/pvmfw/src/device_assignment.rs b/guest/pvmfw/src/device_assignment.rs
index f37f443..bb2e6ce 100644
--- a/guest/pvmfw/src/device_assignment.rs
+++ b/guest/pvmfw/src/device_assignment.rs
@@ -37,18 +37,6 @@
use zerocopy::byteorder::big_endian::U32;
use zerocopy::FromBytes as _;
-// TODO(b/308694211): Use cstr! from vmbase instead.
-macro_rules! cstr {
- ($str:literal) => {{
- const S: &str = concat!($str, "\0");
- const C: &::core::ffi::CStr = match ::core::ffi::CStr::from_bytes_with_nul(S.as_bytes()) {
- Ok(v) => v,
- Err(_) => panic!("string contains interior NUL"),
- };
- C
- }};
-}
-
// TODO(b/277993056): Keep constants derived from platform.dts in one place.
const CELLS_PER_INTERRUPT: usize = 3; // from /intc node in platform.dts
@@ -332,7 +320,7 @@
// };
// };
//
- // Then locate_overlay_target_path(cstr!("/fragment@rng/__overlay__/rng")) is Ok("/rng")
+ // Then locate_overlay_target_path(c"/fragment@rng/__overlay__/rng") is Ok("/rng")
//
// Contrary to fdt_overlay_target_offset(), this API enforces overlay target property
// 'target-path = "/"', so the overlay doesn't modify and/or append platform DT's existing
@@ -343,10 +331,9 @@
dtbo_node: &FdtNode,
) -> Result<CString> {
let fragment_node = dtbo_node.supernode_at_depth(1)?;
- let target_path = fragment_node
- .getprop_str(cstr!("target-path"))?
- .ok_or(DeviceAssignmentError::InvalidDtbo)?;
- if target_path != cstr!("/") {
+ let target_path =
+ fragment_node.getprop_str(c"target-path")?.ok_or(DeviceAssignmentError::InvalidDtbo)?;
+ if target_path != c"/" {
return Err(DeviceAssignmentError::UnsupportedOverlayTarget);
}
@@ -415,7 +402,7 @@
/// Parses Physical devices in VM DTBO
fn parse_physical_devices(&self) -> Result<BTreeMap<Phandle, PhysicalDeviceInfo>> {
- let Some(physical_node) = self.as_ref().node(cstr!("/host"))? else {
+ let Some(physical_node) = self.as_ref().node(c"/host")? else {
return Ok(BTreeMap::new());
};
@@ -459,7 +446,7 @@
let vm_dtbo = self.as_ref();
let mut phandle_map = BTreeMap::new();
- let Some(local_fixups) = vm_dtbo.node(cstr!("/__local_fixups__"))? else {
+ let Some(local_fixups) = vm_dtbo.node(c"/__local_fixups__")? else {
return Ok(phandle_map);
};
@@ -615,15 +602,14 @@
impl PvIommu {
fn parse(node: &FdtNode) -> Result<Self> {
- let iommu_cells = node
- .getprop_u32(cstr!("#iommu-cells"))?
- .ok_or(DeviceAssignmentError::InvalidPvIommu)?;
+ let iommu_cells =
+ node.getprop_u32(c"#iommu-cells")?.ok_or(DeviceAssignmentError::InvalidPvIommu)?;
// Ensures #iommu-cells = <1>. It means that `<iommus>` entry contains pair of
// (pvIOMMU ID, vSID)
if iommu_cells != 1 {
return Err(DeviceAssignmentError::InvalidPvIommu);
}
- let id = node.getprop_u32(cstr!("id"))?.ok_or(DeviceAssignmentError::InvalidPvIommu)?;
+ let id = node.getprop_u32(c"id")?.ok_or(DeviceAssignmentError::InvalidPvIommu)?;
Ok(Self { id })
}
}
@@ -687,10 +673,10 @@
impl PhysIommu {
fn parse(node: &FdtNode) -> Result<Option<Self>> {
- let Some(token) = node.getprop_u64(cstr!("android,pvmfw,token"))? else {
+ let Some(token) = node.getprop_u64(c"android,pvmfw,token")? else {
return Ok(None);
};
- let Some(iommu_cells) = node.getprop_u32(cstr!("#iommu-cells"))? else {
+ let Some(iommu_cells) = node.getprop_u32(c"#iommu-cells")? else {
return Err(DeviceAssignmentError::InvalidPhysIommu);
};
// Currently only supports #iommu-cells = <1>.
@@ -715,7 +701,7 @@
phys_iommus: &BTreeMap<Phandle, PhysIommu>,
) -> Result<Vec<(PhysIommu, Sid)>> {
let mut iommus = vec![];
- let Some(mut cells) = node.getprop_cells(cstr!("iommus"))? else {
+ let Some(mut cells) = node.getprop_cells(c"iommus")? else {
return Ok(iommus);
};
while let Some(cell) = cells.next() {
@@ -735,7 +721,7 @@
}
fn parse(node: &FdtNode, phys_iommus: &BTreeMap<Phandle, PhysIommu>) -> Result<Option<Self>> {
- let Some(phandle) = node.getprop_u32(cstr!("android,pvmfw,target"))? else {
+ let Some(phandle) = node.getprop_u32(c"android,pvmfw,target")? else {
return Ok(None);
};
let target = Phandle::try_from(phandle)?;
@@ -812,7 +798,7 @@
// Validation: Validate if interrupts cell numbers are multiple of #interrupt-cells.
// We can't know how many interrupts would exist.
let interrupts_cells = node
- .getprop_cells(cstr!("interrupts"))?
+ .getprop_cells(c"interrupts")?
.ok_or(DeviceAssignmentError::InvalidInterrupts)?
.count();
if interrupts_cells % CELLS_PER_INTERRUPT != 0 {
@@ -820,7 +806,7 @@
}
// Once validated, keep the raw bytes so patch can be done with setprop()
- Ok(node.getprop(cstr!("interrupts")).unwrap().unwrap().into())
+ Ok(node.getprop(c"interrupts").unwrap().unwrap().into())
}
// TODO(b/277993056): Also validate /__local_fixups__ to ensure that <iommus> has phandle.
@@ -829,7 +815,7 @@
pviommus: &BTreeMap<Phandle, PvIommu>,
) -> Result<Vec<(PvIommu, Vsid)>> {
let mut iommus = vec![];
- let Some(mut cells) = node.getprop_cells(cstr!("iommus"))? else {
+ let Some(mut cells) = node.getprop_cells(c"iommus")? else {
return Ok(iommus);
};
while let Some(cell) = cells.next() {
@@ -917,15 +903,15 @@
fn patch(&self, fdt: &mut Fdt, pviommu_phandles: &BTreeMap<PvIommu, Phandle>) -> Result<()> {
let mut dst = fdt.node_mut(&self.node_path)?.unwrap();
- dst.setprop(cstr!("reg"), &to_be_bytes(&self.reg))?;
- dst.setprop(cstr!("interrupts"), &self.interrupts)?;
+ dst.setprop(c"reg", &to_be_bytes(&self.reg))?;
+ dst.setprop(c"interrupts", &self.interrupts)?;
let mut iommus = Vec::with_capacity(8 * self.iommus.len());
for (pviommu, vsid) in &self.iommus {
let phandle = pviommu_phandles.get(pviommu).unwrap();
iommus.extend_from_slice(&u32::from(*phandle).to_be_bytes());
iommus.extend_from_slice(&vsid.0.to_be_bytes());
}
- dst.setprop(cstr!("iommus"), &iommus)?;
+ dst.setprop(c"iommus", &iommus)?;
Ok(())
}
@@ -939,7 +925,7 @@
}
impl DeviceAssignmentInfo {
- const PVIOMMU_COMPATIBLE: &'static CStr = cstr!("pkvm,pviommu");
+ const PVIOMMU_COMPATIBLE: &'static CStr = c"pkvm,pviommu";
/// Parses pvIOMMUs in fdt
// Note: This will validate pvIOMMU ids' uniqueness, even when unassigned.
@@ -1046,8 +1032,8 @@
Self::validate_pviommu_topology(&assigned_devices)?;
let mut vm_dtbo_mask = vm_dtbo.build_mask(assigned_device_paths)?;
- vm_dtbo_mask.mask_all(&DtPathTokens::new(cstr!("/__local_fixups__"))?);
- vm_dtbo_mask.mask_all(&DtPathTokens::new(cstr!("/__symbols__"))?);
+ vm_dtbo_mask.mask_all(&DtPathTokens::new(c"/__local_fixups__")?);
+ vm_dtbo_mask.mask_all(&DtPathTokens::new(c"/__symbols__")?);
// Note: Any node without __overlay__ will be ignored by fdt_apply_overlay,
// so doesn't need to be filtered.
@@ -1060,7 +1046,7 @@
let vm_dtbo = vm_dtbo.as_mut();
// Filter unused references in /__local_fixups__
- if let Some(local_fixups) = vm_dtbo.node_mut(cstr!("/__local_fixups__"))? {
+ if let Some(local_fixups) = vm_dtbo.node_mut(c"/__local_fixups__")? {
filter_with_mask(local_fixups, &self.vm_dtbo_mask)?;
}
@@ -1078,7 +1064,7 @@
for pviommu in &self.pviommus {
let mut node = compatible.ok_or(DeviceAssignmentError::TooManyPvIommu)?;
let phandle = node.as_node().get_phandle()?.ok_or(DeviceAssignmentError::Internal)?;
- node.setprop_inplace(cstr!("id"), &pviommu.id.to_be_bytes())?;
+ node.setprop_inplace(c"id", &pviommu.id.to_be_bytes())?;
if pviommu_phandles.insert(*pviommu, phandle).is_some() {
return Err(DeviceAssignmentError::Internal);
}
@@ -1108,10 +1094,10 @@
/// Cleans device trees not to contain any pre-populated nodes/props for device assignment.
pub fn clean(fdt: &mut Fdt) -> Result<()> {
- let mut compatible = fdt.root_mut().next_compatible(cstr!("pkvm,pviommu"))?;
+ let mut compatible = fdt.root_mut().next_compatible(c"pkvm,pviommu")?;
// Filters pre-populated
while let Some(filtered_pviommu) = compatible {
- compatible = filtered_pviommu.delete_and_next_compatible(cstr!("pkvm,pviommu"))?;
+ compatible = filtered_pviommu.delete_and_next_compatible(c"pkvm,pviommu")?;
}
// Removes any dangling references in __symbols__ (e.g. removed pvIOMMUs)
@@ -1239,24 +1225,23 @@
return Err(FdtError::NotFound.into());
};
- let reg = node.getprop(cstr!("reg"))?.ok_or(DeviceAssignmentError::MalformedReg)?;
- let interrupts = node
- .getprop(cstr!("interrupts"))?
- .ok_or(DeviceAssignmentError::InvalidInterrupts)?;
+ let reg = node.getprop(c"reg")?.ok_or(DeviceAssignmentError::MalformedReg)?;
+ let interrupts =
+ node.getprop(c"interrupts")?.ok_or(DeviceAssignmentError::InvalidInterrupts)?;
let mut iommus = vec![];
- if let Some(mut cells) = node.getprop_cells(cstr!("iommus"))? {
+ if let Some(mut cells) = node.getprop_cells(c"iommus")? {
while let Some(pviommu_id) = cells.next() {
// pvIOMMU id
let phandle = Phandle::try_from(pviommu_id)?;
let pviommu = fdt
.node_with_phandle(phandle)?
.ok_or(DeviceAssignmentError::MalformedIommus)?;
- let compatible = pviommu.getprop_str(cstr!("compatible"));
- if compatible != Ok(Some(cstr!("pkvm,pviommu"))) {
+ let compatible = pviommu.getprop_str(c"compatible");
+ if compatible != Ok(Some(c"pkvm,pviommu")) {
return Err(DeviceAssignmentError::MalformedIommus);
}
let id = pviommu
- .getprop_u32(cstr!("id"))?
+ .getprop_u32(c"id")?
.ok_or(DeviceAssignmentError::MalformedIommus)?;
iommus.push(id);
@@ -1273,8 +1258,8 @@
fn collect_pviommus(fdt: &Fdt) -> Result<Vec<u32>> {
let mut pviommus = BTreeSet::new();
- for pviommu in fdt.compatible_nodes(cstr!("pkvm,pviommu"))? {
- if let Ok(Some(id)) = pviommu.getprop_u32(cstr!("id")) {
+ for pviommu in fdt.compatible_nodes(c"pkvm,pviommu")? {
+ if let Ok(Some(id)) = pviommu.getprop_u32(c"id") {
pviommus.insert(id);
}
}
@@ -1395,24 +1380,24 @@
let symbols = vm_dtbo.symbols().unwrap().unwrap();
- let rng = vm_dtbo.node(cstr!("/fragment@0/__overlay__/rng")).unwrap();
+ let rng = vm_dtbo.node(c"/fragment@0/__overlay__/rng").unwrap();
assert_ne!(rng, None);
- let rng_symbol = symbols.getprop_str(cstr!("rng")).unwrap();
- assert_eq!(Some(cstr!("/fragment@0/__overlay__/rng")), rng_symbol);
+ let rng_symbol = symbols.getprop_str(c"rng").unwrap();
+ assert_eq!(Some(c"/fragment@0/__overlay__/rng"), rng_symbol);
- let light = vm_dtbo.node(cstr!("/fragment@0/__overlay__/light")).unwrap();
+ let light = vm_dtbo.node(c"/fragment@0/__overlay__/light").unwrap();
assert_eq!(light, None);
- let light_symbol = symbols.getprop_str(cstr!("light")).unwrap();
+ let light_symbol = symbols.getprop_str(c"light").unwrap();
assert_eq!(None, light_symbol);
- let led = vm_dtbo.node(cstr!("/fragment@0/__overlay__/led")).unwrap();
+ let led = vm_dtbo.node(c"/fragment@0/__overlay__/led").unwrap();
assert_eq!(led, None);
- let led_symbol = symbols.getprop_str(cstr!("led")).unwrap();
+ let led_symbol = symbols.getprop_str(c"led").unwrap();
assert_eq!(None, led_symbol);
- let backlight = vm_dtbo.node(cstr!("/fragment@0/__overlay__/bus0/backlight")).unwrap();
+ let backlight = vm_dtbo.node(c"/fragment@0/__overlay__/bus0/backlight").unwrap();
assert_eq!(backlight, None);
- let backlight_symbol = symbols.getprop_str(cstr!("backlight")).unwrap();
+ let backlight_symbol = symbols.getprop_str(c"backlight").unwrap();
assert_eq!(None, backlight_symbol);
}
@@ -1440,19 +1425,19 @@
}
device_info.patch(platform_dt).unwrap();
- let rng_node = platform_dt.node(cstr!("/bus0/backlight")).unwrap().unwrap();
- let phandle = rng_node.getprop_u32(cstr!("phandle")).unwrap();
+ let rng_node = platform_dt.node(c"/bus0/backlight").unwrap().unwrap();
+ let phandle = rng_node.getprop_u32(c"phandle").unwrap();
assert_ne!(None, phandle);
// Note: Intentionally not using AssignedDeviceNode for matching all props.
type FdtResult<T> = libfdt::Result<T>;
let expected: Vec<(FdtResult<&CStr>, FdtResult<Vec<u8>>)> = vec![
- (Ok(cstr!("android,backlight,ignore-gctrl-reset")), Ok(Vec::new())),
- (Ok(cstr!("compatible")), Ok(Vec::from(*b"android,backlight\0"))),
- (Ok(cstr!("interrupts")), Ok(into_fdt_prop(vec![0x0, 0xF, 0x4]))),
- (Ok(cstr!("iommus")), Ok(Vec::new())),
- (Ok(cstr!("phandle")), Ok(into_fdt_prop(vec![phandle.unwrap()]))),
- (Ok(cstr!("reg")), Ok(into_fdt_prop(vec![0x0, 0x9, 0x0, 0xFF]))),
+ (Ok(c"android,backlight,ignore-gctrl-reset"), Ok(Vec::new())),
+ (Ok(c"compatible"), Ok(Vec::from(*b"android,backlight\0"))),
+ (Ok(c"interrupts"), Ok(into_fdt_prop(vec![0x0, 0xF, 0x4]))),
+ (Ok(c"iommus"), Ok(Vec::new())),
+ (Ok(c"phandle"), Ok(into_fdt_prop(vec![phandle.unwrap()]))),
+ (Ok(c"reg"), Ok(into_fdt_prop(vec![0x0, 0x9, 0x0, 0xFF]))),
];
let mut properties: Vec<_> = rng_node
@@ -1493,7 +1478,7 @@
}
device_info.patch(platform_dt).unwrap();
- let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu")).unwrap();
+ let compatible = platform_dt.root().next_compatible(c"pkvm,pviommu").unwrap();
assert_eq!(None, compatible);
if let Some(symbols) = platform_dt.symbols().unwrap() {
@@ -1794,12 +1779,12 @@
let mut platform_dt_data = pvmfw_fdt_template::RAW.to_vec();
let platform_dt = Fdt::from_mut_slice(&mut platform_dt_data).unwrap();
- let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu"));
+ let compatible = platform_dt.root().next_compatible(c"pkvm,pviommu");
assert_ne!(None, compatible.unwrap());
clean(platform_dt).unwrap();
- let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu"));
+ let compatible = platform_dt.root().next_compatible(c"pkvm,pviommu");
assert_eq!(Ok(None), compatible);
}
diff --git a/guest/pvmfw/src/dice.rs b/guest/pvmfw/src/dice.rs
index a72c1fc..78bd6b8 100644
--- a/guest/pvmfw/src/dice.rs
+++ b/guest/pvmfw/src/dice.rs
@@ -185,6 +185,7 @@
use diced_open_dice::KeyAlgorithm;
use diced_open_dice::HIDDEN_SIZE;
use diced_sample_inputs::make_sample_bcc_and_cdis;
+ use hwtrust::{dice, session::Session};
use pvmfw_avb::Capability;
use pvmfw_avb::DebugLevel;
use pvmfw_avb::Digest;
@@ -426,14 +427,11 @@
},
)
.expect("Failed to derive EcdsaP384 -> Ed25519 BCC");
- let _bcc_handover3 = diced_open_dice::bcc_handover_parse(&buffer).unwrap();
+ let bcc_handover3 = diced_open_dice::bcc_handover_parse(&buffer).unwrap();
- // TODO(b/378813154): Check the DICE chain with `hwtrust` once the profile version
- // is updated.
- // The check cannot be done now because parsing the chain causes the following error:
- // Invalid payload at index 3. Caused by:
- // 0: opendice.example.p256
- // 1: unknown profile version
+ let mut session = Session::default();
+ session.set_allow_any_mode(true);
+ let _chain = dice::Chain::from_cbor(&session, bcc_handover3.bcc().unwrap()).unwrap();
}
fn to_bcc_handover(dice_artifacts: &dyn DiceArtifacts) -> Vec<u8> {
diff --git a/guest/pvmfw/src/fdt.rs b/guest/pvmfw/src/fdt.rs
index 4370675..29212f9 100644
--- a/guest/pvmfw/src/fdt.rs
+++ b/guest/pvmfw/src/fdt.rs
@@ -28,7 +28,6 @@
use core::fmt;
use core::mem::size_of;
use core::ops::Range;
-use cstr::cstr;
use hypervisor_backends::get_device_assigner;
use hypervisor_backends::get_mem_sharer;
use libfdt::AddressRange;
@@ -83,10 +82,10 @@
/// Extract from /config the address range containing the pre-loaded kernel. Absence of /config is
/// not an error.
pub fn read_kernel_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
- let addr = cstr!("kernel-address");
- let size = cstr!("kernel-size");
+ let addr = c"kernel-address";
+ let size = c"kernel-size";
- if let Some(config) = fdt.node(cstr!("/config"))? {
+ if let Some(config) = fdt.node(c"/config")? {
if let (Some(addr), Some(size)) = (config.getprop_u32(addr)?, config.getprop_u32(size)?) {
let addr = addr as usize;
let size = size as usize;
@@ -101,8 +100,8 @@
/// Extract from /chosen the address range containing the pre-loaded ramdisk. Absence is not an
/// error as there can be initrd-less VM.
pub fn read_initrd_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
- let start = cstr!("linux,initrd-start");
- let end = cstr!("linux,initrd-end");
+ let start = c"linux,initrd-start";
+ let end = c"linux,initrd-end";
if let Some(chosen) = fdt.chosen()? {
if let (Some(start), Some(end)) = (chosen.getprop_u32(start)?, chosen.getprop_u32(end)?) {
@@ -118,14 +117,14 @@
let end = u32::try_from(initrd_range.end).unwrap();
let mut node = fdt.chosen_mut()?.ok_or(FdtError::NotFound)?;
- node.setprop(cstr!("linux,initrd-start"), &start.to_be_bytes())?;
- node.setprop(cstr!("linux,initrd-end"), &end.to_be_bytes())?;
+ node.setprop(c"linux,initrd-start", &start.to_be_bytes())?;
+ node.setprop(c"linux,initrd-end", &end.to_be_bytes())?;
Ok(())
}
fn read_bootargs_from(fdt: &Fdt) -> libfdt::Result<Option<CString>> {
if let Some(chosen) = fdt.chosen()? {
- if let Some(bootargs) = chosen.getprop_str(cstr!("bootargs"))? {
+ if let Some(bootargs) = chosen.getprop_str(c"bootargs")? {
// We need to copy the string to heap because the original fdt will be invalidated
// by the templated DT
let copy = CString::new(bootargs.to_bytes()).map_err(|_| FdtError::BadValue)?;
@@ -140,7 +139,7 @@
// This function is called before the verification is done. So, we just copy the bootargs to
// the new FDT unmodified. This will be filtered again in the modify_for_next_stage function
// if the VM is not debuggable.
- node.setprop(cstr!("bootargs"), bootargs.to_bytes_with_nul())
+ node.setprop(c"bootargs", bootargs.to_bytes_with_nul())
}
/// Reads and validates the memory range in the DT.
@@ -186,9 +185,9 @@
fn patch_memory_range(fdt: &mut Fdt, memory_range: &Range<usize>) -> libfdt::Result<()> {
let addr = u64::try_from(MEM_START).unwrap();
let size = u64::try_from(memory_range.len()).unwrap();
- fdt.node_mut(cstr!("/memory"))?
+ fdt.node_mut(c"/memory")?
.ok_or(FdtError::NotFound)?
- .setprop_inplace(cstr!("reg"), [addr.to_be(), size.to_be()].as_bytes())
+ .setprop_inplace(c"reg", [addr.to_be(), size.to_be()].as_bytes())
}
#[derive(Debug, Default)]
@@ -207,7 +206,7 @@
let mut table = ArrayVec::new();
let mut opp_nodes = opp_node.subnodes()?;
for subnode in opp_nodes.by_ref().take(table.capacity()) {
- let prop = subnode.getprop_u64(cstr!("opp-hz"))?.ok_or(FdtError::NotFound)?;
+ let prop = subnode.getprop_u64(c"opp-hz")?.ok_or(FdtError::NotFound)?;
table.push(prop);
}
@@ -239,7 +238,7 @@
}
fn read_cpu_map_from(fdt: &Fdt) -> libfdt::Result<Option<BTreeMap<Phandle, (usize, usize)>>> {
- let Some(cpu_map) = fdt.node(cstr!("/cpus/cpu-map"))? else {
+ let Some(cpu_map) = fdt.node(c"/cpus/cpu-map")? else {
return Ok(None);
};
@@ -254,7 +253,7 @@
let Some(core) = cluster.subnode(&name)? else {
break;
};
- let cpu = core.getprop_u32(cstr!("cpu"))?.ok_or(FdtError::NotFound)?;
+ let cpu = core.getprop_u32(c"cpu")?.ok_or(FdtError::NotFound)?;
let prev = topology.insert(cpu.try_into()?, (n, m));
if prev.is_some() {
return Err(FdtError::BadValue);
@@ -273,10 +272,10 @@
let cpu_map = read_cpu_map_from(fdt)?;
let mut topology: CpuTopology = Default::default();
- let mut cpu_nodes = fdt.compatible_nodes(cstr!("arm,armv8"))?;
+ let mut cpu_nodes = fdt.compatible_nodes(c"arm,armv8")?;
for (idx, cpu) in cpu_nodes.by_ref().take(cpus.capacity()).enumerate() {
- let cpu_capacity = cpu.getprop_u32(cstr!("capacity-dmips-mhz"))?;
- let opp_phandle = cpu.getprop_u32(cstr!("operating-points-v2"))?;
+ let cpu_capacity = cpu.getprop_u32(c"capacity-dmips-mhz")?;
+ let opp_phandle = cpu.getprop_u32(c"operating-points-v2")?;
let opptable_info = if let Some(phandle) = opp_phandle {
let phandle = phandle.try_into()?;
let node = fdt.node_with_phandle(phandle)?.ok_or(FdtError::NotFound)?;
@@ -313,7 +312,7 @@
}
fn read_vcpufreq_info(fdt: &Fdt) -> libfdt::Result<Option<VcpufreqInfo>> {
- let mut nodes = fdt.compatible_nodes(cstr!("virtual,android-v-only-cpufreq"))?;
+ let mut nodes = fdt.compatible_nodes(c"virtual,android-v-only-cpufreq")?;
let Some(node) = nodes.next() else {
return Ok(None);
};
@@ -351,7 +350,7 @@
node: FdtNodeMut,
opptable: Option<ArrayVec<[u64; CpuInfo::MAX_OPPTABLES]>>,
) -> libfdt::Result<()> {
- let oppcompat = cstr!("operating-points-v2");
+ let oppcompat = c"operating-points-v2";
let next = node.next_compatible(oppcompat)?.ok_or(FdtError::NoSpace)?;
let Some(opptable) = opptable else {
@@ -362,7 +361,7 @@
for entry in opptable {
let mut subnode = next_subnode.ok_or(FdtError::NoSpace)?;
- subnode.setprop_inplace(cstr!("opp-hz"), &entry.to_be_bytes())?;
+ subnode.setprop_inplace(c"opp-hz", &entry.to_be_bytes())?;
next_subnode = subnode.next_subnode()?;
}
@@ -391,14 +390,14 @@
cpus: &[CpuInfo],
topology: &Option<CpuTopology>,
) -> libfdt::Result<()> {
- const COMPAT: &CStr = cstr!("arm,armv8");
+ const COMPAT: &CStr = c"arm,armv8";
let mut cpu_phandles = Vec::new();
for (idx, cpu) in cpus.iter().enumerate() {
let mut cur = get_nth_compatible(fdt, idx, COMPAT)?.ok_or(FdtError::NoSpace)?;
let phandle = cur.as_node().get_phandle()?.unwrap();
cpu_phandles.push(phandle);
if let Some(cpu_capacity) = cpu.cpu_capacity {
- cur.setprop_inplace(cstr!("capacity-dmips-mhz"), &cpu_capacity.to_be_bytes())?;
+ cur.setprop_inplace(c"capacity-dmips-mhz", &cpu_capacity.to_be_bytes())?;
}
patch_opptable(cur, cpu.opptable_info)?;
}
@@ -418,7 +417,7 @@
iter = if let Some(core_idx) = core {
let phandle = *cpu_phandles.get(core_idx).unwrap();
let value = u32::from(phandle).to_be_bytes();
- core_node.setprop_inplace(cstr!("cpu"), &value)?;
+ core_node.setprop_inplace(c"cpu", &value)?;
core_node.next_subnode()?
} else {
core_node.delete_and_next_subnode()?
@@ -430,7 +429,7 @@
}
}
} else {
- fdt.node_mut(cstr!("/cpus/cpu-map"))?.unwrap().nop()?;
+ fdt.node_mut(c"/cpus/cpu-map")?.unwrap().nop()?;
}
Ok(())
@@ -440,7 +439,7 @@
/// the guest that don't require being validated by pvmfw.
fn parse_untrusted_props(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
let mut props = BTreeMap::new();
- if let Some(node) = fdt.node(cstr!("/avf/untrusted"))? {
+ if let Some(node) = fdt.node(c"/avf/untrusted")? {
for property in node.properties()? {
let name = property.name()?;
let value = property.value()?;
@@ -457,7 +456,7 @@
/// Read candidate properties' names from DT which could be overlaid
fn parse_vm_ref_dt(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
let mut property_map = BTreeMap::new();
- if let Some(avf_node) = fdt.node(cstr!("/avf"))? {
+ if let Some(avf_node) = fdt.node(c"/avf")? {
for property in avf_node.properties()? {
let name = property.name()?;
let value = property.value()?;
@@ -471,8 +470,7 @@
}
fn validate_untrusted_props(props: &BTreeMap<CString, Vec<u8>>) -> Result<(), FdtValidationError> {
- const FORBIDDEN_PROPS: &[&CStr] =
- &[cstr!("compatible"), cstr!("linux,phandle"), cstr!("phandle")];
+ const FORBIDDEN_PROPS: &[&CStr] = &[c"compatible", c"linux,phandle", c"phandle"];
for name in FORBIDDEN_PROPS {
if props.contains_key(*name) {
@@ -491,9 +489,9 @@
props_info: &BTreeMap<CString, Vec<u8>>,
) -> libfdt::Result<()> {
let root_vm_dt = vm_dt.root_mut();
- let mut avf_vm_dt = root_vm_dt.add_subnode(cstr!("avf"))?;
+ let mut avf_vm_dt = root_vm_dt.add_subnode(c"avf")?;
// TODO(b/318431677): Validate nodes beyond /avf.
- let avf_node = vm_ref_dt.node(cstr!("/avf"))?.ok_or(FdtError::NotFound)?;
+ let avf_node = vm_ref_dt.node(c"/avf")?.ok_or(FdtError::NotFound)?;
for (name, value) in props_info.iter() {
if let Some(ref_value) = avf_node.getprop(name)? {
if value != ref_value {
@@ -551,14 +549,13 @@
/// Read pci host controller ranges, irq maps, and irq map masks from DT
fn read_pci_info_from(fdt: &Fdt) -> libfdt::Result<PciInfo> {
- let node =
- fdt.compatible_nodes(cstr!("pci-host-cam-generic"))?.next().ok_or(FdtError::NotFound)?;
+ let node = fdt.compatible_nodes(c"pci-host-cam-generic")?.next().ok_or(FdtError::NotFound)?;
let mut ranges = node.ranges::<(u32, u64), u64, u64>()?.ok_or(FdtError::NotFound)?;
let range0 = ranges.next().ok_or(FdtError::NotFound)?;
let range1 = ranges.next().ok_or(FdtError::NotFound)?;
- let irq_masks = node.getprop_cells(cstr!("interrupt-map-mask"))?.ok_or(FdtError::NotFound)?;
+ let irq_masks = node.getprop_cells(c"interrupt-map-mask")?.ok_or(FdtError::NotFound)?;
let mut chunks = CellChunkIterator::<{ PciInfo::IRQ_MASK_CELLS }>::new(irq_masks);
let irq_masks = (&mut chunks).take(PciInfo::MAX_IRQS).collect();
@@ -567,7 +564,7 @@
return Err(FdtError::NoSpace);
}
- let irq_maps = node.getprop_cells(cstr!("interrupt-map"))?.ok_or(FdtError::NotFound)?;
+ let irq_maps = node.getprop_cells(c"interrupt-map")?.ok_or(FdtError::NotFound)?;
let mut chunks = CellChunkIterator::<{ PciInfo::IRQ_MAP_CELLS }>::new(irq_maps);
let irq_maps = (&mut chunks).take(PciInfo::MAX_IRQS).collect();
@@ -721,16 +718,16 @@
fn patch_pci_info(fdt: &mut Fdt, pci_info: &PciInfo) -> libfdt::Result<()> {
let mut node =
- fdt.root_mut().next_compatible(cstr!("pci-host-cam-generic"))?.ok_or(FdtError::NotFound)?;
+ fdt.root_mut().next_compatible(c"pci-host-cam-generic")?.ok_or(FdtError::NotFound)?;
let irq_masks_size = pci_info.irq_masks.len() * size_of::<PciIrqMask>();
- node.trimprop(cstr!("interrupt-map-mask"), irq_masks_size)?;
+ node.trimprop(c"interrupt-map-mask", irq_masks_size)?;
let irq_maps_size = pci_info.irq_maps.len() * size_of::<PciIrqMap>();
- node.trimprop(cstr!("interrupt-map"), irq_maps_size)?;
+ node.trimprop(c"interrupt-map", irq_maps_size)?;
node.setprop_inplace(
- cstr!("ranges"),
+ c"ranges",
[pci_info.ranges[0].to_cells(), pci_info.ranges[1].to_cells()].as_flattened(),
)
}
@@ -747,7 +744,7 @@
fn read_serial_info_from(fdt: &Fdt) -> libfdt::Result<SerialInfo> {
let mut addrs = ArrayVec::new();
- let mut serial_nodes = fdt.compatible_nodes(cstr!("ns16550a"))?;
+ let mut serial_nodes = fdt.compatible_nodes(c"ns16550a")?;
for node in serial_nodes.by_ref().take(addrs.capacity()) {
let reg = node.first_reg()?;
addrs.push(reg.addr);
@@ -793,7 +790,7 @@
}
fn read_wdt_info_from(fdt: &Fdt) -> libfdt::Result<WdtInfo> {
- let mut node_iter = fdt.compatible_nodes(cstr!("qemu,vcpu-stall-detector"))?;
+ let mut node_iter = fdt.compatible_nodes(c"qemu,vcpu-stall-detector")?;
let node = node_iter.next().ok_or(FdtError::NotFound)?;
let mut ranges = node.reg()?.ok_or(FdtError::NotFound)?;
@@ -803,7 +800,7 @@
warn!("Discarding extra vmwdt <reg> entries.");
}
- let interrupts = node.getprop_cells(cstr!("interrupts"))?.ok_or(FdtError::NotFound)?;
+ let interrupts = node.getprop_cells(c"interrupts")?.ok_or(FdtError::NotFound)?;
let mut chunks = CellChunkIterator::<{ WdtInfo::IRQ_CELLS }>::new(interrupts);
let irq = chunks.next().ok_or(FdtError::NotFound)?;
@@ -831,15 +828,15 @@
let mut node = fdt
.root_mut()
- .next_compatible(cstr!("qemu,vcpu-stall-detector"))?
+ .next_compatible(c"qemu,vcpu-stall-detector")?
.ok_or(libfdt::FdtError::NotFound)?;
- node.setprop_inplace(cstr!("interrupts"), interrupts.as_bytes())?;
+ node.setprop_inplace(c"interrupts", interrupts.as_bytes())?;
Ok(())
}
/// Patch the DT by deleting the ns16550a compatible nodes whose address are unknown
fn patch_serial_info(fdt: &mut Fdt, serial_info: &SerialInfo) -> libfdt::Result<()> {
- let name = cstr!("ns16550a");
+ let name = c"ns16550a";
let mut next = fdt.root_mut().next_compatible(name);
while let Some(current) = next? {
let reg =
@@ -889,27 +886,27 @@
fn patch_swiotlb_info(fdt: &mut Fdt, swiotlb_info: &SwiotlbInfo) -> libfdt::Result<()> {
let mut node =
- fdt.root_mut().next_compatible(cstr!("restricted-dma-pool"))?.ok_or(FdtError::NotFound)?;
+ fdt.root_mut().next_compatible(c"restricted-dma-pool")?.ok_or(FdtError::NotFound)?;
if let Some(range) = swiotlb_info.fixed_range() {
node.setprop_addrrange_inplace(
- cstr!("reg"),
+ c"reg",
range.start.try_into().unwrap(),
range.len().try_into().unwrap(),
)?;
- node.nop_property(cstr!("size"))?;
- node.nop_property(cstr!("alignment"))?;
+ node.nop_property(c"size")?;
+ node.nop_property(c"alignment")?;
} else {
- node.nop_property(cstr!("reg"))?;
- node.setprop_inplace(cstr!("size"), &swiotlb_info.size.to_be_bytes())?;
- node.setprop_inplace(cstr!("alignment"), &swiotlb_info.align.unwrap().to_be_bytes())?;
+ node.nop_property(c"reg")?;
+ node.setprop_inplace(c"size", &swiotlb_info.size.to_be_bytes())?;
+ node.setprop_inplace(c"alignment", &swiotlb_info.align.unwrap().to_be_bytes())?;
}
Ok(())
}
fn patch_gic(fdt: &mut Fdt, num_cpus: usize) -> libfdt::Result<()> {
- let node = fdt.compatible_nodes(cstr!("arm,gic-v3"))?.next().ok_or(FdtError::NotFound)?;
+ let node = fdt.compatible_nodes(c"arm,gic-v3")?.next().ok_or(FdtError::NotFound)?;
let mut ranges = node.reg()?.ok_or(FdtError::NotFound)?;
let range0 = ranges.next().ok_or(FdtError::NotFound)?;
let mut range1 = ranges.next().ok_or(FdtError::NotFound)?;
@@ -927,16 +924,15 @@
let (addr1, size1) = range1.to_cells();
let value = [addr0, size0.unwrap(), addr1, size1.unwrap()];
- let mut node =
- fdt.root_mut().next_compatible(cstr!("arm,gic-v3"))?.ok_or(FdtError::NotFound)?;
- node.setprop_inplace(cstr!("reg"), value.as_flattened())
+ let mut node = fdt.root_mut().next_compatible(c"arm,gic-v3")?.ok_or(FdtError::NotFound)?;
+ node.setprop_inplace(c"reg", value.as_flattened())
}
fn patch_timer(fdt: &mut Fdt, num_cpus: usize) -> libfdt::Result<()> {
const NUM_INTERRUPTS: usize = 4;
const CELLS_PER_INTERRUPT: usize = 3;
- let node = fdt.compatible_nodes(cstr!("arm,armv8-timer"))?.next().ok_or(FdtError::NotFound)?;
- let interrupts = node.getprop_cells(cstr!("interrupts"))?.ok_or(FdtError::NotFound)?;
+ let node = fdt.compatible_nodes(c"arm,armv8-timer")?.next().ok_or(FdtError::NotFound)?;
+ let interrupts = node.getprop_cells(c"interrupts")?.ok_or(FdtError::NotFound)?;
let mut value: ArrayVec<[u32; NUM_INTERRUPTS * CELLS_PER_INTERRUPT]> =
interrupts.take(NUM_INTERRUPTS * CELLS_PER_INTERRUPT).collect();
@@ -953,20 +949,19 @@
let value = value.into_inner();
- let mut node =
- fdt.root_mut().next_compatible(cstr!("arm,armv8-timer"))?.ok_or(FdtError::NotFound)?;
- node.setprop_inplace(cstr!("interrupts"), value.as_bytes())
+ let mut node = fdt.root_mut().next_compatible(c"arm,armv8-timer")?.ok_or(FdtError::NotFound)?;
+ node.setprop_inplace(c"interrupts", value.as_bytes())
}
fn patch_untrusted_props(fdt: &mut Fdt, props: &BTreeMap<CString, Vec<u8>>) -> libfdt::Result<()> {
- let avf_node = if let Some(node) = fdt.node_mut(cstr!("/avf"))? {
+ let avf_node = if let Some(node) = fdt.node_mut(c"/avf")? {
node
} else {
- fdt.root_mut().add_subnode(cstr!("avf"))?
+ fdt.root_mut().add_subnode(c"avf")?
};
// The node shouldn't already be present; if it is, return the error.
- let mut node = avf_node.add_subnode(cstr!("untrusted"))?;
+ let mut node = avf_node.add_subnode(c"untrusted")?;
for (name, value) in props {
node.setprop(name, value)?;
@@ -982,9 +977,9 @@
}
fn patch_vcpufreq(fdt: &mut Fdt, vcpufreq_info: &Option<VcpufreqInfo>) -> libfdt::Result<()> {
- let mut node = fdt.node_mut(cstr!("/cpufreq"))?.unwrap();
+ let mut node = fdt.node_mut(c"/cpufreq")?.unwrap();
if let Some(info) = vcpufreq_info {
- node.setprop_addrrange_inplace(cstr!("reg"), info.addr, info.size)
+ node.setprop_addrrange_inplace(c"reg", info.addr, info.size)
} else {
node.nop()
}
@@ -1304,9 +1299,9 @@
patch_dice_node(fdt, bcc.as_ptr() as usize, bcc.len())?;
if let Some(mut chosen) = fdt.chosen_mut()? {
- empty_or_delete_prop(&mut chosen, cstr!("avf,strict-boot"), strict_boot)?;
- empty_or_delete_prop(&mut chosen, cstr!("avf,new-instance"), new_instance)?;
- chosen.setprop_inplace(cstr!("kaslr-seed"), &kaslr_seed.to_be_bytes())?;
+ empty_or_delete_prop(&mut chosen, c"avf,strict-boot", strict_boot)?;
+ empty_or_delete_prop(&mut chosen, c"avf,new-instance", new_instance)?;
+ chosen.setprop_inplace(c"kaslr-seed", &kaslr_seed.to_be_bytes())?;
};
if !debuggable {
if let Some(bootargs) = read_bootargs_from(fdt)? {
@@ -1323,13 +1318,13 @@
fn patch_dice_node(fdt: &mut Fdt, addr: usize, size: usize) -> libfdt::Result<()> {
// We reject DTs with missing reserved-memory node as validation should have checked that the
// "swiotlb" subnode (compatible = "restricted-dma-pool") was present.
- let node = fdt.node_mut(cstr!("/reserved-memory"))?.ok_or(libfdt::FdtError::NotFound)?;
+ let node = fdt.node_mut(c"/reserved-memory")?.ok_or(libfdt::FdtError::NotFound)?;
- let mut node = node.next_compatible(cstr!("google,open-dice"))?.ok_or(FdtError::NotFound)?;
+ let mut node = node.next_compatible(c"google,open-dice")?.ok_or(FdtError::NotFound)?;
let addr: u64 = addr.try_into().unwrap();
let size: u64 = size.try_into().unwrap();
- node.setprop_inplace(cstr!("reg"), [addr.to_be_bytes(), size.to_be_bytes()].as_flattened())
+ node.setprop_inplace(c"reg", [addr.to_be_bytes(), size.to_be_bytes()].as_flattened())
}
fn empty_or_delete_prop(
@@ -1376,7 +1371,7 @@
}
fn has_common_debug_policy(fdt: &Fdt, debug_feature_name: &CStr) -> libfdt::Result<bool> {
- if let Some(node) = fdt.node(cstr!("/avf/guest/common"))? {
+ if let Some(node) = fdt.node(c"/avf/guest/common")? {
if let Some(value) = node.getprop_u32(debug_feature_name)? {
return Ok(value == 1);
}
@@ -1385,8 +1380,8 @@
}
fn filter_out_dangerous_bootargs(fdt: &mut Fdt, bootargs: &CStr) -> libfdt::Result<()> {
- let has_crashkernel = has_common_debug_policy(fdt, cstr!("ramdump"))?;
- let has_console = has_common_debug_policy(fdt, cstr!("log"))?;
+ let has_crashkernel = has_common_debug_policy(fdt, c"ramdump")?;
+ let has_console = has_common_debug_policy(fdt, c"log")?;
let accepted: &[(&str, Box<dyn Fn(Option<&str>) -> bool>)] = &[
("panic", Box::new(|v| if let Some(v) = v { v == "=-1" } else { false })),
@@ -1417,5 +1412,5 @@
new_bootargs.push(b'\0');
let mut node = fdt.chosen_mut()?.ok_or(FdtError::NotFound)?;
- node.setprop(cstr!("bootargs"), new_bootargs.as_slice())
+ node.setprop(c"bootargs", new_bootargs.as_slice())
}
diff --git a/guest/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index a28a039..0a3dca6 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -40,7 +40,6 @@
use alloc::borrow::Cow;
use alloc::boxed::Box;
use bssl_avf::Digester;
-use cstr::cstr;
use diced_open_dice::{bcc_handover_parse, DiceArtifacts, DiceContext, Hidden, VM_KEY_ALGORITHM};
use libfdt::{Fdt, FdtNode};
use log::{debug, error, info, trace, warn};
@@ -130,7 +129,7 @@
RebootReason::InternalError
})?;
- let instance_hash = if cfg!(llpvm_changes) { Some(salt_from_instance_id(fdt)?) } else { None };
+ let instance_hash = Some(salt_from_instance_id(fdt)?);
let (new_instance, salt, defer_rollback_protection) = perform_rollback_protection(
fdt,
&verified_boot_data,
@@ -220,7 +219,7 @@
fn instance_id(fdt: &Fdt) -> Result<&[u8], RebootReason> {
let node = avf_untrusted_node(fdt)?;
- let id = node.getprop(cstr!("instance-id")).map_err(|e| {
+ let id = node.getprop(c"instance-id").map_err(|e| {
error!("Failed to get instance-id in DT: {e}");
RebootReason::InvalidFdt
})?;
@@ -231,7 +230,7 @@
}
fn avf_untrusted_node(fdt: &Fdt) -> Result<FdtNode, RebootReason> {
- let node = fdt.node(cstr!("/avf/untrusted")).map_err(|e| {
+ let node = fdt.node(c"/avf/untrusted").map_err(|e| {
error!("Failed to get /avf/untrusted node: {e}");
RebootReason::InvalidFdt
})?;
diff --git a/guest/pvmfw/src/rollback.rs b/guest/pvmfw/src/rollback.rs
index bc16332..f7723d7 100644
--- a/guest/pvmfw/src/rollback.rs
+++ b/guest/pvmfw/src/rollback.rs
@@ -19,7 +19,6 @@
use crate::instance::EntryBody;
use crate::instance::Error as InstanceError;
use crate::instance::{get_recorded_entry, record_instance_entry};
-use cstr::cstr;
use diced_open_dice::Hidden;
use libfdt::{Fdt, FdtNode};
use log::{error, info};
@@ -31,7 +30,7 @@
/// Performs RBP based on the input payload, current DICE chain, and host-controlled platform.
///
/// On success, returns a tuple containing:
-/// - `new_instance`: true if a new entry was created using the legacy instance.img solution;
+/// - `new_instance`: true if the legacy instance.img solution was used and a new entry created;
/// - `salt`: the salt representing the instance, to be used during DICE derivation;
/// - `defer_rollback_protection`: if RBP is being deferred.
pub fn perform_rollback_protection(
@@ -42,67 +41,87 @@
cdi_seal: &[u8],
instance_hash: Option<Hidden>,
) -> Result<(bool, Hidden, bool), RebootReason> {
- let defer_rollback_protection = should_defer_rollback_protection(fdt)?
- && verified_boot_data.has_capability(Capability::SecretkeeperProtection);
- let (new_instance, salt) = if defer_rollback_protection {
- info!("Guest OS is capable of Secretkeeper protection, deferring rollback protection");
- // rollback_index of the image is used as security_version and is expected to be > 0 to
- // discourage implicit allocation.
- if verified_boot_data.rollback_index == 0 {
- error!("Expected positive rollback_index, found 0");
- return Err(RebootReason::InvalidPayload);
- };
- (false, instance_hash.unwrap())
+ if should_defer_rollback_protection(fdt)?
+ && verified_boot_data.has_capability(Capability::SecretkeeperProtection)
+ {
+ perform_deferred_rollback_protection(verified_boot_data)?;
+ Ok((false, instance_hash.unwrap(), true))
} else if verified_boot_data.has_capability(Capability::RemoteAttest) {
- info!("Service VM capable of remote attestation detected, performing version checks");
- if service_vm_version::VERSION != verified_boot_data.rollback_index {
- // For RKP VM, we only boot if the version in the AVB footer of its kernel matches
- // the one embedded in pvmfw at build time.
- // This prevents the pvmfw from booting a roll backed RKP VM.
- error!(
- "Service VM version mismatch: expected {}, found {}",
- service_vm_version::VERSION,
- verified_boot_data.rollback_index
- );
- return Err(RebootReason::InvalidPayload);
- }
- (false, instance_hash.unwrap())
+ perform_fixed_index_rollback_protection(verified_boot_data)?;
+ Ok((false, instance_hash.unwrap(), false))
} else if verified_boot_data.has_capability(Capability::TrustySecurityVm) {
- // The rollback protection of Trusty VMs are handled by AuthMgr, so we don't need to
- // handle it here.
- info!("Trusty Security VM detected");
- (false, instance_hash.unwrap())
+ skip_rollback_protection()?;
+ Ok((false, instance_hash.unwrap(), false))
} else {
- info!("Fallback to instance.img based rollback checks");
- let (recorded_entry, mut instance_img, header_index) =
- get_recorded_entry(pci_root, cdi_seal).map_err(|e| {
- error!("Failed to get entry from instance.img: {e}");
- RebootReason::InternalError
- })?;
- let (new_instance, salt) = if let Some(entry) = recorded_entry {
- check_dice_measurements_match_entry(dice_inputs, &entry)?;
- let salt = instance_hash.unwrap_or(entry.salt);
- (false, salt)
- } else {
- // New instance!
- let salt = instance_hash.map_or_else(rand::random_array, Ok).map_err(|e| {
- error!("Failed to generated instance.img salt: {e}");
- RebootReason::InternalError
- })?;
+ perform_legacy_rollback_protection(dice_inputs, pci_root, cdi_seal, instance_hash)
+ }
+}
- let entry = EntryBody::new(dice_inputs, &salt);
- record_instance_entry(&entry, cdi_seal, &mut instance_img, header_index).map_err(
- |e| {
- error!("Failed to get recorded entry in instance.img: {e}");
- RebootReason::InternalError
- },
- )?;
- (true, salt)
- };
- (new_instance, salt)
+fn perform_deferred_rollback_protection(
+ verified_boot_data: &VerifiedBootData,
+) -> Result<(), RebootReason> {
+ info!("Deferring rollback protection");
+ // rollback_index of the image is used as security_version and is expected to be > 0 to
+ // discourage implicit allocation.
+ if verified_boot_data.rollback_index == 0 {
+ error!("Expected positive rollback_index, found 0");
+ Err(RebootReason::InvalidPayload)
+ } else {
+ Ok(())
+ }
+}
+
+fn perform_fixed_index_rollback_protection(
+ verified_boot_data: &VerifiedBootData,
+) -> Result<(), RebootReason> {
+ info!("Performing fixed-index rollback protection");
+ let fixed_index = service_vm_version::VERSION;
+ let index = verified_boot_data.rollback_index;
+ if index != fixed_index {
+ error!("Rollback index mismatch: expected {fixed_index}, found {index}");
+ Err(RebootReason::InvalidPayload)
+ } else {
+ Ok(())
+ }
+}
+
+fn skip_rollback_protection() -> Result<(), RebootReason> {
+ info!("Skipping rollback protection");
+ Ok(())
+}
+
+/// Performs RBP using instance.img where updates require clearing old entries, causing new CDIs.
+fn perform_legacy_rollback_protection(
+ dice_inputs: &PartialInputs,
+ pci_root: &mut PciRoot,
+ cdi_seal: &[u8],
+ instance_hash: Option<Hidden>,
+) -> Result<(bool, Hidden, bool), RebootReason> {
+ info!("Fallback to instance.img based rollback checks");
+ let (recorded_entry, mut instance_img, header_index) = get_recorded_entry(pci_root, cdi_seal)
+ .map_err(|e| {
+ error!("Failed to get entry from instance.img: {e}");
+ RebootReason::InternalError
+ })?;
+ let (new_instance, salt) = if let Some(entry) = recorded_entry {
+ check_dice_measurements_match_entry(dice_inputs, &entry)?;
+ let salt = instance_hash.unwrap_or(entry.salt);
+ (false, salt)
+ } else {
+ // New instance!
+ let salt = instance_hash.map_or_else(rand::random_array, Ok).map_err(|e| {
+ error!("Failed to generated instance.img salt: {e}");
+ RebootReason::InternalError
+ })?;
+
+ let entry = EntryBody::new(dice_inputs, &salt);
+ record_instance_entry(&entry, cdi_seal, &mut instance_img, header_index).map_err(|e| {
+ error!("Failed to get recorded entry in instance.img: {e}");
+ RebootReason::InternalError
+ })?;
+ (true, salt)
};
-
- Ok((new_instance, salt, defer_rollback_protection))
+ Ok((new_instance, salt, false))
}
fn check_dice_measurements_match_entry(
@@ -138,7 +157,7 @@
fn should_defer_rollback_protection(fdt: &Fdt) -> Result<bool, RebootReason> {
let node = avf_untrusted_node(fdt)?;
let defer_rbp = node
- .getprop(cstr!("defer-rollback-protection"))
+ .getprop(c"defer-rollback-protection")
.map_err(|e| {
error!("Failed to get defer-rollback-protection property in DT: {e}");
RebootReason::InvalidFdt
@@ -148,7 +167,7 @@
}
fn avf_untrusted_node(fdt: &Fdt) -> Result<FdtNode, RebootReason> {
- let node = fdt.node(cstr!("/avf/untrusted")).map_err(|e| {
+ let node = fdt.node(c"/avf/untrusted").map_err(|e| {
error!("Failed to get /avf/untrusted node: {e}");
RebootReason::InvalidFdt
})?;
diff --git a/guest/rialto/Android.bp b/guest/rialto/Android.bp
index a525168..35ede7a 100644
--- a/guest/rialto/Android.bp
+++ b/guest/rialto/Android.bp
@@ -12,7 +12,6 @@
"libbssl_avf_nostd",
"libciborium_io_nostd",
"libciborium_nostd",
- "libcstr",
"libdiced_open_dice_nostd",
"libhypervisor_backends",
"liblibfdt_nostd",
diff --git a/guest/rialto/src/fdt.rs b/guest/rialto/src/fdt.rs
index e97a262..06879d0 100644
--- a/guest/rialto/src/fdt.rs
+++ b/guest/rialto/src/fdt.rs
@@ -15,24 +15,23 @@
//! High-level FDT functions.
use core::ops::Range;
-use cstr::cstr;
use libfdt::{Fdt, FdtError};
/// Reads the DICE data range from the given `fdt`.
pub fn read_dice_range_from(fdt: &Fdt) -> libfdt::Result<Range<usize>> {
- let node = fdt.node(cstr!("/reserved-memory"))?.ok_or(FdtError::NotFound)?;
- let node = node.next_compatible(cstr!("google,open-dice"))?.ok_or(FdtError::NotFound)?;
+ let node = fdt.node(c"/reserved-memory")?.ok_or(FdtError::NotFound)?;
+ let node = node.next_compatible(c"google,open-dice")?.ok_or(FdtError::NotFound)?;
node.first_reg()?.try_into()
}
pub(crate) fn read_vendor_hashtree_root_digest(fdt: &Fdt) -> libfdt::Result<Option<&[u8]>> {
- let node = fdt.node(cstr!("/avf"))?.ok_or(FdtError::NotFound)?;
- node.getprop(cstr!("vendor_hashtree_descriptor_root_digest"))
+ let node = fdt.node(c"/avf")?.ok_or(FdtError::NotFound)?;
+ node.getprop(c"vendor_hashtree_descriptor_root_digest")
}
pub(crate) fn read_is_strict_boot(fdt: &Fdt) -> libfdt::Result<bool> {
match fdt.chosen()? {
- Some(node) => Ok(node.getprop(cstr!("avf,strict-boot"))?.is_some()),
+ Some(node) => Ok(node.getprop(c"avf,strict-boot")?.is_some()),
None => Ok(false),
}
}
diff --git a/guest/rialto/tests/test.rs b/guest/rialto/tests/test.rs
index 09f9cc3..c94a0e3 100644
--- a/guest/rialto/tests/test.rs
+++ b/guest/rialto/tests/test.rs
@@ -40,7 +40,6 @@
use service_vm_manager::{ServiceVm, VM_MEMORY_MB};
use std::fs;
use std::fs::File;
-use std::panic;
use std::path::PathBuf;
use std::str::FromStr;
use vmclient::VmInstance;
@@ -300,10 +299,6 @@
.with_tag("rialto")
.with_max_level(log::LevelFilter::Debug),
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- log::error!("{}", panic_info);
- }));
// We need to start the thread pool for Binder to work properly, especially link_to_death.
ProcessState::start_thread_pool();
ServiceVm::start_vm(vm_instance(vm_type, vm_memory_mb)?, vm_type)
diff --git a/guest/shutdown_runner/.cargo/config.toml b/guest/shutdown_runner/.cargo/config.toml
new file mode 100644
index 0000000..a451cda
--- /dev/null
+++ b/guest/shutdown_runner/.cargo/config.toml
@@ -0,0 +1,6 @@
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+rustflags = ["-C", "target-feature=+crt-static"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "target-feature=+crt-static"]
diff --git a/guest/shutdown_runner/Cargo.toml b/guest/shutdown_runner/Cargo.toml
index b74e7ee..0b44baa 100644
--- a/guest/shutdown_runner/Cargo.toml
+++ b/guest/shutdown_runner/Cargo.toml
@@ -15,3 +15,10 @@
[build-dependencies]
tonic-build = "0.12.3"
+
+[package.metadata.deb]
+maintainer = "ferrochrome-dev@google.com"
+copyright = "2024, The Android Open Source Project"
+depends = "$auto"
+maintainer-scripts = "debian/"
+systemd-units = { }
diff --git a/guest/shutdown_runner/debian/service b/guest/shutdown_runner/debian/service
new file mode 100644
index 0000000..d19ff25
--- /dev/null
+++ b/guest/shutdown_runner/debian/service
@@ -0,0 +1,13 @@
+[Unit]
+After=syslog.target
+After=network.target
+After=virtiofs_internal.service
+
+[Service]
+ExecStart=/usr/bin/bash -c '/usr/bin/shutdown_runner --grpc_port $(cat /mnt/internal/debian_service_port)'
+Type=simple
+User=root
+Group=root
+
+[Install]
+WantedBy=multi-user.target
diff --git a/guest/trusty/security_vm/launcher/src/main.rs b/guest/trusty/security_vm/launcher/src/main.rs
index 62febf4..8dd7c43 100644
--- a/guest/trusty/security_vm/launcher/src/main.rs
+++ b/guest/trusty/security_vm/launcher/src/main.rs
@@ -88,7 +88,6 @@
memoryMib: args.memory_size_mib,
cpuTopology: args.cpu_topology,
platformVersion: "~1.0".to_owned(),
- balloon: true, // TODO: probably don't want ballooning.
// TODO: add instanceId
..Default::default()
});
diff --git a/guest/vmbase_example/Android.bp b/guest/vmbase_example/Android.bp
index 09bd77c..ab21191 100644
--- a/guest/vmbase_example/Android.bp
+++ b/guest/vmbase_example/Android.bp
@@ -9,7 +9,6 @@
srcs: ["src/main.rs"],
rustlibs: [
"libaarch64_paging",
- "libcstr",
"libdiced_open_dice_nostd",
"liblibfdt_nostd",
"liblog_rust_nostd",
diff --git a/guest/vmbase_example/src/main.rs b/guest/vmbase_example/src/main.rs
index 4c5e880..f5b41bd 100644
--- a/guest/vmbase_example/src/main.rs
+++ b/guest/vmbase_example/src/main.rs
@@ -27,7 +27,6 @@
use crate::pci::check_pci;
use alloc::{vec, vec::Vec};
use core::ptr::addr_of_mut;
-use cstr::cstr;
use libfdt::Fdt;
use log::{debug, error, info, trace, warn, LevelFilter};
use vmbase::{
@@ -147,7 +146,7 @@
info!("memory @ {reg:#x?}");
}
- let compatible = cstr!("ns16550a");
+ let compatible = c"ns16550a";
for c in reader.compatible_nodes(compatible).unwrap() {
let reg = c.reg().unwrap().unwrap().next().unwrap();
@@ -159,17 +158,17 @@
writer.unpack().unwrap();
info!("FDT successfully unpacked.");
- let path = cstr!("/memory");
+ let path = c"/memory";
let node = writer.node_mut(path).unwrap().unwrap();
- let name = cstr!("child");
+ let name = c"child";
let mut child = node.add_subnode(name).unwrap();
info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
- let name = cstr!("str-property");
+ let name = c"str-property";
child.appendprop(name, b"property-value\0").unwrap();
info!("Appended property '{}'.", name.to_str().unwrap());
- let name = cstr!("pair-property");
+ let name = c"pair-property";
let addr = 0x0123_4567u64;
let size = 0x89ab_cdefu64;
child.appendprop_addrrange(name, addr, size).unwrap();
diff --git a/libs/cstr/Android.bp b/libs/cstr/Android.bp
deleted file mode 100644
index 4ea87df..0000000
--- a/libs/cstr/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-rust_library_rlib {
- name: "libcstr",
- crate_name: "cstr",
- defaults: ["avf_build_flags_rust"],
- srcs: ["src/lib.rs"],
- edition: "2021",
- host_supported: true,
- prefer_rlib: true,
- target: {
- android: {
- no_stdlibs: true,
- stdlibs: [
- "libcompiler_builtins.rust_sysroot",
- "libcore.rust_sysroot",
- ],
- },
- },
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
-}
-
-rust_test {
- name: "libcstr.tests",
- crate_name: "libcstr_test",
- defaults: ["avf_build_flags_rust"],
- srcs: ["src/lib.rs"],
- test_suites: ["general-tests"],
- prefer_rlib: true,
- rustlibs: ["libcstr"],
-}
diff --git a/libs/cstr/src/lib.rs b/libs/cstr/src/lib.rs
deleted file mode 100644
index ddf20fc..0000000
--- a/libs/cstr/src/lib.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2023, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Provide a safe const-compatible no_std macro for readable &'static CStr.
-
-#![no_std]
-
-/// Create &CStr out of &str literal
-#[macro_export]
-macro_rules! cstr {
- ($str:literal) => {{
- const S: &str = concat!($str, "\0");
- const C: &::core::ffi::CStr = match ::core::ffi::CStr::from_bytes_with_nul(S.as_bytes()) {
- Ok(v) => v,
- Err(_) => panic!("string contains interior NUL"),
- };
- C
- }};
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::ffi::CString;
-
- #[test]
- fn valid_input_string() {
- let expected = CString::new("aaa").unwrap();
- assert_eq!(cstr!("aaa"), expected.as_c_str());
- }
-
- #[test]
- fn valid_empty_string() {
- let expected = CString::new("").unwrap();
- assert_eq!(cstr!(""), expected.as_c_str());
- }
-
- // As cstr!() panics at compile time, tests covering invalid inputs fail to compile!
-}
diff --git a/libs/debian_service/proto/DebianService.proto b/libs/debian_service/proto/DebianService.proto
index 739f0ac..43955fa 100644
--- a/libs/debian_service/proto/DebianService.proto
+++ b/libs/debian_service/proto/DebianService.proto
@@ -23,7 +23,6 @@
service DebianService {
rpc ReportVmActivePorts (ReportVmActivePortsRequest) returns (ReportVmActivePortsResponse) {}
- rpc ReportVmIpAddr (IpAddr) returns (ReportVmIpAddrResponse) {}
rpc OpenForwardingRequestQueue (QueueOpeningRequest) returns (stream ForwardingRequestItem) {}
rpc OpenShutdownRequestQueue (ShutdownQueueOpeningRequest) returns (stream ShutdownRequestItem) {}
}
@@ -32,16 +31,13 @@
int32 cid = 1;
}
-message IpAddr {
- string addr = 1;
-}
-
-message ReportVmIpAddrResponse {
- bool success = 1;
+message ActivePort {
+ int32 port = 1;
+ string comm = 2;
}
message ReportVmActivePortsRequest {
- repeated int32 ports = 1;
+ repeated ActivePort ports = 1;
}
message ReportVmActivePortsResponse {
@@ -55,4 +51,4 @@
message ShutdownQueueOpeningRequest {}
-message ShutdownRequestItem {}
\ No newline at end of file
+message ShutdownRequestItem {}
diff --git a/libs/devicemapper/src/loopdevice.rs b/libs/devicemapper/src/loopdevice.rs
index 113a946..130c1c4 100644
--- a/libs/devicemapper/src/loopdevice.rs
+++ b/libs/devicemapper/src/loopdevice.rs
@@ -159,6 +159,7 @@
#[cfg(test)]
mod tests {
use super::*;
+ use rdroidtest::rdroidtest;
use std::fs;
use std::path::Path;
@@ -178,7 +179,7 @@
"0" == fs::read_to_string(ro).unwrap().trim()
}
- #[test]
+ #[rdroidtest]
fn attach_loop_device_with_dio() {
let a_dir = tempfile::TempDir::new().unwrap();
let a_file = a_dir.path().join("test");
@@ -191,7 +192,7 @@
assert!(is_direct_io(&dev));
}
- #[test]
+ #[rdroidtest]
fn attach_loop_device_without_dio() {
let a_dir = tempfile::TempDir::new().unwrap();
let a_file = a_dir.path().join("test");
@@ -204,7 +205,7 @@
assert!(!is_direct_io(&dev));
}
- #[test]
+ #[rdroidtest]
fn attach_loop_device_with_dio_writable() {
let a_dir = tempfile::TempDir::new().unwrap();
let a_file = a_dir.path().join("test");
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index f799fb1..1870ab6 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -128,7 +128,7 @@
rust_defaults {
name: "libopen_dice_cbor_bindgen.rust_defaults",
- wrapper_src: "bindgen/dice.h",
+ wrapper_src: "bindgen/dice/dice.h",
crate_name: "open_dice_cbor_bindgen",
source_stem: "bindings",
bindgen_flags: [
@@ -184,7 +184,7 @@
rust_defaults {
name: "libopen_dice_android_bindgen.rust_defaults",
- wrapper_src: "bindgen/android.h",
+ wrapper_src: "bindgen/android/android.h",
crate_name: "open_dice_android_bindgen",
source_stem: "bindings",
bindgen_flags: [
@@ -264,3 +264,9 @@
clippy_lints: "none",
lints: "none",
}
+
+dirgroup {
+ name: "trusty_dirgroup_packages_modules_virtualization_libs_open_dice",
+ visibility: ["//trusty/vendor/google/aosp/scripts"],
+ dirs: ["."],
+}
diff --git a/libs/dice/open_dice/bindgen/android.h b/libs/dice/open_dice/bindgen/android/android.h
similarity index 100%
rename from libs/dice/open_dice/bindgen/android.h
rename to libs/dice/open_dice/bindgen/android/android.h
diff --git a/libs/dice/open_dice/bindgen/android/lib.rs b/libs/dice/open_dice/bindgen/android/lib.rs
new file mode 100644
index 0000000..7c300de
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/android/lib.rs
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Get the bindgen definitions.
+// The trusty build system doesn't have support for packaging generated
+// bindgen sources as a crate automatically. In the Android tree, this
+// entire file is not used.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(unused)]
+
+include!(env!("BINDGEN_INC_FILE"));
diff --git a/libs/dice/open_dice/bindgen/android/rules.mk b/libs/dice/open_dice/bindgen/android/rules.mk
new file mode 100644
index 0000000..200ec52
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/android/rules.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/lib.rs
+
+MODULE_CRATE_NAME := open_dice_android_bindgen
+
+MODULE_LIBRARY_DEPS += \
+ external/open-dice \
+ $(LOCAL_DIR)/../dice \
+ trusty/user/base/lib/trusty-sys \
+
+MODULE_BINDGEN_ALLOW_FUNCTIONS := \
+ DiceAndroidFormatConfigDescriptor \
+ DiceAndroidMainFlow \
+ DiceAndroidHandoverParse \
+
+MODULE_BINDGEN_ALLOW_VARS := \
+ DICE_ANDROID_CONFIG_.* \
+
+# Prevent DiceInputValues from being generated a second time and
+# import it instead from open_dice_cbor_bindgen.
+MODULE_BINDGEN_FLAGS += \
+ --blocklist-type="DiceInputValues_" \
+ --blocklist-type="DiceInputValues" \
+ --raw-line \
+ "pub use open_dice_cbor_bindgen::DiceInputValues;" \
+
+# Prevent DiceResult from being generated a second time and
+# import it instead from open_dice_cbor_bindgen.
+MODULE_BINDGEN_FLAGS += \
+ --blocklist-type="DiceResult" \
+ --raw-line \
+ "pub use open_dice_cbor_bindgen::DiceResult;" \
+
+MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/android.h
+
+include make/library.mk
diff --git a/libs/dice/open_dice/bindgen/dice.h b/libs/dice/open_dice/bindgen/dice/dice.h
similarity index 100%
rename from libs/dice/open_dice/bindgen/dice.h
rename to libs/dice/open_dice/bindgen/dice/dice.h
diff --git a/libs/dice/open_dice/bindgen/dice/lib.rs b/libs/dice/open_dice/bindgen/dice/lib.rs
new file mode 100644
index 0000000..ed2fd23
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/dice/lib.rs
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Get the bindgen definitions.
+// The trusty build system doesn't have support for packaging generated
+// bindgen sources as a crate automatically. In the Android tree, this
+// entire file is not used.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(unused)]
+
+include!(env!("BINDGEN_INC_FILE"));
diff --git a/libs/dice/open_dice/bindgen/dice/rules.mk b/libs/dice/open_dice/bindgen/dice/rules.mk
new file mode 100644
index 0000000..0ea5c7c
--- /dev/null
+++ b/libs/dice/open_dice/bindgen/dice/rules.mk
@@ -0,0 +1,56 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/lib.rs
+
+MODULE_CRATE_NAME := open_dice_cbor_bindgen
+
+MODULE_LIBRARY_DEPS += \
+ external/open-dice \
+ trusty/user/base/lib/trusty-sys \
+
+MODULE_BINDGEN_FLAGS += \
+ --rustified-enum DiceConfigType \
+ --rustified-enum DiceMode \
+ --rustified-enum DiceResult \
+ --rustified-enum DicePrincipal \
+
+MODULE_BINDGEN_ALLOW_FUNCTIONS := \
+ DiceDeriveCdiPrivateKeySeed \
+ DiceDeriveCdiCertificateId \
+ DiceMainFlow \
+ DiceHash \
+ DiceKdf \
+ DiceKeypairFromSeed \
+ DiceSign \
+ DiceVerify \
+ DiceGenerateCertificate \
+
+MODULE_BINDGEN_ALLOW_VARS := \
+ DICE_CDI_SIZE \
+ DICE_HASH_SIZE \
+ DICE_HIDDEN_SIZE \
+ DICE_INLINE_CONFIG_SIZE \
+ DICE_PRIVATE_KEY_SEED_SIZE \
+ DICE_ID_SIZE \
+ DICE_PRIVATE_KEY_BUFFER_SIZE \
+
+MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/dice.h
+
+include make/library.mk
diff --git a/libs/dice/open_dice/rules.mk b/libs/dice/open_dice/rules.mk
new file mode 100644
index 0000000..d84468d
--- /dev/null
+++ b/libs/dice/open_dice/rules.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/src/lib.rs
+
+MODULE_CRATE_NAME := diced_open_dice
+
+MODULE_LIBRARY_DEPS += \
+ $(call FIND_CRATE,coset) \
+ $(call FIND_CRATE,zeroize) \
+ $(LOCAL_DIR)/bindgen/android \
+ $(LOCAL_DIR)/bindgen/dice \
+
+include make/library.mk
diff --git a/libs/dice/open_dice/src/bcc.rs b/libs/dice/open_dice/src/bcc.rs
index fabd7c7..a3ddd76 100644
--- a/libs/dice/open_dice/src/bcc.rs
+++ b/libs/dice/open_dice/src/bcc.rs
@@ -41,7 +41,7 @@
}
/// Formats a configuration descriptor following the Android Profile for DICE specification.
-/// See https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/android.md.
+/// See <https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/android.md>.
pub fn bcc_format_config_descriptor(values: &DiceConfigValues, buffer: &mut [u8]) -> Result<usize> {
let mut configs = 0;
diff --git a/libs/dice/open_dice/tests/api_test.rs b/libs/dice/open_dice/tests/api_test.rs
index a47265b..d3a91ff 100644
--- a/libs/dice/open_dice/tests/api_test.rs
+++ b/libs/dice/open_dice/tests/api_test.rs
@@ -14,94 +14,108 @@
* limitations under the License.
*/
-use diced_open_dice::{
- derive_cdi_certificate_id, derive_cdi_private_key_seed, hash, kdf, keypair_from_seed, sign,
- verify, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
-};
+#[cfg(test)]
+mod tests {
+ use diced_open_dice::{
+ derive_cdi_certificate_id, derive_cdi_private_key_seed, hash, kdf, keypair_from_seed, sign,
+ verify, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
+ };
-#[test]
-fn hash_succeeds() {
- const EXPECTED_HASH: [u8; HASH_SIZE] = [
- 0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02, 0xf2,
- 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8, 0x6d, 0x4c,
- 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda, 0x34, 0x25, 0x5b,
- 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d, 0xc5, 0x54, 0x2e, 0x93,
- 0xae, 0x9c, 0xd7, 0x6f,
+ // This test initialization is only required for the trusty test harness.
+ #[cfg(feature = "trusty")]
+ test::init!();
+
+ #[test]
+ fn hash_succeeds() {
+ const EXPECTED_HASH: [u8; HASH_SIZE] = [
+ 0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
+ 0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
+ 0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
+ 0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
+ 0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f,
+ ];
+ assert_eq!(EXPECTED_HASH, hash(b"hello world").expect("hash failed"));
+ }
+
+ #[test]
+ fn kdf_succeeds() {
+ let mut derived_key = [0u8; PRIVATE_KEY_SEED_SIZE];
+ kdf(b"myInitialKeyMaterial", b"mySalt", b"myInfo", &mut derived_key).unwrap();
+ const EXPECTED_DERIVED_KEY: [u8; PRIVATE_KEY_SEED_SIZE] = [
+ 0x91, 0x9b, 0x8d, 0x29, 0xc4, 0x1b, 0x93, 0xd7, 0xeb, 0x09, 0xfa, 0xd7, 0xc9, 0x87,
+ 0xb0, 0xd1, 0xcc, 0x26, 0xef, 0x07, 0x83, 0x42, 0xcf, 0xa3, 0x45, 0x0a, 0x57, 0xe9,
+ 0x19, 0x86, 0xef, 0x48,
+ ];
+ assert_eq!(EXPECTED_DERIVED_KEY, derived_key);
+ }
+
+ #[test]
+ fn derive_cdi_certificate_id_succeeds() {
+ const EXPECTED_ID: [u8; ID_SIZE] = [
+ 0x7a, 0x36, 0x45, 0x2c, 0x02, 0xf6, 0x2b, 0xec, 0xf9, 0x80, 0x06, 0x75, 0x87, 0xa5,
+ 0xc1, 0x44, 0x0c, 0xd3, 0xc0, 0x6d,
+ ];
+ assert_eq!(EXPECTED_ID, derive_cdi_certificate_id(b"MyPubKey").unwrap());
+ }
+
+ const EXPECTED_SEED: &[u8] = &[
+ 0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+ 0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+ 0x3a, 0x08, 0x84, 0x8a, 0x98, 0x85, 0x6d, 0xf5, 0x69, 0x21, 0x03, 0xcd, 0x09, 0xc3, 0x28,
+ 0xd6, 0x06, 0xa7, 0x57, 0xbd, 0x48, 0x4b, 0x0f, 0x79, 0x0f, 0xf8, 0x2f, 0xf0, 0x0a, 0x41,
+ 0x94, 0xd8, 0x8c, 0xa8,
];
- assert_eq!(EXPECTED_HASH, hash(b"hello world").expect("hash failed"));
-}
-#[test]
-fn kdf_succeeds() {
- let mut derived_key = [0u8; PRIVATE_KEY_SEED_SIZE];
- kdf(b"myInitialKeyMaterial", b"mySalt", b"myInfo", &mut derived_key).unwrap();
- const EXPECTED_DERIVED_KEY: [u8; PRIVATE_KEY_SEED_SIZE] = [
- 0x91, 0x9b, 0x8d, 0x29, 0xc4, 0x1b, 0x93, 0xd7, 0xeb, 0x09, 0xfa, 0xd7, 0xc9, 0x87, 0xb0,
- 0xd1, 0xcc, 0x26, 0xef, 0x07, 0x83, 0x42, 0xcf, 0xa3, 0x45, 0x0a, 0x57, 0xe9, 0x19, 0x86,
- 0xef, 0x48,
+ const EXPECTED_CDI_ATTEST: &[u8] = &[
+ 0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+ 0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+ 0x3a, 0x08,
];
- assert_eq!(EXPECTED_DERIVED_KEY, derived_key);
-}
-#[test]
-fn derive_cdi_certificate_id_succeeds() {
- const EXPECTED_ID: [u8; ID_SIZE] = [
- 0x7a, 0x36, 0x45, 0x2c, 0x02, 0xf6, 0x2b, 0xec, 0xf9, 0x80, 0x06, 0x75, 0x87, 0xa5, 0xc1,
- 0x44, 0x0c, 0xd3, 0xc0, 0x6d,
+ const EXPECTED_CDI_PRIVATE_KEY_SEED: &[u8] = &[
+ 0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+ 0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+ 0x02, 0x6e,
];
- assert_eq!(EXPECTED_ID, derive_cdi_certificate_id(b"MyPubKey").unwrap());
-}
-const EXPECTED_SEED: &[u8] = &[
- 0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba, 0xaa,
- 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5, 0x3a, 0x08,
- 0x84, 0x8a, 0x98, 0x85, 0x6d, 0xf5, 0x69, 0x21, 0x03, 0xcd, 0x09, 0xc3, 0x28, 0xd6, 0x06, 0xa7,
- 0x57, 0xbd, 0x48, 0x4b, 0x0f, 0x79, 0x0f, 0xf8, 0x2f, 0xf0, 0x0a, 0x41, 0x94, 0xd8, 0x8c, 0xa8,
-];
+ const EXPECTED_PUB_KEY: &[u8] = &[
+ 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23,
+ 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61,
+ 0x06, 0x37,
+ ];
+ const EXPECTED_PRIV_KEY: &[u8] = &[
+ 0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+ 0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+ 0x02, 0x6e, 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b,
+ 0xfc, 0x23, 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52,
+ 0xf1, 0x61, 0x06, 0x37,
+ ];
-const EXPECTED_CDI_ATTEST: &[u8] = &[
- 0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba, 0xaa,
- 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5, 0x3a, 0x08,
-];
+ const EXPECTED_SIGNATURE: &[u8] = &[
+ 0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2,
+ 0x32, 0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29,
+ 0x3c, 0x26, 0xe6, 0x0d, 0x9c, 0xa5, 0xc2, 0x73, 0xcd, 0x8c, 0xb8, 0x3c, 0x3e, 0x5b, 0xfd,
+ 0x62, 0x8d, 0xf6, 0xc4, 0x27, 0xa6, 0xe9, 0x11, 0x06, 0x5a, 0xb2, 0x2b, 0x64, 0xf7, 0xfc,
+ 0xbb, 0xab, 0x4a, 0x0e,
+ ];
-const EXPECTED_CDI_PRIVATE_KEY_SEED: &[u8] = &[
- 0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe, 0x0d,
- 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72, 0x02, 0x6e,
-];
-
-const EXPECTED_PUB_KEY: &[u8] = &[
- 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23, 0xc9,
- 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61, 0x06, 0x37,
-];
-const EXPECTED_PRIV_KEY: &[u8] = &[
- 0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe, 0x0d,
- 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72, 0x02, 0x6e,
- 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23, 0xc9,
- 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61, 0x06, 0x37,
-];
-
-const EXPECTED_SIGNATURE: &[u8] = &[
- 0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2, 0x32,
- 0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29, 0x3c, 0x26,
- 0xe6, 0x0d, 0x9c, 0xa5, 0xc2, 0x73, 0xcd, 0x8c, 0xb8, 0x3c, 0x3e, 0x5b, 0xfd, 0x62, 0x8d, 0xf6,
- 0xc4, 0x27, 0xa6, 0xe9, 0x11, 0x06, 0x5a, 0xb2, 0x2b, 0x64, 0xf7, 0xfc, 0xbb, 0xab, 0x4a, 0x0e,
-];
-
-#[test]
-fn hash_derive_sign_verify() {
- let seed = hash(b"MySeedString").unwrap();
- assert_eq!(seed, EXPECTED_SEED);
- let cdi_attest = &seed[..CDI_SIZE];
- assert_eq!(cdi_attest, EXPECTED_CDI_ATTEST);
- let cdi_private_key_seed = derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
- assert_eq!(cdi_private_key_seed.as_array(), EXPECTED_CDI_PRIVATE_KEY_SEED);
- let (pub_key, priv_key) = keypair_from_seed(cdi_private_key_seed.as_array()).unwrap();
- assert_eq!(&pub_key, EXPECTED_PUB_KEY);
- assert_eq!(priv_key.as_array(), EXPECTED_PRIV_KEY);
- let mut signature = sign(b"MyMessage", priv_key.as_array()).unwrap();
- assert_eq!(&signature, EXPECTED_SIGNATURE);
- assert!(verify(b"MyMessage", &signature, &pub_key).is_ok());
- assert!(verify(b"MyMessage_fail", &signature, &pub_key).is_err());
- signature[0] += 1;
- assert!(verify(b"MyMessage", &signature, &pub_key).is_err());
+ #[test]
+ fn hash_derive_sign_verify() {
+ let seed = hash(b"MySeedString").unwrap();
+ assert_eq!(seed, EXPECTED_SEED);
+ let cdi_attest = &seed[..CDI_SIZE];
+ assert_eq!(cdi_attest, EXPECTED_CDI_ATTEST);
+ let cdi_private_key_seed =
+ derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
+ assert_eq!(cdi_private_key_seed.as_array(), EXPECTED_CDI_PRIVATE_KEY_SEED);
+ let (pub_key, priv_key) = keypair_from_seed(cdi_private_key_seed.as_array()).unwrap();
+ assert_eq!(&pub_key, EXPECTED_PUB_KEY);
+ assert_eq!(priv_key.as_array(), EXPECTED_PRIV_KEY);
+ let mut signature = sign(b"MyMessage", priv_key.as_array()).unwrap();
+ assert_eq!(&signature, EXPECTED_SIGNATURE);
+ assert!(verify(b"MyMessage", &signature, &pub_key).is_ok());
+ assert!(verify(b"MyMessage_fail", &signature, &pub_key).is_err());
+ signature[0] += 1;
+ assert!(verify(b"MyMessage", &signature, &pub_key).is_err());
+ }
}
diff --git a/libs/dice/open_dice/tests/manifest.json b/libs/dice/open_dice/tests/manifest.json
new file mode 100644
index 0000000..28db874
--- /dev/null
+++ b/libs/dice/open_dice/tests/manifest.json
@@ -0,0 +1,9 @@
+{
+ "app_name": "diced_open_dice_tests",
+ "uuid": "0b772481-7c24-4b9b-9d7c-441ac10d969b",
+ "min_heap": 32768,
+ "min_stack": 32768,
+ "mgmt_flags": {
+ "non_critical_app": true
+ }
+}
diff --git a/libs/dice/open_dice/tests/rules.mk b/libs/dice/open_dice/tests/rules.mk
new file mode 100644
index 0000000..a9d332c
--- /dev/null
+++ b/libs/dice/open_dice/tests/rules.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/api_test.rs
+
+MODULE_CRATE_NAME := diced_open_dice_tests
+
+MODULE_LIBRARY_DEPS += \
+ packages/modules/Virtualization/libs/dice/open_dice \
+
+MODULE_RUST_TESTS := true
+
+# Enables trusty test initialization
+MODULE_RUSTFLAGS += \
+ --cfg 'feature="trusty"' \
+
+MANIFEST := $(LOCAL_DIR)/manifest.json
+
+include make/library.mk
diff --git a/libs/dice/sample_inputs/src/sample_inputs.rs b/libs/dice/sample_inputs/src/sample_inputs.rs
index 54f551b..c323bc4 100644
--- a/libs/dice/sample_inputs/src/sample_inputs.rs
+++ b/libs/dice/sample_inputs/src/sample_inputs.rs
@@ -118,6 +118,7 @@
component_name: Some(CStr::from_bytes_with_nul(b"ABL\0").unwrap()),
component_version: Some(1),
resettable: true,
+ security_version: Some(10),
..Default::default()
};
let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
@@ -150,6 +151,7 @@
component_name: Some(CStr::from_bytes_with_nul(b"AVB\0").unwrap()),
component_version: Some(1),
resettable: true,
+ security_version: Some(11),
..Default::default()
};
let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
@@ -174,6 +176,7 @@
component_name: Some(CStr::from_bytes_with_nul(b"Android\0").unwrap()),
component_version: Some(12),
resettable: true,
+ security_version: Some(12),
..Default::default()
};
let config_descriptor = retry_bcc_format_config_descriptor(&config_values)?;
diff --git a/libs/dice/sample_inputs/tests/api_test.rs b/libs/dice/sample_inputs/tests/api_test.rs
index c627824..566d3c7 100644
--- a/libs/dice/sample_inputs/tests/api_test.rs
+++ b/libs/dice/sample_inputs/tests/api_test.rs
@@ -22,8 +22,8 @@
use hwtrust::{dice, session::Session};
const EXPECTED_SAMPLE_CDI_ATTEST: &[u8] = &[
- 0x3e, 0x57, 0x65, 0x5d, 0x48, 0x02, 0xbd, 0x5c, 0x66, 0xcc, 0x1f, 0x0f, 0xbe, 0x5e, 0x32, 0xb6,
- 0x9e, 0x3d, 0x04, 0xaf, 0x00, 0x15, 0xbc, 0xdd, 0x1f, 0xbc, 0x59, 0xe4, 0xc3, 0x87, 0x95, 0x5e,
+ 0xb2, 0x13, 0xde, 0x86, 0xf7, 0x40, 0x7b, 0xd5, 0x20, 0x21, 0x74, 0x4e, 0x75, 0x78, 0x1a, 0xcb,
+ 0x22, 0x57, 0x1c, 0x32, 0xa4, 0x1e, 0xc9, 0x23, 0x73, 0x5b, 0x9c, 0x6b, 0x5f, 0x6b, 0x2d, 0xc0,
];
const EXPECTED_SAMPLE_CDI_SEAL: &[u8] = &[
@@ -35,95 +35,99 @@
0x84, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x3e, 0x85,
0xe5, 0x72, 0x75, 0x55, 0xe5, 0x1e, 0xe7, 0xf3, 0x35, 0x94, 0x8e, 0xbb, 0xbd, 0x74, 0x1e, 0x1d,
0xca, 0x49, 0x9c, 0x97, 0x39, 0x77, 0x06, 0xd3, 0xc8, 0x6e, 0x8b, 0xd7, 0x33, 0xf9, 0x84, 0x43,
- 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28, 0x34, 0x32, 0x64, 0x38, 0x38,
+ 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0xa1, 0xaa, 0x01, 0x78, 0x28, 0x34, 0x32, 0x64, 0x38, 0x38,
0x36, 0x34, 0x66, 0x39, 0x37, 0x62, 0x36, 0x35, 0x34, 0x37, 0x61, 0x35, 0x30, 0x63, 0x31, 0x65,
0x30, 0x61, 0x37, 0x34, 0x39, 0x66, 0x38, 0x65, 0x66, 0x38, 0x62, 0x38, 0x31, 0x65, 0x63, 0x36,
- 0x32, 0x61, 0x66, 0x02, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35,
- 0x32, 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65,
- 0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x3a, 0x00,
+ 0x32, 0x61, 0x66, 0x02, 0x78, 0x28, 0x34, 0x61, 0x61, 0x66, 0x61, 0x38, 0x30, 0x62, 0x30, 0x62,
+ 0x30, 0x63, 0x31, 0x33, 0x34, 0x64, 0x31, 0x36, 0x65, 0x36, 0x30, 0x35, 0x36, 0x66, 0x30, 0x35,
+ 0x35, 0x32, 0x62, 0x65, 0x65, 0x33, 0x38, 0x61, 0x37, 0x37, 0x30, 0x65, 0x35, 0x62, 0x3a, 0x00,
0x47, 0x44, 0x50, 0x58, 0x40, 0x16, 0x48, 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38,
0xc3, 0x64, 0x38, 0x63, 0x26, 0x0f, 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34,
0x4c, 0x6d, 0xa2, 0xbe, 0x25, 0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1, 0xd2,
0xb3, 0x91, 0x4d, 0xd3, 0xfb, 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26, 0x57, 0x5a, 0xba,
- 0x30, 0xf7, 0x15, 0x98, 0x14, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11,
- 0x71, 0x63, 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73,
- 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x47, 0xae, 0x42, 0x27, 0x4c, 0xcb, 0x65, 0x4d,
- 0xee, 0x74, 0x2d, 0x05, 0x78, 0x2a, 0x08, 0x2a, 0xa5, 0xf0, 0xcf, 0xea, 0x3e, 0x60, 0xee, 0x97,
- 0x11, 0x4b, 0x5b, 0xe6, 0x05, 0x0c, 0xe8, 0x90, 0xf5, 0x22, 0xc4, 0xc6, 0x67, 0x7a, 0x22, 0x27,
- 0x17, 0xb3, 0x79, 0xcc, 0x37, 0x64, 0x5e, 0x19, 0x4f, 0x96, 0x37, 0x67, 0x3c, 0xd0, 0xc5, 0xed,
- 0x0f, 0xdd, 0xe7, 0x2e, 0x4f, 0x70, 0x97, 0x30, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf9,
- 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb, 0x3c, 0xe7, 0x6b,
- 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1, 0x23, 0xe6, 0xc8, 0xdf, 0xfb,
- 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b, 0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1,
- 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b, 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d, 0x3a,
- 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01,
- 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xb1, 0x02, 0xcc, 0x2c, 0xb2, 0x6a,
- 0x3b, 0xe9, 0xc1, 0xd3, 0x95, 0x10, 0xa0, 0xe1, 0xff, 0x51, 0xde, 0x57, 0xd5, 0x65, 0x28, 0xfd,
- 0x7f, 0xeb, 0xd4, 0xca, 0x15, 0xf3, 0xca, 0xdf, 0x37, 0x88, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41,
- 0x20, 0x58, 0x40, 0x58, 0xd8, 0x03, 0x24, 0x53, 0x60, 0x57, 0xa9, 0x09, 0xfa, 0xab, 0xdc, 0x57,
- 0x1e, 0xf0, 0xe5, 0x1e, 0x51, 0x6f, 0x9e, 0xa3, 0x42, 0xe6, 0x6a, 0x8c, 0xaa, 0xad, 0x08, 0x48,
- 0xde, 0x7f, 0x4f, 0x6e, 0x2f, 0x7f, 0x39, 0x6c, 0xa1, 0xf8, 0x42, 0x71, 0xfe, 0x17, 0x3d, 0xca,
- 0x31, 0x83, 0x92, 0xed, 0xbb, 0x40, 0xb8, 0x10, 0xe0, 0xf2, 0x5a, 0x99, 0x53, 0x38, 0x46, 0x33,
- 0x97, 0x78, 0x05, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28,
- 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32, 0x39, 0x65, 0x39,
- 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31,
- 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x02, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38,
- 0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66,
- 0x34, 0x34, 0x32, 0x36, 0x37, 0x65, 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35,
- 0x37, 0x32, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa,
- 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f, 0x46, 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14,
- 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56, 0xb3, 0xbf, 0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4,
- 0xd2, 0xa9, 0x6b, 0x18, 0x28, 0xe8, 0x29, 0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54,
- 0xe9, 0x71, 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56,
- 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63, 0x41, 0x56, 0x42, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01,
- 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x93, 0x17, 0xe1,
- 0x11, 0x27, 0x59, 0xd0, 0xef, 0x75, 0x0b, 0x2b, 0x1c, 0x0f, 0x5f, 0x52, 0xc3, 0x29, 0x23, 0xb5,
- 0x2a, 0xe6, 0x12, 0x72, 0x6f, 0x39, 0x86, 0x65, 0x2d, 0xf2, 0xe4, 0xe7, 0xd0, 0xaf, 0x0e, 0xa7,
- 0x99, 0x16, 0x89, 0x97, 0x21, 0xf7, 0xdc, 0x89, 0xdc, 0xde, 0xbb, 0x94, 0x88, 0x1f, 0xda, 0xe2,
- 0xf3, 0xe0, 0x54, 0xf9, 0x0e, 0x29, 0xb1, 0xbd, 0xe1, 0x0c, 0x0b, 0xd7, 0xf6, 0x3a, 0x00, 0x47,
- 0x44, 0x54, 0x58, 0x40, 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9,
- 0x02, 0x35, 0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9,
- 0x35, 0x7d, 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e,
- 0xf6, 0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a,
- 0xef, 0xbc, 0x05, 0x98, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57,
- 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x96,
- 0x6d, 0x96, 0x42, 0xda, 0x64, 0x51, 0xad, 0xfa, 0x00, 0xbc, 0xbc, 0x95, 0x8a, 0xb0, 0xb9, 0x76,
- 0x01, 0xe6, 0xbd, 0xc0, 0x26, 0x79, 0x26, 0xfc, 0x0f, 0x1d, 0x87, 0x65, 0xf1, 0xf3, 0x99, 0x3a,
- 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x10, 0x7f, 0x77, 0xad, 0x70, 0xbd, 0x52, 0x81,
- 0x28, 0x8d, 0x24, 0x81, 0xb4, 0x3f, 0x21, 0x68, 0x9f, 0xc3, 0x80, 0x68, 0x86, 0x55, 0xfb, 0x2e,
- 0x6d, 0x96, 0xe1, 0xe1, 0xb7, 0x28, 0x8d, 0x63, 0x85, 0xba, 0x2a, 0x01, 0x33, 0x87, 0x60, 0x63,
- 0xbb, 0x16, 0x3f, 0x2f, 0x3d, 0xf4, 0x2d, 0x48, 0x5b, 0x87, 0xed, 0xda, 0x34, 0xeb, 0x9c, 0x4d,
- 0x14, 0xac, 0x65, 0xf4, 0xfa, 0xef, 0x45, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01,
- 0x8f, 0xa9, 0x01, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34,
- 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37, 0x65,
- 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35, 0x02, 0x78, 0x28,
- 0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61, 0x39, 0x35, 0x34, 0x61, 0x31,
- 0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38, 0x35, 0x61, 0x66, 0x64, 0x37, 0x32, 0x61,
- 0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61, 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00,
+ 0x30, 0xf7, 0x15, 0x98, 0x14, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x1c, 0xa4, 0x3a, 0x00, 0x01,
+ 0x11, 0x71, 0x63, 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11,
+ 0x73, 0xf6, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x0a, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x27,
+ 0xf2, 0x47, 0xaf, 0xcf, 0xd8, 0x6e, 0x5f, 0x68, 0x97, 0xa9, 0x22, 0x07, 0x81, 0xea, 0x56, 0x1f,
+ 0x7b, 0x81, 0x51, 0x09, 0x8a, 0x0a, 0xab, 0x96, 0xc4, 0x4c, 0x8f, 0xf5, 0x46, 0xf4, 0xa5, 0x64,
+ 0x4b, 0xed, 0x23, 0x5b, 0x9e, 0x36, 0x51, 0x1e, 0xf0, 0x1d, 0xb9, 0xcf, 0xb2, 0x4b, 0xcd, 0x52,
+ 0xfa, 0x1a, 0x82, 0x11, 0x3d, 0x78, 0x1c, 0x9e, 0x0f, 0xff, 0x8a, 0x11, 0x6b, 0xdf, 0x7b, 0x3a,
+ 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf9, 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd,
+ 0xe3, 0x97, 0x4a, 0xcb, 0x3c, 0xe7, 0x6b, 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59,
+ 0x15, 0xb1, 0x23, 0xe6, 0xc8, 0xdf, 0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b,
+ 0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b,
+ 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47,
+ 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58,
+ 0x20, 0x7f, 0x1d, 0xd1, 0xf8, 0xd3, 0xcb, 0xfe, 0xc6, 0x88, 0xa3, 0xfc, 0xa7, 0xd5, 0x34, 0xc6,
+ 0x29, 0x13, 0x57, 0xfa, 0x5d, 0xc9, 0xe2, 0x1b, 0x70, 0x21, 0x48, 0x74, 0x3e, 0xa0, 0x1c, 0xe7,
+ 0x31, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e,
+ 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x31, 0x36, 0x58, 0x40, 0x21, 0x1f, 0xb5, 0x9b, 0x25, 0xab,
+ 0xca, 0x24, 0x58, 0x7f, 0xd1, 0x9f, 0x10, 0x74, 0xbe, 0x8d, 0xbb, 0x46, 0x3e, 0xc2, 0x78, 0x2c,
+ 0x28, 0x65, 0xe3, 0xd5, 0xc6, 0x11, 0x50, 0x36, 0x15, 0xfa, 0x43, 0xe5, 0xf7, 0xfd, 0x5c, 0xec,
+ 0xb8, 0x96, 0xd7, 0x55, 0x51, 0x1f, 0x8e, 0xc2, 0x0b, 0x4a, 0x12, 0xe7, 0x5c, 0x3e, 0xe5, 0xaf,
+ 0x19, 0xe4, 0x15, 0xf3, 0x8a, 0x58, 0x68, 0x25, 0x0e, 0x00, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0,
+ 0x59, 0x01, 0xa1, 0xaa, 0x01, 0x78, 0x28, 0x34, 0x61, 0x61, 0x66, 0x61, 0x38, 0x30, 0x62, 0x30,
+ 0x62, 0x30, 0x63, 0x31, 0x33, 0x34, 0x64, 0x31, 0x36, 0x65, 0x36, 0x30, 0x35, 0x36, 0x66, 0x30,
+ 0x35, 0x35, 0x32, 0x62, 0x65, 0x65, 0x33, 0x38, 0x61, 0x37, 0x37, 0x30, 0x65, 0x35, 0x62, 0x02,
+ 0x78, 0x28, 0x31, 0x61, 0x61, 0x32, 0x65, 0x64, 0x33, 0x63, 0x33, 0x61, 0x35, 0x36, 0x62, 0x36,
+ 0x63, 0x61, 0x37, 0x35, 0x39, 0x63, 0x35, 0x32, 0x34, 0x65, 0x63, 0x38, 0x38, 0x61, 0x35, 0x37,
+ 0x33, 0x30, 0x61, 0x33, 0x38, 0x61, 0x64, 0x31, 0x66, 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58,
+ 0x40, 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f, 0x46,
+ 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56, 0xb3, 0xbf, 0x2f,
+ 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b, 0x18, 0x28, 0xe8, 0x29, 0x20, 0x49,
+ 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9, 0x71, 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3,
+ 0xc7, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x1c, 0xa4, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63, 0x41,
+ 0x56, 0x42, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00,
+ 0x01, 0x11, 0x74, 0x0b, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x69, 0x3d, 0x73, 0x63, 0x70,
+ 0x20, 0x41, 0xc4, 0x2d, 0x04, 0x4a, 0x4c, 0x51, 0xa9, 0x89, 0x97, 0xe4, 0x3a, 0x0f, 0x7b, 0xe2,
+ 0x23, 0x5f, 0x39, 0x7e, 0xd8, 0x6f, 0x8b, 0x17, 0x04, 0x16, 0xe1, 0xb2, 0x1b, 0x5a, 0x47, 0x84,
+ 0x9c, 0x54, 0x19, 0xa3, 0xb2, 0x70, 0xd3, 0xc9, 0x09, 0xf9, 0xe3, 0x3f, 0x7e, 0x19, 0xff, 0xd7,
+ 0xc6, 0xa9, 0x84, 0xf1, 0xcd, 0x44, 0xec, 0x33, 0x7a, 0xa7, 0x9a, 0x3a, 0x00, 0x47, 0x44, 0x54,
+ 0x58, 0x40, 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9, 0x02, 0x35,
+ 0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9, 0x35, 0x7d,
+ 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e, 0xf6, 0x66,
+ 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a, 0xef, 0xbc,
+ 0x05, 0x98, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d,
+ 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x02, 0xcc, 0xfb,
+ 0xac, 0x73, 0xee, 0xf7, 0x46, 0x04, 0xa2, 0x9e, 0x32, 0xac, 0xa1, 0xf8, 0x7a, 0x08, 0x83, 0xec,
+ 0xfb, 0x82, 0x13, 0xce, 0x4a, 0xed, 0x55, 0x52, 0x24, 0x36, 0x67, 0xe8, 0x45, 0x3a, 0x00, 0x47,
+ 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x2e, 0x31, 0x36, 0x58, 0x40, 0xb8, 0x67, 0x7a, 0x4e, 0x89, 0xe4, 0x73, 0xc3, 0xa4, 0x5d,
+ 0x30, 0xea, 0xd4, 0x53, 0x51, 0x15, 0xc2, 0x26, 0x4d, 0xae, 0xeb, 0x94, 0x00, 0x92, 0x9e, 0x05,
+ 0x23, 0x8b, 0xde, 0x4b, 0x56, 0x72, 0x33, 0x2c, 0xf4, 0xf7, 0x81, 0x09, 0xce, 0xf4, 0x41, 0x7a,
+ 0xa4, 0xc6, 0x4e, 0x3a, 0x0b, 0xb3, 0x5a, 0x70, 0x72, 0x9e, 0x41, 0xe3, 0x25, 0x41, 0x9e, 0x77,
+ 0x6d, 0x44, 0x9a, 0x63, 0xc9, 0x0f, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0xa5, 0xaa,
+ 0x01, 0x78, 0x28, 0x31, 0x61, 0x61, 0x32, 0x65, 0x64, 0x33, 0x63, 0x33, 0x61, 0x35, 0x36, 0x62,
+ 0x36, 0x63, 0x61, 0x37, 0x35, 0x39, 0x63, 0x35, 0x32, 0x34, 0x65, 0x63, 0x38, 0x38, 0x61, 0x35,
+ 0x37, 0x33, 0x30, 0x61, 0x33, 0x38, 0x61, 0x64, 0x31, 0x66, 0x36, 0x02, 0x78, 0x28, 0x36, 0x61,
+ 0x38, 0x38, 0x61, 0x31, 0x62, 0x34, 0x31, 0x35, 0x39, 0x35, 0x66, 0x37, 0x66, 0x36, 0x31, 0x39,
+ 0x35, 0x34, 0x31, 0x65, 0x39, 0x33, 0x39, 0x38, 0x31, 0x36, 0x64, 0x35, 0x39, 0x62, 0x32, 0x61,
+ 0x37, 0x62, 0x61, 0x33, 0x31, 0x31, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a,
- 0x00, 0x47, 0x44, 0x53, 0x58, 0x1a, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x67, 0x41, 0x6e, 0x64,
- 0x72, 0x6f, 0x69, 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6,
- 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x26, 0x1a, 0xbd, 0x26, 0xd8, 0x37, 0x8f, 0x4a, 0xf2,
- 0x9e, 0x49, 0x4d, 0x93, 0x23, 0xc4, 0x6e, 0x02, 0xda, 0xe0, 0x00, 0x02, 0xe7, 0xed, 0x29, 0xdf,
- 0x2b, 0xb3, 0x69, 0xf3, 0x55, 0x0e, 0x4c, 0x22, 0xdc, 0xcf, 0xf5, 0x92, 0xc9, 0xfa, 0x78, 0x98,
- 0xf1, 0x0e, 0x55, 0x5f, 0xf4, 0x45, 0xed, 0xc0, 0x0a, 0x72, 0x2a, 0x7a, 0x3a, 0xd2, 0xb1, 0xf7,
- 0x76, 0xfe, 0x2a, 0x6b, 0x7b, 0x2a, 0x53, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0x04, 0x25,
- 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03, 0xb8, 0xd6, 0xe1, 0x99,
- 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37, 0x68, 0x4e, 0x1d, 0xc0, 0x24, 0x74,
- 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43, 0xd2, 0x9c, 0xfc, 0x12, 0x9e, 0x77, 0x0a, 0xde,
- 0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7, 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf, 0x62, 0x9f, 0x3a, 0x00,
- 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03,
- 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xdb, 0xe7, 0x5b, 0x3f, 0xa3, 0x42, 0xb0,
- 0x9c, 0xf8, 0x40, 0x8c, 0xb0, 0x9c, 0xf0, 0x0a, 0xaf, 0xdf, 0x6f, 0xe5, 0x09, 0x21, 0x11, 0x92,
- 0xe1, 0xf8, 0xc5, 0x09, 0x02, 0x3d, 0x1f, 0xb7, 0xc5, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
- 0x58, 0x40, 0xc4, 0xc1, 0xd7, 0x1c, 0x2d, 0x26, 0x89, 0x22, 0xcf, 0xa6, 0x99, 0x77, 0x30, 0x84,
- 0x86, 0x27, 0x59, 0x8f, 0xd8, 0x08, 0x75, 0xe0, 0xb2, 0xef, 0xf9, 0xfa, 0xa5, 0x40, 0x8c, 0xd3,
- 0xeb, 0xbb, 0xda, 0xf2, 0xc8, 0xae, 0x41, 0x22, 0x50, 0x9c, 0xe8, 0xb2, 0x9c, 0x9b, 0x3f, 0x8a,
- 0x78, 0x76, 0xab, 0xd0, 0xbe, 0xfc, 0xe4, 0x79, 0xcb, 0x1b, 0x2b, 0xaa, 0x4d, 0xdd, 0x15, 0x61,
- 0x42, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x47,
+ 0x44, 0x53, 0x58, 0x20, 0xa4, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x67, 0x41, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00,
+ 0x01, 0x11, 0x74, 0x0c, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0xd7, 0x67, 0x6d, 0x47, 0xf1,
+ 0x17, 0xf6, 0x16, 0x58, 0x80, 0x5e, 0x40, 0x92, 0x35, 0x8d, 0xc6, 0x9a, 0x0d, 0x71, 0xe0, 0x56,
+ 0x33, 0x0e, 0xad, 0x95, 0xf3, 0xd9, 0xa5, 0x44, 0x90, 0x2b, 0xa0, 0x73, 0xa0, 0xf8, 0x17, 0x9b,
+ 0x2a, 0xdc, 0xa4, 0x42, 0xdf, 0x8c, 0xfc, 0x32, 0x19, 0x92, 0x66, 0x75, 0x90, 0x88, 0x85, 0x5d,
+ 0x89, 0x5a, 0xb1, 0xdc, 0x95, 0xc9, 0x84, 0x68, 0x3f, 0x35, 0xe4, 0x3a, 0x00, 0x47, 0x44, 0x54,
+ 0x58, 0x40, 0x04, 0x25, 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03,
+ 0xb8, 0xd6, 0xe1, 0x99, 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37, 0x68, 0x4e,
+ 0x1d, 0xc0, 0x24, 0x74, 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43, 0xd2, 0x9c, 0xfc, 0x12,
+ 0x9e, 0x77, 0x0a, 0xde, 0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7, 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf,
+ 0x62, 0x9f, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d,
+ 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x45, 0xc7, 0x2d,
+ 0x68, 0x01, 0x96, 0x6d, 0xaf, 0x0a, 0xcd, 0x51, 0x56, 0xfb, 0xac, 0x27, 0xa1, 0x61, 0x59, 0x9b,
+ 0xfd, 0xb4, 0x86, 0x73, 0x20, 0x65, 0x64, 0x3c, 0x77, 0xf1, 0x7b, 0x1d, 0x4d, 0x3a, 0x00, 0x47,
+ 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x2e, 0x31, 0x36, 0x58, 0x40, 0xa5, 0xf8, 0xfe, 0x9d, 0x8c, 0xda, 0x71, 0x0c, 0x51, 0x99,
+ 0xe5, 0x48, 0xd3, 0x03, 0xb4, 0x96, 0x67, 0xab, 0xf7, 0x82, 0xf5, 0x70, 0x2b, 0x17, 0xe4, 0x02,
+ 0xa1, 0x3c, 0xbc, 0x7c, 0x63, 0x79, 0x0b, 0x01, 0x0c, 0x92, 0x13, 0x39, 0xb2, 0xc8, 0x0e, 0x0c,
+ 0x09, 0x90, 0xb9, 0x19, 0x9b, 0x3b, 0xc3, 0x12, 0x9c, 0xea, 0xf6, 0xcb, 0x84, 0x14, 0xf0, 0xcb,
+ 0xa5, 0x05, 0x58, 0x3d, 0x45, 0x03,
];
const MESSAGE: &[u8] = b"Message for testing";
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index d6b38ea..6311168 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -40,6 +40,7 @@
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.sysprop.HypervisorProperties;
+import android.system.virtualizationservice.AssignedDevices;
import android.system.virtualizationservice.DiskImage;
import android.system.virtualizationservice.Partition;
import android.system.virtualizationservice.SharedPath;
@@ -807,7 +808,7 @@
config.memoryMib = bytesToMebiBytes(mMemoryBytes);
config.cpuTopology = (byte) this.mCpuTopology;
config.consoleInputDevice = mConsoleInputDevice;
- config.devices = EMPTY_STRING_ARRAY;
+ config.devices = AssignedDevices.devices(EMPTY_STRING_ARRAY);
config.platformVersion = "~1.0";
config.audioConfig =
Optional.ofNullable(customImageConfig.getAudioConfig())
diff --git a/libs/hypervisor_props/src/lib.rs b/libs/hypervisor_props/src/lib.rs
index 14614fd..094e895 100644
--- a/libs/hypervisor_props/src/lib.rs
+++ b/libs/hypervisor_props/src/lib.rs
@@ -37,3 +37,8 @@
pub fn version() -> Result<Option<String>> {
Ok(hypervisorproperties::hypervisor_version()?)
}
+
+/// Returns if the hypervisor is Gunyah
+pub fn is_gunyah() -> Result<bool> {
+ Ok(version()?.unwrap_or_default().starts_with("gunyah"))
+}
diff --git a/libs/libavf/Android.bp b/libs/libavf/Android.bp
index e143709..c958796 100644
--- a/libs/libavf/Android.bp
+++ b/libs/libavf/Android.bp
@@ -10,6 +10,10 @@
source_stem: "bindings",
bindgen_flags: ["--default-enum-style rust"],
apex_available: ["com.android.virt"],
+ visibility: [
+ "//packages/modules/Virtualization/tests/vts",
+ "//packages/modules/Virtualization/tests/old_images_avf_test",
+ ],
}
rust_defaults {
@@ -34,7 +38,6 @@
rust_ffi_static {
name: "libavf_impl",
defaults: ["libavf.default"],
- export_include_dirs: ["include"],
}
cc_library {
@@ -49,7 +52,7 @@
"libbinder_rpc_unstable",
"liblog",
],
- export_static_lib_headers: ["libavf_impl"],
+ export_include_dirs: ["include"],
apex_available: ["com.android.virt"],
version_script: "libavf.map.txt",
stubs: {
diff --git a/libs/libavf/include/android/virtualization.h b/libs/libavf/include/android/virtualization.h
index 7ab7431..ef57325 100644
--- a/libs/libavf/include/android/virtualization.h
+++ b/libs/libavf/include/android/virtualization.h
@@ -33,7 +33,7 @@
*
* This only creates the raw config object. `name` and `kernel` must be set with
* calls to {@link AVirtualMachineRawConfig_setName} and {@link AVirtualMachineRawConfig_setKernel}.
- * Other properties, set by {@link AVirtualMachineRawConfig_setMemoryMib},
+ * Other properties, set by {@link AVirtualMachineRawConfig_setMemoryMiB},
* {@link AVirtualMachineRawConfig_setInitRd}, {@link AVirtualMachineRawConfig_addDisk},
* {@link AVirtualMachineRawConfig_setProtectedVm}, and {@link AVirtualMachineRawConfig_setBalloon}
* are optional.
@@ -44,7 +44,7 @@
*
* \return A new virtual machine raw config object. On failure (such as out of memory), it aborts.
*/
-AVirtualMachineRawConfig* _Nonnull AVirtualMachineRawConfig_create() __INTRODUCED_IN(36);
+AVirtualMachineRawConfig* _Nonnull AVirtualMachineRawConfig_create(void) __INTRODUCED_IN(36);
/**
* Destroy a virtual machine config object.
@@ -70,7 +70,13 @@
const char* _Nonnull name) __INTRODUCED_IN(36);
/**
- * Set an instance ID of a virtual machine.
+ * Set an instance ID of a virtual machine. Every virtual machine is identified by a unique
+ * `instanceId` which the virtual machine uses as its persistent identity while performing stateful
+ * operations that are expected to outlast single boot of the VM. For example, some virtual machines
+ * use it as a `Id` for storing secrets in Secretkeeper, which are retrieved on next boot of th VM.
+ *
+ * The `instanceId` is expected to be re-used for the VM instance with an associated state (secret,
+ * encrypted storage) - i.e., rebooting the VM must not change the instanceId.
*
* \param config a virtual machine config object.
* \param instanceId a pointer to a 64-byte buffer for the instance ID.
@@ -79,8 +85,8 @@
* \return If successful, it returns 0. If `instanceIdSize` is incorrect, it returns -EINVAL.
*/
int AVirtualMachineRawConfig_setInstanceId(AVirtualMachineRawConfig* _Nonnull config,
- const int8_t* _Nonnull instanceId, size_t instanceIdSize)
- __INTRODUCED_IN(36);
+ const uint8_t* _Nonnull instanceId,
+ size_t instanceIdSize) __INTRODUCED_IN(36);
/**
* Set a kernel image of a virtual machine.
@@ -121,12 +127,39 @@
/**
* Set how much memory will be given to a virtual machine.
*
+ * When `AVirtualMachineRawConfig_setProtectedVm(..., true)` is set, the memory
+ * size provided here will be automatically augmented with the swiotlb size.
+ *
* \param config a virtual machine config object.
- * \param memoryMib the amount of RAM to give the virtual machine, in MiB. 0 or negative to use the
+ * \param memoryMiB the amount of RAM to give the virtual machine, in MiB. 0 or negative to use the
* default.
*/
-void AVirtualMachineRawConfig_setMemoryMib(AVirtualMachineRawConfig* _Nonnull config,
- int32_t memoryMib) __INTRODUCED_IN(36);
+void AVirtualMachineRawConfig_setMemoryMiB(AVirtualMachineRawConfig* _Nonnull config,
+ int32_t memoryMiB) __INTRODUCED_IN(36);
+
+/**
+ * Set how much swiotlb will be given to a virtual machine.
+ *
+ * Only applicable when `AVirtualMachineRawConfig_setProtectedVm(..., true)` is
+ * set.
+ *
+ * For information on swiotlb, see https://docs.kernel.org/core-api/swiotlb.html.
+ *
+ * \param config a virtual machine config object.
+ * \param memoryMiB the amount of swiotlb to give the virtual machine, in MiB.
+ * 0 or negative to use the default.
+ */
+void AVirtualMachineRawConfig_setSwiotlbMiB(AVirtualMachineRawConfig* _Nonnull config,
+ int32_t swiotlbMiB) __INTRODUCED_IN(36);
+
+/**
+ * Set vCPU count. The default is 1.
+ *
+ * \param config a virtual machine config object.
+ * \param n number of vCPUs. Must be positive.
+ */
+void AVirtualMachineRawConfig_setVCpuCount(AVirtualMachineRawConfig* _Nonnull config, int32_t n)
+ __INTRODUCED_IN(36);
/**
* Set whether the virtual machine's memory will be protected from the host, so the host can't
@@ -166,6 +199,19 @@
int AVirtualMachineRawConfig_addCustomMemoryBackingFile(AVirtualMachineRawConfig* _Nonnull config,
int fd, uint64_t rangeStart,
uint64_t rangeEnd) __INTRODUCED_IN(36);
+/**
+ * Use the specified fd as the device tree overlay blob for booting VM.
+ *
+ * Here's the format of the device tree overlay blob.
+ * link: https://source.android.com/docs/core/architecture/dto
+ *
+ * \param config a virtual machine config object.
+ * \param fd a readable, seekable, and sized (i.e. report a valid size using fstat()) file
+ * descriptor containing device tree overlay, or -1 to unset.
+ * `AVirtualMachineRawConfig_setDeviceTreeOverlay` takes ownership of `fd`.
+ */
+void AVirtualMachineRawConfig_setDeviceTreeOverlay(AVirtualMachineRawConfig* _Nonnull config,
+ int fd) __INTRODUCED_IN(36);
/**
* Represents a handle on a virtualization service, responsible for managing virtual machines.
diff --git a/libs/libavf/libavf.map.txt b/libs/libavf/libavf.map.txt
index efc368a..589c5d3 100644
--- a/libs/libavf/libavf.map.txt
+++ b/libs/libavf/libavf.map.txt
@@ -7,10 +7,13 @@
AVirtualMachineRawConfig_setKernel; # apex llndk
AVirtualMachineRawConfig_setInitRd; # apex llndk
AVirtualMachineRawConfig_addDisk; # apex llndk
- AVirtualMachineRawConfig_setMemoryMib; # apex llndk
+ AVirtualMachineRawConfig_setMemoryMiB; # apex llndk
+ AVirtualMachineRawConfig_setSwiotlbMiB; # apex llndk
+ AVirtualMachineRawConfig_setVCpuCount; # apex llndk
AVirtualMachineRawConfig_setProtectedVm; # apex llndk
AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod; # apex llndk
AVirtualMachineRawConfig_addCustomMemoryBackingFile; # apex llndk
+ AVirtualMachineRawConfig_setDeviceTreeOverlay; # apex llndk
AVirtualizationService_create; # apex llndk
AVirtualizationService_destroy; # apex llndk
AVirtualMachine_createRaw; # apex llndk
diff --git a/libs/libavf/src/lib.rs b/libs/libavf/src/lib.rs
index 56cdfb7..6532ace 100644
--- a/libs/libavf/src/lib.rs
+++ b/libs/libavf/src/lib.rs
@@ -23,14 +23,15 @@
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::{
- DiskImage::DiskImage, IVirtualizationService::IVirtualizationService,
- VirtualMachineConfig::VirtualMachineConfig,
+ AssignedDevices::AssignedDevices, CpuTopology::CpuTopology, DiskImage::DiskImage,
+ IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
VirtualMachineRawConfig::VirtualMachineRawConfig,
},
binder::{ParcelFileDescriptor, Strong},
};
use avf_bindgen::AVirtualMachineStopReason;
use libc::timespec;
+use log::error;
use vmclient::{DeathReason, VirtualizationService, VmInstance};
/// Create a new virtual machine config object with no properties.
@@ -180,7 +181,7 @@
/// # Safety
/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
#[no_mangle]
-pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMib(
+pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMiB(
config: *mut VirtualMachineRawConfig,
memory_mib: i32,
) {
@@ -190,6 +191,37 @@
config.memoryMib = memory_mib;
}
+/// Set how much swiotlb will be given to a virtual machine.
+///
+/// # Safety
+/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
+#[no_mangle]
+pub unsafe extern "C" fn AVirtualMachineRawConfig_setSwiotlbMiB(
+ config: *mut VirtualMachineRawConfig,
+ swiotlb_mib: i32,
+) {
+ // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
+ // AVirtualMachineRawConfig_create. It's the only reference to the object.
+ let config = unsafe { &mut *config };
+ config.swiotlbMib = swiotlb_mib;
+}
+
+/// Set vCPU count.
+///
+/// # Safety
+/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
+#[no_mangle]
+pub unsafe extern "C" fn AVirtualMachineRawConfig_setVCpuCount(
+ config: *mut VirtualMachineRawConfig,
+ n: i32,
+) {
+ // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
+ // AVirtualMachineRawConfig_create. It's the only reference to the object.
+ let config = unsafe { &mut *config };
+ config.cpuTopology = CpuTopology::CUSTOM;
+ config.customVcpuCount = n;
+}
+
/// Set whether a virtual machine is protected or not.
///
/// # Safety
@@ -205,16 +237,21 @@
config.protectedVm = protected_vm;
}
-/// NOT IMPLEMENTED.
+/// Set whether to use an alternate, hypervisor-specific authentication method for protected VMs.
///
-/// # Returns
-/// It always returns `-ENOTSUP`.
+/// # Safety
+/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
#[no_mangle]
-pub extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
- _config: *mut VirtualMachineRawConfig,
- _enable: bool,
+pub unsafe extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
+ config: *mut VirtualMachineRawConfig,
+ enable: bool,
) -> c_int {
- -libc::ENOTSUP
+ // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
+ // AVirtualMachineRawConfig_create. It's the only reference to the object.
+ let config = unsafe { &mut *config };
+ config.enableHypervisorSpecificAuthMethod = enable;
+ // We don't validate whether this is supported until later, when the VM is started.
+ 0
}
/// NOT IMPLEMENTED.
@@ -231,6 +268,32 @@
-libc::ENOTSUP
}
+/// Add device tree overlay blob
+///
+/// # Safety
+/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
+/// file descriptor or -1. `AVirtualMachineRawConfig_setDeviceTreeOverlay` takes ownership of `fd`
+/// and `fd` will be closed upon `AVirtualMachineRawConfig_delete`.
+#[no_mangle]
+pub unsafe extern "C" fn AVirtualMachineRawConfig_setDeviceTreeOverlay(
+ config: *mut VirtualMachineRawConfig,
+ fd: c_int,
+) {
+ // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
+ // AVirtualMachineRawConfig_create. It's the only reference to the object.
+ let config = unsafe { &mut *config };
+
+ match get_file_from_fd(fd) {
+ Some(file) => {
+ let fd = ParcelFileDescriptor::new(file);
+ config.devices = AssignedDevices::Dtbo(Some(fd));
+ }
+ _ => {
+ config.devices = Default::default();
+ }
+ };
+}
+
/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
/// AIDL service, and connect to the child process.
///
@@ -319,7 +382,10 @@
}
0
}
- Err(_) => -libc::EIO,
+ Err(e) => {
+ error!("AVirtualMachine_createRaw failed: {e:?}");
+ -libc::EIO
+ }
}
}
@@ -334,7 +400,10 @@
let vm = unsafe { &*vm };
match vm.start() {
Ok(_) => 0,
- Err(_) => -libc::EIO,
+ Err(e) => {
+ error!("AVirtualMachine_start failed: {e:?}");
+ -libc::EIO
+ }
}
}
@@ -349,7 +418,10 @@
let vm = unsafe { &*vm };
match vm.stop() {
Ok(_) => 0,
- Err(_) => -libc::EIO,
+ Err(e) => {
+ error!("AVirtualMachine_stop failed: {e:?}");
+ -libc::EIO
+ }
}
}
@@ -364,7 +436,10 @@
let vm = unsafe { &*vm };
match vm.connect_vsock(port) {
Ok(pfd) => pfd.into_raw_fd(),
- Err(_) => -libc::EIO,
+ Err(e) => {
+ error!("AVirtualMachine_connectVsock failed: {e:?}");
+ -libc::EIO
+ }
}
}
diff --git a/libs/libfdt/Android.bp b/libs/libfdt/Android.bp
index 09f288d..829b30f 100644
--- a/libs/libfdt/Android.bp
+++ b/libs/libfdt/Android.bp
@@ -35,7 +35,6 @@
],
edition: "2021",
rustlibs: [
- "libcstr",
"liblibfdt_bindgen",
"libstatic_assertions",
"libzerocopy_nostd",
@@ -79,7 +78,6 @@
],
prefer_rlib: true,
rustlibs: [
- "libcstr",
"liblibfdt",
],
}
diff --git a/libs/libfdt/bindgen/rules.mk b/libs/libfdt/bindgen/rules.mk
new file mode 100644
index 0000000..130a317
--- /dev/null
+++ b/libs/libfdt/bindgen/rules.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/src/lib.rs
+
+MODULE_CRATE_NAME := libfdt_bindgen
+
+MODULE_DEPS += \
+ external/dtc/libfdt \
+
+MODULE_BINDGEN_ALLOW_FUNCTIONS := \
+ fdt_.* \
+
+MODULE_BINDGEN_ALLOW_VARS := \
+ FDT_.* \
+
+MODULE_BINDGEN_ALLOW_TYPES := \
+ fdt_.* \
+
+MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/fdt.h
+
+include make/library.mk
diff --git a/libs/libfdt/bindgen/src/lib.rs b/libs/libfdt/bindgen/src/lib.rs
new file mode 100644
index 0000000..015132b
--- /dev/null
+++ b/libs/libfdt/bindgen/src/lib.rs
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! # Interface library for libfdt.
+
+#![no_std]
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+include!(env!("BINDGEN_INC_FILE"));
diff --git a/libs/libfdt/rules.mk b/libs/libfdt/rules.mk
new file mode 100644
index 0000000..ce8aa51
--- /dev/null
+++ b/libs/libfdt/rules.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+SRC_DIR := packages/modules/Virtualization/libs/libfdt
+
+MODULE_SRCS := $(SRC_DIR)/src/lib.rs
+
+MODULE_CRATE_NAME := libfdt
+
+MODULE_RUST_EDITION := 2021
+
+MODULE_LIBRARY_DEPS += \
+ external/dtc/libfdt \
+ packages/modules/Virtualization/libs/libfdt/bindgen \
+ $(call FIND_CRATE,zerocopy) \
+ $(call FIND_CRATE,static_assertions) \
+
+MODULE_RUST_USE_CLIPPY := true
+
+include make/library.mk
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index c969749..0dcd31a 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -31,7 +31,6 @@
use core::ffi::{c_void, CStr};
use core::ops::Range;
-use cstr::cstr;
use libfdt::get_slice_at_ptr;
use zerocopy::IntoBytes as _;
@@ -167,12 +166,12 @@
/// Returns the standard (deprecated) device_type <string> property.
pub fn device_type(&self) -> Result<Option<&CStr>> {
- self.getprop_str(cstr!("device_type"))
+ self.getprop_str(c"device_type")
}
/// Returns the standard reg <prop-encoded-array> property.
pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
- if let Some(cells) = self.getprop_cells(cstr!("reg"))? {
+ if let Some(cells) = self.getprop_cells(c"reg")? {
let parent = self.parent()?;
let addr_cells = parent.address_cells()?;
@@ -186,7 +185,7 @@
/// Returns the standard ranges property.
pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
- if let Some(cells) = self.getprop_cells(cstr!("ranges"))? {
+ if let Some(cells) = self.getprop_cells(c"ranges")? {
let parent = self.parent()?;
let addr_cells = self.address_cells()?;
let parent_addr_cells = parent.address_cells()?;
@@ -320,9 +319,9 @@
/// Returns the phandle
pub fn get_phandle(&self) -> Result<Option<Phandle>> {
// This rewrites the fdt_get_phandle() because it doesn't return error code.
- if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
+ if let Some(prop) = self.getprop_u32(c"phandle")? {
Ok(Some(prop.try_into()?))
- } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
+ } else if let Some(prop) = self.getprop_u32(c"linux,phandle")? {
Ok(Some(prop.try_into()?))
} else {
Ok(None)
@@ -693,8 +692,8 @@
///
/// NOTE: This does not support individual "/memory@XXXX" banks.
pub fn memory(&self) -> Result<MemRegIterator> {
- let node = self.root().subnode(cstr!("memory"))?.ok_or(FdtError::NotFound)?;
- if node.device_type()? != Some(cstr!("memory")) {
+ let node = self.root().subnode(c"memory")?.ok_or(FdtError::NotFound)?;
+ if node.device_type()? != Some(c"memory") {
return Err(FdtError::BadValue);
}
node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
@@ -707,12 +706,12 @@
/// Returns the standard /chosen node.
pub fn chosen(&self) -> Result<Option<FdtNode>> {
- self.root().subnode(cstr!("chosen"))
+ self.root().subnode(c"chosen")
}
/// Returns the standard /chosen node as mutable.
pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
- self.node_mut(cstr!("/chosen"))
+ self.node_mut(c"/chosen")
}
/// Returns the root node of the tree.
@@ -722,12 +721,12 @@
/// Returns the standard /__symbols__ node.
pub fn symbols(&self) -> Result<Option<FdtNode>> {
- self.root().subnode(cstr!("__symbols__"))
+ self.root().subnode(c"__symbols__")
}
/// Returns the standard /__symbols__ node as mutable
pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
- self.node_mut(cstr!("/__symbols__"))
+ self.node_mut(c"/__symbols__")
}
/// Returns a tree node by its full path.
diff --git a/libs/libfdt/src/result.rs b/libs/libfdt/src/result.rs
index 52291ca..d671647 100644
--- a/libs/libfdt/src/result.rs
+++ b/libs/libfdt/src/result.rs
@@ -14,6 +14,7 @@
//! Rust types related to the libfdt C integer results.
+use core::error;
use core::ffi::{c_int, c_uint};
use core::fmt;
use core::result;
@@ -91,6 +92,8 @@
}
}
+impl error::Error for FdtError {}
+
/// Result type with FdtError enum.
pub type Result<T> = result::Result<T, FdtError>;
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index f521a00..e027164 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -17,7 +17,6 @@
//! Integration tests of the library libfdt.
use core::ffi::CStr;
-use cstr::cstr;
use libfdt::{Fdt, FdtError, FdtNodeMut, Phandle};
use std::collections::HashSet;
use std::ffi::CString;
@@ -82,14 +81,14 @@
let fdt = Fdt::from_slice(&data).unwrap();
let root = fdt.root();
- assert_eq!(root.name(), Ok(cstr!("")));
+ assert_eq!(root.name(), Ok(c""));
let chosen = fdt.chosen().unwrap().unwrap();
- assert_eq!(chosen.name(), Ok(cstr!("chosen")));
+ assert_eq!(chosen.name(), Ok(c"chosen"));
- let nested_node_path = cstr!("/cpus/PowerPC,970@0");
+ let nested_node_path = c"/cpus/PowerPC,970@0";
let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
- assert_eq!(nested_node.name(), Ok(cstr!("PowerPC,970@0")));
+ assert_eq!(nested_node.name(), Ok(c"PowerPC,970@0"));
}
#[test]
@@ -97,7 +96,7 @@
let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
let fdt = Fdt::from_slice(&data).unwrap();
let root = fdt.root();
- let expected = [Ok(cstr!("cpus")), Ok(cstr!("randomnode")), Ok(cstr!("chosen"))];
+ let expected = [Ok(c"cpus"), Ok(c"randomnode"), Ok(c"chosen")];
let root_subnodes = root.subnodes().unwrap();
let subnode_names: Vec<_> = root_subnodes.map(|node| node.name()).collect();
@@ -112,11 +111,11 @@
let one_be = 0x1_u32.to_be_bytes();
type Result<T> = core::result::Result<T, FdtError>;
let expected: Vec<(Result<&CStr>, Result<&[u8]>)> = vec![
- (Ok(cstr!("model")), Ok(b"MyBoardName\0".as_ref())),
- (Ok(cstr!("compatible")), Ok(b"MyBoardName\0MyBoardFamilyName\0".as_ref())),
- (Ok(cstr!("#address-cells")), Ok(&one_be)),
- (Ok(cstr!("#size-cells")), Ok(&one_be)),
- (Ok(cstr!("empty_prop")), Ok(&[])),
+ (Ok(c"model"), Ok(b"MyBoardName\0".as_ref())),
+ (Ok(c"compatible"), Ok(b"MyBoardName\0MyBoardFamilyName\0".as_ref())),
+ (Ok(c"#address-cells"), Ok(&one_be)),
+ (Ok(c"#size-cells"), Ok(&one_be)),
+ (Ok(c"empty_prop"), Ok(&[])),
];
let properties = root.properties().unwrap();
@@ -129,8 +128,8 @@
fn node_supernode_at_depth() {
let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
let fdt = Fdt::from_slice(&data).unwrap();
- let node = fdt.node(cstr!("/cpus/PowerPC,970@1")).unwrap().unwrap();
- let expected = vec![Ok(cstr!("")), Ok(cstr!("cpus")), Ok(cstr!("PowerPC,970@1"))];
+ let node = fdt.node(c"/cpus/PowerPC,970@1").unwrap().unwrap();
+ let expected = vec![Ok(c""), Ok(c"cpus"), Ok(c"PowerPC,970@1")];
let mut supernode_names = vec![];
let mut depth = 0;
@@ -187,12 +186,12 @@
// Test linux,phandle
let phandle = Phandle::new(0xFF).unwrap();
let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
- assert_eq!(node.name(), Ok(cstr!("node_zz")));
+ assert_eq!(node.name(), Ok(c"node_zz"));
// Test phandle
let phandle = Phandle::new(0x22).unwrap();
let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
- assert_eq!(node.name(), Ok(cstr!("node_abc")));
+ assert_eq!(node.name(), Ok(c"node_abc"));
}
#[test]
@@ -203,12 +202,12 @@
// Test linux,phandle
let phandle = Phandle::new(0xFF).unwrap();
let node: FdtNodeMut = fdt.node_mut_with_phandle(phandle).unwrap().unwrap();
- assert_eq!(node.as_node().name(), Ok(cstr!("node_zz")));
+ assert_eq!(node.as_node().name(), Ok(c"node_zz"));
// Test phandle
let phandle = Phandle::new(0x22).unwrap();
let node: FdtNodeMut = fdt.node_mut_with_phandle(phandle).unwrap().unwrap();
- assert_eq!(node.as_node().name(), Ok(cstr!("node_abc")));
+ assert_eq!(node.as_node().name(), Ok(c"node_abc"));
}
#[test]
@@ -217,15 +216,15 @@
let fdt = Fdt::from_slice(&data).unwrap();
// Test linux,phandle
- let node = fdt.node(cstr!("/node_z/node_zz")).unwrap().unwrap();
+ let node = fdt.node(c"/node_z/node_zz").unwrap().unwrap();
assert_eq!(node.get_phandle(), Ok(Phandle::new(0xFF)));
// Test phandle
- let node = fdt.node(cstr!("/node_a/node_ab/node_abc")).unwrap().unwrap();
+ let node = fdt.node(c"/node_a/node_ab/node_abc").unwrap().unwrap();
assert_eq!(node.get_phandle(), Ok(Phandle::new(0x22)));
// Test no phandle
- let node = fdt.node(cstr!("/node_b")).unwrap().unwrap();
+ let node = fdt.node(c"/node_b").unwrap().unwrap();
assert_eq!(node.get_phandle(), Ok(None));
}
@@ -234,7 +233,7 @@
let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
let phandle = Phandle::new(0xFF).unwrap();
- let path = cstr!("/node_z/node_zz");
+ let path = c"/node_z/node_zz";
fdt.node_with_phandle(phandle).unwrap().unwrap();
let node = fdt.node_mut(path).unwrap().unwrap();
@@ -259,8 +258,8 @@
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
fdt.unpack().unwrap();
- let node_path = cstr!("/node_z/node_zz");
- let subnode_name = cstr!("123456789");
+ let node_path = c"/node_z/node_zz";
+ let subnode_name = c"123456789";
for len in 0..subnode_name.to_bytes().len() {
let name = &subnode_name.to_bytes()[0..len];
@@ -289,7 +288,7 @@
let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
let fdt = Fdt::from_slice(&data).unwrap();
- let name = cstr!("node_a");
+ let name = c"node_a";
let root = fdt.root();
let node = root.subnode(name).unwrap();
assert_ne!(None, node);
@@ -309,7 +308,7 @@
assert_ne!(None, node);
let node = node.unwrap();
- assert_eq!(Ok(cstr!("node_a")), node.name());
+ assert_eq!(Ok(c"node_a"), node.name());
}
#[test]
@@ -317,7 +316,7 @@
let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
let fdt = Fdt::from_slice(&data).unwrap();
- let name = cstr!("node_a");
+ let name = c"node_a";
let node = {
let root = fdt.root();
root.subnode(name).unwrap().unwrap()
@@ -332,7 +331,7 @@
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
let symbols = fdt.symbols().unwrap().unwrap();
- assert_eq!(symbols.name(), Ok(cstr!("__symbols__")));
+ assert_eq!(symbols.name(), Ok(c"__symbols__"));
// Validates type.
let _symbols: FdtNodeMut = fdt.symbols_mut().unwrap().unwrap();
@@ -343,14 +342,14 @@
let mut data = fs::read(TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH).unwrap();
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
- let mut memory = fdt.node_mut(cstr!("/memory")).unwrap().unwrap();
+ let mut memory = fdt.node_mut(c"/memory").unwrap().unwrap();
{
let memory = memory.as_node();
- assert_eq!(memory.name(), Ok(cstr!("memory")));
+ assert_eq!(memory.name(), Ok(c"memory"));
}
// Just check whether borrow checker doesn't complain this.
- memory.setprop_inplace(cstr!("device_type"), b"MEMORY\0").unwrap();
+ memory.setprop_inplace(c"device_type", b"MEMORY\0").unwrap();
}
#[test]
@@ -358,18 +357,13 @@
let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
- let node_z = fdt.node(cstr!("/node_z")).unwrap().unwrap();
+ let node_z = fdt.node(c"/node_z").unwrap().unwrap();
let descendants: Vec<_> =
node_z.descendants().map(|(node, depth)| (node.name().unwrap(), depth)).collect();
assert_eq!(
descendants,
- vec![
- (cstr!("node_za"), 1),
- (cstr!("node_zb"), 1),
- (cstr!("node_zz"), 1),
- (cstr!("node_zzz"), 2)
- ]
+ vec![(c"node_za", 1), (c"node_zb", 1), (c"node_zz", 1), (c"node_zzz", 2)]
);
}
@@ -382,7 +376,7 @@
let mut subnode_iter = root.first_subnode().unwrap();
while let Some(subnode) = subnode_iter {
- if subnode.as_node().name() == Ok(cstr!("node_z")) {
+ if subnode.as_node().name() == Ok(c"node_z") {
subnode_iter = subnode.delete_and_next_subnode().unwrap();
} else {
subnode_iter = subnode.next_subnode().unwrap();
@@ -390,12 +384,7 @@
}
let root = fdt.root();
- let expected_names = vec![
- Ok(cstr!("node_a")),
- Ok(cstr!("node_b")),
- Ok(cstr!("node_c")),
- Ok(cstr!("__symbols__")),
- ];
+ let expected_names = vec![Ok(c"node_a"), Ok(c"node_b"), Ok(c"node_c"), Ok(c"__symbols__")];
let subnode_names: Vec<_> = root.subnodes().unwrap().map(|node| node.name()).collect();
assert_eq!(expected_names, subnode_names);
@@ -407,19 +396,19 @@
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
let expected_nodes = vec![
- (Ok(cstr!("node_b")), 1),
- (Ok(cstr!("node_c")), 1),
- (Ok(cstr!("node_z")), 1),
- (Ok(cstr!("node_za")), 2),
- (Ok(cstr!("node_zb")), 2),
- (Ok(cstr!("__symbols__")), 1),
+ (Ok(c"node_b"), 1),
+ (Ok(c"node_c"), 1),
+ (Ok(c"node_z"), 1),
+ (Ok(c"node_za"), 2),
+ (Ok(c"node_zb"), 2),
+ (Ok(c"__symbols__"), 1),
];
let mut expected_nodes_iter = expected_nodes.iter();
let mut iter = fdt.root_mut().next_node(0).unwrap();
while let Some((node, depth)) = iter {
let node_name = node.as_node().name();
- if node_name == Ok(cstr!("node_a")) || node_name == Ok(cstr!("node_zz")) {
+ if node_name == Ok(c"node_a") || node_name == Ok(c"node_zz") {
iter = node.delete_and_next_node(depth).unwrap();
} else {
// Note: Checking name here is easier than collecting names and assert_eq!(),
@@ -464,7 +453,7 @@
root.name()
// Make root to be dropped
};
- assert_eq!(Ok(cstr!("")), name);
+ assert_eq!(Ok(c""), name);
}
#[test]
@@ -473,7 +462,7 @@
let fdt = Fdt::create_empty_tree(&mut data).unwrap();
let root = fdt.root_mut();
- let names = [cstr!("a"), cstr!("b")];
+ let names = [c"a", c"b"];
root.add_subnodes(&names).unwrap();
let expected: HashSet<_> = names.into_iter().collect();
@@ -492,14 +481,14 @@
let name = {
let node_a = {
let root = fdt.root();
- root.subnode(cstr!("node_a")).unwrap()
+ root.subnode(c"node_a").unwrap()
// Make root to be dropped
};
assert_ne!(None, node_a);
node_a.unwrap().name()
// Make node_a to be dropped
};
- assert_eq!(Ok(cstr!("node_a")), name);
+ assert_eq!(Ok(c"node_a"), name);
}
#[test]
@@ -521,7 +510,7 @@
first_subnode.name()
// Make first_subnode to be dropped
};
- assert_eq!(Ok(cstr!("node_a")), first_subnode_name);
+ assert_eq!(Ok(c"node_a"), first_subnode_name);
}
#[test]
@@ -543,5 +532,5 @@
first_descendant.name()
// Make first_descendant to be dropped
};
- assert_eq!(Ok(cstr!("node_a")), first_descendant_name);
+ assert_eq!(Ok(c"node_a"), first_descendant_name);
}
diff --git a/libs/libservice_vm_fake_chain/Android.bp b/libs/libservice_vm_fake_chain/Android.bp
index 56fb22a..65eddf8 100644
--- a/libs/libservice_vm_fake_chain/Android.bp
+++ b/libs/libservice_vm_fake_chain/Android.bp
@@ -26,9 +26,6 @@
"//packages/modules/Virtualization/guest/rialto:__subpackages__",
],
prefer_rlib: true,
- rustlibs: [
- "libcstr",
- ],
}
rust_library {
diff --git a/libs/libservice_vm_fake_chain/src/client_vm.rs b/libs/libservice_vm_fake_chain/src/client_vm.rs
index dc499e0..fa72739 100644
--- a/libs/libservice_vm_fake_chain/src/client_vm.rs
+++ b/libs/libservice_vm_fake_chain/src/client_vm.rs
@@ -22,7 +22,6 @@
use ciborium::{cbor, value::Value};
use core::result;
use coset::CborSerializable;
-use cstr::cstr;
use diced_open_dice::{
hash, retry_bcc_format_config_descriptor, retry_bcc_main_flow, Config, DiceArtifacts,
DiceConfigValues, DiceError, DiceMode, InputValues, OwnedDiceArtifacts, Result, HASH_SIZE,
@@ -96,7 +95,7 @@
// Adds an entry describing the Microdroid kernel.
let config_values = DiceConfigValues {
- component_name: Some(cstr!("vm_entry")),
+ component_name: Some(c"vm_entry"),
component_version: Some(12),
resettable: true,
security_version: Some(13),
diff --git a/libs/libservice_vm_fake_chain/src/service_vm.rs b/libs/libservice_vm_fake_chain/src/service_vm.rs
index 04297e4..5064ff8 100644
--- a/libs/libservice_vm_fake_chain/src/service_vm.rs
+++ b/libs/libservice_vm_fake_chain/src/service_vm.rs
@@ -24,7 +24,6 @@
iana::{self, EnumI64},
Algorithm, AsCborValue, CborSerializable, CoseKey, KeyOperation, KeyType, Label,
};
-use cstr::cstr;
use diced_open_dice::{
derive_cdi_private_key_seed, keypair_from_seed, retry_bcc_format_config_descriptor,
retry_bcc_main_flow, retry_dice_main_flow, CdiValues, Config, DiceConfigValues, DiceError,
@@ -113,7 +112,7 @@
// Gets the pvmfw certificate to as the root certificate of DICE chain.
let config_values = DiceConfigValues {
- component_name: Some(cstr!("Protected VM firmware")),
+ component_name: Some(c"Protected VM firmware"),
component_version: Some(1),
resettable: true,
rkp_vm_marker: true,
@@ -156,7 +155,7 @@
pub fn fake_service_vm_dice_artifacts() -> Result<OwnedDiceArtifacts> {
let (cdi_values, dice_chain) = fake_dice_artifacts_up_to_pvmfw()?;
let config_values = DiceConfigValues {
- component_name: Some(cstr!("vm_entry")),
+ component_name: Some(c"vm_entry"),
component_version: Some(12),
resettable: true,
rkp_vm_marker: true,
diff --git a/libs/libservice_vm_manager/src/lib.rs b/libs/libservice_vm_manager/src/lib.rs
index 5bb97d7..0f322bb 100644
--- a/libs/libservice_vm_manager/src/lib.rs
+++ b/libs/libservice_vm_manager/src/lib.rs
@@ -238,8 +238,7 @@
memoryMib: VM_MEMORY_MB,
cpuTopology: CpuTopology::ONE_CPU,
platformVersion: "~1.0".to_string(),
- gdbPort: 0, // No gdb
- balloon: true, // TODO: probably don't want ballooning.
+ gdbPort: 0, // No gdb
..Default::default()
});
let console_out = Some(android_log_fd()?);
diff --git a/libs/libvm_payload/Android.bp b/libs/libvm_payload/Android.bp
index bb91737..1ebbe39 100644
--- a/libs/libvm_payload/Android.bp
+++ b/libs/libvm_payload/Android.bp
@@ -34,6 +34,7 @@
bindgen_flags: [
"--default-enum-style rust",
"--allowlist-type=AVmAttestationStatus",
+ "--allowlist-type=AVmAccessRollbackProtectedSecretStatus",
],
visibility: [":__subpackages__"],
}
diff --git a/libs/libvm_payload/include/vm_payload.h b/libs/libvm_payload/include/vm_payload.h
index 5e15607..e4609fa 100644
--- a/libs/libvm_payload/include/vm_payload.h
+++ b/libs/libvm_payload/include/vm_payload.h
@@ -52,6 +52,22 @@
} AVmAttestationStatus;
/**
+ * Introduced in API 36.
+ * Status type used to indicate error while accessing RollbackProtectedSecret.
+ */
+typedef enum AVmAccessRollbackProtectedSecretStatus : int32_t {
+ /**
+ * Relevant Entry not found. This can happen either due to no value was ever written or because
+ * Android maliciously deleted the value (deletions may not be authenticated).
+ */
+ AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_ENTRY_NOT_FOUND = -1,
+ /** Requested access size is not supported by the implementation */
+ AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_BAD_SIZE = -2,
+ /** Access failed, this could be due to lacking support from Hardware */
+ AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_ACCESS_FAILED = -3,
+} AVmAccessRollbackProtectedSecretStatus;
+
+/**
* Notifies the host that the payload is ready.
*
* If the host app has set a `VirtualMachineCallback` for the VM, its
@@ -102,6 +118,11 @@
* byte sequences and do not need to be kept secret; typically they are
* hardcoded in the calling code.
*
+ * The secret is linked to the instance & will be created for a new instance.
+ * Callers should check `AVmPayload_isNewInstance()` to meaningfully use the secret.
+ * For ex, decryption of any old data is meaningless with the returned secret of a new
+ * VM instance with fresh keys.
+ *
* \param identifier identifier of the secret to return.
* \param identifier_size size of the secret identifier.
* \param secret pointer to size bytes where the secret is written.
@@ -259,5 +280,42 @@
size_t AVmAttestationResult_getCertificateAt(const AVmAttestationResult* _Nonnull result,
size_t index, void* _Nullable data, size_t size)
__INTRODUCED_IN(__ANDROID_API_V__);
+/**
+ * Writes up to n bytes from buffer starting at `buf`, on behalf of the payload, to rollback
+ * detectable storage. The number of bytes written may be less than n if, for example, the
+ * underlying storage has size constraints. This stored data is confidential to the pVM and
+ * protected via appropriate DICE policy on the payload's DICE chain.
+ *
+ * \param buf A pointer to data to be written. This should have the size of at least n bytes.
+ * \param n The maximum number of bytes to be filled in `buf`.
+ *
+ * \return On success, the number of bytes written is returned. On error, appropriate
+ * AVmAccessRollbackProtectedSecretStatus (negative number) is returned.
+ */
+
+int32_t AVmPayload_writeRollbackProtectedSecret(const void* _Nonnull buf, size_t n)
+ __INTRODUCED_IN(36);
+/**
+ * Read up to n bytes of payload's data in rollback detectable storage into `buf`.
+ *
+ * \param buf A pointer to buffer where the requested data is written. This should have the size of
+ * at least n bytes.
+ * \param n The maximum number of bytes to be read.
+ *
+ * \return On success, the number of bytes that would have been written to `buf` if n was
+ * sufficiently large. On error, appropriate AVmAccessRollbackProtectedSecretStatus(a negative
+ * number) is returned.
+ */
+int32_t AVmPayload_readRollbackProtectedSecret(void* _Nullable buf, size_t n) __INTRODUCED_IN(36);
+;
+
+/**
+ * Checks whether the VM instance is new - i.e., if this is the first run of an instance.
+ * This is an indication of fresh new VM secrets. Payload can use this to setup the fresh
+ * instance if needed.
+ *
+ * \return true if this is the first run of an instance, false otherwise.
+ */
+bool AVmPayload_isNewInstance() __INTRODUCED_IN(36);
__END_DECLS
diff --git a/libs/libvm_payload/libvm_payload.map.txt b/libs/libvm_payload/libvm_payload.map.txt
index 3daad00..ca949d9 100644
--- a/libs/libvm_payload/libvm_payload.map.txt
+++ b/libs/libvm_payload/libvm_payload.map.txt
@@ -15,6 +15,9 @@
AVmAttestationStatus_toString; # systemapi introduced=VanillaIceCream
AVmAttestationResult_getCertificateCount; # systemapi introduced=VanillaIceCream
AVmAttestationResult_getCertificateAt; # systemapi introduced=VanillaIceCream
+ AVmPayload_writeRollbackProtectedSecret; # systemapi introduced=36
+ AVmPayload_readRollbackProtectedSecret; # systemapi introduced=36
+ AVmPayload_isNewInstance; # systemapi introduced=36
local:
*;
};
diff --git a/libs/libvm_payload/src/lib.rs b/libs/libvm_payload/src/lib.rs
index eb81752..cbadec2 100644
--- a/libs/libvm_payload/src/lib.rs
+++ b/libs/libvm_payload/src/lib.rs
@@ -16,14 +16,14 @@
use android_system_virtualization_payload::aidl::android::system::virtualization::payload:: IVmPayloadService::{
IVmPayloadService, ENCRYPTEDSTORE_MOUNTPOINT, VM_APK_CONTENTS_PATH,
- VM_PAYLOAD_SERVICE_SOCKET_NAME, AttestationResult::AttestationResult,
+ VM_PAYLOAD_SERVICE_SOCKET_NAME, AttestationResult::AttestationResult
};
use anyhow::{bail, ensure, Context, Result};
use binder::{
unstable_api::{new_spibinder, AIBinder},
Strong, ExceptionCode,
};
-use log::{error, info, LevelFilter};
+use log::{error, info, LevelFilter, debug};
use rpcbinder::{RpcServer, RpcSession};
use openssl::{ec::EcKey, sha::sha256, ecdsa::EcdsaSig};
use std::convert::Infallible;
@@ -38,9 +38,12 @@
Mutex,
};
use vm_payload_status_bindgen::AVmAttestationStatus;
+use vm_payload_status_bindgen::AVmAccessRollbackProtectedSecretStatus::{AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_ENTRY_NOT_FOUND, AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_ACCESS_FAILED, AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_BAD_SIZE};
+use std::cmp::min;
/// Maximum size of an ECDSA signature for EC P-256 key is 72 bytes.
const MAX_ECDSA_P256_SIGNATURE_SIZE: usize = 72;
+const RP_DATA_SIZE: usize = 32;
static VM_APK_CONTENTS_PATH_C: LazyLock<CString> =
LazyLock::new(|| CString::new(VM_APK_CONTENTS_PATH).expect("CString::new failed"));
@@ -566,3 +569,98 @@
ptr::null()
}
}
+
+/// Writes up to n bytes from buffer starting at `buf`, on behalf of the payload, to rollback
+/// detectable storage and return the number of bytes written or appropriate (negative) status.
+/// For this implementation, the backing storage is Secretkeeper HAL, which allows storing & reading
+/// of 32 bytes secret!
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `buf` must be [valid] for reads of n bytes.
+///
+/// [valid]: ptr#safety
+#[no_mangle]
+pub unsafe extern "C" fn AVmPayload_writeRollbackProtectedSecret(buf: *const u8, n: usize) -> i32 {
+ initialize_logging();
+ if n < RP_DATA_SIZE {
+ error!(
+ "Requested writing {} bytes, while Secretkeeper supports only {} bytes",
+ n, RP_DATA_SIZE
+ );
+ return AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_BAD_SIZE as i32;
+ }
+ // Safety: See the requirements on `buf` above and we just checked that n >= RP_DATA_SIZE.
+ let buf = unsafe { std::slice::from_raw_parts(buf, RP_DATA_SIZE) };
+ match try_writing_payload_rollback_protected_data(buf.try_into().unwrap()) {
+ Ok(()) => RP_DATA_SIZE as i32,
+ Err(e) => {
+ error!("Failed to write rollback protected data: {e:?}");
+ AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_ACCESS_FAILED as i32
+ }
+ }
+}
+
+/// Read up to n bytes of payload's data in rollback detectable storage into `buf`.
+/// For this implementation, the backing storage is Secretkeeper HAL, which allows storing & reading
+/// of 32 bytes secret!
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `buf` must be [valid] for writes of n bytes.
+///
+/// [valid]: ptr#safety
+#[no_mangle]
+pub unsafe extern "C" fn AVmPayload_readRollbackProtectedSecret(buf: *mut u8, n: usize) -> i32 {
+ initialize_logging();
+ match try_read_rollback_protected_data() {
+ Err(e) => {
+ error!("Failed to read rollback protected data: {e:?}");
+ AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_ACCESS_FAILED as i32
+ }
+ Ok(stored_data) => {
+ if let Some(stored_data) = stored_data {
+ // SAFETY: See the requirements on `buf` above; `stored_data` is known to have
+ // length `RP_DATA_SIZE`, and cannot overlap `data` because we just allocated
+ // it.
+ unsafe {
+ ptr::copy_nonoverlapping(stored_data.as_ptr(), buf, min(n, RP_DATA_SIZE));
+ }
+ RP_DATA_SIZE as i32
+ } else {
+ debug!("No relevant entry found in Secretkeeper");
+ AVMACCESSROLLBACKPROTECTEDSECRETSTATUS_ENTRY_NOT_FOUND as i32
+ }
+ }
+ }
+}
+
+fn try_writing_payload_rollback_protected_data(data: &[u8; RP_DATA_SIZE]) -> Result<()> {
+ get_vm_payload_service()?
+ .writePayloadRpData(data)
+ .context("Failed to write payload rollback protected data")?;
+ Ok(())
+}
+
+fn try_read_rollback_protected_data() -> Result<Option<[u8; RP_DATA_SIZE]>> {
+ let rp = get_vm_payload_service()?
+ .readPayloadRpData()
+ .context("Failed to read rollback protected data")?;
+ Ok(rp)
+}
+
+/// Checks whether the VM instance is new - i.e., if this is the first run of an instance.
+///
+/// Panics on error (including unexpected server exit).
+#[no_mangle]
+pub extern "C" fn AVmPayload_isNewInstance() -> bool {
+ unwrap_or_abort(try_is_new_instance())
+}
+
+fn try_is_new_instance() -> Result<bool> {
+ get_vm_payload_service()?.isNewInstance().context("Cannot determine if the instance is new")
+}
diff --git a/libs/libvm_payload/wrapper/lib.rs b/libs/libvm_payload/wrapper/lib.rs
index b9ce6c8..bf274b0 100644
--- a/libs/libvm_payload/wrapper/lib.rs
+++ b/libs/libvm_payload/wrapper/lib.rs
@@ -31,7 +31,9 @@
use std::ptr;
use vm_payload_bindgen::{
AIBinder, AVmPayload_getApkContentsPath, AVmPayload_getEncryptedStoragePath,
- AVmPayload_getVmInstanceSecret, AVmPayload_notifyPayloadReady, AVmPayload_runVsockRpcServer,
+ AVmPayload_getVmInstanceSecret, AVmPayload_isNewInstance, AVmPayload_notifyPayloadReady,
+ AVmPayload_readRollbackProtectedSecret, AVmPayload_runVsockRpcServer,
+ AVmPayload_writeRollbackProtectedSecret,
};
/// The functions declared here are restricted to VMs created with a config file;
@@ -194,3 +196,23 @@
)
}
}
+
+/// Read payload's `data` written on behalf of the payload in Secretkeeper.
+pub fn read_rollback_protected_secret(data: &mut [u8]) -> i32 {
+ // SAFETY: The function only reads from`[data]` within its bounds.
+ unsafe { AVmPayload_readRollbackProtectedSecret(data.as_ptr() as *mut c_void, data.len()) }
+}
+
+/// Write `data`, on behalf of the payload, to Secretkeeper.
+pub fn write_rollback_protected_secret(data: &[u8]) -> i32 {
+ // SAFETY: The function only writes to `[data]` within its bounds.
+ unsafe { AVmPayload_writeRollbackProtectedSecret(data.as_ptr() as *const c_void, data.len()) }
+}
+
+/// Checks whether the VM instance is new - i.e., if this is the first run of an instance.
+/// This is an indication of fresh new VM secrets. Payload can use this to setup the fresh
+/// instance if needed.
+pub fn is_new_instance_status() -> bool {
+ // SAFETY: The function returns bool, no arguments are needed.
+ unsafe { AVmPayload_isNewInstance() }
+}
diff --git a/libs/libvmbase/Android.bp b/libs/libvmbase/Android.bp
index 3088633..de347c7 100644
--- a/libs/libvmbase/Android.bp
+++ b/libs/libvmbase/Android.bp
@@ -80,7 +80,6 @@
"libaarch64_paging",
"libbuddy_system_allocator",
"libcfg_if",
- "libcstr",
"libhypervisor_backends",
"liblibfdt_nostd",
"liblog_rust_nostd",
diff --git a/libs/libvmbase/src/bionic.rs b/libs/libvmbase/src/bionic.rs
index 580b0cb..7b9fe2a 100644
--- a/libs/libvmbase/src/bionic.rs
+++ b/libs/libvmbase/src/bionic.rs
@@ -24,7 +24,6 @@
use core::slice;
use core::str;
-use cstr::cstr;
use log::error;
use log::info;
@@ -229,138 +228,138 @@
fn cstr_error(n: c_int) -> &'static CStr {
// Messages taken from errno(1).
match n {
- 0 => cstr!("Success"),
- 1 => cstr!("Operation not permitted"),
- 2 => cstr!("No such file or directory"),
- 3 => cstr!("No such process"),
- 4 => cstr!("Interrupted system call"),
- 5 => cstr!("Input/output error"),
- 6 => cstr!("No such device or address"),
- 7 => cstr!("Argument list too long"),
- 8 => cstr!("Exec format error"),
- 9 => cstr!("Bad file descriptor"),
- 10 => cstr!("No child processes"),
- 11 => cstr!("Resource temporarily unavailable"),
- 12 => cstr!("Cannot allocate memory"),
- 13 => cstr!("Permission denied"),
- 14 => cstr!("Bad address"),
- 15 => cstr!("Block device required"),
- 16 => cstr!("Device or resource busy"),
- 17 => cstr!("File exists"),
- 18 => cstr!("Invalid cross-device link"),
- 19 => cstr!("No such device"),
- 20 => cstr!("Not a directory"),
- 21 => cstr!("Is a directory"),
- 22 => cstr!("Invalid argument"),
- 23 => cstr!("Too many open files in system"),
- 24 => cstr!("Too many open files"),
- 25 => cstr!("Inappropriate ioctl for device"),
- 26 => cstr!("Text file busy"),
- 27 => cstr!("File too large"),
- 28 => cstr!("No space left on device"),
- 29 => cstr!("Illegal seek"),
- 30 => cstr!("Read-only file system"),
- 31 => cstr!("Too many links"),
- 32 => cstr!("Broken pipe"),
- 33 => cstr!("Numerical argument out of domain"),
- 34 => cstr!("Numerical result out of range"),
- 35 => cstr!("Resource deadlock avoided"),
- 36 => cstr!("File name too long"),
- 37 => cstr!("No locks available"),
- 38 => cstr!("Function not implemented"),
- 39 => cstr!("Directory not empty"),
- 40 => cstr!("Too many levels of symbolic links"),
- 42 => cstr!("No message of desired type"),
- 43 => cstr!("Identifier removed"),
- 44 => cstr!("Channel number out of range"),
- 45 => cstr!("Level 2 not synchronized"),
- 46 => cstr!("Level 3 halted"),
- 47 => cstr!("Level 3 reset"),
- 48 => cstr!("Link number out of range"),
- 49 => cstr!("Protocol driver not attached"),
- 50 => cstr!("No CSI structure available"),
- 51 => cstr!("Level 2 halted"),
- 52 => cstr!("Invalid exchange"),
- 53 => cstr!("Invalid request descriptor"),
- 54 => cstr!("Exchange full"),
- 55 => cstr!("No anode"),
- 56 => cstr!("Invalid request code"),
- 57 => cstr!("Invalid slot"),
- 59 => cstr!("Bad font file format"),
- 60 => cstr!("Device not a stream"),
- 61 => cstr!("No data available"),
- 62 => cstr!("Timer expired"),
- 63 => cstr!("Out of streams resources"),
- 64 => cstr!("Machine is not on the network"),
- 65 => cstr!("Package not installed"),
- 66 => cstr!("Object is remote"),
- 67 => cstr!("Link has been severed"),
- 68 => cstr!("Advertise error"),
- 69 => cstr!("Srmount error"),
- 70 => cstr!("Communication error on send"),
- 71 => cstr!("Protocol error"),
- 72 => cstr!("Multihop attempted"),
- 73 => cstr!("RFS specific error"),
- 74 => cstr!("Bad message"),
- 75 => cstr!("Value too large for defined data type"),
- 76 => cstr!("Name not unique on network"),
- 77 => cstr!("File descriptor in bad state"),
- 78 => cstr!("Remote address changed"),
- 79 => cstr!("Can not access a needed shared library"),
- 80 => cstr!("Accessing a corrupted shared library"),
- 81 => cstr!(".lib section in a.out corrupted"),
- 82 => cstr!("Attempting to link in too many shared libraries"),
- 83 => cstr!("Cannot exec a shared library directly"),
- 84 => cstr!("Invalid or incomplete multibyte or wide character"),
- 85 => cstr!("Interrupted system call should be restarted"),
- 86 => cstr!("Streams pipe error"),
- 87 => cstr!("Too many users"),
- 88 => cstr!("Socket operation on non-socket"),
- 89 => cstr!("Destination address required"),
- 90 => cstr!("Message too long"),
- 91 => cstr!("Protocol wrong type for socket"),
- 92 => cstr!("Protocol not available"),
- 93 => cstr!("Protocol not supported"),
- 94 => cstr!("Socket type not supported"),
- 95 => cstr!("Operation not supported"),
- 96 => cstr!("Protocol family not supported"),
- 97 => cstr!("Address family not supported by protocol"),
- 98 => cstr!("Address already in use"),
- 99 => cstr!("Cannot assign requested address"),
- 100 => cstr!("Network is down"),
- 101 => cstr!("Network is unreachable"),
- 102 => cstr!("Network dropped connection on reset"),
- 103 => cstr!("Software caused connection abort"),
- 104 => cstr!("Connection reset by peer"),
- 105 => cstr!("No buffer space available"),
- 106 => cstr!("Transport endpoint is already connected"),
- 107 => cstr!("Transport endpoint is not connected"),
- 108 => cstr!("Cannot send after transport endpoint shutdown"),
- 109 => cstr!("Too many references: cannot splice"),
- 110 => cstr!("Connection timed out"),
- 111 => cstr!("Connection refused"),
- 112 => cstr!("Host is down"),
- 113 => cstr!("No route to host"),
- 114 => cstr!("Operation already in progress"),
- 115 => cstr!("Operation now in progress"),
- 116 => cstr!("Stale file handle"),
- 117 => cstr!("Structure needs cleaning"),
- 118 => cstr!("Not a XENIX named type file"),
- 119 => cstr!("No XENIX semaphores available"),
- 120 => cstr!("Is a named type file"),
- 121 => cstr!("Remote I/O error"),
- 122 => cstr!("Disk quota exceeded"),
- 123 => cstr!("No medium found"),
- 124 => cstr!("Wrong medium type"),
- 125 => cstr!("Operation canceled"),
- 126 => cstr!("Required key not available"),
- 127 => cstr!("Key has expired"),
- 128 => cstr!("Key has been revoked"),
- 129 => cstr!("Key was rejected by service"),
- 130 => cstr!("Owner died"),
- 131 => cstr!("State not recoverable"),
- 132 => cstr!("Operation not possible due to RF-kill"),
- 133 => cstr!("Memory page has hardware error"),
- _ => cstr!("Unknown errno value"),
+ 0 => c"Success",
+ 1 => c"Operation not permitted",
+ 2 => c"No such file or directory",
+ 3 => c"No such process",
+ 4 => c"Interrupted system call",
+ 5 => c"Input/output error",
+ 6 => c"No such device or address",
+ 7 => c"Argument list too long",
+ 8 => c"Exec format error",
+ 9 => c"Bad file descriptor",
+ 10 => c"No child processes",
+ 11 => c"Resource temporarily unavailable",
+ 12 => c"Cannot allocate memory",
+ 13 => c"Permission denied",
+ 14 => c"Bad address",
+ 15 => c"Block device required",
+ 16 => c"Device or resource busy",
+ 17 => c"File exists",
+ 18 => c"Invalid cross-device link",
+ 19 => c"No such device",
+ 20 => c"Not a directory",
+ 21 => c"Is a directory",
+ 22 => c"Invalid argument",
+ 23 => c"Too many open files in system",
+ 24 => c"Too many open files",
+ 25 => c"Inappropriate ioctl for device",
+ 26 => c"Text file busy",
+ 27 => c"File too large",
+ 28 => c"No space left on device",
+ 29 => c"Illegal seek",
+ 30 => c"Read-only file system",
+ 31 => c"Too many links",
+ 32 => c"Broken pipe",
+ 33 => c"Numerical argument out of domain",
+ 34 => c"Numerical result out of range",
+ 35 => c"Resource deadlock avoided",
+ 36 => c"File name too long",
+ 37 => c"No locks available",
+ 38 => c"Function not implemented",
+ 39 => c"Directory not empty",
+ 40 => c"Too many levels of symbolic links",
+ 42 => c"No message of desired type",
+ 43 => c"Identifier removed",
+ 44 => c"Channel number out of range",
+ 45 => c"Level 2 not synchronized",
+ 46 => c"Level 3 halted",
+ 47 => c"Level 3 reset",
+ 48 => c"Link number out of range",
+ 49 => c"Protocol driver not attached",
+ 50 => c"No CSI structure available",
+ 51 => c"Level 2 halted",
+ 52 => c"Invalid exchange",
+ 53 => c"Invalid request descriptor",
+ 54 => c"Exchange full",
+ 55 => c"No anode",
+ 56 => c"Invalid request code",
+ 57 => c"Invalid slot",
+ 59 => c"Bad font file format",
+ 60 => c"Device not a stream",
+ 61 => c"No data available",
+ 62 => c"Timer expired",
+ 63 => c"Out of streams resources",
+ 64 => c"Machine is not on the network",
+ 65 => c"Package not installed",
+ 66 => c"Object is remote",
+ 67 => c"Link has been severed",
+ 68 => c"Advertise error",
+ 69 => c"Srmount error",
+ 70 => c"Communication error on send",
+ 71 => c"Protocol error",
+ 72 => c"Multihop attempted",
+ 73 => c"RFS specific error",
+ 74 => c"Bad message",
+ 75 => c"Value too large for defined data type",
+ 76 => c"Name not unique on network",
+ 77 => c"File descriptor in bad state",
+ 78 => c"Remote address changed",
+ 79 => c"Can not access a needed shared library",
+ 80 => c"Accessing a corrupted shared library",
+ 81 => c".lib section in a.out corrupted",
+ 82 => c"Attempting to link in too many shared libraries",
+ 83 => c"Cannot exec a shared library directly",
+ 84 => c"Invalid or incomplete multibyte or wide character",
+ 85 => c"Interrupted system call should be restarted",
+ 86 => c"Streams pipe error",
+ 87 => c"Too many users",
+ 88 => c"Socket operation on non-socket",
+ 89 => c"Destination address required",
+ 90 => c"Message too long",
+ 91 => c"Protocol wrong type for socket",
+ 92 => c"Protocol not available",
+ 93 => c"Protocol not supported",
+ 94 => c"Socket type not supported",
+ 95 => c"Operation not supported",
+ 96 => c"Protocol family not supported",
+ 97 => c"Address family not supported by protocol",
+ 98 => c"Address already in use",
+ 99 => c"Cannot assign requested address",
+ 100 => c"Network is down",
+ 101 => c"Network is unreachable",
+ 102 => c"Network dropped connection on reset",
+ 103 => c"Software caused connection abort",
+ 104 => c"Connection reset by peer",
+ 105 => c"No buffer space available",
+ 106 => c"Transport endpoint is already connected",
+ 107 => c"Transport endpoint is not connected",
+ 108 => c"Cannot send after transport endpoint shutdown",
+ 109 => c"Too many references: cannot splice",
+ 110 => c"Connection timed out",
+ 111 => c"Connection refused",
+ 112 => c"Host is down",
+ 113 => c"No route to host",
+ 114 => c"Operation already in progress",
+ 115 => c"Operation now in progress",
+ 116 => c"Stale file handle",
+ 117 => c"Structure needs cleaning",
+ 118 => c"Not a XENIX named type file",
+ 119 => c"No XENIX semaphores available",
+ 120 => c"Is a named type file",
+ 121 => c"Remote I/O error",
+ 122 => c"Disk quota exceeded",
+ 123 => c"No medium found",
+ 124 => c"Wrong medium type",
+ 125 => c"Operation canceled",
+ 126 => c"Required key not available",
+ 127 => c"Key has expired",
+ 128 => c"Key has been revoked",
+ 129 => c"Key was rejected by service",
+ 130 => c"Owner died",
+ 131 => c"State not recoverable",
+ 132 => c"Operation not possible due to RF-kill",
+ 133 => c"Memory page has hardware error",
+ _ => c"Unknown errno value",
}
}
diff --git a/libs/libvmbase/src/fdt.rs b/libs/libvmbase/src/fdt.rs
index aaf354e..2113787 100644
--- a/libs/libvmbase/src/fdt.rs
+++ b/libs/libvmbase/src/fdt.rs
@@ -17,7 +17,6 @@
pub mod pci;
use core::ops::Range;
-use cstr::cstr;
use libfdt::{self, Fdt, FdtError};
/// Represents information about a SWIOTLB buffer.
@@ -34,7 +33,7 @@
impl SwiotlbInfo {
/// Creates a `SwiotlbInfo` struct from the given device tree.
pub fn new_from_fdt(fdt: &Fdt) -> libfdt::Result<Option<SwiotlbInfo>> {
- let Some(node) = fdt.compatible_nodes(cstr!("restricted-dma-pool"))?.next() else {
+ let Some(node) = fdt.compatible_nodes(c"restricted-dma-pool")?.next() else {
return Ok(None);
};
let (addr, size, align) = if let Some(mut reg) = node.reg()? {
@@ -42,8 +41,8 @@
let size = reg.size.ok_or(FdtError::BadValue)?;
(Some(reg.addr.try_into().unwrap()), size.try_into().unwrap(), None)
} else {
- let size = node.getprop_u64(cstr!("size"))?.ok_or(FdtError::NotFound)?;
- let align = node.getprop_u64(cstr!("alignment"))?.ok_or(FdtError::NotFound)?;
+ let size = node.getprop_u64(c"size")?.ok_or(FdtError::NotFound)?;
+ let align = node.getprop_u64(c"alignment")?.ok_or(FdtError::NotFound)?;
(None, size.try_into().unwrap(), Some(align.try_into().unwrap()))
};
Ok(Some(Self { addr, size, align }))
diff --git a/libs/service-virtualization/src/com/android/system/virtualmachine/VirtualizationSystemService.java b/libs/service-virtualization/src/com/android/system/virtualmachine/VirtualizationSystemService.java
index afa286c..febf343 100644
--- a/libs/service-virtualization/src/com/android/system/virtualmachine/VirtualizationSystemService.java
+++ b/libs/service-virtualization/src/com/android/system/virtualmachine/VirtualizationSystemService.java
@@ -163,11 +163,8 @@
@Override
public void enableVmTethering() {
- LinkAddress local = new LinkAddress("192.168.0.1/24");
- LinkAddress client = new LinkAddress("192.168.0.2/24");
final TetheringRequest tr =
new TetheringRequest.Builder(TetheringManager.TETHERING_VIRTUAL)
- .setStaticIpv4Addresses(local, client)
.setConnectivityScope(TetheringManager.CONNECTIVITY_SCOPE_GLOBAL)
.build();
diff --git a/libs/vmconfig/src/lib.rs b/libs/vmconfig/src/lib.rs
index e520f0e..8357f99 100644
--- a/libs/vmconfig/src/lib.rs
+++ b/libs/vmconfig/src/lib.rs
@@ -15,6 +15,7 @@
//! Struct for VM configuration with JSON (de)serialization and AIDL parcelables
use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::AssignedDevices::AssignedDevices,
aidl::android::system::virtualizationservice::CpuTopology::CpuTopology,
aidl::android::system::virtualizationservice::DiskImage::DiskImage as AidlDiskImage,
aidl::android::system::virtualizationservice::Partition::Partition as AidlPartition,
@@ -124,13 +125,16 @@
memoryMib: memory_mib,
cpuTopology: cpu_topology,
platformVersion: self.platform_version.to_string(),
- devices: self
- .devices
- .iter()
- .map(|x| {
- x.to_str().map(String::from).ok_or(anyhow!("Failed to convert {x:?} to String"))
- })
- .collect::<Result<_>>()?,
+ devices: AssignedDevices::Devices(
+ self.devices
+ .iter()
+ .map(|x| {
+ x.to_str()
+ .map(String::from)
+ .ok_or(anyhow!("Failed to convert {x:?} to String"))
+ })
+ .collect::<Result<_>>()?,
+ ),
consoleInputDevice: self.console_input_device.clone(),
usbConfig: usb_config,
balloon: true,
diff --git a/tests/Terminal/Android.bp b/tests/Terminal/Android.bp
index 029fbea..a4e1f6b 100644
--- a/tests/Terminal/Android.bp
+++ b/tests/Terminal/Android.bp
@@ -4,7 +4,7 @@
android_test {
name: "TerminalAppTests",
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.kt"],
libs: [
"android.test.runner.stubs.system",
"android.test.base.stubs.system",
diff --git a/tests/Terminal/AndroidManifest.xml b/tests/Terminal/AndroidManifest.xml
index 0abcb5c..08bcb39 100644
--- a/tests/Terminal/AndroidManifest.xml
+++ b/tests/Terminal/AndroidManifest.xml
@@ -21,6 +21,6 @@
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.google.android.virtualization.terminal"
+ android:targetPackage="com.android.virtualization.terminal"
android:label="Test for Linux Terminal"/>
</manifest>
diff --git a/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.java b/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.java
deleted file mode 100644
index 4a18ee8..0000000
--- a/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virtualization.terminal;
-
-import static org.junit.Assert.assertTrue;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.microdroid.test.common.MetricsProcessor;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-@RunWith(AndroidJUnit4.class)
-public class TerminalAppTest {
- private Instrumentation mInstr;
- private Context mTargetContext;
- private final MetricsProcessor mMetricsProc = new MetricsProcessor("avf_perf/terminal/");
-
- @Before
- public void setup() {
- mInstr = InstrumentationRegistry.getInstrumentation();
- mTargetContext = mInstr.getTargetContext();
- installVmImage();
- }
-
- private void installVmImage() {
- final long INSTALL_TIMEOUT_MILLIS = 300_000; // 5 min
-
- Intent intent = new Intent(mTargetContext, InstallerActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- if (mInstr.startActivitySync(intent) instanceof InstallerActivity activity) {
- assertTrue(
- "Failed to install VM image",
- activity.waitForInstallCompleted(INSTALL_TIMEOUT_MILLIS));
- }
- }
-
- @Test
- public void boot() throws Exception {
- final long BOOT_TIMEOUT_MILLIS = 30_000; // 30 sec
-
- Intent intent = new Intent(mTargetContext, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- long start = System.currentTimeMillis();
- if (mInstr.startActivitySync(intent) instanceof MainActivity activity) {
- assertTrue("Failed to boot in 30s", activity.waitForBootCompleted(BOOT_TIMEOUT_MILLIS));
- }
- long delay = System.currentTimeMillis() - start;
-
- // TODO: measure multiple times?
- List<Long> measurements = new ArrayList<>();
- measurements.add(delay);
- Map<String, Double> stats = mMetricsProc.computeStats(measurements, "boot", "ms");
- Bundle bundle = new Bundle();
- for (Map.Entry<String, Double> entry : stats.entrySet()) {
- bundle.putDouble(entry.getKey(), entry.getValue());
- }
- mInstr.sendStatus(0, bundle);
- }
-
- @After
- public void tearDown() throws IOException {
- PortsStateManager.getInstance(mTargetContext).clearEnabledPorts();
- InstalledImage.getDefault(mTargetContext).uninstallFully();
- }
-}
diff --git a/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.kt b/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.kt
new file mode 100644
index 0000000..88bdfab
--- /dev/null
+++ b/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Instrumentation
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.SystemProperties
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.microdroid.test.common.DeviceProperties
+import com.android.microdroid.test.common.MetricsProcessor
+import java.io.IOException
+import java.lang.Exception
+import java.util.ArrayList
+import org.junit.After
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TerminalAppTest {
+ private lateinit var instr: Instrumentation
+ private lateinit var targetContext: Context
+ private lateinit var properties: DeviceProperties
+ private val metricsProc = MetricsProcessor("avf_perf/terminal/")
+
+ @Before
+ fun setup() {
+ instr = InstrumentationRegistry.getInstrumentation()
+ targetContext = instr.targetContext
+ properties =
+ DeviceProperties.create(DeviceProperties.PropertyGetter { SystemProperties.get(it) })
+ installVmImage()
+ }
+
+ private fun installVmImage() {
+ val INSTALL_TIMEOUT_MILLIS: Long = 300000 // 5 min
+
+ val intent = Intent(targetContext, InstallerActivity::class.java)
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ val activity = instr.startActivitySync(intent)
+ if (activity is InstallerActivity) {
+ Assert.assertTrue(
+ "Failed to install VM image",
+ activity.waitForInstallCompleted(INSTALL_TIMEOUT_MILLIS),
+ )
+ }
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun boot() {
+ val isNestedVirt = properties.isCuttlefish() || properties.isGoldfish()
+ val BOOT_TIMEOUT_MILLIS =
+ (if (isNestedVirt) 180000 else 30000).toLong() // 30 sec (or 3 min)
+
+ val intent = Intent(targetContext, MainActivity::class.java)
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ val start = System.currentTimeMillis()
+ val activity = instr.startActivitySync(intent)
+ if (activity is MainActivity) {
+ Assert.assertTrue(
+ "Failed to boot in 30s",
+ activity.waitForBootCompleted(BOOT_TIMEOUT_MILLIS),
+ )
+ }
+ val delay = System.currentTimeMillis() - start
+
+ // TODO: measure multiple times?
+ val measurements: MutableList<Long?> = ArrayList<Long?>()
+ measurements.add(delay)
+ val stats = metricsProc.computeStats(measurements, "boot", "ms")
+ val bundle = Bundle()
+ for (entry in stats.entries) {
+ bundle.putDouble(entry.key, entry.value)
+ }
+ instr.sendStatus(0, bundle)
+ }
+
+ @After
+ @Throws(IOException::class)
+ fun tearDown() {
+ PortsStateManager.getInstance(targetContext).clearEnabledPorts()
+ InstalledImage.getDefault(targetContext).uninstallFully()
+ }
+}
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index 6a3bc1b..6a413d6 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -80,8 +80,28 @@
String readLineFromConsole();
/**
+ * Read payload's rollback protected data. The `AVmAccessRollbackProtectedSecretStatus` is
+ * wrapped as service_specific error in case of failure. This is _only_ used for testing.
+ */
+ byte[32] insecurelyReadPayloadRpData();
+
+ /**
+ * Request VM to write payload's rollback protected data. The
+ * `AVmAccessRollbackProtectedSecretStatus` is wrapped as service_specific error in case of
+ * failure. This is _only_ used for testing.
+ */
+ void insecurelyWritePayloadRpData(in byte[32] data);
+
+ /**
* Request the service to exit, triggering the termination of the VM. This may cause any
* requests in flight to fail.
*/
oneway void quit();
+
+ /**
+ * Checks whether the VM instance is new - i.e., if this is the first run of an instance.
+ *
+ * @return true on the first boot of the instance & false on subsequent boot.
+ */
+ boolean isNewInstance();
}
diff --git a/tests/backcompat_test/Android.bp b/tests/backcompat_test/Android.bp
new file mode 100644
index 0000000..aa1e089
--- /dev/null
+++ b/tests/backcompat_test/Android.bp
@@ -0,0 +1,36 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_test {
+ name: "avf_backcompat_tests",
+ crate_name: "backcompat_test",
+ srcs: ["src/main.rs"],
+ prefer_rlib: true,
+ edition: "2021",
+ rustlibs: [
+ "android.system.virtualizationservice-rust",
+ "libandroid_logger",
+ "libanyhow",
+ "liblibc",
+ "libnix",
+ "libvmclient",
+ "liblog_rust",
+ ],
+ test_config: "AndroidTest.xml",
+ data: [
+ "goldens/dt_dump_*",
+ ":vmbase_example_kernel_bin",
+ ],
+ data_bins: [
+ "dtc_static",
+ "dtcompare",
+ ],
+ test_suites: ["general-tests"],
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+}
diff --git a/tests/backcompat_test/AndroidTest.xml b/tests/backcompat_test/AndroidTest.xml
new file mode 100644
index 0000000..dd8b43d
--- /dev/null
+++ b/tests/backcompat_test/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config to run backcompat_tests.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file" key="avf_backcompat_tests" value="/data/local/tmp/avf_backcompat_tests" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+ <option name="module-name" value="avf_backcompat_tests" />
+ <!-- Run tests serially because the VMs may overwrite the generated Device Tree. -->
+ <option name="native-test-flag" value="--test-threads=1" />
+ </test>
+</configuration>
diff --git a/tests/backcompat_test/goldens/dt_dump_golden.dts b/tests/backcompat_test/goldens/dt_dump_golden.dts
new file mode 100644
index 0000000..a583514
--- /dev/null
+++ b/tests/backcompat_test/goldens/dt_dump_golden.dts
@@ -0,0 +1,143 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <0x02>;
+ #size-cells = <0x02>;
+ compatible = "linux,dummy-virt";
+ interrupt-parent = <0x01>;
+ name = "reference";
+
+ U6_16550A@2e8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x02 0x01>;
+ reg = <0x00 0x2e8 0x00 0x08>;
+ };
+
+ U6_16550A@2f8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x02 0x01>;
+ reg = <0x00 0x2f8 0x00 0x08>;
+ };
+
+ U6_16550A@3e8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x00 0x01>;
+ reg = <0x00 0x3e8 0x00 0x08>;
+ };
+
+ U6_16550A@3f8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x00 0x01>;
+ reg = <0x00 0x3f8 0x00 0x08>;
+ };
+
+ __symbols__ {
+ intc = "/intc";
+ };
+
+ avf {
+ secretkeeper_public_key = [a4 01 01 03 27 20 06 21 58 20 de c2 79 41 b5 2a d8 1e eb dd 8a c5 a0 2f e4 56 12 42 5e b5 a4 c6 6a 8c 32 81 65 75 1c 6e b2 87];
+
+ untrusted {
+ defer-rollback-protection;
+ instance-id = <0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00>;
+ };
+ };
+
+ chosen {
+ bootargs = "panic=-1";
+ kaslr-seed = <0xab3b03c7 0xbb04cfd9>;
+ linux,pci-probe-only = <0x01>;
+ rng-seed = <0xa738baa8 0xf125e39b 0x5016f377 0xe2439805 0x94624c7e 0xac404bf6 0x68ece261 0xd45cca77 0x72328c0d 0xfdb9674f 0x74c1eb50 0x5665af83 0x1e8ccb52 0x120ed001 0xdc057599 0xbb3d33ea 0x6f9eb8e7 0x44f0517e 0x65d1cd16 0xeb4506a7 0x63fe5a00 0x8e330a52 0x2ab37c64 0x9aec3871 0x80f24353 0xfcdea704 0xd0e4fa1b 0x86412d49 0xed12a31d 0x1fbe26f3 0x97e442c5 0x25b31828 0xbe8626eb 0xea8098b8 0x6bf93ad9 0x3676d94a 0xcdbf695a 0x8b68008c 0xf598963b 0x483d0817 0xcea64b84 0xbbe0d7af 0xb09d31d7 0xfa461596 0xc47f9be8 0xd992c480 0x98372ef6 0xe1e70464 0xdc2752e4 0xe40a042c 0x5bb3a936 0x8af0aaff 0xd52f6723 0x8ac81a1b 0x15ed83d 0xee00b9eb 0x107f8ce 0xda99d512 0xed26543c 0x959f76f 0x1b85d5dc 0xa0b36c99 0xcdc8351 0xa4196327>;
+ stdout-path = "/U6_16550A@3f8";
+ };
+
+ config {
+ kernel-address = <0x80000000>;
+ kernel-size = <0x2c880>;
+ };
+
+ cpufreq {
+ compatible = "virtual,kvm-cpufreq";
+ };
+
+ cpus {
+ #address-cells = <0x01>;
+ #size-cells = <0x00>;
+
+ cpu@0 {
+ compatible = "arm,armv8";
+ device_type = "cpu";
+ phandle = <0x100>;
+ reg = <0x00>;
+ };
+ };
+
+ intc {
+ #address-cells = <0x02>;
+ #interrupt-cells = <0x03>;
+ #size-cells = <0x02>;
+ compatible = "arm,gic-v3";
+ interrupt-controller;
+ phandle = <0x01>;
+ reg = <0x00 0x3fff0000 0x00 0x10000 0x00 0x3ffd0000 0x00 0x20000>;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00 0x80000000 0x00 0x12c00000>;
+ };
+
+ pci {
+ #address-cells = <0x03>;
+ #interrupt-cells = <0x01>;
+ #size-cells = <0x02>;
+ bus-range = <0x00 0x00>;
+ compatible = "pci-host-cam-generic";
+ device_type = "pci";
+ dma-coherent;
+ interrupt-map = <0x800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x04 0x04 0x1000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x05 0x04 0x1800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x06 0x04 0x2000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x07 0x04 0x2800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x08 0x04 0x3000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x09 0x04 0x3800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0a 0x04 0x4000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0b 0x04>;
+ interrupt-map-mask = <0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07>;
+ ranges = <0x3000000 0x00 0x70000000 0x00 0x70000000 0x00 0x2000000 0x43000000 0x00 0x93400000 0x00 0x93400000 0xff 0x6cc00000>;
+ reg = <0x00 0x72000000 0x00 0x1000000>;
+ };
+
+ pclk@3M {
+ #clock-cells = <0x00>;
+ clock-frequency = <0x2fefd8>;
+ compatible = "fixed-clock";
+ phandle = <0x18>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0\0arm,psci-0.2";
+ method = "hvc";
+ };
+
+ rtc@2000 {
+ arm,primecell-periphid = <0x41030>;
+ clock-names = "apb_pclk";
+ clocks = <0x18>;
+ compatible = "arm,primecell";
+ interrupts = <0x00 0x01 0x04>;
+ reg = <0x00 0x2000 0x00 0x1000>;
+ };
+
+ timer {
+ always-on;
+ compatible = "arm,armv8-timer";
+ interrupts = <0x01 0x0d 0x108 0x01 0x0e 0x108 0x01 0x0b 0x108 0x01 0x0a 0x108>;
+ };
+
+ vmwdt@3000 {
+ clock-frequency = <0x02>;
+ compatible = "qemu,vcpu-stall-detector";
+ interrupts = <0x01 0x0f 0x101>;
+ reg = <0x00 0x3000 0x00 0x1000>;
+ timeout-sec = <0x0a>;
+ };
+};
diff --git a/tests/backcompat_test/goldens/dt_dump_protected_golden.dts b/tests/backcompat_test/goldens/dt_dump_protected_golden.dts
new file mode 100644
index 0000000..656958d
--- /dev/null
+++ b/tests/backcompat_test/goldens/dt_dump_protected_golden.dts
@@ -0,0 +1,157 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <0x02>;
+ #size-cells = <0x02>;
+ compatible = "linux,dummy-virt";
+ interrupt-parent = <0x01>;
+ name = "reference";
+
+ U6_16550A@2e8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x02 0x01>;
+ reg = <0x00 0x2e8 0x00 0x08>;
+ };
+
+ U6_16550A@2f8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x02 0x01>;
+ reg = <0x00 0x2f8 0x00 0x08>;
+ };
+
+ U6_16550A@3e8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x00 0x01>;
+ reg = <0x00 0x3e8 0x00 0x08>;
+ };
+
+ U6_16550A@3f8 {
+ clock-frequency = <0x1c2000>;
+ compatible = "ns16550a";
+ interrupts = <0x00 0x00 0x01>;
+ reg = <0x00 0x3f8 0x00 0x08>;
+ };
+
+ __symbols__ {
+ intc = "/intc";
+ };
+
+ avf {
+ secretkeeper_public_key = [a4 01 01 03 27 20 06 21 58 20 de c2 79 41 b5 2a d8 1e eb dd 8a c5 a0 2f e4 56 12 42 5e b5 a4 c6 6a 8c 32 81 65 75 1c 6e b2 87];
+
+ untrusted {
+ defer-rollback-protection;
+ instance-id = <0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00>;
+ };
+ };
+
+ chosen {
+ bootargs = "panic=-1";
+ kaslr-seed = <0xbbf0472d 0xbef495c>;
+ linux,pci-probe-only = <0x01>;
+ rng-seed = <0xb6e3fa0c 0xa0546147 0xeca61840 0x4f07da9d 0xacb41a21 0x8aa7ff1f 0xd32dd43 0x93fb4ad3 0xab5f9bf1 0x66d5913d 0x2b389a9f 0xc2c268d2 0xfd1d9a22 0xa8dba850 0xd443014d 0x10b3dfcb 0x77597882 0x66008b71 0x3d29575c 0xd917ee2f 0xb6e98504 0x6a5c9fde 0xa02daf16 0x3a60b1d5 0xa4416447 0x9e8a996d 0x3b4bf5e9 0xdf7639cb 0x4b608f7e 0x3434d9b4 0xb84cd15 0x86d724ae 0x404a1353 0x8afc6a43 0x916c4b8d 0xebe878c0 0xd67a99a4 0x94fb22ca 0xef53a3bf 0xaf5fc4b 0xd6d405d8 0xb6ed6cb5 0xc4d13a21 0x6aff3f79 0x93b56581 0x622e8da3 0x59047c4b 0x9a7562ee 0x93762d9a 0xeab995f7 0x33e1cdea 0x5d071401 0x2d57f0d1 0x73367772 0x532a74b6 0x3fb875fe 0x7340d4dd 0x492fa79f 0x7749f27 0xe8eefd10 0xeb00c401 0xd51bd6b3 0x904b5ac8 0x4316f75b>;
+ stdout-path = "/U6_16550A@3f8";
+ };
+
+ config {
+ kernel-address = <0x80000000>;
+ kernel-size = <0x2c880>;
+ };
+
+ cpufreq {
+ compatible = "virtual,kvm-cpufreq";
+ };
+
+ cpus {
+ #address-cells = <0x01>;
+ #size-cells = <0x00>;
+
+ cpu@0 {
+ compatible = "arm,armv8";
+ device_type = "cpu";
+ phandle = <0x100>;
+ reg = <0x00>;
+ };
+ };
+
+ intc {
+ #address-cells = <0x02>;
+ #interrupt-cells = <0x03>;
+ #size-cells = <0x02>;
+ compatible = "arm,gic-v3";
+ interrupt-controller;
+ phandle = <0x01>;
+ reg = <0x00 0x3fff0000 0x00 0x10000 0x00 0x3ffd0000 0x00 0x20000>;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00 0x80000000 0x00 0x13800000>;
+ };
+
+ pci {
+ #address-cells = <0x03>;
+ #interrupt-cells = <0x01>;
+ #size-cells = <0x02>;
+ bus-range = <0x00 0x00>;
+ compatible = "pci-host-cam-generic";
+ device_type = "pci";
+ dma-coherent;
+ interrupt-map = <0x800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x04 0x04 0x1000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x05 0x04 0x1800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x06 0x04 0x2000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x07 0x04 0x2800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x08 0x04 0x3000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x09 0x04 0x3800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0a 0x04>;
+ interrupt-map-mask = <0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07>;
+ memory-region = <0x02>;
+ ranges = <0x3000000 0x00 0x70000000 0x00 0x70000000 0x00 0x2000000 0x43000000 0x00 0x94000000 0x00 0x94000000 0xff 0x6c000000>;
+ reg = <0x00 0x72000000 0x00 0x1000000>;
+ };
+
+ pclk@3M {
+ #clock-cells = <0x00>;
+ clock-frequency = <0x2fefd8>;
+ compatible = "fixed-clock";
+ phandle = <0x18>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0\0arm,psci-0.2";
+ method = "hvc";
+ };
+
+ reserved-memory {
+ #address-cells = <0x02>;
+ #size-cells = <0x02>;
+ ranges;
+
+ restricted_dma_reserved {
+ alignment = <0x00 0x1000>;
+ compatible = "restricted-dma-pool";
+ phandle = <0x02>;
+ size = <0x00 0xc00000>;
+ };
+ };
+
+ rtc@2000 {
+ arm,primecell-periphid = <0x41030>;
+ clock-names = "apb_pclk";
+ clocks = <0x18>;
+ compatible = "arm,primecell";
+ interrupts = <0x00 0x01 0x04>;
+ reg = <0x00 0x2000 0x00 0x1000>;
+ };
+
+ timer {
+ always-on;
+ compatible = "arm,armv8-timer";
+ interrupts = <0x01 0x0d 0x108 0x01 0x0e 0x108 0x01 0x0b 0x108 0x01 0x0a 0x108>;
+ };
+
+ vmwdt@3000 {
+ clock-frequency = <0x02>;
+ compatible = "qemu,vcpu-stall-detector";
+ interrupts = <0x01 0x0f 0x101>;
+ reg = <0x00 0x3000 0x00 0x1000>;
+ timeout-sec = <0x0a>;
+ };
+};
diff --git a/tests/backcompat_test/src/main.rs b/tests/backcompat_test/src/main.rs
new file mode 100644
index 0000000..4113881
--- /dev/null
+++ b/tests/backcompat_test/src/main.rs
@@ -0,0 +1,204 @@
+// Copyright 2024, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Integration test for VMs on device.
+
+use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::{
+ CpuTopology::CpuTopology, DiskImage::DiskImage, VirtualMachineConfig::VirtualMachineConfig,
+ VirtualMachineRawConfig::VirtualMachineRawConfig,
+ },
+ binder::{ParcelFileDescriptor, ProcessState},
+};
+use anyhow::anyhow;
+use anyhow::Context;
+use anyhow::Error;
+use log::error;
+use log::info;
+use std::fs::read_to_string;
+use std::fs::File;
+use std::io::Write;
+use std::process::Command;
+use vmclient::VmInstance;
+
+const VMBASE_EXAMPLE_KERNEL_PATH: &str = "vmbase_example_kernel.bin";
+const TEST_DISK_IMAGE_PATH: &str = "test_disk.img";
+const EMPTY_DISK_IMAGE_PATH: &str = "empty_disk.img";
+const GOLDEN_DEVICE_TREE: &str = "./goldens/dt_dump_golden.dts";
+const GOLDEN_DEVICE_TREE_PROTECTED: &str = "./goldens/dt_dump_protected_golden.dts";
+
+/// Runs an unprotected VM and validates it against a golden device tree.
+#[test]
+fn test_device_tree_compat() -> Result<(), Error> {
+ run_test(false, GOLDEN_DEVICE_TREE)
+}
+
+/// Runs a protected VM and validates it against a golden device tree.
+#[test]
+fn test_device_tree_protected_compat() -> Result<(), Error> {
+ run_test(true, GOLDEN_DEVICE_TREE_PROTECTED)
+}
+
+fn run_test(protected: bool, golden_dt: &str) -> Result<(), Error> {
+ let kernel = Some(open_payload(VMBASE_EXAMPLE_KERNEL_PATH)?);
+ android_logger::init_once(
+ android_logger::Config::default()
+ .with_tag("backcompat")
+ .with_max_level(log::LevelFilter::Debug),
+ );
+
+ // We need to start the thread pool for Binder to work properly, especially link_to_death.
+ ProcessState::start_thread_pool();
+
+ let virtmgr =
+ vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
+ let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
+
+ // Make file for test disk image.
+ let mut test_image = File::options()
+ .create(true)
+ .read(true)
+ .write(true)
+ .truncate(true)
+ .open(TEST_DISK_IMAGE_PATH)
+ .with_context(|| format!("Failed to open test disk image {}", TEST_DISK_IMAGE_PATH))?;
+ // Write 4 sectors worth of 4-byte numbers counting up.
+ for i in 0u32..512 {
+ test_image.write_all(&i.to_le_bytes())?;
+ }
+ let test_image = ParcelFileDescriptor::new(test_image);
+ let disk_image = DiskImage { image: Some(test_image), writable: false, partitions: vec![] };
+
+ // Make file for empty test disk image.
+ let empty_image = File::options()
+ .create(true)
+ .read(true)
+ .write(true)
+ .truncate(true)
+ .open(EMPTY_DISK_IMAGE_PATH)
+ .with_context(|| format!("Failed to open empty disk image {}", EMPTY_DISK_IMAGE_PATH))?;
+ let empty_image = ParcelFileDescriptor::new(empty_image);
+ let empty_disk_image =
+ DiskImage { image: Some(empty_image), writable: false, partitions: vec![] };
+
+ let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
+ name: String::from("VmBaseTest"),
+ kernel,
+ disks: vec![disk_image, empty_disk_image],
+ protectedVm: protected,
+ memoryMib: 300,
+ cpuTopology: CpuTopology::ONE_CPU,
+ platformVersion: "~1.0".to_string(),
+ ..Default::default()
+ });
+
+ let dump_dt = File::options()
+ .create(true)
+ .read(true)
+ .write(true)
+ .truncate(true)
+ .open("dump_dt.dtb")
+ .with_context(|| "Failed to open device tree dump file dump_dt.dtb")?;
+ let vm = VmInstance::create(
+ service.as_ref(),
+ &config,
+ None,
+ /* consoleIn */ None,
+ None,
+ Some(dump_dt),
+ None,
+ )
+ .context("Failed to create VM")?;
+ vm.start().context("Failed to start VM")?;
+ info!("Started example VM.");
+
+ // Wait for VM to finish
+ let _ = vm.wait_for_death();
+
+ if !Command::new("./dtc_static")
+ .arg("-I")
+ .arg("dts")
+ .arg("-O")
+ .arg("dtb")
+ .arg("-qqq")
+ .arg("-f")
+ .arg("-s")
+ .arg("-o")
+ .arg("dump_dt_golden.dtb")
+ .arg(golden_dt)
+ .output()?
+ .status
+ .success()
+ {
+ return Err(anyhow!("failed to execute dtc"));
+ }
+ let dtcompare_res = Command::new("./dtcompare")
+ .arg("--dt1")
+ .arg("dump_dt_golden.dtb")
+ .arg("--dt2")
+ .arg("dump_dt.dtb")
+ .arg("--ignore-path-value")
+ .arg("/chosen/kaslr-seed")
+ .arg("--ignore-path-value")
+ .arg("/chosen/rng-seed")
+ .arg("--ignore-path-value")
+ .arg("/avf/untrusted/instance-id")
+ .arg("--ignore-path-value")
+ .arg("/chosen/linuxinitrd-start")
+ .arg("--ignore-path-value")
+ .arg("/chosen/linuxinitrd-end")
+ .arg("--ignore-path-value")
+ .arg("/avf/secretkeeper_public_key")
+ .arg("--ignore-path")
+ .arg("/avf/name")
+ .output()
+ .context("failed to execute dtcompare")?;
+ if !dtcompare_res.status.success() {
+ if !Command::new("./dtc_static")
+ .arg("-I")
+ .arg("dtb")
+ .arg("-O")
+ .arg("dts")
+ .arg("-qqq")
+ .arg("-f")
+ .arg("-s")
+ .arg("-o")
+ .arg("dump_dt_failed.dts")
+ .arg("dump_dt.dtb")
+ .output()?
+ .status
+ .success()
+ {
+ return Err(anyhow!("failed to execute dtc"));
+ }
+ let dt2 = read_to_string("dump_dt_failed.dts")?;
+ error!(
+ "Device tree 2 does not match golden DT.\n
+ Device Tree 2: {}",
+ dt2
+ );
+ return Err(anyhow!(
+ "stdout: {:?}\n stderr: {:?}",
+ dtcompare_res.stdout,
+ dtcompare_res.stderr
+ ));
+ }
+
+ Ok(())
+}
+
+fn open_payload(path: &str) -> Result<ParcelFileDescriptor, Error> {
+ let file = File::open(path).with_context(|| format!("Failed to open VM image {path}"))?;
+ Ok(ParcelFileDescriptor::new(file))
+}
diff --git a/tests/dtcompare/Android.bp b/tests/dtcompare/Android.bp
new file mode 100644
index 0000000..988f420
--- /dev/null
+++ b/tests/dtcompare/Android.bp
@@ -0,0 +1,18 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+ name: "dtcompare",
+ crate_root: "src/main.rs",
+ srcs: ["src/main.rs"],
+ edition: "2021",
+ rustlibs: [
+ "libanyhow",
+ "libclap",
+ "libhex_nostd",
+ "liblibfdt_nostd",
+ "liblog_rust",
+ ],
+ visibility: ["//packages/modules/Virtualization:__subpackages__"],
+}
diff --git a/tests/dtcompare/src/main.rs b/tests/dtcompare/src/main.rs
new file mode 100644
index 0000000..db3aac2
--- /dev/null
+++ b/tests/dtcompare/src/main.rs
@@ -0,0 +1,192 @@
+// Copyright 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Compare device tree contents.
+//! Allows skipping over fields provided.
+
+use anyhow::anyhow;
+use anyhow::Context;
+use anyhow::Result;
+use clap::Parser;
+use hex::encode;
+use libfdt::Fdt;
+use libfdt::FdtNode;
+
+use std::collections::BTreeMap;
+use std::collections::BTreeSet;
+use std::fs::read;
+use std::path::PathBuf;
+
+#[derive(Debug, Parser)]
+/// Device Tree Compare arguments.
+struct DtCompareArgs {
+ /// first device tree
+ #[arg(long)]
+ dt1: PathBuf,
+ /// second device tree
+ #[arg(long)]
+ dt2: PathBuf,
+ /// list of properties that should exist but are expected to hold different values in the
+ /// trees.
+ #[arg(short = 'I', long)]
+ ignore_path_value: Vec<String>,
+ /// list of paths that will be ignored, whether added, removed, or changed.
+ /// Paths can be nodes, subnodes, or even properties:
+ /// Ex: /avf/unstrusted // this is a path to a subnode. All properties and subnodes underneath
+ /// // it will also be ignored.
+ /// /avf/name // This is a path for a property. Only this property will be ignored.
+ #[arg(short = 'S', long)]
+ ignore_path: Vec<String>,
+}
+
+fn main() -> Result<()> {
+ let args = DtCompareArgs::parse();
+ let dt1: Vec<u8> = read(args.dt1)?;
+ let dt2: Vec<u8> = read(args.dt2)?;
+ let ignore_value_set = BTreeSet::from_iter(args.ignore_path_value);
+ let ignore_set = BTreeSet::from_iter(args.ignore_path);
+ compare_device_trees(dt1.as_slice(), dt2.as_slice(), ignore_value_set, ignore_set)
+}
+
+// Compare device trees by doing a pre-order traversal of the trees.
+fn compare_device_trees(
+ dt1: &[u8],
+ dt2: &[u8],
+ ignore_value_set: BTreeSet<String>,
+ ignore_set: BTreeSet<String>,
+) -> Result<()> {
+ let fdt1 = Fdt::from_slice(dt1).context("invalid device tree: Dt1")?;
+ let fdt2 = Fdt::from_slice(dt2).context("invalid device tree: Dt2")?;
+ let mut errors = Vec::new();
+ compare_subnodes(
+ &fdt1.root(),
+ &fdt2.root(),
+ &ignore_value_set,
+ &ignore_set,
+ /* path */ &mut ["".to_string()],
+ &mut errors,
+ )?;
+ if !errors.is_empty() {
+ return Err(anyhow!(
+ "Following properties had different values: [\n{}\n]\ndetected {} diffs",
+ errors.join("\n"),
+ errors.len()
+ ));
+ }
+ Ok(())
+}
+
+fn compare_props(
+ root1: &FdtNode,
+ root2: &FdtNode,
+ ignore_value_set: &BTreeSet<String>,
+ ignore_set: &BTreeSet<String>,
+ path: &mut [String],
+ errors: &mut Vec<String>,
+) -> Result<()> {
+ let mut prop_map: BTreeMap<String, &[u8]> = BTreeMap::new();
+ for prop in root1.properties().context("Error getting properties")? {
+ let prop_path =
+ path.join("/") + "/" + prop.name().context("Error getting property name")?.to_str()?;
+ // Do not add to prop map if skipping
+ if ignore_set.contains(&prop_path) {
+ continue;
+ }
+ let value = prop.value().context("Error getting value")?;
+ if prop_map.insert(prop_path.clone(), value).is_some() {
+ return Err(anyhow!("Duplicate property detected in subnode: {}", prop_path));
+ }
+ }
+ for prop in root2.properties().context("Error getting properties")? {
+ let prop_path =
+ path.join("/") + "/" + prop.name().context("Error getting property name")?.to_str()?;
+ if ignore_set.contains(&prop_path) {
+ continue;
+ }
+ let Some(prop1_value) = prop_map.remove(&prop_path) else {
+ errors.push(format!("added prop_path: {}", prop_path));
+ continue;
+ };
+ let prop_compare = prop1_value == prop.value().context("Error getting value")?;
+ // Check if value should be ignored. If yes, skip field.
+ if ignore_value_set.contains(&prop_path) {
+ continue;
+ }
+ if !prop_compare {
+ errors.push(format!(
+ "prop {} value mismatch: old: {} -> new: {}",
+ prop_path,
+ encode(prop1_value),
+ encode(prop.value().context("Error getting value")?)
+ ));
+ }
+ }
+ if !prop_map.is_empty() {
+ errors.push(format!("missing properties: {:?}", prop_map));
+ }
+ Ok(())
+}
+
+fn compare_subnodes(
+ node1: &FdtNode,
+ node2: &FdtNode,
+ ignore_value_set: &BTreeSet<String>,
+ ignore_set: &BTreeSet<String>,
+ path: &mut [String],
+ errors: &mut Vec<String>,
+) -> Result<()> {
+ let mut subnodes_map: BTreeMap<String, FdtNode> = BTreeMap::new();
+ for subnode in node1.subnodes().context("Error getting subnodes of first FDT")? {
+ let sn_path = path.join("/")
+ + "/"
+ + subnode.name().context("Error getting property name")?.to_str()?;
+ // Do not add to subnode map if skipping
+ if ignore_set.contains(&sn_path) {
+ continue;
+ }
+ if subnodes_map.insert(sn_path.clone(), subnode).is_some() {
+ return Err(anyhow!("Duplicate subnodes detected: {}", sn_path));
+ }
+ }
+ for sn2 in node2.subnodes().context("Error getting subnodes of second FDT")? {
+ let sn_path =
+ path.join("/") + "/" + sn2.name().context("Error getting subnode name")?.to_str()?;
+ let sn1 = subnodes_map.remove(&sn_path);
+ match sn1 {
+ Some(sn) => {
+ compare_props(
+ &sn,
+ &sn2,
+ ignore_value_set,
+ ignore_set,
+ &mut [sn_path.clone()],
+ errors,
+ )?;
+ compare_subnodes(
+ &sn,
+ &sn2,
+ ignore_value_set,
+ ignore_set,
+ &mut [sn_path.clone()],
+ errors,
+ )?;
+ }
+ None => errors.push(format!("added node: {}", sn_path)),
+ }
+ }
+ if !subnodes_map.is_empty() {
+ errors.push(format!("missing nodes: {:?}", subnodes_map));
+ }
+ Ok(())
+}
diff --git a/tests/early_vm_test/Android.bp b/tests/early_vm_test/Android.bp
new file mode 100644
index 0000000..dbb0c28
--- /dev/null
+++ b/tests/early_vm_test/Android.bp
@@ -0,0 +1,53 @@
+prebuilt_etc {
+ name: "avf_early_vm_test_kernel",
+ filename: "rialto.bin",
+ src: ":empty_file",
+ target: {
+ android_arm64: {
+ src: ":rialto_signed",
+ },
+ },
+ installable: false,
+ system_ext_specific: true,
+ visibility: ["//visibility:private"],
+}
+
+rust_binary {
+ name: "avf_early_vm_test_launcher",
+ crate_name: "avf_early_vm_test_launcher",
+ srcs: ["src/main.rs"],
+ rustlibs: [
+ "android.system.virtualizationservice-rust",
+ "libanyhow",
+ "libclap",
+ "libhypervisor_props",
+ "liblog_rust",
+ "libservice_vm_comm",
+ "libservice_vm_manager",
+ "libvmclient",
+ ],
+ cfgs: select(release_flag("RELEASE_AVF_ENABLE_EARLY_VM"), {
+ true: ["early_vm_enabled"],
+ default: [],
+ }),
+ prefer_rlib: true,
+ system_ext_specific: true,
+ compile_multilib: "first",
+ installable: false,
+}
+
+python_test_host {
+ name: "avf_early_vm_test",
+ main: "avf_early_vm_test.py",
+ srcs: ["avf_early_vm_test.py"],
+ device_first_data: [
+ ":avf_early_vm_test_kernel",
+ ":avf_early_vm_test_launcher",
+ ],
+ data: ["early_vms_rialto_test.xml"],
+ test_suites: ["general-tests"],
+ test_config: "AndroidTest.xml",
+ test_options: {
+ unit_test: false,
+ },
+}
diff --git a/tests/early_vm_test/AndroidTest.xml b/tests/early_vm_test/AndroidTest.xml
new file mode 100644
index 0000000..3eae96d
--- /dev/null
+++ b/tests/early_vm_test/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs avf_early_vm_test.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="true"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="abort-on-push-failure" value="true" />
+ <option name="remount-system" value="true" />
+ <option name="push-file" key="avf_early_vm_test_launcher" value="/system_ext/bin/avf_early_vm_test_launcher" />
+ <option name="push-file" key="rialto.bin" value="/system_ext/etc/avf/rialto_test.bin" />
+ <option name="push-file" key="early_vms_rialto_test.xml" value="/system_ext/etc/avf/early_vms_rialto_test.xml" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest">
+ <option name="par-file-name" value="avf_early_vm_test" />
+ <option name="test-timeout" value="5m" />
+ </test>
+</configuration>
diff --git a/tests/early_vm_test/TEST_MAPPING b/tests/early_vm_test/TEST_MAPPING
new file mode 100644
index 0000000..1f2335b
--- /dev/null
+++ b/tests/early_vm_test/TEST_MAPPING
@@ -0,0 +1,9 @@
+// When adding or removing tests here, don't forget to amend _all_modules list in
+// wireless/android/busytown/ath_config/configs/prod/avf/tests.gcl
+{
+ "avf-presubmit": [
+ {
+ "name": "avf_early_vm_test"
+ }
+ ]
+}
diff --git a/tests/early_vm_test/avf_early_vm_test.py b/tests/early_vm_test/avf_early_vm_test.py
new file mode 100644
index 0000000..0003351
--- /dev/null
+++ b/tests/early_vm_test/avf_early_vm_test.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+#
+# Copyright 2025 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import logging
+import os
+import subprocess
+import unittest
+
+_DEFAULT_COMMAND_TIMEOUT = 300
+_LAUNCHER_PATH = "/system_ext/bin/avf_early_vm_test_launcher"
+_RIALTO_PATH = "/system_ext/etc/avf/rialto_test.bin"
+
+def _RunCommand(cmd, timeout=_DEFAULT_COMMAND_TIMEOUT):
+ with subprocess.Popen(args=cmd,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ universal_newlines=True) as proc:
+ try:
+ out, err = proc.communicate(timeout=timeout)
+ returncode = proc.returncode
+ except subprocess.TimeoutExpired:
+ proc.kill()
+ out, err = proc.communicate()
+ returncode = proc.returncode
+
+ return out, err, returncode
+
+class AvfEarlyVmTest(unittest.TestCase):
+ def setUp(self):
+ self._serial_number = os.environ.get("ANDROID_SERIAL")
+ self.assertTrue(self._serial_number, "$ANDROID_SERIAL is empty.")
+
+ def _TestAvfEarlyVm(self, protected):
+ adb_cmd = ["adb", "-s", self._serial_number, "shell", _LAUNCHER_PATH, "--kernel",
+ _RIALTO_PATH]
+ if protected:
+ adb_cmd.append("--protected")
+
+ _, err, returncode = _RunCommand(adb_cmd)
+ self.assertEqual(returncode, 0, f"{adb_cmd} failed: {err}")
+
+ def testAvfEarlyVmNonProtected(self):
+ self._TestAvfEarlyVm(False)
+
+ def testAvfEarlyVmProtected(self):
+ self._TestAvfEarlyVm(True)
+
+if __name__ == "__main__":
+ # Setting verbosity is required to generate output that the TradeFed test
+ # runner can parse.
+ unittest.main(verbosity=3)
diff --git a/tests/early_vm_test/early_vms_rialto_test.xml b/tests/early_vm_test/early_vms_rialto_test.xml
new file mode 100644
index 0000000..799fc3f
--- /dev/null
+++ b/tests/early_vm_test/early_vms_rialto_test.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<early_vms>
+ <early_vm>
+ <name>avf_early_vm_test_launcher</name>
+ <cid>299</cid>
+ <path>/system_ext/bin/avf_early_vm_test_launcher</path>
+ </early_vm>
+</early_vms>
diff --git a/tests/early_vm_test/src/main.rs b/tests/early_vm_test/src/main.rs
new file mode 100644
index 0000000..a3c80ca
--- /dev/null
+++ b/tests/early_vm_test/src/main.rs
@@ -0,0 +1,116 @@
+// Copyright 2025 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Tests running an early VM
+
+use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::{
+ IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
+ VirtualMachineRawConfig::VirtualMachineRawConfig,
+ },
+ binder::{ParcelFileDescriptor, ProcessState, Strong},
+};
+use anyhow::{Context, Result};
+use clap::Parser;
+use log::info;
+use std::fs::File;
+use std::path::PathBuf;
+
+use service_vm_comm::{Request, Response, VmType};
+use service_vm_manager::ServiceVm;
+use vmclient::VmInstance;
+
+const VM_MEMORY_MB: i32 = 16;
+
+#[derive(Parser)]
+/// Collection of CLI for avf_early_vm_test_rialto
+pub struct Args {
+ /// Path to the Rialto kernel image.
+ #[arg(long)]
+ kernel: PathBuf,
+
+ /// Whether the VM is protected or not.
+ #[arg(long)]
+ protected: bool,
+}
+
+fn get_service() -> Result<Strong<dyn IVirtualizationService>> {
+ let virtmgr = vmclient::VirtualizationService::new_early()
+ .context("Failed to spawn VirtualizationService")?;
+ virtmgr.connect().context("Failed to connect to VirtualizationService")
+}
+
+fn main() -> Result<()> {
+ if std::env::consts::ARCH != "aarch64" {
+ info!("{} not supported. skipping test", std::env::consts::ARCH);
+ return Ok(());
+ }
+
+ if !cfg!(early_vm_enabled) {
+ info!("early VM disabled. skipping test");
+ return Ok(());
+ }
+
+ let args = Args::parse();
+
+ if args.protected {
+ if !hypervisor_props::is_protected_vm_supported()? {
+ info!("pVMs are not supported on device. skipping test");
+ return Ok(());
+ }
+ } else if !hypervisor_props::is_vm_supported()? {
+ info!("non-pVMs are not supported on device. skipping test");
+ return Ok(());
+ }
+
+ let service = get_service()?;
+ let kernel =
+ File::open(&args.kernel).with_context(|| format!("Failed to open {:?}", &args.kernel))?;
+ let kernel = ParcelFileDescriptor::new(kernel);
+
+ let vm_config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
+ name: "avf_early_vm_test_launcher".to_owned(),
+ kernel: Some(kernel),
+ protectedVm: args.protected,
+ memoryMib: VM_MEMORY_MB,
+ platformVersion: "~1.0".to_owned(),
+ ..Default::default()
+ });
+
+ let vm_instance = VmInstance::create(
+ service.as_ref(),
+ &vm_config,
+ // console_in, console_out, and log will be redirected to the kernel log by virtmgr
+ None, // console_in
+ None, // console_out
+ None, // log
+ None, // dump_dt
+ None, // callback
+ )
+ .context("Failed to create VM")?;
+
+ ProcessState::start_thread_pool();
+
+ let vm_type = if args.protected { VmType::ProtectedVm } else { VmType::NonProtectedVm };
+ let mut vm_service = ServiceVm::start_vm(vm_instance, vm_type)?;
+
+ let request_data = vec![1, 2, 3, 4, 5];
+ let reversed_data = vec![5, 4, 3, 2, 1];
+ let response = vm_service
+ .process_request(Request::Reverse(request_data))
+ .context("Failed to process request")?;
+ assert_eq!(Response::Reverse(reversed_data), response);
+
+ Ok(())
+}
diff --git a/tests/helper/Android.bp b/tests/helper/Android.bp
index 1c38d12..2402721 100644
--- a/tests/helper/Android.bp
+++ b/tests/helper/Android.bp
@@ -7,6 +7,7 @@
srcs: ["src/java/com/android/microdroid/test/common/*.java"],
host_supported: true,
sdk_version: "system_current",
+ apex_available: ["com.android.virt"],
}
java_library_static {
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index e6f15ff..c05fb0b 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -207,9 +207,6 @@
assume().withMessage("Skip where protected VMs aren't supported")
.that(capabilities & VirtualMachineManager.CAPABILITY_PROTECTED_VM)
.isNotEqualTo(0);
- assume().withMessage("Testing protected VMs on GSI isn't supported. b/272443823")
- .that(isGsi())
- .isFalse();
// TODO(b/376870129): remove this
assume().withMessage("pVMs with 16k kernel are not supported yet :(")
.that(mOs)
@@ -259,11 +256,11 @@
}
/**
- * @return The first vendor API level when the vendor images for an SoC that is qualified for
- * vendor freeze are first released with this property, or 0 if the property is not set.
+ * @return The vendor API level that the device as a whole must conform to, this value should be
+ * available on both GRF and non-GRF devices.
*/
protected static int getFirstVendorApiLevel() {
- return SystemProperties.getInt("ro.board.first_api_level", 0);
+ return SystemProperties.getInt("ro.vendor.api_level", -1);
}
protected void assumeSupportedDevice() {
@@ -281,9 +278,11 @@
}
protected void assumeNoUpdatableVmSupport() throws VirtualMachineException {
- assume().withMessage("Secretkeeper not supported")
- .that(getVirtualMachineManager().isUpdatableVmSupported())
- .isFalse();
+ assume().withMessage("Secretkeeper not supported").that(isUpdatableVmSupported()).isFalse();
+ }
+
+ protected boolean isUpdatableVmSupported() throws VirtualMachineException {
+ return getVirtualMachineManager().isUpdatableVmSupported();
}
protected void ensureVmAttestationSupported() throws Exception {
@@ -615,6 +614,8 @@
public String mConsoleInput;
public byte[] mInstanceSecret;
public int mPageSize;
+ public byte[] mPayloadRpData;
+ public boolean mIsNewInstance;
public void assertNoException() {
if (mException != null) {
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 48e369c..6d7c25e 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -2,14 +2,9 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-java_test_host {
- name: "MicrodroidHostTestCases",
+java_defaults {
+ name: "MicrodroidHostTestCases.default",
srcs: ["java/**/*.java"],
- test_suites: [
- "cts",
- "general-tests",
- "pts",
- ],
libs: [
"androidx.annotation_annotation",
"tradefed",
@@ -21,27 +16,6 @@
"microdroid_payload_metadata",
],
per_testcase_directory: true,
- device_common_data: [
- ":MicrodroidTestApp",
- ":MicrodroidTestAppUpdated",
- ":microdroid_general_sepolicy.conf",
- ":test.com.android.virt.pem",
- ":test2.com.android.virt.pem",
- "java/**/goldens/dt_dump_*",
- ],
- data_native_bins: [
- "sepolicy-analyze",
- // For re-sign test
- "avbtool",
- "img2simg",
- "initrd_bootconfig",
- "lpmake",
- "lpunpack",
- "lz4",
- "sign_virt_apex",
- "simg2img",
- "dtc",
- ],
// java_test_host doesn't have data_native_libs but jni_libs can be used to put
// native modules under ./lib directory.
// This works because host tools have rpath (../lib and ./lib).
@@ -58,3 +32,105 @@
"libz",
],
}
+
+DEVICE_DATA = [
+ ":MicrodroidTestApp",
+ ":MicrodroidTestAppUpdated",
+ ":microdroid_general_sepolicy.conf",
+ ":test.com.android.virt.pem",
+ ":test2.com.android.virt.pem",
+ "java/**/goldens/dt_dump_*",
+]
+
+BINS = [
+ "sepolicy-analyze",
+ // For re-sign test
+ "avbtool",
+ "img2simg",
+ "initrd_bootconfig",
+ "lpmake",
+ "lpunpack",
+ "lz4",
+ "sign_virt_apex",
+ "simg2img",
+ "dtc",
+]
+
+java_test_host {
+ name: "MicrodroidHostTestCases",
+ defaults: ["MicrodroidHostTestCases.default"],
+ test_config_template: "AndroidTestTemplate.xml",
+ auto_gen_config: true,
+ test_suites: [
+ "general-tests",
+ "pts",
+ ],
+ device_common_data: DEVICE_DATA,
+ data_native_bins: BINS,
+}
+
+java_test_host {
+ name: "MicrodroidHostTestCases.CTS",
+ defaults: ["MicrodroidHostTestCases.default"],
+ test_config_template: "AndroidTestTemplate.xml",
+ test_suites: ["cts"],
+ auto_gen_config: true,
+ test_options: {
+ tradefed_options: [
+ {
+ name: "include-annotation",
+ value: "com.android.compatibility.common.util.CddTest",
+ },
+ {
+ name: "test-suite-tag",
+ value: "cts",
+ },
+ ],
+ },
+ device_common_data: DEVICE_DATA,
+ data_native_bins: BINS,
+}
+
+java_test_host {
+ name: "MicrodroidHostTestCases.VTS",
+ defaults: ["MicrodroidHostTestCases.default"],
+ test_config_template: "AndroidTestTemplate.xml",
+ test_suites: ["vts"],
+ auto_gen_config: true,
+ test_options: {
+ tradefed_options: [
+ {
+ name: "include-annotation",
+ value: "com.android.compatibility.common.util.VsrTest",
+ },
+ {
+ name: "test-suite-tag",
+ value: "vts",
+ },
+ ],
+ },
+ device_common_data: DEVICE_DATA,
+ data_native_bins: BINS,
+}
+
+java_test_host {
+ name: "MicrodroidHostTestCases.GTS",
+ defaults: ["MicrodroidHostTestCases.default"],
+ test_config_template: "AndroidTestTemplate.xml",
+ test_suites: ["gts"],
+ auto_gen_config: true,
+ test_options: {
+ tradefed_options: [
+ {
+ name: "include-annotation",
+ value: "com.android.compatibility.common.util.GmsTest",
+ },
+ {
+ name: "test-suite-tag",
+ value: "gts",
+ },
+ ],
+ },
+ device_common_data: DEVICE_DATA,
+ data_native_bins: BINS,
+}
diff --git a/tests/hostside/AndroidTest.xml b/tests/hostside/AndroidTestTemplate.xml
similarity index 93%
rename from tests/hostside/AndroidTest.xml
rename to tests/hostside/AndroidTestTemplate.xml
index f77def3..ac066bc 100644
--- a/tests/hostside/AndroidTest.xml
+++ b/tests/hostside/AndroidTestTemplate.xml
@@ -14,7 +14,6 @@
limitations under the License.
-->
<configuration description="Host driven tests for Microdroid">
- <option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="security" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
@@ -26,10 +25,12 @@
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
- <option name="jar" value="MicrodroidHostTestCases.jar" />
+ <option name="jar" value="{MODULE}.jar" />
</test>
<!-- Controller that will skip the module if a native bridge situation is detected -->
<!-- For example: module wants to run arm and device is x86 -->
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
+
+ {EXTRA_CONFIGS}
</configuration>
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 01ac6a1..1873c2c 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -36,6 +36,7 @@
import android.cts.statsdatom.lib.ReportUtils;
import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.GmsTest;
import com.android.compatibility.common.util.PropertyUtil;
import com.android.compatibility.common.util.VsrTest;
import com.android.microdroid.test.common.ProcessUtil;
@@ -100,6 +101,9 @@
private static final String INSTANCE_IMG = TEST_ROOT + "instance.img";
private static final String INSTANCE_ID_FILE = TEST_ROOT + "instance_id";
+ private static final String DEBUG_LEVEL_FULL = "full";
+ private static final String DEBUG_LEVEL_NONE = "none";
+
private static final int MIN_MEM_ARM64 = 170;
private static final int MIN_MEM_X86_64 = 196;
@@ -415,7 +419,8 @@
@Test
@CddTest
- @VsrTest(requirements = {"VSR-7.1-001.008"})
+ @GmsTest(requirements = {"GMS-3-7.1-002", "GMS-VSR-7.1-001.006"})
+ @VsrTest(requirements = {"VSR-7.1-001.007"})
public void UpgradedPackageIsAcceptedWithSecretkeeper() throws Exception {
// Preconditions
assumeVmTypeSupported("microdroid", true); // Non-protected VMs may not support upgrades
@@ -433,7 +438,8 @@
@Test
@CddTest
- @VsrTest(requirements = {"VSR-7.1-001.008"})
+ @GmsTest(requirements = {"GMS-3-7.1-002", "GMS-VSR-7.1-001.006"})
+ @VsrTest(requirements = {"VSR-7.1-001.007"})
public void DowngradedPackageIsRejectedProtectedVm() throws Exception {
// Preconditions: Rollback protection is provided only for protected VM.
assumeVmTypeSupported("microdroid", true);
@@ -462,7 +468,7 @@
try {
microdroid =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(true)
@@ -482,7 +488,7 @@
@Test
@Parameters(method = "osVersions")
@TestCaseName("{method}_os_{0}")
- @CddTest(requirements = {"9.17/C-2-1", "9.17/C-2-2", "9.17/C-2-6"})
+ @GmsTest(requirements = {"GMS-3-7.1-010"})
public void protectedVmRunsPvmfw(String os) throws Exception {
// Arrange
assumeKernelSupported(os);
@@ -492,7 +498,7 @@
// Act
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(true)
@@ -515,7 +521,7 @@
@Test
@Parameters(method = "osVersions")
@TestCaseName("{method}_os_{0}")
- @CddTest(requirements = {"9.17/C-2-1", "9.17/C-2-2", "9.17/C-2-5", "9.17/C-2-6"})
+ @GmsTest(requirements = {"GMS-3-7.1-003", "GMS-3-7.1-010"})
public void protectedVmWithImageSignedWithDifferentKeyFailsToVerifyPayload(String os)
throws Exception {
assumeKernelSupported(os);
@@ -544,7 +550,7 @@
@Test
@Parameters(method = "osVersions")
@TestCaseName("{method}_os_{0}")
- @CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-6"})
+ @GmsTest(requirements = {"GMS-3-7.1-003", "GMS-3-7.1-010"})
public void testBootSucceedsWhenNonProtectedVmStartsWithImagesSignedWithDifferentKey(String os)
throws Exception {
// Preconditions
@@ -572,7 +578,7 @@
@Test
@Parameters(method = "osVersions")
@TestCaseName("{method}_os_{0}")
- @CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-5", "9.17/C-2-6"})
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void testBootFailsWhenVbMetaDigestDoesNotMatchBootconfig(String os) throws Exception {
// protectedVmWithImageSignedWithDifferentKeyRunsPvmfw() is the protected case.
assumeKernelSupported(os);
@@ -641,7 +647,7 @@
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -748,7 +754,7 @@
VIRT_APEX + "bin/vm",
"run-app",
"--debug",
- debuggable ? "full" : "none",
+ debuggable ? DEBUG_LEVEL_FULL : DEBUG_LEVEL_NONE,
apkPath,
idsigPath,
instanceImgPath));
@@ -868,7 +874,7 @@
final String configPath = "assets/vm_config_apex.json"; // path inside the APK
ITestDevice microdroid =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1010,7 +1016,8 @@
@Test
@Parameters(method = "params")
@TestCaseName("{method}_protectedVm_{0}_os_{1}")
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-1-2", "9.17/C/1-3"})
+ @CddTest
+ @GmsTest(requirements = {"GMS-3-7.1-001.002"})
public void testMicrodroidBoots(boolean protectedVm, String os) throws Exception {
// Preconditions
assumeKernelSupported(os);
@@ -1019,7 +1026,7 @@
final String configPath = "assets/vm_config.json"; // path inside the APK
testMicrodroidBootsWithBuilder(
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1057,7 +1064,7 @@
final String configPath = "assets/vm_config.json";
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1097,6 +1104,7 @@
}
@Test
+ @CddTest
public void testPathToBinaryIsRejected() throws Exception {
CommandRunner android = new CommandRunner(getDevice());
@@ -1145,6 +1153,7 @@
}
@Test
+ @CddTest
public void testRunEmptyPayload() throws Exception {
CommandRunner android = new CommandRunner(getDevice());
@@ -1169,7 +1178,7 @@
"shell",
VIRT_APEX + "bin/vm",
"run-app",
- "--debug full",
+ "--debug " + DEBUG_LEVEL_FULL,
"--console " + CONSOLE_PATH,
"--payload-binary-name",
"MicrodroidEmptyPayloadJniLib.so",
@@ -1198,7 +1207,6 @@
}
@Test
- @CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-6"})
public void testAllVbmetaUseSHA256() throws Exception {
File virtApexDir = FileUtil.createTempDir("virt_apex");
// Pull the virt apex's etc/ directory (which contains images)
@@ -1309,6 +1317,7 @@
@Test
@Parameters(method = "params")
@TestCaseName("{method}_protectedVm_{0}_os_{1}")
+ @CddTest
public void testDeviceAssignment(boolean protectedVm, String os) throws Exception {
// Preconditions
assumeKernelSupported(os);
@@ -1351,7 +1360,7 @@
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1364,6 +1373,8 @@
}
@Test
+ @CddTest
+ @GmsTest(requirements = {"GMS-3-7.1-001.002"})
public void testOsVersions() throws Exception {
for (String os : getSupportedOSList()) {
assertWithMessage("Unknown OS \"%s\"", os).that(SUPPORTED_OSES.values()).contains(os);
@@ -1395,7 +1406,7 @@
final String configPath = "assets/vm_config.json";
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1414,6 +1425,7 @@
@Test
@Parameters(method = "osVersions")
@TestCaseName("{method}_os_{0}")
+ @CddTest
public void microdroidDeviceTreeCompat(String os) throws Exception {
assumeArm64Supported();
final String configPath = "assets/vm_config.json";
@@ -1425,7 +1437,7 @@
// Start the VM with the dump DT option.
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(mem_size)
.cpuTopology("one_cpu")
.protectedVm(false)
@@ -1442,6 +1454,7 @@
@Test
@Parameters(method = "osVersions")
@TestCaseName("{method}_os_{0}")
+ @CddTest
public void microdroidProtectedDeviceTreeCompat(String os) throws Exception {
assumeArm64Supported();
final String configPath = "assets/vm_config.json";
@@ -1454,7 +1467,7 @@
// Start the VM with the dump DT option.
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(mem_size)
.cpuTopology("one_cpu")
.protectedVm(true)
diff --git a/tests/old_images_avf_test/Android.bp b/tests/old_images_avf_test/Android.bp
new file mode 100644
index 0000000..b3d5baf
--- /dev/null
+++ b/tests/old_images_avf_test/Android.bp
@@ -0,0 +1,57 @@
+prebuilt_etc {
+ name: "backcompat_rialto_kernel",
+ filename: "rialto.bin",
+ src: ":empty_file",
+ target: {
+ android_arm64: {
+ src: ":rialto_signed",
+ },
+ },
+ installable: false,
+ visibility: ["//visibility:private"],
+}
+
+prebuilt_etc {
+ name: "android16_rialto_kernel",
+ filename: "android16_rialto.bin",
+ src: ":empty_file",
+ target: {
+ android_arm64: {
+ src: "images/android16_rialto.bin",
+ },
+ },
+ installable: false,
+ visibility: ["//visibility:private"],
+}
+
+rust_test {
+ name: "old_images_avf_test",
+ crate_name: "old_images_avf_test",
+ srcs: ["src/main.rs"],
+ rustlibs: [
+ "libanyhow",
+ "libavf_bindgen",
+ "libciborium",
+ "liblog_rust",
+ "libhypervisor_props",
+ "libscopeguard",
+ "libservice_vm_comm",
+ "libvsock",
+ ],
+ shared_libs: ["libavf"],
+ test_suites: [
+ "general-tests",
+ ],
+ data: [
+ ":android16_rialto_kernel",
+ ":backcompat_rialto_kernel",
+ ],
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+ test_config: "AndroidTest.xml",
+ compile_multilib: "first",
+}
diff --git a/tests/old_images_avf_test/AndroidTest.xml b/tests/old_images_avf_test/AndroidTest.xml
new file mode 100644
index 0000000..089a424
--- /dev/null
+++ b/tests/old_images_avf_test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2025 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs old images on current AVF VM.">
+ <option name="test-suite-tag" value="general-tests" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="old_images_avf_test->/data/local/tmp/old_images_avf_test" />
+ <option name="push" value="rialto.bin->/data/local/tmp/rialto.bin" />
+ <option name="push" value="android16_rialto.bin->/data/local/tmp/android16_rialto.bin" />
+ </target_preparer>
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ArchModuleController">
+ <option name="arch" value="arm64" />
+ </object>
+ <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+ <option name="test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="old_images_avf_test" />
+ <!-- rialto uses a fixed port number for the host, can't run two tests at the same time -->
+ <option name="native-test-flag" value="--test-threads=1" />
+ </test>
+</configuration>
diff --git a/tests/old_images_avf_test/images/android16_rialto.bin b/tests/old_images_avf_test/images/android16_rialto.bin
new file mode 100644
index 0000000..ff4c38e
--- /dev/null
+++ b/tests/old_images_avf_test/images/android16_rialto.bin
Binary files differ
diff --git a/tests/old_images_avf_test/src/main.rs b/tests/old_images_avf_test/src/main.rs
new file mode 100644
index 0000000..018a80e
--- /dev/null
+++ b/tests/old_images_avf_test/src/main.rs
@@ -0,0 +1,229 @@
+// Copyright 2025 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Tests running a VM with older images
+
+use anyhow::{bail, ensure, Context, Result};
+use log::info;
+use std::ffi::CStr;
+use std::fs::File;
+use std::io::{self, BufWriter, Write};
+use std::os::fd::IntoRawFd;
+use std::time::{Duration, Instant};
+use vsock::{VsockListener, VsockStream, VMADDR_CID_HOST};
+
+use avf_bindgen::*;
+use service_vm_comm::{Request, Response, ServiceVmRequest, VmType};
+
+const VM_MEMORY_MB: i32 = 16;
+const WRITE_BUFFER_CAPACITY: usize = 512;
+
+const LISTEN_TIMEOUT: Duration = Duration::from_secs(10);
+const READ_TIMEOUT: Duration = Duration::from_secs(10);
+const WRITE_TIMEOUT: Duration = Duration::from_secs(10);
+const STOP_TIMEOUT: timespec = timespec { tv_sec: 10, tv_nsec: 0 };
+
+/// Processes the request in the service VM.
+fn process_request(vsock_stream: &mut VsockStream, request: Request) -> Result<Response> {
+ write_request(vsock_stream, &ServiceVmRequest::Process(request))?;
+ read_response(vsock_stream)
+}
+
+/// Sends the request to the service VM.
+fn write_request(vsock_stream: &mut VsockStream, request: &ServiceVmRequest) -> Result<()> {
+ let mut buffer = BufWriter::with_capacity(WRITE_BUFFER_CAPACITY, vsock_stream);
+ ciborium::into_writer(request, &mut buffer)?;
+ buffer.flush().context("Failed to flush the buffer")?;
+ Ok(())
+}
+
+/// Reads the response from the service VM.
+fn read_response(vsock_stream: &mut VsockStream) -> Result<Response> {
+ let response: Response = ciborium::from_reader(vsock_stream)
+ .context("Failed to read the response from the service VM")?;
+ Ok(response)
+}
+
+fn listen_from_guest(port: u32) -> Result<VsockStream> {
+ let vsock_listener =
+ VsockListener::bind_with_cid_port(VMADDR_CID_HOST, port).context("Failed to bind vsock")?;
+ vsock_listener.set_nonblocking(true).context("Failed to set nonblocking")?;
+ let start_time = Instant::now();
+ loop {
+ if start_time.elapsed() >= LISTEN_TIMEOUT {
+ bail!("Timeout while listening");
+ }
+ match vsock_listener.accept() {
+ Ok((vsock_stream, _peer_addr)) => return Ok(vsock_stream),
+ Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+ std::thread::sleep(Duration::from_millis(100));
+ }
+ Err(e) => bail!("Failed to listen: {e:?}"),
+ }
+ }
+}
+
+fn run_vm(image_path: &str, test_name: &CStr, protected_vm: bool) -> Result<()> {
+ let kernel_file = File::open(image_path).context("Failed to open kernel file")?;
+ let kernel_fd = kernel_file.into_raw_fd();
+
+ // SAFETY: AVirtualMachineRawConfig_create() isn't unsafe but rust_bindgen forces it to be seen
+ // as unsafe
+ let config = unsafe { AVirtualMachineRawConfig_create() };
+
+ info!("raw config created");
+
+ // SAFETY: config is the only reference to a valid object
+ unsafe {
+ AVirtualMachineRawConfig_setName(config, test_name.as_ptr());
+ AVirtualMachineRawConfig_setKernel(config, kernel_fd);
+ AVirtualMachineRawConfig_setProtectedVm(config, protected_vm);
+ AVirtualMachineRawConfig_setMemoryMiB(config, VM_MEMORY_MB);
+ }
+
+ let mut vm = std::ptr::null_mut();
+ let mut service = std::ptr::null_mut();
+
+ ensure!(
+ // SAFETY: &mut service is a valid pointer to *AVirtualizationService
+ unsafe { AVirtualizationService_create(&mut service, false) } == 0,
+ "AVirtualizationService_create failed"
+ );
+
+ scopeguard::defer! {
+ // SAFETY: service is a valid pointer to AVirtualizationService
+ unsafe { AVirtualizationService_destroy(service); }
+ }
+
+ ensure!(
+ // SAFETY: &mut vm is a valid pointer to *AVirtualMachine
+ unsafe {
+ AVirtualMachine_createRaw(
+ service, config, -1, // console_in
+ -1, // console_out
+ -1, // log
+ &mut vm,
+ )
+ } == 0,
+ "AVirtualMachine_createRaw failed"
+ );
+
+ scopeguard::defer! {
+ // SAFETY: vm is a valid pointer to AVirtualMachine
+ unsafe { AVirtualMachine_destroy(vm); }
+ }
+
+ info!("vm created");
+
+ let vm_type = if protected_vm { VmType::ProtectedVm } else { VmType::NonProtectedVm };
+
+ let listener_thread = std::thread::spawn(move || listen_from_guest(vm_type.port()));
+
+ // SAFETY: vm is the only reference to a valid object
+ unsafe {
+ AVirtualMachine_start(vm);
+ }
+
+ info!("VM started");
+
+ let mut vsock_stream = listener_thread.join().unwrap()?;
+ vsock_stream.set_read_timeout(Some(READ_TIMEOUT))?;
+ vsock_stream.set_write_timeout(Some(WRITE_TIMEOUT))?;
+
+ info!("client connected");
+
+ let request_data = vec![1, 2, 3, 4, 5];
+ let expected_data = vec![5, 4, 3, 2, 1];
+ let response = process_request(&mut vsock_stream, Request::Reverse(request_data))
+ .context("Failed to process request")?;
+ let Response::Reverse(reversed_data) = response else {
+ bail!("Expected Response::Reverse but was {response:?}");
+ };
+ ensure!(reversed_data == expected_data, "Expected {expected_data:?} but was {reversed_data:?}");
+
+ info!("request processed");
+
+ write_request(&mut vsock_stream, &ServiceVmRequest::Shutdown)
+ .context("Failed to send shutdown")?;
+
+ info!("shutdown sent");
+
+ let mut stop_reason = AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED;
+ ensure!(
+ // SAFETY: vm is the only reference to a valid object
+ unsafe { AVirtualMachine_waitForStop(vm, &STOP_TIMEOUT, &mut stop_reason) },
+ "AVirtualMachine_waitForStop failed"
+ );
+ assert_eq!(stop_reason, AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN);
+
+ info!("stopped");
+
+ Ok(())
+}
+
+#[test]
+fn test_run_rialto_protected() -> Result<()> {
+ if hypervisor_props::is_protected_vm_supported()? {
+ run_vm(
+ "/data/local/tmp/rialto.bin", /* image_path */
+ c"test_rialto", /* test_name */
+ true, /* protected_vm */
+ )
+ } else {
+ info!("pVMs are not supported on device. skipping test");
+ Ok(())
+ }
+}
+
+#[test]
+fn test_run_rialto_non_protected() -> Result<()> {
+ if hypervisor_props::is_vm_supported()? {
+ run_vm(
+ "/data/local/tmp/rialto.bin", /* image_path */
+ c"test_rialto", /* test_name */
+ false, /* protected_vm */
+ )
+ } else {
+ info!("VMs are not supported on device. skipping test");
+ Ok(())
+ }
+}
+
+#[test]
+fn test_run_android16_rialto_protected() -> Result<()> {
+ if hypervisor_props::is_protected_vm_supported()? {
+ run_vm(
+ "/data/local/tmp/android16_rialto.bin", /* image_path */
+ c"android16_test_rialto", /* test_name */
+ true, /* protected_vm */
+ )
+ } else {
+ info!("pVMs are not supported on device. skipping test");
+ Ok(())
+ }
+}
+
+#[test]
+fn test_run_android16_rialto_non_protected() -> Result<()> {
+ if hypervisor_props::is_vm_supported()? {
+ run_vm(
+ "/data/local/tmp/android16_rialto.bin", /* image_path */
+ c"android16_test_rialto", /* test_name */
+ false, /* protected_vm */
+ )
+ } else {
+ info!("VMs are not supported on device. skipping test");
+ Ok(())
+ }
+}
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index cb374a5..d0e045b 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -73,7 +73,8 @@
defaults: ["MicrodroidVersionsTestAppDefaults"],
manifest: "AndroidManifestV5.xml",
test_suites: ["general-tests"],
- test_config: "AndroidTest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ auto_gen_config: true,
data: DATA,
}
@@ -81,8 +82,21 @@
name: "MicrodroidTestApp.CTS",
defaults: ["MicrodroidVersionsTestAppDefaults"],
manifest: "AndroidManifestV5.xml",
+ test_config_template: "AndroidTestTemplate.xml",
test_suites: ["cts"],
- test_config: ":MicrodroidTestApp.CTS.config",
+ auto_gen_config: true,
+ test_options: {
+ tradefed_options: [
+ {
+ name: "include-annotation",
+ value: "com.android.compatibility.common.util.CddTest",
+ },
+ {
+ name: "test-suite-tag",
+ value: "cts",
+ },
+ ],
+ },
data: DATA,
}
@@ -90,31 +104,44 @@
name: "MicrodroidTestApp.VTS",
defaults: ["MicrodroidVersionsTestAppDefaults"],
manifest: "AndroidManifestV5.xml",
+ test_config_template: "AndroidTestTemplate.xml",
test_suites: ["vts"],
- test_config: ":MicrodroidTestApp.VTS.config",
+ auto_gen_config: true,
+ test_options: {
+ tradefed_options: [
+ {
+ name: "include-annotation",
+ value: "com.android.compatibility.common.util.VsrTest",
+ },
+ {
+ name: "test-suite-tag",
+ value: "vts",
+ },
+ ],
+ },
data: DATA,
}
-genrule {
- name: "MicrodroidTestApp.CTS.config",
- srcs: ["AndroidTest.xml"],
- out: ["out.xml"],
- cmd: "sed " +
- "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
- "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.CddTest\" \\/>/' " +
- "-e 's/MicrodroidTestApp.apk/MicrodroidTestApp.CTS.apk/' " +
- "$(in) > $(out)",
-}
-
-genrule {
- name: "MicrodroidTestApp.VTS.config",
- srcs: ["AndroidTest.xml"],
- out: ["out.xml"],
- cmd: "sed " +
- "-e 's/<!-- PLACEHOLDER_FOR_ANNOTATION -->/" +
- "<option name=\"include-annotation\" value=\"com.android.compatibility.common.util.VsrTest\" \\/>/' " +
- "-e 's/MicrodroidTestApp.apk/MicrodroidTestApp.VTS.apk/' " +
- "$(in) > $(out)",
+android_test {
+ name: "MicrodroidTestApp.GTS",
+ defaults: ["MicrodroidVersionsTestAppDefaults"],
+ manifest: "AndroidManifestV5.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ test_suites: ["gts"],
+ auto_gen_config: true,
+ test_options: {
+ tradefed_options: [
+ {
+ name: "include-annotation",
+ value: "com.android.compatibility.common.util.GmsTest",
+ },
+ {
+ name: "test-suite-tag",
+ value: "gts",
+ },
+ ],
+ },
+ data: DATA,
}
android_test_helper_app {
@@ -224,7 +251,6 @@
"libandroid_logger",
"libanyhow",
"libavflog",
- "libcstr",
"liblog_rust",
"libvm_payload_rs",
],
diff --git a/tests/testapk/AndroidTest.xml b/tests/testapk/AndroidTestTemplate.xml
similarity index 92%
rename from tests/testapk/AndroidTest.xml
rename to tests/testapk/AndroidTestTemplate.xml
index 221c25c..613ce28 100644
--- a/tests/testapk/AndroidTest.xml
+++ b/tests/testapk/AndroidTestTemplate.xml
@@ -14,14 +14,12 @@
limitations under the License.
-->
<configuration description="Runs Microdroid device-side tests.">
- <option name="test-suite-tag" value="cts" />
- <option name="test-suite-tag" value="vts" />
<option name="config-descriptor:metadata" key="component" value="security" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="test-file-name" value="MicrodroidTestApp.apk" />
+ <option name="test-file-name" value="{MODULE}.apk" />
<option name="test-file-name" value="MicrodroidVmShareApp.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
@@ -44,5 +42,5 @@
<!-- For example: module wants to run arm and device is x86 -->
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
- <!-- PLACEHOLDER_FOR_ANNOTATION -->
+ {EXTRA_CONFIGS}
</configuration>
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java
index 08bc310..df5525f 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidCapabilitiesTest.java
@@ -40,7 +40,7 @@
@RunWith(JUnit4.class)
public class MicrodroidCapabilitiesTest extends MicrodroidDeviceTestBase {
@Test
- @CddTest(requirements = "9.17/C-1-6")
+ @CddTest(requirements = "9.17/C-1-1")
public void supportForProtectedOrNonProtectedVms() {
assumeSupportedDevice();
@@ -61,7 +61,7 @@
}
@Test
- @VsrTest(requirements = "VSR-7.1-001.005")
+ @VsrTest(requirements = "VSR-7.1-001.004")
public void avfIsRequired() {
assumeVsrCompliant();
assume().withMessage("Requirement doesn't apply due to vendor API level")
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index e6ac490..8502ec3 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -66,6 +66,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.GmsTest;
import com.android.compatibility.common.util.VsrTest;
import com.android.microdroid.test.device.MicrodroidDeviceTestBase;
import com.android.microdroid.test.vmshare.IVmShareTestService;
@@ -216,13 +217,13 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
public void createAndConnectToVm() throws Exception {
createAndConnectToVmHelper(CPU_TOPOLOGY_ONE_CPU, /* shouldUseHugepages= */ false);
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
public void createAndConnectToVm_HostCpuTopology() throws Exception {
createAndConnectToVmHelper(CPU_TOPOLOGY_MATCH_HOST, /* shouldUseHugepages= */ false);
}
@@ -248,8 +249,9 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
@VsrTest(requirements = {"VSR-7.1-001.006"})
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.005"})
public void vmAttestationWhenRemoteAttestationIsNotSupported() throws Exception {
// pVM remote attestation is only supported on protected VMs.
assumeProtectedVM();
@@ -276,8 +278,9 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
@VsrTest(requirements = {"VSR-7.1-001.006"})
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.005"})
public void vmAttestationWithVendorPartitionWhenSupported() throws Exception {
// pVM remote attestation is only supported on protected VMs.
assumeProtectedVM();
@@ -294,8 +297,9 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
@VsrTest(requirements = {"VSR-7.1-001.006"})
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.005"})
public void vmAttestationWhenRemoteAttestationIsSupported() throws Exception {
// pVM remote attestation is only supported on protected VMs.
assumeProtectedVM();
@@ -340,7 +344,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
public void createAndRunNoDebugVm() throws Exception {
assumeSupportedDevice();
@@ -361,7 +365,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void autoCloseVm() throws Exception {
assumeSupportedDevice();
@@ -391,7 +395,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void autoCloseVmDescriptor() throws Exception {
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -420,7 +424,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmDescriptorClosedOnImport() throws Exception {
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -443,7 +447,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmLifecycleChecks() throws Exception {
assumeSupportedDevice();
@@ -491,7 +495,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void connectVsock() throws Exception {
assumeSupportedDevice();
@@ -529,7 +533,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void binderCallbacksWork() throws Exception {
assumeSupportedDevice();
@@ -581,7 +585,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmConfigGetAndSetTests() {
// Minimal has as little as specified as possible; everything that can be is defaulted.
VirtualMachineConfig.Builder minimalBuilder =
@@ -650,7 +654,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmConfigBuilderValidationTests() {
VirtualMachineConfig.Builder builder =
new VirtualMachineConfig.Builder(getContext()).setProtectedVm(mProtectedVm);
@@ -700,7 +704,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void compatibleConfigTests() {
VirtualMachineConfig baseline = newBaselineBuilder().build();
@@ -787,7 +791,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmUnitTests() throws Exception {
VirtualMachineConfig.Builder builder = newVmConfigBuilderWithPayloadBinary("binary.so");
VirtualMachineConfig config = builder.build();
@@ -808,7 +812,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void testAvfRequiresUpdatableApex() throws Exception {
assertWithMessage("Devices that support AVF must also support updatable APEX")
.that(SystemProperties.getBoolean("ro.apex.updatable", false))
@@ -816,7 +820,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmmGetAndCreate() throws Exception {
assumeSupportedDevice();
@@ -863,7 +867,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmFilesStoredInDeDirWhenCreatedFromDEContext() throws Exception {
final Context ctx = getContext().createDeviceProtectedStorageContext();
final int userId = ctx.getUserId();
@@ -881,7 +885,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void vmFilesStoredInCeDirWhenCreatedFromCEContext() throws Exception {
final Context ctx = getContext().createCredentialProtectedStorageContext();
final int userId = ctx.getUserId();
@@ -898,7 +902,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void differentManagersForDifferentContexts() throws Exception {
final Context ceCtx = getContext().createCredentialProtectedStorageContext();
final Context deCtx = getContext().createDeviceProtectedStorageContext();
@@ -907,12 +911,7 @@
}
@Test
- @CddTest(
- requirements = {
- "9.17/C-1-1",
- "9.17/C-1-2",
- "9.17/C-1-4",
- })
+ @CddTest
public void createVmWithConfigRequiresPermission() throws Exception {
assumeSupportedDevice();
revokePermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
@@ -934,10 +933,7 @@
}
@Test
- @CddTest(
- requirements = {
- "9.17/C-1-1",
- })
+ @CddTest
public void deleteVm() throws Exception {
assumeSupportedDevice();
@@ -961,10 +957,7 @@
}
@Test
- @CddTest(
- requirements = {
- "9.17/C-1-1",
- })
+ @CddTest
public void deleteVmFiles() throws Exception {
assumeSupportedDevice();
@@ -994,10 +987,7 @@
}
@Test
- @CddTest(
- requirements = {
- "9.17/C-1-1",
- })
+ @CddTest
public void validApkPathIsAccepted() throws Exception {
assumeSupportedDevice();
@@ -1022,7 +1012,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void invalidVmNameIsRejected() {
VirtualMachineManager vmm = getVirtualMachineManager();
assertThrows(IllegalArgumentException.class, () -> vmm.get("../foo"));
@@ -1030,7 +1020,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
public void extraApk() throws Exception {
assumeSupportedDevice();
@@ -1055,7 +1045,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
public void extraApkInVmConfig() throws Exception {
assumeSupportedDevice();
assumeFeatureEnabled(VirtualMachineManager.FEATURE_MULTI_TENANT);
@@ -1114,7 +1104,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+ @CddTest
public void changingNonDebuggableVmDebuggableInvalidatesVmIdentity() throws Exception {
// Debuggability changes initrd which is verified by pvmfw.
// Therefore, skip this on non-protected VM.
@@ -1168,7 +1158,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+ @CddTest
public void changingDebuggableVmNonDebuggableInvalidatesVmIdentity() throws Exception {
// Debuggability changes initrd which is verified by pvmfw.
// Therefore, skip this on non-protected VM.
@@ -1249,7 +1239,8 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7", "9.17/C-3-4"})
+ @CddTest
+ @GmsTest(requirements = {"GMS-3-7.1-011"})
public void instancesOfSameVmHaveDifferentCdis() throws Exception {
assumeSupportedDevice();
// TODO(b/325094712): VMs on CF with same payload have the same secret. This is because
@@ -1276,7 +1267,8 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7", "9.17/C-3-4"})
+ @CddTest
+ @GmsTest(requirements = {"GMS-3-7.1-011"})
public void sameInstanceKeepsSameCdis() throws Exception {
assumeSupportedDevice();
assume().withMessage("Skip on CF. Too Slow. b/257270529").that(isCuttlefish()).isFalse();
@@ -1297,7 +1289,9 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+ @CddTest
+ @VsrTest(requirements = {"VSR-7.1-001.005"})
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.004"})
public void bccIsSuperficiallyWellFormed() throws Exception {
assumeSupportedDevice();
@@ -1342,7 +1336,8 @@
}
@Test
- @VsrTest(requirements = {"VSR-7.1-001.004"})
+ @VsrTest(requirements = {"VSR-7.1-001.005"})
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.004"})
public void protectedVmHasValidDiceChain() throws Exception {
// This test validates two things regarding the pVM DICE chain:
// 1. The DICE chain is well-formed that all the entries conform to the DICE spec.
@@ -1376,7 +1371,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-1-2"})
+ @CddTest
public void accessToCdisIsRestricted() throws Exception {
assumeSupportedDevice();
@@ -1453,7 +1448,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenMicrodroidDataIsCompromised() throws Exception {
// If Updatable VM is supported => No instance.img required
assumeNoUpdatableVmSupport();
@@ -1461,7 +1456,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-7"})
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenPvmFwDataIsCompromised() throws Exception {
// If Updatable VM is supported => No instance.img required
assumeNoUpdatableVmSupport();
@@ -1474,6 +1469,7 @@
}
@Test
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenConfigIsInvalid() throws Exception {
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig config =
@@ -1488,6 +1484,7 @@
}
@Test
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenBinaryNameIsInvalid() throws Exception {
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadBinary("DoesNotExist.so")
@@ -1501,6 +1498,7 @@
}
@Test
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenApkPathIsInvalid() {
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -1514,6 +1512,7 @@
}
@Test
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenExtraApkPackageIsInvalid() {
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
@@ -1557,6 +1556,7 @@
}
@Test
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenBinaryIsMissingEntryFunction() throws Exception {
VirtualMachineConfig normalConfig =
newVmConfigBuilderWithPayloadBinary("MicrodroidEmptyNativeLib.so")
@@ -1569,6 +1569,7 @@
}
@Test
+ @GmsTest(requirements = {"GMS-3-7.1-006"})
public void bootFailsWhenBinaryTriesToLinkAgainstPrivateLibs() throws Exception {
VirtualMachineConfig normalConfig =
newVmConfigBuilderWithPayloadBinary("MicrodroidPrivateLinkingNativeLib.so")
@@ -1581,6 +1582,7 @@
}
@Test
+ @CddTest
public void sameInstancesShareTheSameVmObject() throws Exception {
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so").build();
@@ -1597,6 +1599,7 @@
}
@Test
+ @CddTest
public void importedVmAndOriginalVmHaveTheSameCdi() throws Exception {
assumeSupportedDevice();
// Arrange
@@ -1692,7 +1695,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void encryptedStorageAvailable() throws Exception {
assumeSupportedDevice();
@@ -1715,7 +1718,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void encryptedStorageIsInaccessibleToDifferentVm() throws Exception {
assumeSupportedDevice();
// TODO(b/325094712): VMs on CF with same payload have the same secret. This is because
@@ -1780,7 +1783,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ @CddTest
public void microdroidLauncherHasEmptyCapabilities() throws Exception {
assumeSupportedDevice();
@@ -1804,7 +1807,8 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
+ @GmsTest(requirements = {"GMS-3-7.1-005"})
public void payloadIsNotRoot() throws Exception {
assumeSupportedDevice();
assumeFeatureEnabled(VirtualMachineManager.FEATURE_MULTI_TENANT);
@@ -1827,7 +1831,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-1"})
+ @CddTest
public void encryptedStorageIsPersistent() throws Exception {
assumeSupportedDevice();
@@ -1862,6 +1866,122 @@
assertThat(testResults.mFileContent).isEqualTo(EXAMPLE_STRING);
}
+ private boolean deviceCapableOfProtectedVm() {
+ int capabilities = getVirtualMachineManager().getCapabilities();
+ if ((capabilities & CAPABILITY_PROTECTED_VM) != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private void ensureUpdatableVmSupported() throws Exception {
+ if (getVendorApiLevel() >= 202504 && deviceCapableOfProtectedVm()) {
+ assertTrue(
+ "Missing Updatable VM support, have you declared Secretkeeper interface?",
+ isUpdatableVmSupported());
+ } else {
+ assumeTrue("Device does not support Updatable VM", isUpdatableVmSupported());
+ }
+ }
+
+ @Test
+ public void rollbackProtectedDataOfPayload() throws Exception {
+ assumeSupportedDevice();
+ // Rollback protected data is only possible if Updatable VMs is supported -
+ // which implies Secretkeeper support.
+ ensureUpdatableVmSupported();
+ byte[] value1 = new byte[32];
+ Arrays.fill(value1, (byte) 0xcc);
+ byte[] value2 = new byte[32];
+ Arrays.fill(value2, (byte) 0xdd);
+
+ VirtualMachineConfig config =
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setMemoryBytes(minMemoryRequired())
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES)
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mPayloadRpData = ts.insecurelyReadPayloadRpData();
+ });
+ // ainsecurelyReadPayloadRpData()` must've failed since no data was ever written!
+ assertWithMessage("The read (unexpectedly) succeeded!")
+ .that(testResults.mException)
+ .isNotNull();
+
+ // Re-run the same VM & write/read th RP data & verify it what we just wrote!
+ testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ ts.insecurelyWritePayloadRpData(value1);
+ tr.mPayloadRpData = ts.insecurelyReadPayloadRpData();
+ ts.insecurelyWritePayloadRpData(value2);
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mPayloadRpData).isEqualTo(value1);
+
+ // Re-run the same VM again
+ testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mPayloadRpData = ts.insecurelyReadPayloadRpData();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mPayloadRpData).isEqualTo(value2);
+ }
+
+ @Test
+ @CddTest
+ public void isNewInstanceTest() throws Exception {
+ assumeSupportedDevice();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setMemoryBytes(minMemoryRequired())
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+ // TODO(b/325094712): Cuttlefish doesn't support device tree overlays which is required to
+ // find if the VM run is a new instance.
+ assumeFalse(
+ "Cuttlefish/Goldfish doesn't support device tree under /proc/device-tree",
+ isCuttlefish() || isGoldfish());
+ if (!isUpdatableVmSupported()) {
+ // TODO(b/389611249): Non protected VMs using legacy secret mechanisms do not reliably
+ // implement `AVmPayload_isNewInstance`.
+ assumeProtectedVM();
+ }
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_a", config);
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mIsNewInstance = ts.isNewInstance();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mIsNewInstance).isTrue();
+
+ // Re-run the same VM & ensure isNewInstance is false.
+ testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mIsNewInstance = ts.isNewInstance();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mIsNewInstance).isFalse();
+ }
+
@Test
@CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
public void canReadFileFromAssets_debugFull() throws Exception {
@@ -1887,6 +2007,7 @@
}
@Test
+ @CddTest
public void outputShouldBeExplicitlyCaptured() throws Exception {
assumeSupportedDevice();
@@ -1909,6 +2030,7 @@
}
@Test
+ @CddTest
public void inputShouldBeExplicitlyAllowed() throws Exception {
assumeSupportedDevice();
@@ -1960,6 +2082,7 @@
}
@Test
+ @CddTest
public void outputIsRedirectedToLogcatIfNotCaptured() throws Exception {
assumeSupportedDevice();
@@ -1980,6 +2103,7 @@
}
@Test
+ @CddTest
public void outputIsNotRedirectedToLogcatIfNotDebuggable() throws Exception {
assumeSupportedDevice();
@@ -1990,6 +2114,7 @@
}
@Test
+ @CddTest
public void testConsoleInputSupported() throws Exception {
assumeSupportedDevice();
assumeFalse("Not supported on GKI kernels", mOs.startsWith("microdroid_gki-"));
@@ -2019,6 +2144,7 @@
}
@Test
+ @CddTest
public void testStartVmWithPayloadOfAnotherApp() throws Exception {
assumeSupportedDevice();
@@ -2048,6 +2174,7 @@
}
@Test
+ @CddTest
public void testVmDescriptorParcelUnparcel_noTrustedStorage() throws Exception {
assumeSupportedDevice();
@@ -2081,6 +2208,7 @@
}
@Test
+ @CddTest
public void testVmDescriptorParcelUnparcel_withTrustedStorage() throws Exception {
assumeSupportedDevice();
@@ -2134,6 +2262,7 @@
}
@Test
+ @CddTest
public void testShareVmWithAnotherApp() throws Exception {
assumeSupportedDevice();
@@ -2179,6 +2308,7 @@
}
@Test
+ @CddTest
public void testShareVmWithAnotherApp_encryptedStorage() throws Exception {
assumeSupportedDevice();
@@ -2248,7 +2378,8 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-5"})
+ @CddTest
+ @GmsTest(requirements = {"GMS-3-7.1-005"})
public void testFileUnderBinHasExecutePermission() throws Exception {
assumeSupportedDevice();
@@ -2291,7 +2422,7 @@
private static final int MS_NOATIME = 1024;
@Test
- @CddTest(requirements = {"9.17/C-1-5"})
+ @GmsTest(requirements = {"GMS-3-7.1-004", "GMS-3-7.1-005"})
public void dataIsMountedWithNoExec() throws Exception {
assumeSupportedDevice();
@@ -2316,7 +2447,7 @@
}
@Test
- @CddTest(requirements = {"9.17/C-1-5"})
+ @GmsTest(requirements = {"GMS-3-7.1-004", "GMS-3-7.1-005"})
public void encryptedStoreIsMountedWithNoExec() throws Exception {
assumeSupportedDevice();
@@ -2342,7 +2473,6 @@
}
@Test
- @VsrTest(requirements = {"VSR-7.1-001.003"})
public void kernelVersionRequirement() throws Exception {
assumeVsrCompliant();
int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0);
@@ -2444,6 +2574,9 @@
}
@Test
+ @CddTest
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+ @VsrTest(requirements = {"VSR-7.1-001.008"})
public void configuringVendorDiskImageRequiresCustomPermission() throws Exception {
File vendorDiskImage =
new File("/data/local/tmp/cts/microdroid/test_microdroid_vendor_image.img");
@@ -2461,6 +2594,9 @@
}
@Test
+ @CddTest
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+ @VsrTest(requirements = {"VSR-7.1-001.008"})
public void bootsWithVendorPartition() throws Exception {
File vendorDiskImage = new File("/vendor/etc/avf/microdroid/microdroid_vendor.img");
assumeTrue("Microdroid vendor image doesn't exist, skip", vendorDiskImage.exists());
@@ -2480,6 +2616,9 @@
}
@Test
+ @CddTest
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+ @VsrTest(requirements = {"VSR-7.1-001.008"})
public void bootsWithCustomVendorPartitionForNonPvm() throws Exception {
assumeNonProtectedVM();
File vendorDiskImage =
@@ -2501,6 +2640,9 @@
}
@Test
+ @CddTest
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+ @VsrTest(requirements = {"VSR-7.1-001.008"})
public void bootFailsWithCustomVendorPartitionForPvm() throws Exception {
assumeProtectedVM();
File vendorDiskImage =
@@ -2513,6 +2655,9 @@
}
@Test
+ @CddTest
+ @GmsTest(requirements = {"GMS-VSR-7.1-001.007"})
+ @VsrTest(requirements = {"VSR-7.1-001.008"})
public void creationFailsWithUnsignedVendorPartition() throws Exception {
File vendorDiskImage =
new File(
@@ -2525,6 +2670,7 @@
}
@Test
+ @GmsTest(requirements = {"GMS-3-7.1-004", "GMS-3-7.1-005"})
public void systemPartitionMountFlags() throws Exception {
assumeSupportedDevice();
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 632f648..06c7e9d 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -99,6 +99,9 @@
char* line = nullptr;
size_t size = 0;
if (getline(&line, &size, input) < 0) {
+ if (errno == 0) {
+ return {}; // the input was closed
+ }
return ErrnoError() << "Failed to read";
}
@@ -136,12 +139,12 @@
}
std::thread accept_thread{[listening_fd = std::move(server_fd)] {
- auto result = run_echo_reverse_server(listening_fd);
- if (!result.ok()) {
- __android_log_write(ANDROID_LOG_ERROR, TAG, result.error().message().c_str());
- // Make sure the VM exits so the test will fail solidly
- exit(1);
+ Result<void> result;
+ while ((result = run_echo_reverse_server(listening_fd)).ok()) {
}
+ __android_log_write(ANDROID_LOG_ERROR, TAG, result.error().message().c_str());
+ // Make sure the VM exits so the test will fail solidly
+ exit(1);
}};
accept_thread.detach();
@@ -344,6 +347,28 @@
return ScopedAStatus::ok();
}
+ ScopedAStatus insecurelyReadPayloadRpData(std::array<uint8_t, 32>* out) override {
+ int32_t ret = AVmPayload_readRollbackProtectedSecret(out->data(), 32);
+ if (ret != 32) {
+ return ScopedAStatus::fromServiceSpecificError(ret);
+ }
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus insecurelyWritePayloadRpData(
+ const std::array<uint8_t, 32>& inputData) override {
+ int32_t ret = AVmPayload_writeRollbackProtectedSecret(inputData.data(), 32);
+ if (ret != 32) {
+ return ScopedAStatus::fromServiceSpecificError(ret);
+ }
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus isNewInstance(bool* is_new_instance_out) override {
+ *is_new_instance_out = AVmPayload_isNewInstance();
+ return ScopedAStatus::ok();
+ }
+
ScopedAStatus quit() override { exit(0); }
};
auto testService = ndk::SharedRefBase::make<TestService>();
diff --git a/tests/testapk/src/native/testbinary.rs b/tests/testapk/src/native/testbinary.rs
index e479342..c9d46b8 100644
--- a/tests/testapk/src/native/testbinary.rs
+++ b/tests/testapk/src/native/testbinary.rs
@@ -24,9 +24,7 @@
},
binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, Strong},
};
-use cstr::cstr;
use log::{error, info};
-use std::panic;
use std::process::exit;
use std::string::String;
use std::vec::Vec;
@@ -40,10 +38,6 @@
.with_tag("microdroid_testlib_rust")
.with_max_level(log::LevelFilter::Debug),
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- error!("{panic_info}");
- }));
if let Err(e) = try_main() {
error!("failed with {:?}", e);
exit(1);
@@ -132,10 +126,19 @@
fn readLineFromConsole(&self) -> BinderResult<String> {
unimplemented()
}
+ fn insecurelyReadPayloadRpData(&self) -> BinderResult<[u8; 32]> {
+ unimplemented()
+ }
+ fn insecurelyWritePayloadRpData(&self, _: &[u8; 32]) -> BinderResult<()> {
+ unimplemented()
+ }
+ fn isNewInstance(&self) -> BinderResult<bool> {
+ unimplemented()
+ }
}
fn unimplemented<T>() -> BinderResult<T> {
- let message = cstr!("Got a call to an unimplemented ITestService method in testbinary.rs");
+ let message = c"Got a call to an unimplemented ITestService method in testbinary.rs";
error!("{message:?}");
Err(Status::new_exception(ExceptionCode::UNSUPPORTED_OPERATION, Some(message)))
}
diff --git a/tests/vm_attestation/src/native/main.rs b/tests/vm_attestation/src/native/main.rs
index 52635ad..e8038b5 100644
--- a/tests/vm_attestation/src/native/main.rs
+++ b/tests/vm_attestation/src/native/main.rs
@@ -24,10 +24,7 @@
binder::{self, BinderFeatures, Interface, IntoBinderResult, Strong},
};
use log::{error, info};
-use std::{
- panic,
- sync::{Arc, Mutex},
-};
+use std::sync::{Arc, Mutex};
use vm_payload::{AttestationError, AttestationResult};
vm_payload::main!(main);
@@ -39,10 +36,6 @@
.with_tag("service_vm_client")
.with_max_level(log::LevelFilter::Debug),
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- error!("{}", panic_info);
- }));
if let Err(e) = try_main() {
error!("failed with {:?}", e);
std::process::exit(1);
diff --git a/tests/vmbase_example/src/main.rs b/tests/vmbase_example/src/main.rs
index 34a2b0b..cbe90d8 100644
--- a/tests/vmbase_example/src/main.rs
+++ b/tests/vmbase_example/src/main.rs
@@ -27,7 +27,7 @@
collections::{HashSet, VecDeque},
fs::File,
io::{self, BufRead, BufReader, Read, Write},
- panic, thread,
+ thread,
};
use vmclient::{DeathReason, VmInstance};
@@ -58,11 +58,6 @@
.with_max_level(log::LevelFilter::Debug),
);
- // Redirect panic messages to logcat.
- panic::set_hook(Box::new(|panic_info| {
- log::error!("{}", panic_info);
- }));
-
// We need to start the thread pool for Binder to work properly, especially link_to_death.
ProcessState::start_thread_pool();
diff --git a/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java b/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
index 13b0c51..1f71888 100644
--- a/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
+++ b/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
@@ -276,5 +276,20 @@
public void quit() throws RemoteException {
throw new UnsupportedOperationException("Not supported");
}
+
+ @Override
+ public byte[] insecurelyReadPayloadRpData() {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
+ public void insecurelyWritePayloadRpData(byte[] data) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
+ public boolean isNewInstance() {
+ throw new UnsupportedOperationException("Not supported");
+ }
}
}
diff --git a/tests/vts/Android.bp b/tests/vts/Android.bp
new file mode 100644
index 0000000..c570873
--- /dev/null
+++ b/tests/vts/Android.bp
@@ -0,0 +1,37 @@
+prebuilt_etc {
+ name: "vts_libavf_test_kernel",
+ filename: "rialto.bin",
+ src: ":empty_file",
+ target: {
+ android_arm64: {
+ src: ":rialto_signed",
+ },
+ },
+ installable: false,
+ visibility: ["//visibility:private"],
+}
+
+rust_test {
+ name: "vts_libavf_test",
+ crate_name: "vts_libavf_test",
+ srcs: ["src/vts_libavf_test.rs"],
+ rustlibs: [
+ "libanyhow",
+ "libavf_bindgen",
+ "libciborium",
+ "liblog_rust",
+ "libhypervisor_props",
+ "libscopeguard",
+ "libservice_vm_comm",
+ "libvsock",
+ ],
+ shared_libs: ["libavf"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ data: [":vts_libavf_test_kernel"],
+ test_config: "AndroidTest.xml",
+ compile_multilib: "first",
+ vendor: true,
+}
diff --git a/tests/vts/AndroidTest.xml b/tests/vts/AndroidTest.xml
new file mode 100644
index 0000000..6926f9f
--- /dev/null
+++ b/tests/vts/AndroidTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs vts_libavf_test.">
+ <option name="test-suite-tag" value="vts" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="vts_libavf_test->/data/nativetest64/vendor/vts_libavf_test" />
+ <option name="push" value="rialto.bin->/data/local/tmp/rialto.bin" />
+ </target_preparer>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ArchModuleController">
+ <option name="arch" value="arm64" />
+ </object>
+
+ <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+ <option name="test-device-path" value="/data/nativetest64/vendor" />
+ <option name="module-name" value="vts_libavf_test" />
+ <!-- rialto uses a fixed port number for the host, can't run two tests at the same time -->
+ <option name="native-test-flag" value="--test-threads=1" />
+ </test>
+</configuration>
diff --git a/tests/vts/src/vts_libavf_test.rs b/tests/vts/src/vts_libavf_test.rs
new file mode 100644
index 0000000..e30c175
--- /dev/null
+++ b/tests/vts/src/vts_libavf_test.rs
@@ -0,0 +1,196 @@
+// Copyright 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Tests running a VM with LLNDK
+
+use anyhow::{bail, ensure, Context, Result};
+use log::info;
+use std::ffi::CStr;
+use std::fs::File;
+use std::io::{self, BufWriter, Write};
+use std::os::fd::IntoRawFd;
+use std::time::{Duration, Instant};
+use vsock::{VsockListener, VsockStream, VMADDR_CID_HOST};
+
+use avf_bindgen::*;
+use service_vm_comm::{Request, Response, ServiceVmRequest, VmType};
+
+const VM_MEMORY_MB: i32 = 16;
+const WRITE_BUFFER_CAPACITY: usize = 512;
+
+const LISTEN_TIMEOUT: Duration = Duration::from_secs(10);
+const READ_TIMEOUT: Duration = Duration::from_secs(10);
+const WRITE_TIMEOUT: Duration = Duration::from_secs(10);
+const STOP_TIMEOUT: timespec = timespec { tv_sec: 10, tv_nsec: 0 };
+
+/// Processes the request in the service VM.
+fn process_request(vsock_stream: &mut VsockStream, request: Request) -> Result<Response> {
+ write_request(vsock_stream, &ServiceVmRequest::Process(request))?;
+ read_response(vsock_stream)
+}
+
+/// Sends the request to the service VM.
+fn write_request(vsock_stream: &mut VsockStream, request: &ServiceVmRequest) -> Result<()> {
+ let mut buffer = BufWriter::with_capacity(WRITE_BUFFER_CAPACITY, vsock_stream);
+ ciborium::into_writer(request, &mut buffer)?;
+ buffer.flush().context("Failed to flush the buffer")?;
+ Ok(())
+}
+
+/// Reads the response from the service VM.
+fn read_response(vsock_stream: &mut VsockStream) -> Result<Response> {
+ let response: Response = ciborium::from_reader(vsock_stream)
+ .context("Failed to read the response from the service VM")?;
+ Ok(response)
+}
+
+fn listen_from_guest(port: u32) -> Result<VsockStream> {
+ let vsock_listener =
+ VsockListener::bind_with_cid_port(VMADDR_CID_HOST, port).context("Failed to bind vsock")?;
+ vsock_listener.set_nonblocking(true).context("Failed to set nonblocking")?;
+ let start_time = Instant::now();
+ loop {
+ if start_time.elapsed() >= LISTEN_TIMEOUT {
+ bail!("Timeout while listening");
+ }
+ match vsock_listener.accept() {
+ Ok((vsock_stream, _peer_addr)) => return Ok(vsock_stream),
+ Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+ std::thread::sleep(Duration::from_millis(100));
+ }
+ Err(e) => bail!("Failed to listen: {e:?}"),
+ }
+ }
+}
+
+fn run_rialto(protected_vm: bool) -> Result<()> {
+ let kernel_file =
+ File::open("/data/local/tmp/rialto.bin").context("Failed to open kernel file")?;
+ let kernel_fd = kernel_file.into_raw_fd();
+
+ // SAFETY: AVirtualMachineRawConfig_create() isn't unsafe but rust_bindgen forces it to be seen
+ // as unsafe
+ let config = unsafe { AVirtualMachineRawConfig_create() };
+
+ info!("raw config created");
+
+ // SAFETY: config is the only reference to a valid object
+ unsafe {
+ AVirtualMachineRawConfig_setName(
+ config,
+ CStr::from_bytes_with_nul(b"vts_libavf_test_rialto\0").unwrap().as_ptr(),
+ );
+ AVirtualMachineRawConfig_setKernel(config, kernel_fd);
+ AVirtualMachineRawConfig_setProtectedVm(config, protected_vm);
+ AVirtualMachineRawConfig_setMemoryMiB(config, VM_MEMORY_MB);
+ }
+
+ let mut vm = std::ptr::null_mut();
+ let mut service = std::ptr::null_mut();
+
+ ensure!(
+ // SAFETY: &mut service is a valid pointer to *AVirtualizationService
+ unsafe { AVirtualizationService_create(&mut service, false) } == 0,
+ "AVirtualizationService_create failed"
+ );
+
+ scopeguard::defer! {
+ // SAFETY: service is a valid pointer to AVirtualizationService
+ unsafe { AVirtualizationService_destroy(service); }
+ }
+
+ ensure!(
+ // SAFETY: &mut vm is a valid pointer to *AVirtualMachine
+ unsafe {
+ AVirtualMachine_createRaw(
+ service, config, -1, // console_in
+ -1, // console_out
+ -1, // log
+ &mut vm,
+ )
+ } == 0,
+ "AVirtualMachine_createRaw failed"
+ );
+
+ scopeguard::defer! {
+ // SAFETY: vm is a valid pointer to AVirtualMachine
+ unsafe { AVirtualMachine_destroy(vm); }
+ }
+
+ info!("vm created");
+
+ let vm_type = if protected_vm { VmType::ProtectedVm } else { VmType::NonProtectedVm };
+
+ let listener_thread = std::thread::spawn(move || listen_from_guest(vm_type.port()));
+
+ // SAFETY: vm is the only reference to a valid object
+ unsafe {
+ AVirtualMachine_start(vm);
+ }
+
+ info!("VM started");
+
+ let mut vsock_stream = listener_thread.join().unwrap()?;
+ vsock_stream.set_read_timeout(Some(READ_TIMEOUT))?;
+ vsock_stream.set_write_timeout(Some(WRITE_TIMEOUT))?;
+
+ info!("client connected");
+
+ let request_data = vec![1, 2, 3, 4, 5];
+ let expected_data = vec![5, 4, 3, 2, 1];
+ let response = process_request(&mut vsock_stream, Request::Reverse(request_data))
+ .context("Failed to process request")?;
+ let Response::Reverse(reversed_data) = response else {
+ bail!("Expected Response::Reverse but was {response:?}");
+ };
+ ensure!(reversed_data == expected_data, "Expected {expected_data:?} but was {reversed_data:?}");
+
+ info!("request processed");
+
+ write_request(&mut vsock_stream, &ServiceVmRequest::Shutdown)
+ .context("Failed to send shutdown")?;
+
+ info!("shutdown sent");
+
+ let mut stop_reason = AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED;
+ ensure!(
+ // SAFETY: vm is the only reference to a valid object
+ unsafe { AVirtualMachine_waitForStop(vm, &STOP_TIMEOUT, &mut stop_reason) },
+ "AVirtualMachine_waitForStop failed"
+ );
+
+ info!("stopped");
+
+ Ok(())
+}
+
+#[test]
+fn test_run_rialto_protected() -> Result<()> {
+ if hypervisor_props::is_protected_vm_supported()? {
+ run_rialto(true /* protected_vm */)
+ } else {
+ info!("pVMs are not supported on device. skipping test");
+ Ok(())
+ }
+}
+
+#[test]
+fn test_run_rialto_non_protected() -> Result<()> {
+ if hypervisor_props::is_vm_supported()? {
+ run_rialto(false /* protected_vm */)
+ } else {
+ info!("non-pVMs are not supported on device. skipping test");
+ Ok(())
+ }
+}