diff options
author | 2019-03-25 01:44:48 +0000 | |
---|---|---|
committer | 2019-03-25 01:44:48 +0000 | |
commit | b31576dfa6f735f98ff27fa8a93c25f348e8ef1a (patch) | |
tree | 6df78ee73a0aa744a3cb7dd517368a24ac78b9da | |
parent | a4d92da88d603bb75eb500d244ebf472c9ba4310 (diff) | |
parent | 6b2331cb3aadaddb240d312d06807e18c647335d (diff) |
Merge "Adds StatusBarNotificationActivityStarterTest"
8 files changed, 387 insertions, 82 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityIntentHelper.java b/packages/SystemUI/src/com/android/systemui/ActivityIntentHelper.java new file mode 100644 index 000000000000..2b62e040b1fd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/ActivityIntentHelper.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2019 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.systemui; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; + +import java.util.List; + +/** + * Contains useful methods for querying properties of an Activity Intent. + */ +public class ActivityIntentHelper { + + private final Context mContext; + + public ActivityIntentHelper(Context context) { + mContext = context; + } + + /** + * Determines if sending the given intent would result in starting an Intent resolver activity, + * instead of resolving to a specific component. + * + * @param intent the intent + * @param currentUserId the id for the user to resolve as + * @return true if the intent would launch a resolver activity + */ + public boolean wouldLaunchResolverActivity(Intent intent, int currentUserId) { + ActivityInfo targetActivityInfo = getTargetActivityInfo(intent, currentUserId, + false /* onlyDirectBootAware */); + return targetActivityInfo == null; + } + + /** + * Returns info about the target Activity of a given intent, or null if the intent does not + * resolve to a specific component meeting the requirements. + * + * @param onlyDirectBootAware a boolean indicating whether the matched activity packages must + * be direct boot aware when in direct boot mode if false, all packages are considered + * a match even if they are not aware. + * @return the target activity info of the intent it resolves to a specific package or + * {@code null} if it resolved to the resolver activity + */ + public ActivityInfo getTargetActivityInfo(Intent intent, int currentUserId, + boolean onlyDirectBootAware) { + PackageManager packageManager = mContext.getPackageManager(); + int flags = PackageManager.MATCH_DEFAULT_ONLY; + if (!onlyDirectBootAware) { + flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; + } + final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( + intent, flags, currentUserId); + if (appList.size() == 0) { + return null; + } + ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, + flags | PackageManager.GET_META_DATA, currentUserId); + if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) { + return null; + } else { + return resolved.activityInfo; + } + } + + /** + * Determines if the given intent resolves to an Activity which is allowed to appear above + * the lock screen. + * + * @param intent the intent to resolve + * @return true if the launched Activity would appear above the lock screen + */ + public boolean wouldShowOverLockscreen(Intent intent, int currentUserId) { + ActivityInfo targetActivityInfo = getTargetActivityInfo(intent, + currentUserId, false /* onlyDirectBootAware */); + return targetActivityInfo != null + && (targetActivityInfo.flags & (ActivityInfo.FLAG_SHOW_WHEN_LOCKED + | ActivityInfo.FLAG_SHOW_FOR_ALL_USERS)) > 0; + } + + /** + * Determines if sending the given intent would result in starting an Intent resolver activity, + * instead of resolving to a specific component. + * + * @param resolved the resolveInfo for the intent as returned by resolveActivityAsUser + * @param appList a list of resolveInfo as returned by queryIntentActivitiesAsUser + * @return true if the intent would launch a resolver activity + */ + public boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) { + // If the list contains the above resolved activity, then it can't be + // ResolverActivity itself. + for (int i = 0; i < appList.size(); i++) { + ResolveInfo tmp = appList.get(i); + if (tmp.activityInfo.name.equals(resolved.activityInfo.name) + && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) { + return false; + } + } + return true; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 847f3ff9f24d..800ae5801016 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -67,6 +67,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.systemui.ActivityIntentHelper; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -170,6 +171,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private boolean mDozing; private int mIndicationBottomMargin; private float mDarkAmount; + private ActivityIntentHelper mActivityIntentHelper; public KeyguardBottomAreaView(Context context) { this(context, null); @@ -235,6 +237,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL protected void onFinishInflate() { super.onFinishInflate(); mLockPatternUtils = new LockPatternUtils(mContext); + mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext), + new ActivityIntentHelper(mContext)); mPreviewContainer = findViewById(R.id.preview_container); mOverlayContainer = findViewById(R.id.overlay_container); mRightAffordanceView = findViewById(R.id.camera_button); @@ -254,7 +258,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mLockIcon.update(); setClipChildren(false); setClipToPadding(false); - mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext)); inflateCameraPreview(); mLockIcon.setOnClickListener(this); mLockIcon.setOnLongClickListener(this); @@ -266,6 +269,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mAccessibilityController = Dependency.get(AccessibilityController.class); mAssistManager = Dependency.get(AssistManager.class); mLockIcon.setAccessibilityController(mAccessibilityController); + mActivityIntentHelper = new ActivityIntentHelper(getContext()); updateLeftAffordance(); } @@ -459,7 +463,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void bindCameraPrewarmService() { Intent intent = getCameraIntent(); - ActivityInfo targetInfo = PreviewInflater.getTargetActivityInfo(mContext, intent, + ActivityInfo targetInfo = mActivityIntentHelper.getTargetActivityInfo(intent, KeyguardUpdateMonitor.getCurrentUser(), true /* onlyDirectBootAware */); if (targetInfo != null && targetInfo.metaData != null) { String clazz = targetInfo.metaData.getString( @@ -500,8 +504,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void launchCamera(String source) { final Intent intent = getCameraIntent(); intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source); - boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity( - mContext, intent, KeyguardUpdateMonitor.getCurrentUser()); + boolean wouldLaunchResolverActivity = mActivityIntentHelper.wouldLaunchResolverActivity( + intent, KeyguardUpdateMonitor.getCurrentUser()); if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) { AsyncTask.execute(new Runnable() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 319a504c17a5..5d52359480e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -25,6 +25,7 @@ import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static com.android.systemui.Dependency.MAIN_HANDLER; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; @@ -126,6 +127,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; +import com.android.systemui.ActivityIntentHelper; import com.android.systemui.ActivityStarterDelegate; import com.android.systemui.AutoReinflateContainer; import com.android.systemui.DemoMode; @@ -219,7 +221,6 @@ import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; -import com.android.systemui.statusbar.policy.PreviewInflater; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; @@ -586,11 +587,12 @@ public class StatusBar extends SystemUI implements DemoMode, mEntryManager.updateNotifications(); updateScrimController(); }; + private ActivityIntentHelper mActivityIntentHelper; @Override public void onActiveStateChanged(int code, int uid, String packageName, boolean active) { mForegroundServiceController.onAppOpChanged(code, uid, packageName, active); - Dependency.get(Dependency.MAIN_HANDLER).post(() -> { + Dependency.get(MAIN_HANDLER).post(() -> { mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active); }); } @@ -635,6 +637,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNavigationBarController = Dependency.get(NavigationBarController.class); mBubbleController = Dependency.get(BubbleController.class); mBubbleController.setExpandListener(mBubbleExpandListener); + mActivityIntentHelper = new ActivityIntentHelper(mContext); KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance(); if (sliceProvider != null) { sliceProvider.initDependencies(mMediaManager, mStatusBarStateController); @@ -1069,7 +1072,8 @@ public class StatusBar extends SystemUI implements DemoMode, mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager, mLockscreenUserManager, shadeController, mKeyguardMonitor, mNotificationInterruptionStateProvider, mMetricsLogger, - new LockPatternUtils(mContext)); + new LockPatternUtils(mContext), Dependency.get(MAIN_HANDLER), + mActivityIntentHelper); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); @@ -2449,8 +2453,8 @@ public class StatusBar extends SystemUI implements DemoMode, final Callback callback, int flags) { if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return; - final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( - mContext, intent, mLockscreenUserManager.getCurrentUserId()); + final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity( + intent, mLockscreenUserManager.getCurrentUserId()); Runnable runnable = () -> { mAssistManager.hideAssist(); intent.setFlags( @@ -4315,7 +4319,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void startPendingIntentDismissingKeyguard( final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) { final boolean afterKeyguardGone = intent.isActivity() - && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), + && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); executeActionDismissingKeyguard(() -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 7e45507b4985..215f5c4dfc5b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.Dependency.MAIN_HANDLER; import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions; import android.app.ActivityManager; @@ -29,6 +28,7 @@ import android.app.TaskStackBuilder; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; +import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; @@ -43,6 +43,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.ActivityIntentHelper; import com.android.systemui.Dependency; import com.android.systemui.EventLogTags; import com.android.systemui.UiOffloadThread; @@ -65,7 +66,6 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.KeyguardMonitor; -import com.android.systemui.statusbar.policy.PreviewInflater; /** * Status bar implementation of {@link NotificationActivityStarter}. @@ -97,6 +97,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final IStatusBarService mBarService; private final CommandQueue mCommandQueue; private final IDreamManager mDreamManager; + private final Handler mMainThreadHandler; + private final ActivityIntentHelper mActivityIntentHelper; private boolean mIsCollapsingToShowActivityOverLockscreen; @@ -121,7 +123,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit KeyguardMonitor keyguardMonitor, NotificationInterruptionStateProvider notificationInterruptionStateProvider, MetricsLogger metricsLogger, - LockPatternUtils lockPatternUtils) { + LockPatternUtils lockPatternUtils, + Handler mainThreadHandler, + ActivityIntentHelper activityIntentHelper) { mContext = context; mNotificationPanel = panel; mPresenter = presenter; @@ -150,6 +154,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } }); mStatusBarRemoteInputCallback = remoteInputCallback; + mMainThreadHandler = mainThreadHandler; + mActivityIntentHelper = activityIntentHelper; } /** @@ -176,12 +182,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit boolean isActivityIntent = intent.isActivity(); final boolean afterKeyguardGone = isActivityIntent - && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), + && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); final boolean wasOccluded = mShadeController.isOccluded(); boolean showOverLockscreen = mKeyguardMonitor.isShowing() - && PreviewInflater.wouldShowOverLockscreen(mContext, - intent.getIntent(), + && mActivityIntentHelper.wouldShowOverLockscreen(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); ActivityStarter.OnDismissAction postKeyguardAction = () -> handleNotificationClickAfterKeyguardDismissed( @@ -358,7 +363,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */); if (shouldCollapse()) { // Putting it back on the main thread, since we're touching views - Dependency.get(MAIN_HANDLER).post(() -> mCommandQueue.animateCollapsePanels( + mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels( CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */)); } }); @@ -425,7 +430,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit if (Looper.getMainLooper().isCurrentThread()) { mShadeController.collapsePanel(); } else { - Dependency.get(MAIN_HANDLER).post(mShadeController::collapsePanel); + mMainThreadHandler.post(mShadeController::collapsePanel); } } @@ -444,7 +449,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private void removeNotification(StatusBarNotification notification) { // We have to post it to the UI thread for synchronization - Dependency.get(MAIN_HANDLER).post(() -> { + mMainThreadHandler.post(() -> { Runnable removeRunnable = () -> mEntryManager.performRemoveNotification(notification); if (mPresenter.isCollapsing()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 21d9dcc6897d..471d5113a502 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -33,6 +33,7 @@ import android.os.UserHandle; import android.view.View; import android.view.ViewParent; +import com.android.systemui.ActivityIntentHelper; import com.android.systemui.Dependency; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -46,7 +47,6 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.KeyguardMonitor; -import com.android.systemui.statusbar.policy.PreviewInflater; import javax.inject.Inject; import javax.inject.Singleton; @@ -64,6 +64,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, Dependency.get(NotificationLockscreenUserManager.class); private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); private final Context mContext; + private final ActivityIntentHelper mActivityIntentHelper; private View mPendingWorkRemoteInputView; private View mPendingRemoteInputView; private final ShadeController mShadeController = Dependency.get(ShadeController.class); @@ -83,6 +84,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, mKeyguardManager = context.getSystemService(KeyguardManager.class); mCommandQueue = getComponent(context, CommandQueue.class); mCommandQueue.addCallback(this); + mActivityIntentHelper = new ActivityIntentHelper(mContext); } @Override @@ -220,8 +222,8 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, NotificationRemoteInputManager.ClickHandler defaultHandler) { final boolean isActivity = pendingIntent.isActivity(); if (isActivity) { - final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( - mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId()); + final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity( + pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId()); mActivityStarter.dismissKeyguardThenExecute(() -> { try { ActivityManager.getService().resumeAppSwitches(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java index 92034b2be0ed..3d317143eb51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.policy; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; @@ -29,6 +28,7 @@ import android.view.View; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.ActivityIntentHelper; import com.android.systemui.statusbar.phone.KeyguardPreviewContainer; import java.util.List; @@ -41,13 +41,16 @@ public class PreviewInflater { private static final String TAG = "PreviewInflater"; private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout"; + private final ActivityIntentHelper mActivityIntentHelper; private Context mContext; private LockPatternUtils mLockPatternUtils; - public PreviewInflater(Context context, LockPatternUtils lockPatternUtils) { + public PreviewInflater(Context context, LockPatternUtils lockPatternUtils, + ActivityIntentHelper activityIntentHelper) { mContext = context; mLockPatternUtils = lockPatternUtils; + mActivityIntentHelper = activityIntentHelper; } public View inflatePreview(Intent intent) { @@ -130,7 +133,7 @@ public class PreviewInflater { ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, flags | PackageManager.GET_META_DATA, KeyguardUpdateMonitor.getCurrentUser()); - if (wouldLaunchResolverActivity(resolved, appList)) { + if (mActivityIntentHelper.wouldLaunchResolverActivity(resolved, appList)) { return null; } if (resolved == null || resolved.activityInfo == null) { @@ -140,63 +143,6 @@ public class PreviewInflater { resolved.activityInfo.metaData); } - public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent, - int currentUserId) { - return getTargetActivityInfo(ctx, intent, currentUserId, false /* onlyDirectBootAware */) - == null; - } - - public static boolean wouldShowOverLockscreen(Context ctx, Intent intent, int currentUserId) { - ActivityInfo targetActivityInfo = getTargetActivityInfo(ctx, intent, currentUserId, - false /* onlyDirectBootAware */); - return targetActivityInfo != null - && (targetActivityInfo.flags & (ActivityInfo.FLAG_SHOW_WHEN_LOCKED - | ActivityInfo.FLAG_SHOW_FOR_ALL_USERS)) > 0; - } - - /** - * @param onlyDirectBootAware a boolean indicating whether the matched activity packages must - * be direct boot aware when in direct boot mode if false, all - * packages are considered a match even if they are not aware. - * @return the target activity info of the intent it resolves to a specific package or - * {@code null} if it resolved to the resolver activity - */ - public static ActivityInfo getTargetActivityInfo(Context ctx, Intent intent, - int currentUserId, boolean onlyDirectBootAware) { - PackageManager packageManager = ctx.getPackageManager(); - int flags = PackageManager.MATCH_DEFAULT_ONLY; - if (!onlyDirectBootAware) { - flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; - } - final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( - intent, flags, currentUserId); - if (appList.size() == 0) { - return null; - } - ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, - flags | PackageManager.GET_META_DATA, currentUserId); - if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) { - return null; - } else { - return resolved.activityInfo; - } - } - - private static boolean wouldLaunchResolverActivity( - ResolveInfo resolved, List<ResolveInfo> appList) { - // If the list contains the above resolved activity, then it can't be - // ResolverActivity itself. - for (int i = 0; i < appList.size(); i++) { - ResolveInfo tmp = appList.get(i); - if (tmp.activityInfo.name.equals(resolved.activityInfo.name) - && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) { - return false; - } - } - return true; - } - private static class WidgetInfo { String contextPackage; int layoutId; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 63b66732c02e..c9b550cd6e64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -35,6 +35,7 @@ import android.widget.FrameLayout; import androidx.test.filters.SmallTest; +import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.NotificationEntryListener; @@ -89,6 +90,8 @@ public class BubbleControllerTest extends SysuiTestCase { private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener; @Mock private BubbleController.BubbleExpandListener mBubbleExpandListener; + @Mock + NotificationVisibility mNotificationVisibility; @Mock private PendingIntent mDeleteIntent; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java new file mode 100644 index 000000000000..20af1ac5a42f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2019 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.systemui.statusbar.phone; + +import static org.mockito.AdditionalAnswers.answerVoid; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.KeyguardManager; +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.RemoteException; +import android.os.UserHandle; +import android.service.dreams.IDreamManager; +import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; +import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.ActivityIntentHelper; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; +import com.android.systemui.statusbar.notification.NotificationActivityStarter; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.policy.KeyguardMonitor; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; + +import java.util.ArrayList; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { + + @Mock + private AssistManager mAssistManager; + @Mock + private NotificationEntryManager mEntryManager; + @Mock + private ActivityStarter mActivityStarter; + @Mock + private IStatusBarService mStatusBarService; + @Mock + private StatusBarStateController mStatusBarStateController; + @Mock + private NotificationRemoteInputManager mRemoteInputManager; + @Mock + private RemoteInputController mRemoteInputController; + @Mock + private ShadeController mShadeController; + @Mock + private KeyguardMonitor mKeyguardMonitor; + @Mock + private Handler mHandler; + + @Mock + private ActivityIntentHelper mActivityIntentHelper; + @Mock + private PendingIntent mContentIntent; + @Mock + private NotificationData mNotificationData; + @Mock + private NotificationEntry mNotificationEntry; + @Mock + private NotificationEntry mBubbleEntry; + + private NotificationActivityStarter mNotificationActivityStarter; + + private NotificationTestHelper mNotificationTestHelper; + ExpandableNotificationRow mNotificationRow; + + private final Answer<Void> mCallOnDismiss = answerVoid( + (ActivityStarter.OnDismissAction dismissAction, Runnable cancel, + Boolean afterKeyguardGone) -> dismissAction.onDismiss()); + private ArrayList<NotificationEntry> mActiveNotifications; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); + when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); + + mActiveNotifications = new ArrayList<>(); + mActiveNotifications.add(mNotificationEntry); + mActiveNotifications.add(mBubbleEntry); + when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications); + when(mNotificationEntry.getRow()).thenReturn(mNotificationRow); + + mNotificationTestHelper = new NotificationTestHelper(mContext); + mNotificationRow = mNotificationTestHelper.createRow(); + + mNotificationActivityStarter = new StatusBarNotificationActivityStarter(getContext(), + mock(CommandQueue.class), mAssistManager, mock(NotificationPanelView.class), + mock(NotificationPresenter.class), mEntryManager, mock(HeadsUpManagerPhone.class), + mActivityStarter, mock(ActivityLaunchAnimator.class), mStatusBarService, + mock(StatusBarStateController.class), mock(KeyguardManager.class), + mock(IDreamManager.class), mRemoteInputManager, + mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class), + mock(NotificationLockscreenUserManager.class), mShadeController, mKeyguardMonitor, + mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class), + mock(LockPatternUtils.class), mHandler, mActivityIntentHelper); + + + when(mContentIntent.isActivity()).thenReturn(true); + when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1)); + + // SBNActivityStarter expects contentIntent or fullScreenIntent to be set + mNotificationRow.getEntry().notification.getNotification().contentIntent = mContentIntent; + + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); + + // set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg + doAnswer(mCallOnDismiss).when(mActivityStarter).dismissKeyguardThenExecute( + any(ActivityStarter.OnDismissAction.class), any(), anyBoolean()); + + // set up addAfterKeyguardGoneRunnable to synchronously invoke the Runnable arg + doAnswer(answerVoid(Runnable::run)) + .when(mShadeController).addAfterKeyguardGoneRunnable(any(Runnable.class)); + + // set up addPostCollapseAction to synchronously invoke the Runnable arg + doAnswer(answerVoid(Runnable::run)) + .when(mShadeController).addPostCollapseAction(any(Runnable.class)); + + // set up Handler to synchronously invoke the Runnable arg + doAnswer(answerVoid(Runnable::run)) + .when(mHandler).post(any(Runnable.class)); + } + + @Test + public void testOnNotificationClicked_whileKeyguardVisible() + throws PendingIntent.CanceledException, RemoteException { + // Given + when(mKeyguardMonitor.isShowing()).thenReturn(true); + when(mShadeController.isOccluded()).thenReturn(true); + when(mContentIntent.isActivity()).thenReturn(true); + when(mActivityIntentHelper.wouldShowOverLockscreen(any(Intent.class), anyInt())) + .thenReturn(false); + when(mActivityIntentHelper.wouldLaunchResolverActivity(any(Intent.class), anyInt())) + .thenReturn(false); + + StatusBarNotification statusBarNotification = mNotificationRow.getEntry().notification; + statusBarNotification.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; + + // When + mNotificationActivityStarter.onNotificationClicked(statusBarNotification, + mNotificationRow); + + // Then + verify(mActivityStarter).dismissKeyguardThenExecute( + any(ActivityStarter.OnDismissAction.class), + any() /* cancel */, + anyBoolean() /* afterKeyguardGone */); + + verify(mShadeController, atLeastOnce()).collapsePanel(); + + verify(mContentIntent).sendAndReturnResult( + any(Context.class), + anyInt() /* code */, + any() /* fillInIntent */, + any() /* PendingIntent.OnFinished */, + any() /* Handler */, + any() /* requiredPermission */, + any() /* Bundle options */); + + verify(mAssistManager).hideAssist(); + + verify(mStatusBarService).onNotificationClick( + eq(mNotificationRow.getEntry().key), any(NotificationVisibility.class)); + + // Notification is removed due to FLAG_AUTO_CANCEL + verify(mEntryManager).performRemoveNotification(eq(statusBarNotification)); + } +} |