Extracts NotificationActivityStarter from NotificationPresenter.
This change simplifies the NotificationPresenter interface by extracting the methods dealing with starting an activity due to actions taken on a notification to a separate interface, NotificationActivityStarter. The extracted methods in StatusBarNotificationActivityStarter are also cleaned up to make the control flow easier to read. Pure refactor; no functional changes. Test: atest SystemUITests Change-Id: I2e8cf0626a005dc52b9969865a097cc14da9b669
This commit is contained in:
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
@@ -38,12 +35,6 @@ public interface NotificationPresenter extends ExpandableNotificationRow.OnExpan
|
||||
*/
|
||||
boolean isPresenterFullyCollapsed();
|
||||
|
||||
/**
|
||||
* Runs the given intent. The presenter may want to run some animations or close itself when
|
||||
* this happens.
|
||||
*/
|
||||
void startNotificationGutsIntent(Intent intent, int appUid, ExpandableNotificationRow row);
|
||||
|
||||
/**
|
||||
* Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
|
||||
*/
|
||||
@@ -74,8 +65,7 @@ public interface NotificationPresenter extends ExpandableNotificationRow.OnExpan
|
||||
int getMaxNotificationsWhileLocked(boolean recompute);
|
||||
|
||||
/**
|
||||
* True if the presenter
|
||||
* @return
|
||||
* True if the presenter is currently locked.
|
||||
*/
|
||||
default boolean isPresenterLocked() { return false; }
|
||||
|
||||
@@ -88,22 +78,4 @@ public interface NotificationPresenter extends ExpandableNotificationRow.OnExpan
|
||||
* @return true if the shade is collapsing.
|
||||
*/
|
||||
boolean isCollapsing();
|
||||
|
||||
/**
|
||||
* @return true if the shade is collapsing to show an activity over the lock screen
|
||||
*/
|
||||
default public boolean isCollapsingToShowActivityOverLockscreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ActivityLaunchAnimator} from the presenter so it can be queried by
|
||||
* {@link com.android.systemui.statusbar.phone.StatusBar}
|
||||
* @return the current animator
|
||||
* @deprecated This is only here for now because StatusBar is still the ActivityLaunchAnimator
|
||||
* callback but shouldn't be.
|
||||
*/
|
||||
default public ActivityLaunchAnimator getActivityLaunchAnimator() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,6 @@ public class NotificationRemoteInputManager implements Dumpable {
|
||||
private final KeyguardManager mKeyguardManager;
|
||||
|
||||
protected RemoteInputController mRemoteInputController;
|
||||
protected NotificationPresenter mPresenter;
|
||||
protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
|
||||
mNotificationLifetimeFinishedCallback;
|
||||
protected IStatusBarService mBarService;
|
||||
@@ -320,10 +319,8 @@ public class NotificationRemoteInputManager implements Dumpable {
|
||||
mKeyguardManager = context.getSystemService(KeyguardManager.class);
|
||||
}
|
||||
|
||||
public void setUpWithPresenter(NotificationPresenter presenter,
|
||||
Callback callback,
|
||||
RemoteInputController.Delegate delegate) {
|
||||
mPresenter = presenter;
|
||||
/** Initializes this component with the provided dependencies. */
|
||||
public void setUpWithCallback(Callback callback, RemoteInputController.Delegate delegate) {
|
||||
mCallback = callback;
|
||||
mRemoteInputController = new RemoteInputController(delegate);
|
||||
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.notification;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
|
||||
/**
|
||||
* Component responsible for handling actions on a notification which cause activites to start.
|
||||
* (e.g. clicking on a notification, tapping on the settings icon in the notification guts)
|
||||
*/
|
||||
public interface NotificationActivityStarter {
|
||||
/** Called when the user clicks on the surface of a notification. */
|
||||
void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row);
|
||||
|
||||
/** Called when the user clicks on a button in the notification guts which fires an intent. */
|
||||
void startNotificationGutsIntent(Intent intent, int appUid,
|
||||
ExpandableNotificationRow row);
|
||||
|
||||
default boolean isCollapsingToShowActivityOverLockscreen() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -143,6 +143,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
|
||||
protected IStatusBarService mBarService;
|
||||
private NotificationPresenter mPresenter;
|
||||
private Callback mCallback;
|
||||
private NotificationActivityStarter mNotificationActivityStarter;
|
||||
protected PowerManager mPowerManager;
|
||||
private NotificationListenerService.RankingMap mLatestRankingMap;
|
||||
protected HeadsUpManager mHeadsUpManager;
|
||||
@@ -193,7 +194,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
|
||||
mBubbleController.collapseStack();
|
||||
}
|
||||
|
||||
mCallback.onNotificationClicked(sbn, row);
|
||||
mNotificationActivityStarter.onNotificationClicked(sbn, row);
|
||||
}
|
||||
|
||||
private boolean isMenuVisible(ExpandableNotificationRow row) {
|
||||
@@ -346,6 +347,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
|
||||
mOnAppOpsClickListener = mGutsManager::openGuts;
|
||||
}
|
||||
|
||||
public void setNotificationActivityStarter(
|
||||
NotificationActivityStarter notificationActivityStarter) {
|
||||
mNotificationActivityStarter = notificationActivityStarter;
|
||||
}
|
||||
|
||||
public NotificationData getNotificationData() {
|
||||
return mNotificationData;
|
||||
}
|
||||
@@ -1247,15 +1253,6 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
|
||||
*/
|
||||
void onNotificationRemoved(String key, StatusBarNotification old);
|
||||
|
||||
|
||||
/**
|
||||
* Called when a notification is clicked.
|
||||
*
|
||||
* @param sbn notification that was clicked
|
||||
* @param row row for that notification
|
||||
*/
|
||||
void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row);
|
||||
|
||||
/**
|
||||
* Called when a new notification and row is created.
|
||||
*
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.app.NotificationChannel;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
@@ -42,13 +41,13 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.statusbar.NotificationLifetimeExtender;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationPresenter;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationData;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
|
||||
@@ -79,13 +78,13 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
Dependency.get(StatusBarStateController.class);
|
||||
private final DeviceProvisionedController mDeviceProvisionedController =
|
||||
Dependency.get(DeviceProvisionedController.class);
|
||||
private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
|
||||
|
||||
// which notification is currently being longpress-examined by the user
|
||||
private NotificationGuts mNotificationGutsExposed;
|
||||
private NotificationMenuRowPlugin.MenuItem mGutsMenuItem;
|
||||
private NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
|
||||
private NotificationPresenter mPresenter;
|
||||
private NotificationActivityStarter mNotificationActivityStarter;
|
||||
private NotificationListContainer mListContainer;
|
||||
private CheckSaveListener mCheckSaveListener;
|
||||
private OnSettingsClickListener mOnSettingsClickListener;
|
||||
@@ -94,8 +93,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
|
||||
public NotificationGutsManager(Context context) {
|
||||
mContext = context;
|
||||
Resources res = context.getResources();
|
||||
|
||||
mAccessibilityManager = (AccessibilityManager)
|
||||
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
||||
}
|
||||
@@ -109,6 +106,11 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
mOnSettingsClickListener = onSettingsClick;
|
||||
}
|
||||
|
||||
public void setNotificationActivityStarter(
|
||||
NotificationActivityStarter notificationActivityStarter) {
|
||||
mNotificationActivityStarter = notificationActivityStarter;
|
||||
}
|
||||
|
||||
public void onDensityOrFontScaleChanged(NotificationData.Entry entry) {
|
||||
setExposedGuts(entry.getGuts());
|
||||
bindGuts(entry.getRow());
|
||||
@@ -127,7 +129,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
if (channel != null) {
|
||||
intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
|
||||
}
|
||||
mPresenter.startNotificationGutsIntent(intent, appUid, row);
|
||||
mNotificationActivityStarter.startNotificationGutsIntent(intent, appUid, row);
|
||||
}
|
||||
|
||||
protected void startAppOpsSettingsActivity(String pkg, int uid, ArraySet<Integer> ops,
|
||||
@@ -138,12 +140,12 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
} else {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
|
||||
intent.setData(Uri.fromParts("package", pkg, null));
|
||||
mPresenter.startNotificationGutsIntent(intent, uid, row);
|
||||
mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
|
||||
}
|
||||
} else if (ops.contains(OP_CAMERA) || ops.contains(OP_RECORD_AUDIO)) {
|
||||
Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS);
|
||||
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, pkg);
|
||||
mPresenter.startNotificationGutsIntent(intent, uid, row);
|
||||
mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +264,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
||||
(View v, Intent intent) -> {
|
||||
mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_APP_NOTE_SETTINGS);
|
||||
guts.resetFalsingCheck();
|
||||
mPresenter.startNotificationGutsIntent(intent, sbn.getUid(), row);
|
||||
mNotificationActivityStarter.startNotificationGutsIntent(intent, sbn.getUid(),
|
||||
row);
|
||||
};
|
||||
boolean isForBlockingHelper = row.isBlockingHelperShowing();
|
||||
|
||||
|
||||
@@ -187,6 +187,7 @@ import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
|
||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationData;
|
||||
import com.android.systemui.statusbar.notification.NotificationData.Entry;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
@@ -578,7 +579,9 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
private HeadsUpAppearanceController mHeadsUpAppearanceController;
|
||||
private boolean mVibrateOnOpening;
|
||||
private VibratorHelper mVibratorHelper;
|
||||
private ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
protected NotificationPresenter mPresenter;
|
||||
private NotificationActivityStarter mNotificationActivityStarter;
|
||||
private boolean mPulsing;
|
||||
|
||||
@Override
|
||||
@@ -1014,13 +1017,23 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
protected void setUpPresenter() {
|
||||
// Set up the initial notification state.
|
||||
mActivityLaunchAnimator = new ActivityLaunchAnimator(
|
||||
mStatusBarWindow, this, mNotificationPanel,
|
||||
(NotificationListContainer) mStackScroller);
|
||||
|
||||
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
|
||||
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
|
||||
mScrimController, this);
|
||||
mScrimController, mActivityLaunchAnimator);
|
||||
|
||||
mAppOpsController.addCallback(APP_OPS, this);
|
||||
mNotificationListener.setUpWithPresenter(mPresenter);
|
||||
mNotificationShelf.setOnActivatedListener(mPresenter);
|
||||
mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
|
||||
|
||||
mNotificationActivityStarter = new StatusBarNotificationActivityStarter(
|
||||
mContext, mNotificationPanel, mPresenter, mHeadsUpManager, mActivityLaunchAnimator);
|
||||
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
|
||||
mEntryManager.setNotificationActivityStarter(mNotificationActivityStarter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1639,9 +1652,9 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
@Override
|
||||
public void onExpandAnimationTimedOut() {
|
||||
ActivityLaunchAnimator animator = mPresenter.getActivityLaunchAnimator();
|
||||
if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing()
|
||||
&& animator != null && !animator.isLaunchForActivity()) {
|
||||
&& mActivityLaunchAnimator != null
|
||||
&& !mActivityLaunchAnimator.isLaunchForActivity()) {
|
||||
onClosingFinished();
|
||||
} else {
|
||||
collapsePanel(true /* animate */);
|
||||
@@ -1940,7 +1953,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
runPostCollapseRunnables();
|
||||
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
|
||||
if (!mPresenter.isCollapsingToShowActivityOverLockscreen()) {
|
||||
if (!mNotificationActivityStarter.isCollapsingToShowActivityOverLockscreen()) {
|
||||
showBouncerIfKeyguard();
|
||||
} else if (DEBUG) {
|
||||
Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 com.android.systemui.Dependency.MAIN_HANDLER;
|
||||
import static com.android.systemui.SysUiServiceProvider.getComponent;
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.TaskStackBuilder;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
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.RemoteInputController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
|
||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationData;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
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}.
|
||||
*/
|
||||
public class StatusBarNotificationActivityStarter implements NotificationActivityStarter {
|
||||
|
||||
private static final String TAG = "NotificationClickHandler";
|
||||
|
||||
private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
|
||||
private final NotificationGroupManager mGroupManager =
|
||||
Dependency.get(NotificationGroupManager.class);
|
||||
private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
|
||||
(StatusBarRemoteInputCallback) Dependency.get(
|
||||
NotificationRemoteInputManager.Callback.class);
|
||||
private final NotificationRemoteInputManager mRemoteInputManager =
|
||||
Dependency.get(NotificationRemoteInputManager.class);
|
||||
private final NotificationLockscreenUserManager mLockscreenUserManager =
|
||||
Dependency.get(NotificationLockscreenUserManager.class);
|
||||
private final ShadeController mShadeController = Dependency.get(ShadeController.class);
|
||||
private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
|
||||
private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
|
||||
private final NotificationEntryManager mEntryManager =
|
||||
Dependency.get(NotificationEntryManager.class);
|
||||
private final StatusBarStateController mStatusBarStateController =
|
||||
Dependency.get(StatusBarStateController.class);
|
||||
|
||||
private final Context mContext;
|
||||
private final NotificationPanelView mNotificationPanel;
|
||||
private final NotificationPresenter mPresenter;
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
private final HeadsUpManagerPhone mHeadsUpManager;
|
||||
private final KeyguardManager mKeyguardManager;
|
||||
private final ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
private final IStatusBarService mBarService;
|
||||
private final CommandQueue mCommandQueue;
|
||||
|
||||
private boolean mIsCollapsingToShowActivityOverLockscreen;
|
||||
|
||||
public StatusBarNotificationActivityStarter(Context context,
|
||||
NotificationPanelView panel,
|
||||
NotificationPresenter presenter,
|
||||
HeadsUpManagerPhone headsUpManager,
|
||||
ActivityLaunchAnimator activityLaunchAnimator) {
|
||||
mContext = context;
|
||||
mNotificationPanel = panel;
|
||||
mPresenter = presenter;
|
||||
mLockPatternUtils = new LockPatternUtils(context);
|
||||
mHeadsUpManager = headsUpManager;
|
||||
mKeyguardManager = context.getSystemService(KeyguardManager.class);
|
||||
mActivityLaunchAnimator = activityLaunchAnimator;
|
||||
mBarService = IStatusBarService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
||||
mCommandQueue = getComponent(context, CommandQueue.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a notification is clicked.
|
||||
*
|
||||
* @param sbn notification that was clicked
|
||||
* @param row row for that notification
|
||||
*/
|
||||
@Override
|
||||
public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
|
||||
RemoteInputController controller = mRemoteInputManager.getController();
|
||||
if (controller.isRemoteInputActive(row.getEntry())
|
||||
&& !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
|
||||
// We have an active remote input typed and the user clicked on the notification.
|
||||
// this was probably unintentional, so we're closing the edit text instead.
|
||||
controller.closeRemoteInputs();
|
||||
return;
|
||||
}
|
||||
Notification notification = sbn.getNotification();
|
||||
final PendingIntent intent = notification.contentIntent != null
|
||||
? notification.contentIntent
|
||||
: notification.fullScreenIntent;
|
||||
final String notificationKey = sbn.getKey();
|
||||
|
||||
boolean isActivityIntent = intent.isActivity();
|
||||
final boolean afterKeyguardGone = isActivityIntent
|
||||
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
|
||||
mLockscreenUserManager.getCurrentUserId());
|
||||
final boolean wasOccluded = mShadeController.isOccluded();
|
||||
boolean showOverLockscreen = mKeyguardMonitor.isShowing()
|
||||
&& PreviewInflater.wouldShowOverLockscreen(mContext,
|
||||
intent.getIntent(),
|
||||
mLockscreenUserManager.getCurrentUserId());
|
||||
ActivityStarter.OnDismissAction postKeyguardAction =
|
||||
() -> handleNotificationClickAfterKeyguardDismissed(
|
||||
sbn, row, controller, intent, notificationKey,
|
||||
isActivityIntent, wasOccluded, showOverLockscreen);
|
||||
if (showOverLockscreen) {
|
||||
mIsCollapsingToShowActivityOverLockscreen = true;
|
||||
postKeyguardAction.onDismiss();
|
||||
} else {
|
||||
mActivityStarter.dismissKeyguardThenExecute(
|
||||
postKeyguardAction, null /* cancel */, afterKeyguardGone);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleNotificationClickAfterKeyguardDismissed(
|
||||
StatusBarNotification sbn,
|
||||
ExpandableNotificationRow row,
|
||||
RemoteInputController controller,
|
||||
PendingIntent intent,
|
||||
String notificationKey,
|
||||
boolean isActivityIntent,
|
||||
boolean wasOccluded,
|
||||
boolean showOverLockscreen) {
|
||||
// TODO: Some of this code may be able to move to NotificationEntryManager.
|
||||
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
|
||||
// Release the HUN notification to the shade.
|
||||
|
||||
if (mPresenter.isPresenterFullyCollapsed()) {
|
||||
HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
|
||||
}
|
||||
//
|
||||
// In most cases, when FLAG_AUTO_CANCEL is set, the notification will
|
||||
// become canceled shortly by NoMan, but we can't assume that.
|
||||
mHeadsUpManager.removeNotification(sbn.getKey(),
|
||||
true /* releaseImmediately */);
|
||||
}
|
||||
StatusBarNotification parentToCancel = null;
|
||||
if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
|
||||
StatusBarNotification summarySbn =
|
||||
mGroupManager.getLogicalGroupSummary(sbn).notification;
|
||||
if (shouldAutoCancel(summarySbn)) {
|
||||
parentToCancel = summarySbn;
|
||||
}
|
||||
}
|
||||
final StatusBarNotification parentToCancelFinal = parentToCancel;
|
||||
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
|
||||
sbn, row, controller, intent, notificationKey,
|
||||
isActivityIntent, wasOccluded, parentToCancelFinal);
|
||||
|
||||
if (showOverLockscreen) {
|
||||
mShadeController.addPostCollapseAction(runnable);
|
||||
mShadeController.collapsePanel(true /* animate */);
|
||||
} else if (mKeyguardMonitor.isShowing()
|
||||
&& mShadeController.isOccluded()) {
|
||||
mShadeController.addAfterKeyguardGoneRunnable(runnable);
|
||||
mShadeController.collapsePanel();
|
||||
} else {
|
||||
new Thread(runnable).start();
|
||||
}
|
||||
|
||||
return !mNotificationPanel.isFullyCollapsed();
|
||||
}
|
||||
|
||||
private void handleNotificationClickAfterPanelCollapsed(
|
||||
StatusBarNotification sbn,
|
||||
ExpandableNotificationRow row,
|
||||
RemoteInputController controller,
|
||||
PendingIntent intent,
|
||||
String notificationKey,
|
||||
boolean isActivityIntent,
|
||||
boolean wasOccluded,
|
||||
StatusBarNotification parentToCancelFinal) {
|
||||
try {
|
||||
// The intent we are sending is for the application, which
|
||||
// won't have permission to immediately start an activity after
|
||||
// the user switches to home. We know it is safe to do at this
|
||||
// point, so make sure new activity switches are now allowed.
|
||||
ActivityManager.getService().resumeAppSwitches();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
int launchResult;
|
||||
// If we are launching a work activity and require to launch
|
||||
// separate work challenge, we defer the activity action and cancel
|
||||
// notification until work challenge is unlocked.
|
||||
if (isActivityIntent) {
|
||||
final int userId = intent.getCreatorUserHandle().getIdentifier();
|
||||
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
|
||||
&& mKeyguardManager.isDeviceLocked(userId)) {
|
||||
// TODO(b/28935539): should allow certain activities to
|
||||
// bypass work challenge
|
||||
if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId,
|
||||
intent.getIntentSender(), notificationKey)) {
|
||||
// Show work challenge, do not run PendingIntent and
|
||||
// remove notification
|
||||
collapseOnMainThread();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Intent fillInIntent = null;
|
||||
NotificationData.Entry entry = row.getEntry();
|
||||
CharSequence remoteInputText = null;
|
||||
if (!TextUtils.isEmpty(entry.remoteInputText)) {
|
||||
remoteInputText = entry.remoteInputText;
|
||||
}
|
||||
if (!TextUtils.isEmpty(remoteInputText) && !controller.isSpinning(entry.key)) {
|
||||
fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
|
||||
remoteInputText.toString());
|
||||
}
|
||||
RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
|
||||
row, wasOccluded);
|
||||
try {
|
||||
if (adapter != null) {
|
||||
ActivityTaskManager.getService()
|
||||
.registerRemoteAnimationForNextActivityStart(
|
||||
intent.getCreatorPackage(), adapter);
|
||||
}
|
||||
launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
|
||||
null, null, getActivityOptions(adapter));
|
||||
mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
|
||||
} catch (RemoteException | PendingIntent.CanceledException e) {
|
||||
// the stack trace isn't very helpful here.
|
||||
// Just log the exception message.
|
||||
Log.w(TAG, "Sending contentIntent failed: " + e);
|
||||
|
||||
// TODO: Dismiss Keyguard.
|
||||
}
|
||||
if (isActivityIntent) {
|
||||
mAssistManager.hideAssist();
|
||||
}
|
||||
if (shouldCollapse()) {
|
||||
collapseOnMainThread();
|
||||
}
|
||||
|
||||
final int count =
|
||||
mEntryManager.getNotificationData().getActiveNotifications().size();
|
||||
final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
|
||||
final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
|
||||
rank, count, true);
|
||||
try {
|
||||
mBarService.onNotificationClick(notificationKey, nv);
|
||||
} catch (RemoteException ex) {
|
||||
// system process is dead if we're here.
|
||||
}
|
||||
if (parentToCancelFinal != null) {
|
||||
removeNotification(parentToCancelFinal);
|
||||
}
|
||||
if (shouldAutoCancel(sbn)
|
||||
|| mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
|
||||
notificationKey)) {
|
||||
// Automatically remove all notifications that we may have kept around longer
|
||||
removeNotification(sbn);
|
||||
}
|
||||
mIsCollapsingToShowActivityOverLockscreen = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startNotificationGutsIntent(final Intent intent, final int appUid,
|
||||
ExpandableNotificationRow row) {
|
||||
mActivityStarter.dismissKeyguardThenExecute(() -> {
|
||||
AsyncTask.execute(() -> {
|
||||
int launchResult = TaskStackBuilder.create(mContext)
|
||||
.addNextIntentWithParentStack(intent)
|
||||
.startActivities(getActivityOptions(
|
||||
mActivityLaunchAnimator.getLaunchAnimation(
|
||||
row, mShadeController.isOccluded())),
|
||||
new UserHandle(UserHandle.getUserId(appUid)));
|
||||
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(
|
||||
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}, null, false /* afterKeyguardGone */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollapsingToShowActivityOverLockscreen() {
|
||||
return mIsCollapsingToShowActivityOverLockscreen;
|
||||
}
|
||||
|
||||
private static boolean shouldAutoCancel(StatusBarNotification sbn) {
|
||||
int flags = sbn.getNotification().flags;
|
||||
if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
|
||||
return false;
|
||||
}
|
||||
if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void collapseOnMainThread() {
|
||||
if (Looper.getMainLooper().isCurrentThread()) {
|
||||
mShadeController.collapsePanel();
|
||||
} else {
|
||||
Dependency.get(MAIN_HANDLER).post(mShadeController::collapsePanel);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldCollapse() {
|
||||
return mStatusBarStateController.getState() != StatusBarState.SHADE
|
||||
|| !mActivityLaunchAnimator.isAnimationPending();
|
||||
}
|
||||
|
||||
private void removeNotification(StatusBarNotification notification) {
|
||||
// We have to post it to the UI thread for synchronization
|
||||
Dependency.get(MAIN_HANDLER).post(() -> {
|
||||
Runnable removeRunnable =
|
||||
() -> mEntryManager.performRemoveNotification(notification);
|
||||
if (mPresenter.isCollapsing()) {
|
||||
// To avoid lags we're only performing the remove
|
||||
// after the shade was collapsed
|
||||
mShadeController.addPostCollapseAction(removeRunnable);
|
||||
} else {
|
||||
removeRunnable.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -14,35 +14,22 @@
|
||||
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import static com.android.systemui.Dependency.MAIN_HANDLER;
|
||||
import static com.android.systemui.SysUiServiceProvider.getComponent;
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.CLOSE_PANEL_WHEN_EMPTIED;
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.SPEW;
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.TaskStackBuilder;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.service.vr.IVrManager;
|
||||
import android.service.vr.IVrStateCallbacks;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
@@ -50,13 +37,10 @@ import android.widget.TextView;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.NotificationVisibility;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.InitController;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
|
||||
import com.android.systemui.statusbar.AmbientPulseManager;
|
||||
@@ -65,9 +49,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationMediaManager;
|
||||
import com.android.systemui.statusbar.NotificationPresenter;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback;
|
||||
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
|
||||
import com.android.systemui.statusbar.RemoteInputController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.notification.AboveShelfObserver;
|
||||
@@ -80,9 +62,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpUtil;
|
||||
import com.android.systemui.statusbar.policy.KeyguardMonitor;
|
||||
import com.android.systemui.statusbar.policy.PreviewInflater;
|
||||
|
||||
public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
|
||||
@@ -93,7 +73,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
|
||||
private final ShadeController mShadeController = Dependency.get(ShadeController.class);
|
||||
private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
|
||||
private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
|
||||
private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
|
||||
private final NotificationViewHierarchyManager mViewHierarchyManager =
|
||||
Dependency.get(NotificationViewHierarchyManager.class);
|
||||
@@ -105,12 +84,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
Dependency.get(NotificationEntryManager.class);
|
||||
private final NotificationMediaManager mMediaManager =
|
||||
Dependency.get(NotificationMediaManager.class);
|
||||
private final NotificationRemoteInputManager mRemoteInputManager =
|
||||
Dependency.get(NotificationRemoteInputManager.class);
|
||||
private final NotificationGroupManager mGroupManager =
|
||||
Dependency.get(NotificationGroupManager.class);
|
||||
private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
|
||||
(StatusBarRemoteInputCallback) Dependency.get(Callback.class);
|
||||
protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
|
||||
|
||||
private final NotificationPanelView mNotificationPanel;
|
||||
@@ -122,7 +95,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
private final CommandQueue mCommandQueue;
|
||||
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
private final KeyguardManager mKeyguardManager;
|
||||
private final ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
private final int mMaxAllowedKeyguardNotifications;
|
||||
@@ -133,34 +105,32 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
|
||||
protected boolean mVrMode;
|
||||
private int mMaxKeyguardNotifications;
|
||||
private boolean mIsCollapsingToShowActivityOverLockscreen;
|
||||
|
||||
public StatusBarNotificationPresenter(Context context, NotificationPanelView panel,
|
||||
HeadsUpManagerPhone headsUp, StatusBarWindowView statusBarWindow,
|
||||
ViewGroup stackScroller, DozeScrimController dozeScrimController,
|
||||
public StatusBarNotificationPresenter(Context context,
|
||||
NotificationPanelView panel,
|
||||
HeadsUpManagerPhone headsUp,
|
||||
StatusBarWindowView statusBarWindow,
|
||||
ViewGroup stackScroller,
|
||||
DozeScrimController dozeScrimController,
|
||||
ScrimController scrimController,
|
||||
ActivityLaunchAnimator.Callback launchAnimatorCallback) {
|
||||
ActivityLaunchAnimator activityLaunchAnimator) {
|
||||
mContext = context;
|
||||
mNotificationPanel = panel;
|
||||
mHeadsUpManager = headsUp;
|
||||
mCommandQueue = getComponent(context, CommandQueue.class);
|
||||
mAboveShelfObserver = new AboveShelfObserver(stackScroller);
|
||||
mActivityLaunchAnimator = activityLaunchAnimator;
|
||||
mAboveShelfObserver.setListener(statusBarWindow.findViewById(
|
||||
R.id.notification_container_parent));
|
||||
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
|
||||
mDozeScrimController = dozeScrimController;
|
||||
mScrimController = scrimController;
|
||||
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
|
||||
mLockPatternUtils = new LockPatternUtils(context);
|
||||
mKeyguardManager = context.getSystemService(KeyguardManager.class);
|
||||
mMaxAllowedKeyguardNotifications = context.getResources().getInteger(
|
||||
R.integer.keyguard_max_notification_count);
|
||||
mBarService = IStatusBarService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
||||
mActivityLaunchAnimator = new ActivityLaunchAnimator(statusBarWindow,
|
||||
launchAnimatorCallback,
|
||||
mNotificationPanel,
|
||||
(NotificationListContainer) stackScroller);
|
||||
|
||||
if (MULTIUSER_DEBUG) {
|
||||
mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
|
||||
@@ -176,10 +146,12 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
Slog.e(TAG, "Failed to register VR mode state listener: " + e);
|
||||
}
|
||||
}
|
||||
mRemoteInputManager.setUpWithPresenter(this,
|
||||
NotificationRemoteInputManager remoteInputManager =
|
||||
Dependency.get(NotificationRemoteInputManager.class);
|
||||
remoteInputManager.setUpWithCallback(
|
||||
Dependency.get(NotificationRemoteInputManager.Callback.class),
|
||||
mNotificationPanel.createRemoteInputDelegate());
|
||||
mRemoteInputManager.getController().addCallback(
|
||||
remoteInputManager.getController().addCallback(
|
||||
Dependency.get(StatusBarWindowController.class));
|
||||
|
||||
NotificationListContainer notifListContainer = (NotificationListContainer) stackScroller;
|
||||
@@ -203,11 +175,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityLaunchAnimator getActivityLaunchAnimator() {
|
||||
return mActivityLaunchAnimator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollapsing() {
|
||||
return mNotificationPanel.isCollapsing()
|
||||
@@ -215,11 +182,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
|| mActivityLaunchAnimator.isAnimationRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollapsingToShowActivityOverLockscreen() {
|
||||
return mIsCollapsingToShowActivityOverLockscreen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPerformRemoveNotification(StatusBarNotification n) {
|
||||
if (mNotificationPanel.hasPulsingNotifications() &&
|
||||
@@ -376,201 +338,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
mMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
|
||||
RemoteInputController controller = mRemoteInputManager.getController();
|
||||
if (controller.isRemoteInputActive(row.getEntry())
|
||||
&& !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
|
||||
// We have an active remote input typed and the user clicked on the notification.
|
||||
// this was probably unintentional, so we're closing the edit text instead.
|
||||
controller.closeRemoteInputs();
|
||||
return;
|
||||
}
|
||||
Notification notification = sbn.getNotification();
|
||||
final PendingIntent intent = notification.contentIntent != null
|
||||
? notification.contentIntent
|
||||
: notification.fullScreenIntent;
|
||||
final String notificationKey = sbn.getKey();
|
||||
|
||||
boolean isActivityIntent = intent.isActivity();
|
||||
final boolean afterKeyguardGone = isActivityIntent
|
||||
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
|
||||
mLockscreenUserManager.getCurrentUserId());
|
||||
final boolean wasOccluded = mShadeController.isOccluded();
|
||||
boolean showOverLockscreen = mKeyguardMonitor.isShowing()
|
||||
&& PreviewInflater.wouldShowOverLockscreen(mContext,
|
||||
intent.getIntent(),
|
||||
mLockscreenUserManager.getCurrentUserId());
|
||||
OnDismissAction postKeyguardAction = () -> {
|
||||
// TODO: Some of this code may be able to move to NotificationEntryManager.
|
||||
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
|
||||
// Release the HUN notification to the shade.
|
||||
|
||||
if (isPresenterFullyCollapsed()) {
|
||||
HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
|
||||
}
|
||||
//
|
||||
// In most cases, when FLAG_AUTO_CANCEL is set, the notification will
|
||||
// become canceled shortly by NoMan, but we can't assume that.
|
||||
mHeadsUpManager.removeNotification(sbn.getKey(),
|
||||
true /* releaseImmediately */);
|
||||
}
|
||||
StatusBarNotification parentToCancel = null;
|
||||
if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
|
||||
StatusBarNotification summarySbn =
|
||||
mGroupManager.getLogicalGroupSummary(sbn).notification;
|
||||
if (shouldAutoCancel(summarySbn)) {
|
||||
parentToCancel = summarySbn;
|
||||
}
|
||||
}
|
||||
final StatusBarNotification parentToCancelFinal = parentToCancel;
|
||||
final Runnable runnable = () -> {
|
||||
try {
|
||||
// The intent we are sending is for the application, which
|
||||
// won't have permission to immediately start an activity after
|
||||
// the user switches to home. We know it is safe to do at this
|
||||
// point, so make sure new activity switches are now allowed.
|
||||
ActivityManager.getService().resumeAppSwitches();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
int launchResult = ActivityManager.START_CANCELED;
|
||||
if (intent != null) {
|
||||
// If we are launching a work activity and require to launch
|
||||
// separate work challenge, we defer the activity action and cancel
|
||||
// notification until work challenge is unlocked.
|
||||
if (isActivityIntent) {
|
||||
final int userId = intent.getCreatorUserHandle().getIdentifier();
|
||||
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
|
||||
&& mKeyguardManager.isDeviceLocked(userId)) {
|
||||
// TODO(b/28935539): should allow certain activities to
|
||||
// bypass work challenge
|
||||
if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId,
|
||||
intent.getIntentSender(), notificationKey)) {
|
||||
// Show work challenge, do not run PendingIntent and
|
||||
// remove notification
|
||||
collapseOnMainThread();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Intent fillInIntent = null;
|
||||
Entry entry = row.getEntry();
|
||||
CharSequence remoteInputText = null;
|
||||
if (!TextUtils.isEmpty(entry.remoteInputText)) {
|
||||
remoteInputText = entry.remoteInputText;
|
||||
}
|
||||
if (!TextUtils.isEmpty(remoteInputText)
|
||||
&& !controller.isSpinning(entry.key)) {
|
||||
fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
|
||||
remoteInputText.toString());
|
||||
}
|
||||
RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
|
||||
row, wasOccluded);
|
||||
try {
|
||||
if (adapter != null) {
|
||||
ActivityTaskManager.getService()
|
||||
.registerRemoteAnimationForNextActivityStart(
|
||||
intent.getCreatorPackage(), adapter);
|
||||
}
|
||||
launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
|
||||
null, null, getActivityOptions(adapter));
|
||||
mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
|
||||
} catch (RemoteException | PendingIntent.CanceledException e) {
|
||||
// the stack trace isn't very helpful here.
|
||||
// Just log the exception message.
|
||||
Log.w(TAG, "Sending contentIntent failed: " + e);
|
||||
|
||||
// TODO: Dismiss Keyguard.
|
||||
}
|
||||
if (isActivityIntent) {
|
||||
mAssistManager.hideAssist();
|
||||
}
|
||||
}
|
||||
if (shouldCollapse()) {
|
||||
collapseOnMainThread();
|
||||
}
|
||||
|
||||
final int count =
|
||||
mEntryManager.getNotificationData().getActiveNotifications().size();
|
||||
final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
|
||||
final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
|
||||
rank, count, true);
|
||||
try {
|
||||
mBarService.onNotificationClick(notificationKey, nv);
|
||||
} catch (RemoteException ex) {
|
||||
// system process is dead if we're here.
|
||||
}
|
||||
if (parentToCancelFinal != null) {
|
||||
removeNotification(parentToCancelFinal);
|
||||
}
|
||||
if (shouldAutoCancel(sbn)
|
||||
|| mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
|
||||
notificationKey)) {
|
||||
// Automatically remove all notifications that we may have kept around longer
|
||||
removeNotification(sbn);
|
||||
}
|
||||
mIsCollapsingToShowActivityOverLockscreen = false;
|
||||
};
|
||||
|
||||
if (showOverLockscreen) {
|
||||
mShadeController.addPostCollapseAction(runnable);
|
||||
mShadeController.collapsePanel(true /* animate */);
|
||||
} else if (mKeyguardMonitor.isShowing()
|
||||
&& mShadeController.isOccluded()) {
|
||||
mShadeController.addAfterKeyguardGoneRunnable(runnable);
|
||||
mShadeController.collapsePanel();
|
||||
} else {
|
||||
new Thread(runnable).start();
|
||||
}
|
||||
|
||||
return !mNotificationPanel.isFullyCollapsed();
|
||||
};
|
||||
if (showOverLockscreen) {
|
||||
mIsCollapsingToShowActivityOverLockscreen = true;
|
||||
postKeyguardAction.onDismiss();
|
||||
} else {
|
||||
mActivityStarter.dismissKeyguardThenExecute(
|
||||
postKeyguardAction, null /* cancel */, afterKeyguardGone);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeNotification(StatusBarNotification notification) {
|
||||
// We have to post it to the UI thread for synchronization
|
||||
Dependency.get(MAIN_HANDLER).post(() -> {
|
||||
Runnable removeRunnable =
|
||||
() -> mEntryManager.performRemoveNotification(notification);
|
||||
if (isCollapsing()) {
|
||||
// To avoid lags we're only performing the remove
|
||||
// after the shade was collapsed
|
||||
mShadeController.addPostCollapseAction(removeRunnable);
|
||||
} else {
|
||||
removeRunnable.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startNotificationGutsIntent(final Intent intent, final int appUid,
|
||||
ExpandableNotificationRow row) {
|
||||
mActivityStarter.dismissKeyguardThenExecute(() -> {
|
||||
AsyncTask.execute(() -> {
|
||||
int launchResult = TaskStackBuilder.create(mContext)
|
||||
.addNextIntentWithParentStack(intent)
|
||||
.startActivities(getActivityOptions(
|
||||
mActivityLaunchAnimator.getLaunchAnimation(
|
||||
row, mShadeController.isOccluded())),
|
||||
new UserHandle(UserHandle.getUserId(appUid)));
|
||||
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(
|
||||
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}, null, false /* afterKeyguardGone */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxNotificationsWhileLocked(boolean recompute) {
|
||||
if (recompute) {
|
||||
@@ -600,41 +367,12 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
return mVrMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPresenterLocked() {
|
||||
return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
|
||||
}
|
||||
|
||||
private void collapseOnMainThread() {
|
||||
if (Looper.getMainLooper().isCurrentThread()) {
|
||||
mShadeController.collapsePanel();
|
||||
} else {
|
||||
Dependency.get(MAIN_HANDLER).post(mShadeController::collapsePanel);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldCollapse() {
|
||||
return mStatusBarStateController.getState() != StatusBarState.SHADE
|
||||
|| !mActivityLaunchAnimator.isAnimationPending();
|
||||
}
|
||||
|
||||
private void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
|
||||
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
|
||||
mActivityStarter.dismissKeyguardThenExecute(dismissAction, null,
|
||||
true /* afterKeyguardGone */);
|
||||
}
|
||||
|
||||
private static boolean shouldAutoCancel(StatusBarNotification sbn) {
|
||||
int flags = sbn.getNotification().flags;
|
||||
if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
|
||||
return false;
|
||||
}
|
||||
if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
|
||||
@Override
|
||||
public void onVrStateChanged(boolean enabled) {
|
||||
@@ -645,7 +383,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter {
|
||||
private final CheckSaveListener mCheckSaveListener = new CheckSaveListener() {
|
||||
@Override
|
||||
public void checkSave(Runnable saveImportance, StatusBarNotification sbn) {
|
||||
int state = mStatusBarStateController.getState();
|
||||
// If the user has security enabled, show challenge if the setting is changed.
|
||||
if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
|
||||
&& mKeyguardManager.isKeyguardLocked()) {
|
||||
|
||||
@@ -17,8 +17,7 @@ package com.android.systemui.statusbar.phone;
|
||||
import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
|
||||
|
||||
import static com.android.systemui.SysUiServiceProvider.getComponent;
|
||||
import static com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
.NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
|
||||
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.KeyguardManager;
|
||||
@@ -163,7 +162,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks {
|
||||
mPendingWorkRemoteInputView = clicked;
|
||||
}
|
||||
|
||||
protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
|
||||
boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
|
||||
String notificationKey) {
|
||||
// Clear pending remote view, as we do not want to trigger pending remote input view when
|
||||
// it's called by other code
|
||||
|
||||
@@ -91,7 +91,7 @@ public class NonPhoneDependencyTest extends SysuiTestCase {
|
||||
mCheckSaveListener, mOnSettingsClickListener);
|
||||
notificationLogger.setUpWithContainer(mListContainer);
|
||||
mediaManager.setUpWithPresenter(mPresenter);
|
||||
remoteInputManager.setUpWithPresenter(mPresenter, mRemoteInputManagerCallback,
|
||||
remoteInputManager.setUpWithCallback(mRemoteInputManagerCallback,
|
||||
mDelegate);
|
||||
lockscreenUserManager.setUpWithPresenter(mPresenter);
|
||||
viewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -22,13 +22,12 @@ import android.testing.TestableLooper;
|
||||
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import com.android.systemui.statusbar.notification.NotificationData;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
|
||||
import com.android.systemui.statusbar.notification.NotificationData;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
|
||||
import com.google.android.collect.Sets;
|
||||
|
||||
@@ -80,7 +79,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
|
||||
mEntry = new NotificationData.Entry(mSbn);
|
||||
mEntry.setRow(mRow);
|
||||
|
||||
mRemoteInputManager.setUpWithPresenterForTest(mPresenter, mCallback,
|
||||
mRemoteInputManager.setUpWithPresenterForTest(mCallback,
|
||||
mDelegate, mController);
|
||||
for (NotificationLifetimeExtender extender : mRemoteInputManager.getLifetimeExtenders()) {
|
||||
extender.setCallback(
|
||||
@@ -201,11 +200,10 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void setUpWithPresenterForTest(NotificationPresenter presenter,
|
||||
Callback callback,
|
||||
public void setUpWithPresenterForTest(Callback callback,
|
||||
RemoteInputController.Delegate delegate,
|
||||
RemoteInputController controller) {
|
||||
super.setUpWithPresenter(presenter, callback, delegate);
|
||||
super.setUpWithCallback(callback, delegate);
|
||||
mRemoteInputController = controller;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public class SmartReplyControllerTest extends SysuiTestCase {
|
||||
mSmartReplyController);
|
||||
|
||||
mRemoteInputManager = new NotificationRemoteInputManager(mContext);
|
||||
mRemoteInputManager.setUpWithPresenter(mPresenter, mCallback, mDelegate);
|
||||
mRemoteInputManager.setUpWithCallback(mCallback, mDelegate);
|
||||
mNotification = new Notification.Builder(mContext, "")
|
||||
.setSmallIcon(R.drawable.ic_person)
|
||||
.setContentTitle("Title")
|
||||
|
||||
@@ -59,8 +59,8 @@ import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.statusbar.NotificationPresenter;
|
||||
import com.android.systemui.statusbar.NotificationTestHelper;
|
||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
import com.android.systemui.statusbar.notification.NotificationData;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
|
||||
@@ -92,7 +92,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
|
||||
@Rule public MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Mock private NotificationPresenter mPresenter;
|
||||
@Mock private NotificationEntryManager mEntryManager;
|
||||
@Mock private NotificationActivityStarter mNotificationActivityStarter;
|
||||
@Mock private NotificationStackScrollLayout mStackScroller;
|
||||
@Mock private NotificationInfo.CheckSaveListener mCheckSaveListener;
|
||||
@Mock private OnSettingsClickListener mOnSettingsClickListener;
|
||||
@@ -110,6 +110,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
mGutsManager = new NotificationGutsManager(mContext);
|
||||
mGutsManager.setUpWithPresenter(mPresenter, mStackScroller,
|
||||
mCheckSaveListener, mOnSettingsClickListener);
|
||||
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -217,7 +218,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
ops.add(OP_CAMERA);
|
||||
mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
verify(mNotificationActivityStarter, times(1))
|
||||
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
@@ -227,7 +229,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
ops.add(OP_RECORD_AUDIO);
|
||||
mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
verify(mNotificationActivityStarter, times(1))
|
||||
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
@@ -238,7 +241,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
ops.add(OP_RECORD_AUDIO);
|
||||
mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
verify(mNotificationActivityStarter, times(1))
|
||||
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
@@ -248,7 +252,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
ops.add(OP_SYSTEM_ALERT_WINDOW);
|
||||
mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
verify(mNotificationActivityStarter, times(1))
|
||||
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
assertEquals(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
@@ -260,7 +265,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
ops.add(OP_SYSTEM_ALERT_WINDOW);
|
||||
mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
verify(mNotificationActivityStarter, times(1))
|
||||
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
@@ -271,7 +277,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
ops.add(OP_SYSTEM_ALERT_WINDOW);
|
||||
mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
verify(mNotificationActivityStarter, times(1))
|
||||
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
@@ -282,7 +289,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
||||
ops.add(OP_SYSTEM_ALERT_WINDOW);
|
||||
mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
verify(mNotificationActivityStarter, times(1))
|
||||
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
|
||||
assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
|
||||
mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class),
|
||||
statusBarWindowView, mock(NotificationListContainerViewGroup.class),
|
||||
mock(DozeScrimController.class), mock(ScrimController.class),
|
||||
mock(ActivityLaunchAnimator.Callback.class));
|
||||
mock(ActivityLaunchAnimator.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user