Move port forward notification handling routines to PortNotifier
Bug: N/A
Test: N/A
Change-Id: Ib22a0e421c02d4b839c58929a368de2992c04087
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.java b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.java
new file mode 100644
index 0000000..e353b1d
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.java
@@ -0,0 +1,160 @@
+/*
+ * 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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.graphics.drawable.Icon;
+import android.util.Log;
+
+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 final Context mContext;
+ private final NotificationManager mNotificationManager;
+ private final BroadcastReceiver mReceiver;
+
+ public PortNotifier(Context context) {
+ mContext = context;
+ mNotificationManager = mContext.getSystemService(NotificationManager.class);
+ mReceiver = new PortForwardingRequestReceiver();
+
+ IntentFilter intentFilter =
+ new IntentFilter(PortForwardingRequestReceiver.ACTION_PORT_FORWARDING);
+ mContext.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED);
+ }
+
+ public void onActivePortsChanged(Set<String> oldPorts, Set<String> newPorts) {
+ Set<String> union = new HashSet<>(oldPorts);
+ union.addAll(newPorts);
+ for (String portStr : union) {
+ try {
+ if (!oldPorts.contains(portStr)) {
+ showPortForwardingNotification(Integer.parseInt(portStr));
+ } else if (!newPorts.contains(portStr)) {
+ discardPortForwardingNotification(Integer.parseInt(portStr));
+ }
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Failed to parse port: " + portStr);
+ throw e;
+ }
+ }
+ }
+
+ public void stop() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ private String getString(int resId) {
+ return mContext.getString(resId);
+ }
+
+ private PendingIntent getPortForwardingPendingIntent(int port, boolean enabled) {
+ Intent intent = new Intent(PortForwardingRequestReceiver.ACTION_PORT_FORWARDING);
+ intent.setPackage(mContext.getPackageName());
+ intent.setIdentifier(String.format(Locale.ROOT, "%d_%b", port, enabled));
+ intent.putExtra(PortForwardingRequestReceiver.KEY_PORT, port);
+ intent.putExtra(PortForwardingRequestReceiver.KEY_ENABLED, enabled);
+ return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ private void showPortForwardingNotification(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);
+
+ Notification notification =
+ new Notification.Builder(mContext, mContext.getPackageName())
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setContentIntent(tapPendingIntent)
+ .addAction(
+ new Notification.Action.Builder(
+ icon,
+ acceptText,
+ getPortForwardingPendingIntent(
+ port, true /* enabled */))
+ .build())
+ .addAction(
+ new Notification.Action.Builder(
+ icon,
+ denyText,
+ getPortForwardingPendingIntent(
+ port, false /* enabled */))
+ .build())
+ .build();
+ mNotificationManager.notify(TAG, port, notification);
+ }
+
+ private void discardPortForwardingNotification(int port) {
+ mNotificationManager.cancel(TAG, port);
+ }
+
+ private final class PortForwardingRequestReceiver extends BroadcastReceiver {
+ 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";
+
+ @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);
+
+ SharedPreferences sharedPref =
+ context.getSharedPreferences(
+ context.getString(R.string.preference_file_key), Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putBoolean(
+ context.getString(R.string.preference_forwarding_port_is_enabled)
+ + Integer.toString(port),
+ enabled);
+ editor.apply();
+
+ mNotificationManager.cancel(TAG, port);
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
index cd1f65b..652af8e 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.java
@@ -20,14 +20,9 @@
import android.app.Notification;
import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.app.Service;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -56,8 +51,6 @@
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
-import java.util.HashSet;
-import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -82,7 +75,7 @@
private ResultReceiver mResultReceiver;
private Server mServer;
private DebianServiceImpl mDebianService;
- private PortForwardingRequestReceiver mPortForwardingReceiver;
+ private PortNotifier mPortNotifier;
private static Intent getMyIntent(Context context) {
return new Intent(context.getApplicationContext(), VmLauncherService.class);
@@ -202,10 +195,7 @@
mResultReceiver.send(RESULT_START, null);
- IntentFilter intentFilter =
- new IntentFilter(PortForwardingRequestReceiver.ACTION_PORT_FORWARDING);
- mPortForwardingReceiver = new PortForwardingRequestReceiver();
- registerReceiver(mPortForwardingReceiver, intentFilter, RECEIVER_NOT_EXPORTED);
+ mPortNotifier = new PortNotifier(this);
startDebianServer();
return START_NOT_STICKY;
@@ -273,6 +263,11 @@
mResultReceiver.send(VmLauncherService.RESULT_IPADDR, b);
}
+ @Override
+ public void onActivePortsChanged(Set<String> oldPorts, Set<String> newPorts) {
+ mPortNotifier.onActivePortsChanged(oldPorts, newPorts);
+ }
+
public static void stop(Context context) {
Intent i = getMyIntent(context);
context.stopService(i);
@@ -280,7 +275,7 @@
@Override
public void onDestroy() {
- unregisterReceiver(mPortForwardingReceiver);
+ mPortNotifier.stop();
getSystemService(NotificationManager.class).cancelAll();
stopDebianServer();
if (mVirtualMachine != null) {
@@ -307,102 +302,4 @@
mServer.shutdown();
}
}
-
- @Override
- public void onActivePortsChanged(Set<String> oldPorts, Set<String> newPorts) {
- Set<String> union = new HashSet<>(oldPorts);
- union.addAll(newPorts);
- for (String portStr : union) {
- try {
- if (!oldPorts.contains(portStr)) {
- showPortForwardingNotification(Integer.parseInt(portStr));
- } else if (!newPorts.contains(portStr)) {
- discardPortForwardingNotification(Integer.parseInt(portStr));
- }
- } catch (NumberFormatException e) {
- Log.e(TAG, "Failed to parse port: " + portStr);
- throw e;
- }
- }
- }
-
- private PendingIntent getPortForwardingPendingIntent(int port, boolean enabled) {
- Intent intent = new Intent(PortForwardingRequestReceiver.ACTION_PORT_FORWARDING);
- intent.setPackage(getPackageName());
- intent.setIdentifier(String.format(Locale.ROOT, "%d_%b", port, enabled));
- intent.putExtra(PortForwardingRequestReceiver.KEY_PORT, port);
- intent.putExtra(PortForwardingRequestReceiver.KEY_ENABLED, enabled);
- return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
- }
-
- private void showPortForwardingNotification(int port) {
- Intent tapIntent = new Intent(this, SettingsPortForwardingActivity.class);
- tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- PendingIntent tapPendingIntent =
- PendingIntent.getActivity(this, 0, tapIntent, PendingIntent.FLAG_IMMUTABLE);
-
- String title = getString(R.string.settings_port_forwarding_notification_title);
- String content = 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(this, R.drawable.ic_launcher_foreground);
-
- Notification notification =
- new Notification.Builder(this, this.getPackageName())
- .setSmallIcon(R.drawable.ic_launcher_foreground)
- .setContentTitle(title)
- .setContentText(content)
- .setContentIntent(tapPendingIntent)
- .addAction(
- new Notification.Action.Builder(
- icon,
- acceptText,
- getPortForwardingPendingIntent(
- port, true /* enabled */))
- .build())
- .addAction(
- new Notification.Action.Builder(
- icon,
- denyText,
- getPortForwardingPendingIntent(
- port, false /* enabled */))
- .build())
- .build();
- getSystemService(NotificationManager.class).notify(TAG, port, notification);
- }
-
- private void discardPortForwardingNotification(int port) {
- getSystemService(NotificationManager.class).cancel(TAG, port);
- }
-
- private static final class PortForwardingRequestReceiver extends BroadcastReceiver {
- 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";
-
- @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);
-
- SharedPreferences sharedPref =
- context.getSharedPreferences(
- context.getString(R.string.preference_file_key), Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putBoolean(
- context.getString(R.string.preference_forwarding_port_is_enabled)
- + Integer.toString(port),
- enabled);
- editor.apply();
-
- context.getSystemService(NotificationManager.class).cancel(TAG, port);
- }
- }
}