VmTerminalApp: Implement error activity
Screenshot is attached to the bug
Bug: 376796062
Test: Manually. Also checked that back key on error activity doesn't \
go back to the main activity.
Change-Id: I82713b130a9d25b673b9c9b984077a0d55e4cd92
diff --git a/android/TerminalApp/AndroidManifest.xml b/android/TerminalApp/AndroidManifest.xml
index 1af6c8a..b74b8b0 100644
--- a/android/TerminalApp/AndroidManifest.xml
+++ b/android/TerminalApp/AndroidManifest.xml
@@ -46,14 +46,11 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
- <activity android:name=".SettingsActivity">
- </activity>
- <activity android:name=".SettingsDiskResizeActivity">
- </activity>
- <activity android:name=".SettingsPortForwardingActivity">
- </activity>
- <activity android:name=".SettingsRecoveryActivity">
- </activity>
+ <activity android:name=".SettingsActivity" />
+ <activity android:name=".SettingsDiskResizeActivity" />
+ <activity android:name=".SettingsPortForwardingActivity" />
+ <activity android:name=".SettingsRecoveryActivity" />
+ <activity android:name=".ErrorActivity" />
<property
android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
android:value="true" />
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.java
new file mode 100644
index 0000000..ee1f1ad
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.java
@@ -0,0 +1,64 @@
+/*
+ * 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.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 {
+ public static final String EXTRA_CAUSE = "cause";
+
+ @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/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index 10451ec..0c35823 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -28,6 +28,7 @@
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;
@@ -35,6 +36,7 @@
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -46,7 +48,6 @@
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
-import android.widget.Toast;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultLauncher;
@@ -142,6 +143,17 @@
}
}
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (Build.isDebuggable() && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ launchErrorActivity(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);
@@ -379,16 +391,13 @@
@Override
public void onVmStop() {
- Toast.makeText(this, R.string.vm_stop_message, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onVmStop()");
- finish();
}
@Override
public void onVmError() {
- Toast.makeText(this, R.string.vm_error_message, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onVmError()");
- finish();
+ launchErrorActivity(new Exception("onVmError"));
}
@Override
@@ -435,6 +444,13 @@
}
}
+ private void launchErrorActivity(Exception e) {
+ Intent intent = new Intent(this, ErrorActivity.class);
+ intent.putExtra(ErrorActivity.EXTRA_CAUSE, e);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ this.startActivity(intent);
+ }
+
private boolean installIfNecessary() {
// If payload from external storage exists(only for debuggable build) or there is no
// installed image, launch installer activity.
diff --git a/android/TerminalApp/res/layout/activity_error.xml b/android/TerminalApp/res/layout/activity_error.xml
new file mode 100644
index 0000000..1b5026e
--- /dev/null
+++ b/android/TerminalApp/res/layout/activity_error.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+ -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
+ tools:context=".ErrorActivity">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/error_title"
+ android:layout_marginVertical="24dp"
+ android:layout_marginHorizontal="24dp"
+ android:layout_alignParentTop="true"
+ android:hyphenationFrequency="normal"
+ android:textSize="48sp" />
+
+ <TextView
+ android:id="@+id/desc"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/error_desc"
+ android:lineSpacingExtra="5sp"
+ android:layout_marginTop="20dp"
+ android:layout_marginHorizontal="48dp"
+ android:layout_below="@id/title"
+ android:textSize="20sp" />
+
+ <TextView
+ android:id="@+id/cause"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lineSpacingExtra="5sp"
+ android:layout_marginTop="24dp"
+ android:layout_marginHorizontal="60dp"
+ android:layout_below="@id/desc"
+ android:textSize="14sp" />
+
+ <Button
+ android:id="@+id/recovery"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_marginBottom="32dp"
+ android:layout_marginHorizontal="40dp"
+ android:backgroundTint="?attr/colorPrimaryDark"
+ android:text="@string/settings_recovery_title" />
+
+</RelativeLayout>
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index c89fcfa..0ae3b5c 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -96,6 +96,13 @@
<!-- Dialog button cancel for resetting the terminal [CHAR LIMIT=16] -->
<string name="settings_recovery_reset_dialog_cancel">Cancel</string>
+ <!-- Error page that shows error page [CHAR LIMIT=none] -->
+ <string name="error_title">Unrecoverable Error</string>
+ <!-- Error page that shows error page [CHAR LIMIT=none] -->
+ <string name="error_desc">Failed to recover from an error.\nYou can try restart the app, or try one of recovery option.</string>
+ <!-- Error page that shows detailed error code (error reason) for bugreport. [CHAR LIMIT=none] -->
+ <string name="error_code">Error code: <xliff:g id="error_code" example="ACCESS_DENIED">%s</xliff:g></string>
+
<!-- Notification action button for settings [CHAR LIMIT=20] -->
<string name="service_notification_settings">Settings</string>
<!-- Notification title for foreground service notification [CHAR LIMIT=none] -->