Create dialog for adding a new inactive port
Bug: 382998392
Test: Run VmTerminalApp
Change-Id: I597b92cd732ec92564418786d2d0f61710c652e5
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
index 83a8d05..27d6ce7 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
@@ -15,10 +15,20 @@
*/
package com.android.virtualization.terminal
+import android.content.DialogInterface
import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.widget.EditText
+import android.widget.ImageButton
+import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+
+private const val PORT_RANGE_MIN: Int = 1024
+private const val PORT_RANGE_MAX: Int = 65535
class SettingsPortForwardingActivity : AppCompatActivity() {
private lateinit var mPortsStateManager: PortsStateManager
@@ -45,6 +55,88 @@
inactiveRecyclerView.adapter = mInactivePortsAdapter
mPortsStateListener = Listener()
+
+ val addButton = findViewById<ImageButton>(R.id.settings_port_forwarding_inactive_add_button)
+ addButton.setOnClickListener {
+ val dialog =
+ MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.settings_port_forwarding_dialog_title)
+ .setView(R.layout.settings_port_forwarding_inactive_add_dialog)
+ .setPositiveButton(R.string.settings_port_forwarding_dialog_save) {
+ dialogInterface,
+ _ ->
+ val alertDialog = dialogInterface as AlertDialog
+ val editText =
+ alertDialog.findViewById<EditText>(
+ R.id.settings_port_forwarding_inactive_add_dialog_text
+ )!!
+ val port = editText.text.toString().toInt()
+ mPortsStateManager.updateEnabledPort(port, true)
+ }
+ .setNegativeButton(R.string.settings_port_forwarding_dialog_cancel, null)
+ .create()
+ dialog.show()
+
+ val positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE)
+ positiveButton.setEnabled(false)
+ val editText =
+ dialog.findViewById<EditText>(
+ R.id.settings_port_forwarding_inactive_add_dialog_text
+ )!!
+ editText.addTextChangedListener(
+ object : TextWatcher {
+ override fun beforeTextChanged(
+ s: CharSequence?,
+ start: Int,
+ count: Int,
+ after: Int,
+ ) {}
+
+ override fun afterTextChanged(s: Editable?) {}
+
+ override fun onTextChanged(
+ s: CharSequence?,
+ start: Int,
+ before: Int,
+ count: Int,
+ ) {
+ val port =
+ try {
+ s.toString().toInt()
+ } catch (e: NumberFormatException) {
+ editText.setError(
+ getString(
+ R.string.settings_port_forwarding_dialog_error_invalid_input
+ )
+ )
+ positiveButton.setEnabled(false)
+ return@onTextChanged
+ }
+ if (port > PORT_RANGE_MAX || port < PORT_RANGE_MIN) {
+ editText.setError(
+ getString(
+ R.string
+ .settings_port_forwarding_dialog_error_invalid_port_range
+ )
+ )
+ positiveButton.setEnabled(false)
+ } else if (
+ mPortsStateManager.getActivePorts().contains(port) ||
+ mPortsStateManager.getEnabledPorts().contains(port)
+ ) {
+ editText.setError(
+ getString(
+ R.string.settings_port_forwarding_dialog_error_existing_port
+ )
+ )
+ positiveButton.setEnabled(false)
+ } else {
+ positiveButton.setEnabled(true)
+ }
+ }
+ }
+ )
+ }
}
private fun refreshAdapters() {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
index ee0bee5..d572129 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
@@ -38,7 +38,7 @@
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val closeButton: ImageButton =
- view.findViewById(R.id.settings_port_forwarding_active_item_close_button)
+ view.findViewById(R.id.settings_port_forwarding_inactive_item_close_button)
val port: TextView = view.findViewById(R.id.settings_port_forwarding_inactive_item_port)
}
diff --git a/android/TerminalApp/res/drawable/ic_add.xml b/android/TerminalApp/res/drawable/ic_add.xml
new file mode 100644
index 0000000..ebe9284
--- /dev/null
+++ b/android/TerminalApp/res/drawable/ic_add.xml
@@ -0,0 +1,26 @@
+<?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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M440,520L200,520L200,440L440,440L440,200L520,200L520,440L760,440L760,520L520,520L520,760L440,760L440,520Z"/>
+</vector>
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding.xml b/android/TerminalApp/res/layout/settings_port_forwarding.xml
index 77b9bf7..880ac44 100644
--- a/android/TerminalApp/res/layout/settings_port_forwarding.xml
+++ b/android/TerminalApp/res/layout/settings_port_forwarding.xml
@@ -14,7 +14,9 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -46,13 +48,35 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
- <TextView
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/settings_port_forwarding_other_enabled_ports_title"
- android:textSize="24sp"
- android:hyphenationFrequency="full"
- android:layout_marginBottom="24dp"/>
+ android:layout_marginBottom="24dp">
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_port_forwarding_other_enabled_ports_title"
+ android:textSize="24sp"
+ android:hyphenationFrequency="full"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageButton
+ android:id="@+id/settings_port_forwarding_inactive_add_button"
+ android:src="@drawable/ic_add"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/settings_port_forwarding_other_enabled_port_add_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="16dp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/settings_port_forwarding_inactive_recycler_view"
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding_inactive_add_dialog.xml b/android/TerminalApp/res/layout/settings_port_forwarding_inactive_add_dialog.xml
new file mode 100644
index 0000000..84fb611
--- /dev/null
+++ b/android/TerminalApp/res/layout/settings_port_forwarding_inactive_add_dialog.xml
@@ -0,0 +1,31 @@
+<?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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+ <EditText
+ android:id="@+id/settings_port_forwarding_inactive_add_dialog_text"
+ android:hint="@string/settings_port_forwarding_dialog_textview_hint"
+ android:importantForAutofill="no"
+ android:inputType="number"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding_inactive_item.xml b/android/TerminalApp/res/layout/settings_port_forwarding_inactive_item.xml
index 127b152..3e0d53b 100644
--- a/android/TerminalApp/res/layout/settings_port_forwarding_inactive_item.xml
+++ b/android/TerminalApp/res/layout/settings_port_forwarding_inactive_item.xml
@@ -34,7 +34,7 @@
app:layout_constraintStart_toStartOf="parent"/>
<ImageButton
- android:id="@+id/settings_port_forwarding_active_item_close_button"
+ android:id="@+id/settings_port_forwarding_inactive_item_close_button"
android:src="@drawable/ic_close"
android:background="@android:color/transparent"
android:contentDescription="@null"
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index 493496c..e39c7c6 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -89,7 +89,9 @@
<string name="settings_port_forwarding_active_ports_title">Listening ports</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 close button for other enabled ports. Used for talkback. [CHAR LIMIT=none] -->
+ <!-- Description of add button for other enabled ports. Used for talkback. [CHAR LIMIT=16] -->
+ <string name="settings_port_forwarding_other_enabled_port_add_button">Add</string>
+ <!-- Description of close button for other enabled ports. Used for talkback. [CHAR LIMIT=16] -->
<string name="settings_port_forwarding_other_enabled_port_close_button">Delete <xliff:g id="port_number" example="8000">%d</xliff:g></string>
<!-- Dialog title for enabling a new port [CHAR LIMIT=none] -->
@@ -100,6 +102,12 @@
<string name="settings_port_forwarding_dialog_save">Save</string>
<!-- Dialog cancel action for enabling a new port [CHAR LIMIT=16] -->
<string name="settings_port_forwarding_dialog_cancel">Cancel</string>
+ <!-- Dialog error message for non number format input [CHAR LIMIT=none] -->
+ <string name="settings_port_forwarding_dialog_error_invalid_input">Please enter a number</string>
+ <!-- Dialog error message for invalid port number [CHAR LIMIT=none] -->
+ <string name="settings_port_forwarding_dialog_error_invalid_port_range">Invalid port number</string>
+ <!-- Dialog error message for existing port [CHAR LIMIT=none] -->
+ <string name="settings_port_forwarding_dialog_error_existing_port">Port already exists</string>
<!-- 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>