Merge "Adds StatusBarNotificationActivityStarterTest"
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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(() -> {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user