Extract Instant Apps notification code into InstantAppNotifier
The code to show notifications of Instant App was in
PhoneStatsuBarPolicy. This CL moves these code into new class
named InstantAppNotifier.
Bug: 123917211
Test: build passes
Change-Id: Ib4bd988c94e2382d776c5c0b1886c8d20d3a1b16
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index e0c5e59..4a86484 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -16,53 +16,29 @@
package com.android.systemui.statusbar.phone;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-
import android.app.ActivityManager;
-import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.AlarmManager.AlarmClockInfo;
-import android.app.AppGlobals;
-import android.app.Notification;
-import android.app.Notification.Action;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.app.SynchronousUserSwitchObserver;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Icon;
import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
import android.provider.Settings.Global;
-import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.telecom.TelecomManager;
import android.text.format.DateFormat;
-import android.util.ArraySet;
import android.util.Log;
-import android.util.Pair;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.Dependency;
-import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.UiOffloadThread;
@@ -70,12 +46,8 @@
import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.BluetoothController.Callback;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
@@ -90,7 +62,6 @@
import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.NotificationChannels;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -98,18 +69,22 @@
import java.util.Locale;
/**
- * This class contains all of the policy about which icons are installed in the status
- * bar at boot time. It goes through the normal API for icons, even though it probably
- * strictly doesn't need to.
+ * This class contains all of the policy about which icons are installed in the status bar at boot
+ * time. It goes through the normal API for icons, even though it probably strictly doesn't need to.
*/
-public class PhoneStatusBarPolicy implements Callback, Callbacks,
- RotationLockControllerCallback, Listener, ZenModeController.Callback,
- DeviceProvisionedListener, KeyguardMonitor.Callback, PrivacyItemController.Callback {
+public class PhoneStatusBarPolicy
+ implements BluetoothController.Callback,
+ CommandQueue.Callbacks,
+ RotationLockControllerCallback,
+ Listener,
+ ZenModeController.Callback,
+ DeviceProvisionedListener,
+ KeyguardMonitor.Callback,
+ PrivacyItemController.Callback {
private static final String TAG = "PhoneStatusBarPolicy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final int LOCATION_STATUS_ICON_ID = R.drawable.stat_sys_location;
- public static final int NUM_TASKS_FOR_INSTANT_APP_INFO = 5;
private final String mSlotCast;
private final String mSlotHotspot;
@@ -142,7 +117,6 @@
private final KeyguardMonitor mKeyguardMonitor;
private final LocationController mLocationController;
private final PrivacyItemController mPrivacyItemController;
- private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
// Assume it's all good unless we hear otherwise. We don't always seem
@@ -152,7 +126,6 @@
private boolean mZenVisible;
private boolean mVolumeVisible;
private boolean mCurrentUserSetup;
- private boolean mDockedStackExists;
private boolean mManagedProfileIconVisible = false;
@@ -271,19 +244,6 @@
mPrivacyItemController.addCallback(this);
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
-
- // Clear out all old notifications on startup (only present in the case where sysui dies)
- NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
- for (StatusBarNotification notification : noMan.getActiveNotifications()) {
- if (notification.getId() == SystemMessage.NOTE_INSTANT_APPS) {
- noMan.cancel(notification.getTag(), notification.getId());
- }
- }
- DockedStackExistsListener.register(exists -> {
- mDockedStackExists = exists;
- updateForegroundInstantApps();
- });
}
@Override
@@ -515,169 +475,6 @@
});
}
- private void updateForegroundInstantApps() {
- NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
- ArraySet<Pair<String, Integer>> notifs = new ArraySet<>(mCurrentNotifs);
- IPackageManager pm = AppGlobals.getPackageManager();
- mCurrentNotifs.clear();
- mUiOffloadThread.submit(() -> {
- try {
- final StackInfo focusedStack =
- ActivityTaskManager.getService().getFocusedStackInfo();
- if (focusedStack != null) {
- final int windowingMode =
- focusedStack.configuration.windowConfiguration.getWindowingMode();
- if (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- checkStack(focusedStack, notifs, noMan, pm);
- }
- }
- if (mDockedStackExists) {
- checkStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED,
- notifs, noMan, pm);
- }
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- // Cancel all the leftover notifications that don't have a foreground process anymore.
- notifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
- new UserHandle(v.second)));
- });
- }
-
- private void checkStack(int windowingMode, int activityType,
- ArraySet<Pair<String, Integer>> notifs, NotificationManager noMan, IPackageManager pm) {
- try {
- final StackInfo info =
- ActivityTaskManager.getService().getStackInfo(windowingMode, activityType);
- checkStack(info, notifs, noMan, pm);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
- private void checkStack(StackInfo info, ArraySet<Pair<String, Integer>> notifs,
- NotificationManager noMan, IPackageManager pm) {
- try {
- if (info == null || info.topActivity == null) return;
- String pkg = info.topActivity.getPackageName();
- if (!hasNotif(notifs, pkg, info.userId)) {
- // TODO: Optimize by not always needing to get application info.
- // Maybe cache non-ephemeral packages?
- ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES, info.userId);
- if (appInfo.isInstantApp()) {
- postEphemeralNotif(pkg, info.userId, appInfo, noMan, info.taskIds[info.taskIds.length - 1]);
- }
- }
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
-
- private void postEphemeralNotif(String pkg, int userId, ApplicationInfo appInfo,
- NotificationManager noMan, int taskId) {
- final Bundle extras = new Bundle();
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- mContext.getString(R.string.instant_apps));
- mCurrentNotifs.add(new Pair<>(pkg, userId));
-
- String helpUrl = mContext.getString(R.string.instant_apps_help_url);
- boolean hasHelpUrl = !helpUrl.isEmpty();
- String message = mContext.getString(hasHelpUrl
- ? R.string.instant_apps_message_with_help
- : R.string.instant_apps_message);
-
- UserHandle user = UserHandle.of(userId);
- PendingIntent appInfoAction = PendingIntent.getActivityAsUser(mContext, 0,
- new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
- .setData(Uri.fromParts("package", pkg, null)), 0, null, user);
- Action action = new Notification.Action.Builder(null, mContext.getString(R.string.app_info),
- appInfoAction).build();
- PendingIntent helpCenterIntent = hasHelpUrl
- ? PendingIntent.getActivityAsUser(mContext, 0,
- new Intent(Intent.ACTION_VIEW).setData(Uri.parse(
- helpUrl)),
- 0, null, user)
- : null;
-
- Intent browserIntent = getTaskIntent(taskId, userId);
- Notification.Builder builder = new Notification.Builder(mContext,
- NotificationChannels.GENERAL);
- if (browserIntent != null && browserIntent.isWebIntent()) {
- // Make sure that this doesn't resolve back to an instant app
- browserIntent.setComponent(null)
- .setPackage(null)
- .addFlags(Intent.FLAG_IGNORE_EPHEMERAL)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext,
- 0 /* requestCode */, browserIntent, 0 /* flags */, null, user);
- ComponentName aiaComponent = null;
- try {
- aiaComponent = AppGlobals.getPackageManager().getInstantAppInstallerComponent();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- Intent goToWebIntent = new Intent()
- .setComponent(aiaComponent)
- .setAction(Intent.ACTION_VIEW)
- .addCategory(Intent.CATEGORY_BROWSABLE)
- .addCategory("unique:" + System.currentTimeMillis())
- .putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
- .putExtra(Intent.EXTRA_VERSION_CODE, (int) (appInfo.versionCode & 0x7fffffff))
- .putExtra(Intent.EXTRA_LONG_VERSION_CODE, appInfo.versionCode)
- .putExtra(Intent.EXTRA_INSTANT_APP_FAILURE, pendingIntent);
-
- PendingIntent webPendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
- goToWebIntent, 0, null, user);
- Action webAction = new Notification.Action.Builder(null,
- mContext.getString(R.string.go_to_web),
- webPendingIntent).build();
- builder.addAction(webAction);
- }
-
- noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS, builder
- .addExtras(extras)
- .addAction(action)
- .setContentIntent(helpCenterIntent)
- .setColor(mContext.getColor(R.color.instant_apps_color))
- .setContentTitle(mContext.getString(R.string.instant_apps_title,
- appInfo.loadLabel(mContext.getPackageManager())))
- .setLargeIcon(Icon.createWithResource(pkg, appInfo.icon))
- .setSmallIcon(Icon.createWithResource(mContext.getPackageName(),
- R.drawable.instant_icon))
- .setContentText(message)
- .setStyle(new Notification.BigTextStyle().bigText(message))
- .setOngoing(true)
- .build(),
- new UserHandle(userId));
- }
-
- private Intent getTaskIntent(int taskId, int userId) {
- try {
- final List<ActivityManager.RecentTaskInfo> tasks =
- ActivityTaskManager.getService().getRecentTasks(
- NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId).getList();
- for (int i = 0; i < tasks.size(); i++) {
- if (tasks.get(i).id == taskId) {
- return tasks.get(i).baseIntent;
- }
- }
- } catch (RemoteException e) {
- // Fall through
- }
- return null;
- }
-
- private boolean hasNotif(ArraySet<Pair<String, Integer>> notifs, String pkg, int userId) {
- Pair<String, Integer> key = new Pair<>(pkg, userId);
- if (notifs.remove(key)) {
- mCurrentNotifs.add(key);
- return true;
- }
- return false;
- }
-
private final SynchronousUserSwitchObserver mUserSwitchListener =
new SynchronousUserSwitchObserver() {
@Override
@@ -690,7 +487,6 @@
mHandler.post(() -> {
updateAlarm();
updateManagedProfile();
- updateForegroundInstantApps();
});
}
};
@@ -723,14 +519,12 @@
boolean forced) {
if (mContext.getDisplayId() == displayId) {
updateManagedProfile();
- updateForegroundInstantApps();
}
}
@Override
public void onKeyguardShowingChanged() {
updateManagedProfile();
- updateForegroundInstantApps();
}
@Override
@@ -743,11 +537,6 @@
}
@Override
- public void preloadRecentApps() {
- updateForegroundInstantApps();
- }
-
- @Override
public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
boolean portrait = RotationLockTile.isCurrentOrientationLockPortrait(
mRotationLockController, mContext);
@@ -822,14 +611,6 @@
mIconController.setIconVisibility(mSlotLocation, showLocation);
}
- private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {
- @Override
- public void onTaskStackChanged() {
- // Listen for changes to stacks and then check which instant apps are foreground.
- updateForegroundInstantApps();
- }
- };
-
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {