Make StatusBar not be a NotificationPresenter
Break the NotificationPresenter out of the StatusBar and most of
the logic with it.
- Break RemoteInput Callbacks out of NotificationPresenter
- Break Environment Callbacks out of NotificationPresenter
- Add ShadeController interface for StatusBar (abstraction
layer from StatusBar)
- Add InitController to allow for post-init tasks (dependency
resolution should not go here)
- Make some dependencies (ShadeController, NotificationEntryManager,
NotificationLockscreenUserManager usually) lazily-resolved to break
some dependency cycles
- Lots of other cleanup
Test: Existing tests do not pass
Change-Id: Ic043c6b15a4ffe551fc27f99b25d5c3caa1be582
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index e58538d..e1b8dc8 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -29,46 +29,69 @@
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
- if (mActualStarter == null) return;
+ if (mActualStarter == null) {
+ return;
+ }
mActualStarter.startPendingIntentDismissingKeyguard(intent);
}
@Override
public void startActivity(Intent intent, boolean dismissShade) {
- if (mActualStarter == null) return;
+ if (mActualStarter == null) {
+ return;
+ }
mActualStarter.startActivity(intent, dismissShade);
}
@Override
public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
- if (mActualStarter == null) return;
+ if (mActualStarter == null) {
+ return;
+ }
mActualStarter.startActivity(intent, onlyProvisioned, dismissShade);
}
@Override
public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
- if (mActualStarter == null) return;
+ if (mActualStarter == null) {
+ return;
+ }
mActualStarter.startActivity(intent, dismissShade, callback);
}
@Override
public void postStartActivityDismissingKeyguard(Intent intent, int delay) {
- if (mActualStarter == null) return;
+ if (mActualStarter == null) {
+ return;
+ }
mActualStarter.postStartActivityDismissingKeyguard(intent, delay);
}
@Override
public void postStartActivityDismissingKeyguard(PendingIntent intent) {
- if (mActualStarter == null) return;
+ if (mActualStarter == null) {
+ return;
+ }
mActualStarter.postStartActivityDismissingKeyguard(intent);
}
@Override
public void postQSRunnableDismissingKeyguard(Runnable runnable) {
- if (mActualStarter == null) return;
+ if (mActualStarter == null) {
+ return;
+ }
mActualStarter.postQSRunnableDismissingKeyguard(runnable);
}
+ @Override
+ public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancel,
+ boolean afterKeyguardGone) {
+ if (mActualStarter == null) {
+ return;
+ }
+ mActualStarter.dismissKeyguardThenExecute(action, cancel, afterKeyguardGone);
+ }
+
public void setActivityStarterImpl(ActivityStarter starter) {
mActualStarter = starter;
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 2c821b2..494880e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -48,16 +48,22 @@
import com.android.systemui.power.EnhancedEstimatesImpl;
import com.android.systemui.power.PowerNotificationWarnings;
import com.android.systemui.power.PowerUI;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.AppOpsListener;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -343,6 +349,14 @@
mProviders.put(LockscreenGestureLogger.class, () -> new LockscreenGestureLogger());
+ mProviders.put(KeyguardEnvironment.class, () -> new KeyguardEnvironmentImpl());
+ mProviders.put(ShadeController.class, () ->
+ SysUiServiceProvider.getComponent(mContext, StatusBar.class));
+ mProviders.put(NotificationRemoteInputManager.Callback.class,
+ () -> new StatusBarRemoteInputCallback(mContext));
+
+ mProviders.put(InitController.class, InitController::new);
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/InitController.java b/packages/SystemUI/src/com/android/systemui/InitController.java
new file mode 100644
index 0000000..52ba66a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/InitController.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+
+/**
+ * Created by {@link Dependency} on SystemUI startup. Add tasks which need to be executed only
+ * after all other dependencies have been created.
+ */
+public class InitController {
+
+ private final ArrayList<Runnable> mTasks = new ArrayList<>();
+
+ /**
+ * Add a task to be executed after {@link Dependency#start()}
+ * @param runnable the task to be executed
+ */
+ public void addPostInitTask(Runnable runnable) {
+ mTasks.add(runnable);
+ }
+
+ /**
+ * Run post-init tasks and remove them from the tasks list
+ */
+ public void executePostInitTasks() {
+ while (!mTasks.isEmpty()) {
+ mTasks.remove(0).run();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 78053b2..92aa652 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -194,6 +194,7 @@
mServices[i].onBootCompleted();
}
}
+ Dependency.get(InitController.class).executePostInitTasks();
log.traceEnd();
Dependency.get(PluginManager.class).addPluginListener(
new PluginListener<OverlayPlugin>() {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 258b6f6..c4bf27b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -32,6 +32,7 @@
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -133,7 +134,7 @@
Context context) {
providers.put(StatusBarStateController.class, StatusBarStateController::new);
providers.put(NotificationLockscreenUserManager.class,
- () -> new NotificationLockscreenUserManager(context));
+ () -> new NotificationLockscreenUserManagerImpl(context));
providers.put(VisualStabilityManager.class, VisualStabilityManager::new);
providers.put(NotificationGroupManager.class, NotificationGroupManager::new);
providers.put(NotificationMediaManager.class, () -> new NotificationMediaManager(context));
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 38a90cf..53cdee5 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -202,7 +202,8 @@
// Close Recent Apps if needed
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL);
+ CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+ false /* force */);
boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index 5739c99..96af08b 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -44,7 +44,7 @@
// Because space is usually constrained in the auto use-case, there should not be a
// pinned notification when the shade has been expanded. Ensure this by not pinning any
// notification if the shade is already opened.
- if (!mPresenter.isPresenterFullyCollapsed()) {
+ if (!getPresenter().isPresenterFullyCollapsed()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarNotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/car/CarNotificationMediaManager.java
new file mode 100644
index 0000000..f34d6b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/car/CarNotificationMediaManager.java
@@ -0,0 +1,30 @@
+/*
+ * 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.car;
+
+import android.content.Context;
+
+import com.android.systemui.statusbar.NotificationMediaManager;
+
+public class CarNotificationMediaManager extends NotificationMediaManager {
+ public CarNotificationMediaManager(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
+ // Do nothing, we don't want to display media art in the lock screen for a car.
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
index a015a18..e4b2e07 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
@@ -22,6 +22,7 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dependency.DependencyProvider;
import com.android.systemui.SystemUIFactory;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.car.CarFacetButtonController;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
@@ -46,5 +47,7 @@
() -> new CarNotificationEntryManager(context));
providers.put(CarFacetButtonController.class, () -> new CarFacetButtonController(context));
providers.put(HvacController.class, () -> new HvacController(context));
+ providers.put(NotificationMediaManager.class,
+ () -> new CarNotificationMediaManager(context));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 5c0b328..daaefb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
+
+import android.app.StatusBarManager;
import android.content.ComponentName;
import android.graphics.Rect;
import android.hardware.biometrics.IBiometricPromptReceiver;
@@ -24,7 +27,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
+
import androidx.annotation.VisibleForTesting;
import android.util.Pair;
@@ -117,7 +120,7 @@
default void removeIcon(String slot) { }
default void disable(int state1, int state2, boolean animate) { }
default void animateExpandNotificationsPanel() { }
- default void animateCollapsePanels(int flags) { }
+ default void animateCollapsePanels(int flags, boolean force) { }
default void togglePanel() { }
default void animateExpandSettingsPanel(String obj) { }
default void setSystemUiVisibility(int vis, int fullscreenStackVis,
@@ -169,7 +172,13 @@
}
@VisibleForTesting
- protected CommandQueue() {
+ public CommandQueue() {
+ }
+
+ public boolean panelsEnabled() {
+ return (mDisable1 & StatusBarManager.DISABLE_EXPAND) == 0
+ && (mDisable2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
+ && !ONLY_CORE_APPS;
}
public void addCallbacks(Callbacks callbacks) {
@@ -234,10 +243,10 @@
}
}
- public void animateCollapsePanels(int flags) {
+ public void animateCollapsePanels(int flags, boolean force) {
synchronized (mLock) {
mHandler.removeMessages(MSG_COLLAPSE_PANELS);
- mHandler.obtainMessage(MSG_COLLAPSE_PANELS, flags, 0).sendToTarget();
+ mHandler.obtainMessage(MSG_COLLAPSE_PANELS, flags, force ? 1 : 0).sendToTarget();
}
}
@@ -592,7 +601,7 @@
break;
case MSG_COLLAPSE_PANELS:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).animateCollapsePanels(msg.arg1);
+ mCallbacks.get(i).animateCollapsePanels(msg.arg1, msg.arg2 != 0);
}
break;
case MSG_TOGGLE_PANEL:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index cfa09bc..f3a46ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -29,6 +29,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
/**
@@ -41,11 +42,14 @@
// Dependencies:
private final NotificationRemoteInputManager mRemoteInputManager =
Dependency.get(NotificationRemoteInputManager.class);
+ private final NotificationEntryManager mEntryManager =
+ Dependency.get(NotificationEntryManager.class);
+ private final NotificationGroupManager mGroupManager =
+ Dependency.get(NotificationGroupManager.class);
private final Context mContext;
protected NotificationPresenter mPresenter;
- protected NotificationEntryManager mEntryManager;
public NotificationListener(Context context) {
mContext = context;
@@ -61,7 +65,7 @@
return;
}
final RankingMap currentRanking = getCurrentRanking();
- mPresenter.getHandler().post(() -> {
+ Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
for (StatusBarNotification sbn : notifications) {
mEntryManager.addNotification(sbn, currentRanking);
}
@@ -73,7 +77,7 @@
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
- mPresenter.getHandler().post(() -> {
+ Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
processForRemoteInput(sbn.getNotification(), mContext);
String key = sbn.getKey();
boolean isUpdate =
@@ -83,7 +87,7 @@
// anyway. This is true also when the summary is canceled,
// because children are automatically canceled by NoMan in that case.
if (!ENABLE_CHILD_NOTIFICATIONS
- && mPresenter.getGroupManager().isChildInGroupWithSummary(sbn)) {
+ && mGroupManager.isChildInGroupWithSummary(sbn)) {
if (DEBUG) {
Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
}
@@ -112,7 +116,7 @@
if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
final String key = sbn.getKey();
- mPresenter.getHandler().post(() -> {
+ Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
mEntryManager.removeNotification(key, rankingMap);
});
}
@@ -123,16 +127,14 @@
if (DEBUG) Log.d(TAG, "onRankingUpdate");
if (rankingMap != null) {
RankingMap r = onPluginRankingUpdate(rankingMap);
- mPresenter.getHandler().post(() -> {
+ Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
mEntryManager.updateNotificationRanking(r);
});
}
}
- public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationEntryManager entryManager) {
+ public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
- mEntryManager = entryManager;
try {
registerAsSystemService(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 89a842e..bc662e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -1,516 +1,61 @@
/*
* Copyright (C) 2017 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
+ * 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
+ * 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;
-import android.app.ActivityManager;
-import android.app.KeyguardManager;
-import android.app.Notification;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-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.Dumpable;
-import com.android.systemui.OverviewProxyService;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Handles keeping track of the current user, profiles, and various things related to hiding
- * contents, redacting notifications, and the lockscreen.
- */
-public class NotificationLockscreenUserManager implements Dumpable, StateListener {
- private static final String TAG = "LockscreenUserManager";
- private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
- public static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
- public static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
+public interface NotificationLockscreenUserManager {
+ String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+ String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
= "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
- private final DevicePolicyManager mDevicePolicyManager;
- private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
- private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
- private final DeviceProvisionedController mDeviceProvisionedController =
- Dependency.get(DeviceProvisionedController.class);
- private final UserManager mUserManager;
- private final IStatusBarService mBarService;
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardManager mKeyguardManager;
- private StatusBarKeyguardViewManager mKeyguardViewManager;
-
- private boolean mShowLockscreenNotifications;
- private boolean mAllowLockscreenRemoteInput;
- private int mState = StatusBarState.SHADE;
-
- protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-
- if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
- isCurrentProfile(getSendingUserId())) {
- mUsersAllowingPrivateNotifications.clear();
- updateLockscreenNotificationSetting();
- mEntryManager.updateNotifications();
- } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
- if (userId != mCurrentUserId && isCurrentProfile(userId)) {
- updatePublicMode();
- mPresenter.onWorkChallengeChanged();
- mEntryManager.updateNotifications();
- }
- }
- }
- };
-
- protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- updateCurrentProfilesCache();
- Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
-
- updateLockscreenNotificationSetting();
- updatePublicMode();
- mPresenter.onUserSwitched(mCurrentUserId);
- mEntryManager.getNotificationData().filterAndSort();
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
- updateCurrentProfilesCache();
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- // Start the overview connection to the launcher service
- Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
- } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
- final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
- if (intentSender != null) {
- try {
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
- if (notificationKey != null) {
- 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 e) {
- /* ignore */
- }
- }
- }
- }
- };
-
- protected final Context mContext;
- protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
-
- protected int mCurrentUserId = 0;
- protected NotificationPresenter mPresenter;
- protected NotificationEntryManager mEntryManager;
- protected ContentObserver mLockscreenSettingsObserver;
- protected ContentObserver mSettingsObserver;
-
- public NotificationLockscreenUserManager(Context context) {
- mContext = context;
- mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mCurrentUserId = ActivityManager.getCurrentUser();
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- mLockPatternUtils = new LockPatternUtils(mContext);
- mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- Dependency.get(StatusBarStateController.class).addListener(this);
- }
-
- public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationEntryManager entryManager) {
- mPresenter = presenter;
- mEntryManager = entryManager;
-
- mLockscreenSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
- // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
- mUsersAllowingPrivateNotifications.clear();
- mUsersAllowingNotifications.clear();
- // ... and refresh all the notifications
- updateLockscreenNotificationSetting();
- mEntryManager.updateNotifications();
- }
- };
-
- mSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- updateLockscreenNotificationSetting();
- if (mDeviceProvisionedController.isDeviceProvisioned()) {
- mEntryManager.updateNotifications();
- }
- }
- };
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
- mLockscreenSettingsObserver,
- UserHandle.USER_ALL);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
- true,
- mLockscreenSettingsObserver,
- UserHandle.USER_ALL);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
- mSettingsObserver);
-
- if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
- false,
- mSettingsObserver,
- UserHandle.USER_ALL);
- }
-
- IntentFilter allUsersFilter = new IntentFilter();
- allUsersFilter.addAction(
- DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
- mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
- null, null);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- filter.addAction(Intent.ACTION_USER_ADDED);
- filter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiver(mBaseBroadcastReceiver, filter);
-
- IntentFilter internalFilter = new IntentFilter();
- internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
- mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
-
- updateCurrentProfilesCache();
-
- mSettingsObserver.onChange(false); // set up
- }
-
- public boolean shouldShowLockscreenNotifications() {
- return mShowLockscreenNotifications;
- }
-
- public boolean shouldAllowLockscreenRemoteInput() {
- return mAllowLockscreenRemoteInput;
- }
-
- public boolean isCurrentProfile(int userId) {
- synchronized (mCurrentProfiles) {
- return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
- }
- }
-
- public void setKeyguardViewManager(StatusBarKeyguardViewManager sbkvm) {
- mKeyguardViewManager = sbkvm;
- }
-
- @Override
- public void onStateChanged(int newState) {
- mState = newState;
- updatePublicMode();
- }
-
- public void updatePublicMode() {
- //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
- // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
- // asking if the keyguard is showing. We still need to check it though because showing the
- // camera on the keyguard has a state of SHADE but the keyguard is still showing.
- boolean showingKeyguard = mState != StatusBarState.SHADE
- || mKeyguardViewManager.isShowing();
- boolean devicePublic = showingKeyguard && mKeyguardViewManager.isSecure(getCurrentUserId());
-
- SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
- for (int i = currentProfiles.size() - 1; i >= 0; i--) {
- final int userId = currentProfiles.valueAt(i).id;
- boolean isProfilePublic = devicePublic;
- if (!devicePublic && userId != mCurrentUserId) {
- // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
- // due to a race condition where this code could be called before
- // TrustManagerService updates its internal records, resulting in an incorrect
- // state being cached in mLockscreenPublicMode. (b/35951989)
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
- && mKeyguardViewManager.isSecure(userId)) {
- isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
- }
- }
- setLockscreenPublicMode(isProfilePublic, userId);
- }
- }
+ boolean shouldAllowLockscreenRemoteInput();
/**
- * Returns true if notifications are temporarily disabled for this user for security reasons,
- * regardless of the normal settings for that user.
+ * @param userId user Id
+ * @return true if we re on a secure lock screen
*/
- private boolean shouldTemporarilyHideNotifications(int userId) {
- if (userId == UserHandle.USER_ALL) {
- userId = mCurrentUserId;
- }
- return KeyguardUpdateMonitor.getInstance(mContext).isUserInLockdown(userId);
- }
+ boolean isLockscreenPublicMode(int userId);
- /**
- * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
- * If so, notifications should be hidden.
- */
- public boolean shouldHideNotifications(int userId) {
- return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
- || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
- || shouldTemporarilyHideNotifications(userId);
- }
+ void setUpWithPresenter(NotificationPresenter presenter);
- /**
- * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
- * package-specific override.
- */
- public boolean shouldHideNotifications(String key) {
- if (mEntryManager == null) {
- Log.wtf(TAG, "mEntryManager was null!", new Throwable());
- return true;
- }
- return isLockscreenPublicMode(mCurrentUserId)
- && mEntryManager.getNotificationData().getVisibilityOverride(key) ==
- Notification.VISIBILITY_SECRET;
- }
+ int getCurrentUserId();
- public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
- if (mEntryManager == null) {
- Log.wtf(TAG, "mEntryManager was null!", new Throwable());
- return false;
- }
- return mShowLockscreenNotifications
- && !mEntryManager.getNotificationData().isAmbient(sbn.getKey());
- }
+ boolean isCurrentProfile(int userId);
- private void setShowLockscreenNotifications(boolean show) {
- mShowLockscreenNotifications = show;
- }
+ void destroy();
- private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
- mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
- }
+ SparseArray<UserInfo> getCurrentProfiles();
- protected void updateLockscreenNotificationSetting() {
- final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- 1,
- mCurrentUserId) != 0;
- final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
- null /* admin */, mCurrentUserId);
- final boolean allowedByDpm = (dpmFlags
- & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+ void setLockscreenPublicMode(boolean isProfilePublic, int userId);
- setShowLockscreenNotifications(show && allowedByDpm);
+ boolean shouldShowLockscreenNotifications();
- if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
- final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
- 0,
- mCurrentUserId) != 0;
- final boolean remoteInputDpm =
- (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+ boolean shouldHideNotifications(int userId);
+ boolean shouldHideNotifications(String key);
+ boolean shouldShowOnKeyguard(StatusBarNotification sbn);
- setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm);
- } else {
- setLockscreenAllowRemoteInput(false);
- }
- }
+ boolean isAnyProfilePublicMode();
- /**
- * Has the given user chosen to allow their private (full) notifications to be shown even
- * when the lockscreen is in "public" (secure & locked) mode?
- */
- public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
+ void updatePublicMode();
- if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
- final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
- DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
- final boolean allowed = allowedByUser && allowedByDpm;
- mUsersAllowingPrivateNotifications.append(userHandle, allowed);
- return allowed;
- }
+ boolean needsRedaction(Entry entry);
- return mUsersAllowingPrivateNotifications.get(userHandle);
- }
-
- private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
- if (userHandle == UserHandle.USER_ALL) {
- return true;
- }
- final int dpmFlags =
- mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle);
- return (dpmFlags & feature) == 0;
- }
-
- /**
- * Save the current "public" (locked and secure) state of the lockscreen.
- */
- public void setLockscreenPublicMode(boolean publicMode, int userId) {
- mLockscreenPublicMode.put(userId, publicMode);
- }
-
- public boolean isLockscreenPublicMode(int userId) {
- if (userId == UserHandle.USER_ALL) {
- return mLockscreenPublicMode.get(mCurrentUserId, false);
- }
- return mLockscreenPublicMode.get(userId, false);
- }
-
- /**
- * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
- * "public" (secure & locked) mode?
- */
- private boolean userAllowsNotificationsInPublic(int userHandle) {
- if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
- return true;
- }
-
- if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
- final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
- DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
- final boolean allowed = allowedByUser && allowedByDpm;
- mUsersAllowingNotifications.append(userHandle, allowed);
- return allowed;
- }
-
- return mUsersAllowingNotifications.get(userHandle);
- }
-
- /** @return true if the entry needs redaction when on the lockscreen. */
- public boolean needsRedaction(NotificationData.Entry ent) {
- int userId = ent.notification.getUserId();
-
- boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
- boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
- boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
-
- boolean notificationRequestsRedaction =
- ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
- boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
-
- return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
- }
-
- private boolean packageHasVisibilityOverride(String key) {
- if (mEntryManager == null) {
- Log.wtf(TAG, "mEntryManager was null!", new Throwable());
- return true;
- }
- return mEntryManager.getNotificationData().getVisibilityOverride(key) ==
- Notification.VISIBILITY_PRIVATE;
- }
-
- private void updateCurrentProfilesCache() {
- synchronized (mCurrentProfiles) {
- mCurrentProfiles.clear();
- if (mUserManager != null) {
- for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
- mCurrentProfiles.put(user.id, user);
- }
- }
- }
- }
-
- public boolean isAnyProfilePublicMode() {
- for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
- if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns the current user id. This can change if the user is switched.
- */
- public int getCurrentUserId() {
- return mCurrentUserId;
- }
-
- public SparseArray<UserInfo> getCurrentProfiles() {
- return mCurrentProfiles;
- }
-
- public void destroy() {
- mContext.unregisterReceiver(mBaseBroadcastReceiver);
- mContext.unregisterReceiver(mAllUsersReceiver);
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("NotificationLockscreenUserManager state:");
- pw.print(" mCurrentUserId=");
- pw.println(mCurrentUserId);
- pw.print(" mShowLockscreenNotifications=");
- pw.println(mShowLockscreenNotifications);
- pw.print(" mAllowLockscreenRemoteInput=");
- pw.println(mAllowLockscreenRemoteInput);
- pw.print(" mCurrentProfiles=");
- for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
- final int userId = mCurrentProfiles.valueAt(i).id;
- pw.print("" + userId + " ");
- }
- pw.println();
- }
+ boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
new file mode 100644
index 0000000..178c5c5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -0,0 +1,551 @@
+/*
+ * 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;
+
+import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
+
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.app.Notification;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+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.Dumpable;
+import com.android.systemui.OverviewProxyService;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Handles keeping track of the current user, profiles, and various things related to hiding
+ * contents, redacting notifications, and the lockscreen.
+ */
+public class NotificationLockscreenUserManagerImpl implements
+ Dumpable, NotificationLockscreenUserManager, StateListener {
+ private static final String TAG = "LockscreenUserManager";
+ private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
+
+ private final DeviceProvisionedController mDeviceProvisionedController =
+ Dependency.get(DeviceProvisionedController.class);
+ private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+
+ // Lazy
+ private NotificationEntryManager mEntryManager;
+
+ private final DevicePolicyManager mDevicePolicyManager;
+ private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
+ private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
+ private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
+ private final UserManager mUserManager;
+ private final IStatusBarService mBarService;
+
+ private boolean mShowLockscreenNotifications;
+ private boolean mAllowLockscreenRemoteInput;
+ private LockPatternUtils mLockPatternUtils;
+ protected KeyguardManager mKeyguardManager;
+ private int mState = StatusBarState.SHADE;
+
+ protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+
+ if (ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
+ isCurrentProfile(getSendingUserId())) {
+ mUsersAllowingPrivateNotifications.clear();
+ updateLockscreenNotificationSetting();
+ getEntryManager().updateNotifications();
+ }
+ }
+ };
+
+ protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ updateCurrentProfilesCache();
+ Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+ updateLockscreenNotificationSetting();
+ updatePublicMode();
+ mPresenter.onUserSwitched(mCurrentUserId);
+ getEntryManager().getNotificationData().filterAndSort();
+ } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ updateCurrentProfilesCache();
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ // Start the overview connection to the launcher service
+ Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+ } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
+ final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ if (intentSender != null) {
+ try {
+ mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
+ }
+ if (notificationKey != null) {
+ final int count =
+ getEntryManager().getNotificationData().getActiveNotifications().size();
+ final int rank = getEntryManager().getNotificationData().getRank(notificationKey);
+ final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
+ rank, count, true);
+ try {
+ mBarService.onNotificationClick(notificationKey, nv);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ };
+
+ protected final Context mContext;
+ protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
+
+ protected int mCurrentUserId = 0;
+ protected NotificationPresenter mPresenter;
+ protected ContentObserver mLockscreenSettingsObserver;
+ protected ContentObserver mSettingsObserver;
+
+ private NotificationEntryManager getEntryManager() {
+ if (mEntryManager == null) {
+ mEntryManager = Dependency.get(NotificationEntryManager.class);
+ }
+ return mEntryManager;
+ }
+
+ public NotificationLockscreenUserManagerImpl(Context context) {
+ mContext = context;
+ mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ Dependency.get(StatusBarStateController.class).addListener(this);
+ mLockPatternUtils = new LockPatternUtils(context);
+ mKeyguardManager = context.getSystemService(KeyguardManager.class);
+ }
+
+ public void setUpWithPresenter(NotificationPresenter presenter) {
+ mPresenter = presenter;
+
+ mLockscreenSettingsObserver = new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
+ @Override
+ public void onChange(boolean selfChange) {
+ // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
+ // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
+ mUsersAllowingPrivateNotifications.clear();
+ mUsersAllowingNotifications.clear();
+ // ... and refresh all the notifications
+ updateLockscreenNotificationSetting();
+ getEntryManager().updateNotifications();
+ }
+ };
+
+ mSettingsObserver = new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateLockscreenNotificationSetting();
+ if (mDeviceProvisionedController.isDeviceProvisioned()) {
+ getEntryManager().updateNotifications();
+ }
+ }
+ };
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
+ mLockscreenSettingsObserver,
+ UserHandle.USER_ALL);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ mLockscreenSettingsObserver,
+ UserHandle.USER_ALL);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
+ mSettingsObserver);
+
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
+ false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+ }
+
+ mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL,
+ new IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ null, null);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ mContext.registerReceiver(mBaseBroadcastReceiver, filter);
+
+ IntentFilter internalFilter = new IntentFilter();
+ internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
+ mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
+
+ updateCurrentProfilesCache();
+
+ mSettingsObserver.onChange(false); // set up
+ }
+
+ public boolean shouldShowLockscreenNotifications() {
+ return mShowLockscreenNotifications;
+ }
+
+ public boolean shouldAllowLockscreenRemoteInput() {
+ return mAllowLockscreenRemoteInput;
+ }
+
+ public boolean isCurrentProfile(int userId) {
+ synchronized (mCurrentProfiles) {
+ return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
+ }
+ }
+
+ /**
+ * Returns true if notifications are temporarily disabled for this user for security reasons,
+ * regardless of the normal settings for that user.
+ */
+ private boolean shouldTemporarilyHideNotifications(int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ userId = mCurrentUserId;
+ }
+ return KeyguardUpdateMonitor.getInstance(mContext).isUserInLockdown(userId);
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
+ * If so, notifications should be hidden.
+ */
+ public boolean shouldHideNotifications(int userId) {
+ return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
+ || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
+ || shouldTemporarilyHideNotifications(userId);
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
+ * package-specific override.
+ */
+ public boolean shouldHideNotifications(String key) {
+ if (getEntryManager() == null) {
+ Log.wtf(TAG, "mEntryManager was null!", new Throwable());
+ return true;
+ }
+ return isLockscreenPublicMode(mCurrentUserId)
+ && getEntryManager().getNotificationData().getVisibilityOverride(key) ==
+ Notification.VISIBILITY_SECRET;
+ }
+
+ public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+ if (getEntryManager() == null) {
+ Log.wtf(TAG, "mEntryManager was null!", new Throwable());
+ return false;
+ }
+ return mShowLockscreenNotifications
+ && !getEntryManager().getNotificationData().isAmbient(sbn.getKey());
+ }
+
+ private void setShowLockscreenNotifications(boolean show) {
+ mShowLockscreenNotifications = show;
+ }
+
+ private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
+ mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
+ }
+
+ protected void updateLockscreenNotificationSetting() {
+ final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ 1,
+ mCurrentUserId) != 0;
+ final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
+ null /* admin */, mCurrentUserId);
+ final boolean allowedByDpm = (dpmFlags
+ & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+
+ setShowLockscreenNotifications(show && allowedByDpm);
+
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+ 0,
+ mCurrentUserId) != 0;
+ final boolean remoteInputDpm =
+ (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+
+ setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm);
+ } else {
+ setLockscreenAllowRemoteInput(false);
+ }
+ }
+
+ /**
+ * Has the given user chosen to allow their private (full) notifications to be shown even
+ * when the lockscreen is in "public" (secure & locked) mode?
+ */
+ public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+
+ if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
+ final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
+ DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+ final boolean allowed = allowedByUser && allowedByDpm;
+ mUsersAllowingPrivateNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingPrivateNotifications.get(userHandle);
+ }
+
+ private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+ final int dpmFlags =
+ mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle);
+ return (dpmFlags & feature) == 0;
+ }
+
+ /**
+ * Save the current "public" (locked and secure) state of the lockscreen.
+ */
+ public void setLockscreenPublicMode(boolean publicMode, int userId) {
+ mLockscreenPublicMode.put(userId, publicMode);
+ }
+
+ public boolean isLockscreenPublicMode(int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return mLockscreenPublicMode.get(mCurrentUserId, false);
+ }
+ return mLockscreenPublicMode.get(userId, false);
+ }
+
+ /**
+ * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+ * "public" (secure & locked) mode?
+ */
+ private boolean userAllowsNotificationsInPublic(int userHandle) {
+ if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
+ return true;
+ }
+
+ if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+ final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
+ DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+ final boolean allowed = allowedByUser && allowedByDpm;
+ mUsersAllowingNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingNotifications.get(userHandle);
+ }
+
+ /** @return true if the entry needs redaction when on the lockscreen. */
+ public boolean needsRedaction(NotificationData.Entry ent) {
+ int userId = ent.notification.getUserId();
+
+ boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
+ boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
+ boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
+
+ boolean notificationRequestsRedaction =
+ ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
+ boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
+
+ return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
+ }
+
+ private boolean packageHasVisibilityOverride(String key) {
+ if (getEntryManager() == null) {
+ Log.wtf(TAG, "mEntryManager was null!", new Throwable());
+ return true;
+ }
+ return getEntryManager().getNotificationData().getVisibilityOverride(key) ==
+ Notification.VISIBILITY_PRIVATE;
+ }
+
+ private void updateCurrentProfilesCache() {
+ synchronized (mCurrentProfiles) {
+ mCurrentProfiles.clear();
+ if (mUserManager != null) {
+ for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
+ mCurrentProfiles.put(user.id, user);
+ }
+ }
+ }
+ }
+
+ public boolean isAnyProfilePublicMode() {
+ for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+ if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the current user id. This can change if the user is switched.
+ */
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
+ public SparseArray<UserInfo> getCurrentProfiles() {
+ return mCurrentProfiles;
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ mState = newState;
+ updatePublicMode();
+ }
+
+ public void updatePublicMode() {
+ //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
+ // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
+ // asking if the keyguard is showing. We still need to check it though because showing the
+ // camera on the keyguard has a state of SHADE but the keyguard is still showing.
+ final boolean showingKeyguard = mState != StatusBarState.SHADE
+ || mKeyguardMonitor.isShowing();
+ final boolean devicePublic = showingKeyguard && isSecure(getCurrentUserId());
+
+
+ // Look for public mode users. Users are considered public in either case of:
+ // - device keyguard is shown in secure mode;
+ // - profile is locked with a work challenge.
+ SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
+ for (int i = currentProfiles.size() - 1; i >= 0; i--) {
+ final int userId = currentProfiles.valueAt(i).id;
+ boolean isProfilePublic = devicePublic;
+ if (!devicePublic && userId != getCurrentUserId()) {
+ // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
+ // due to a race condition where this code could be called before
+ // TrustManagerService updates its internal records, resulting in an incorrect
+ // state being cached in mLockscreenPublicMode. (b/35951989)
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+ && isSecure(userId)) {
+ isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
+ }
+ }
+ setLockscreenPublicMode(isProfilePublic, userId);
+ }
+ }
+
+
+// public void updatePublicMode() {
+// //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
+// // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
+// // asking if the keyguard is showing. We still need to check it though because showing the
+// // camera on the keyguard has a state of SHADE but the keyguard is still showing.
+// final boolean showingKeyguard = mState != StatusBarState.SHADE
+// || mKeyguardMonitor.isShowing();
+// final boolean devicePublic = showingKeyguard && isSecure(getCurrentUserId());
+//
+//
+// // Look for public mode users. Users are considered public in either case of:
+// // - device keyguard is shown in secure mode;
+// // - profile is locked with a work challenge.
+// SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
+// for (int i = currentProfiles.size() - 1; i >= 0; i--) {
+// final int userId = currentProfiles.valueAt(i).id;
+// boolean isProfilePublic = devicePublic;
+// if (!devicePublic && userId != getCurrentUserId()) {
+// // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
+// // due to a race condition where this code could be called before
+// // TrustManagerService updates its internal records, resulting in an incorrect
+// // state being cached in mLockscreenPublicMode. (b/35951989)
+// if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+// && isSecure(userId)) {
+// isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
+// }
+// }
+// setLockscreenPublicMode(isProfilePublic, userId);
+// }
+// }
+
+ private boolean isSecure(int userId) {
+ return mKeyguardMonitor.isSecure() || mLockPatternUtils.isSecure(userId);
+ }
+
+ public void destroy() {
+ mContext.unregisterReceiver(mBaseBroadcastReceiver);
+ mContext.unregisterReceiver(mAllUsersReceiver);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("NotificationLockscreenUserManager state:");
+ pw.print(" mCurrentUserId=");
+ pw.println(mCurrentUserId);
+ pw.print(" mShowLockscreenNotifications=");
+ pw.println(mShowLockscreenNotifications);
+ pw.print(" mAllowLockscreenRemoteInput=");
+ pw.println(mAllowLockscreenRemoteInput);
+ pw.print(" mCurrentProfiles=");
+ for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+ final int userId = mCurrentProfiles.valueAt(i).id;
+ pw.print("" + userId + " ");
+ }
+ pw.println();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 2db9945..67b21e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -15,19 +15,46 @@
*/
package com.android.systemui.statusbar;
+import static com.android.systemui.Dependency.MAIN_HANDLER;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK;
+import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER;
+import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK;
+
+import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
+import android.os.Handler;
+import android.os.Trace;
import android.os.UserHandle;
import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
+import com.android.systemui.Interpolators;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.LockscreenWallpaper;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ScrimState;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -42,15 +69,45 @@
private static final String TAG = "NotificationMediaManager";
public static final boolean DEBUG_MEDIA = false;
+ private final StatusBarStateController mStatusBarStateController
+ = Dependency.get(StatusBarStateController.class);
+ private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+ private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+
+ // Late binding
+ private NotificationEntryManager mEntryManager;
+
+ // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
+ @Nullable
+ private ShadeController mShadeController;
+ @Nullable
+ private StatusBarWindowController mStatusBarWindowController;
+
+ @Nullable
+ private BiometricUnlockController mBiometricUnlockController;
+ @Nullable
+ private ScrimController mScrimController;
+ @Nullable
+ private LockscreenWallpaper mLockscreenWallpaper;
+
+ protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
+ protected final PorterDuffXfermode mSrcOverXferMode =
+ new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
+
+ private final Handler mHandler = Dependency.get(MAIN_HANDLER);
+
private final Context mContext;
private final MediaSessionManager mMediaSessionManager;
protected NotificationPresenter mPresenter;
- protected NotificationEntryManager mEntryManager;
private MediaController mMediaController;
private String mMediaNotificationKey;
private MediaMetadata mMediaMetadata;
+ private BackDropView mBackdrop;
+ private ImageView mBackdropFront;
+ private ImageView mBackdropBack;
+
private final MediaController.Callback mMediaListener = new MediaController.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
@@ -77,6 +134,29 @@
}
};
+ @Nullable
+ private ShadeController getShadeController() {
+ if (mShadeController == null) {
+ mShadeController = Dependency.get(ShadeController.class);
+ }
+ return mShadeController;
+ }
+
+ @Nullable
+ private StatusBarWindowController getWindowController() {
+ if (mStatusBarWindowController == null) {
+ mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+ }
+ return mStatusBarWindowController;
+ }
+
+ private NotificationEntryManager getEntryManager() {
+ if (mEntryManager == null) {
+ mEntryManager = Dependency.get(NotificationEntryManager.class);
+ }
+ return mEntryManager;
+ }
+
public NotificationMediaManager(Context context) {
mContext = context;
mMediaSessionManager
@@ -85,10 +165,8 @@
// in session state
}
- public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationEntryManager entryManager) {
+ public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
- mEntryManager = entryManager;
}
public void onNotificationRemoved(String key) {
@@ -109,8 +187,9 @@
public void findAndUpdateMediaNotifications() {
boolean metaDataChanged = false;
- synchronized (mEntryManager.getNotificationData()) {
- ArrayList<NotificationData.Entry> activeNotifications = mEntryManager
+ NotificationEntryManager manager = getEntryManager();
+ synchronized (manager.getNotificationData()) {
+ ArrayList<NotificationData.Entry> activeNotifications = manager
.getNotificationData().getActiveNotifications();
final int N = activeNotifications.size();
@@ -199,7 +278,7 @@
}
if (metaDataChanged) {
- mEntryManager.updateNotifications();
+ getEntryManager().updateNotifications();
}
mPresenter.updateMediaMetaData(metaDataChanged, true);
}
@@ -272,4 +351,202 @@
}
mMediaController = null;
}
+
+ /**
+ * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
+ */
+ public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
+ Trace.beginSection("StatusBar#updateMediaMetaData");
+ if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
+ Trace.endSection();
+ return;
+ }
+
+ if (mBackdrop == null) {
+ Trace.endSection();
+ return; // called too early
+ }
+
+ boolean wakeAndUnlock = mBiometricUnlockController != null
+ && mBiometricUnlockController.isWakeAndUnlock();
+ if (mKeyguardMonitor.isLaunchTransitionFadingAway() || wakeAndUnlock) {
+ mBackdrop.setVisibility(View.INVISIBLE);
+ Trace.endSection();
+ return;
+ }
+
+ MediaMetadata mediaMetadata = getMediaMetadata();
+
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
+ + getMediaNotificationKey()
+ + " metadata=" + mediaMetadata
+ + " metaDataChanged=" + metaDataChanged
+ + " state=" + mStatusBarStateController.getState());
+ }
+
+ Drawable artworkDrawable = null;
+ if (mediaMetadata != null) {
+ Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+ if (artworkBitmap == null) {
+ artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ // might still be null
+ }
+ if (artworkBitmap != null) {
+ artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
+ }
+ }
+ boolean allowWhenShade = false;
+ if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
+ Bitmap lockWallpaper =
+ mLockscreenWallpaper != null ? mLockscreenWallpaper.getBitmap() : null;
+ if (lockWallpaper != null) {
+ artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
+ mBackdropBack.getResources(), lockWallpaper);
+ // We're in the SHADE mode on the SIM screen - yet we still need to show
+ // the lockscreen wallpaper in that mode.
+ allowWhenShade = mStatusBarStateController.getState() == KEYGUARD;
+ }
+ }
+
+ boolean hideBecauseOccluded = getShadeController() != null
+ && getShadeController().isOccluded();
+
+ final boolean hasArtwork = artworkDrawable != null;
+ mColorExtractor.setHasBackdrop(hasArtwork);
+ if (mScrimController != null) {
+ mScrimController.setHasBackdrop(hasArtwork);
+ }
+
+ if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
+ && (mStatusBarStateController.getState() != StatusBarState.SHADE || allowWhenShade)
+ && mBiometricUnlockController != null && mBiometricUnlockController.getMode()
+ != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ && !hideBecauseOccluded) {
+ // time to show some art!
+ if (mBackdrop.getVisibility() != View.VISIBLE) {
+ mBackdrop.setVisibility(View.VISIBLE);
+ if (allowEnterAnimation) {
+ mBackdrop.setAlpha(0);
+ mBackdrop.animate().alpha(1f);
+ } else {
+ mBackdrop.animate().cancel();
+ mBackdrop.setAlpha(1f);
+ }
+ if (getWindowController() != null) {
+ getWindowController().setBackdropShowing(true);
+ }
+ metaDataChanged = true;
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
+ }
+ }
+ if (metaDataChanged) {
+ if (mBackdropBack.getDrawable() != null) {
+ Drawable drawable =
+ mBackdropBack.getDrawable().getConstantState()
+ .newDrawable(mBackdropFront.getResources()).mutate();
+ mBackdropFront.setImageDrawable(drawable);
+ mBackdropFront.setAlpha(1f);
+ mBackdropFront.setVisibility(View.VISIBLE);
+ } else {
+ mBackdropFront.setVisibility(View.INVISIBLE);
+ }
+
+ if (DEBUG_MEDIA_FAKE_ARTWORK) {
+ final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
+ Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
+ mBackdropBack.setBackgroundColor(0xFFFFFFFF);
+ mBackdropBack.setImageDrawable(new ColorDrawable(c));
+ } else {
+ mBackdropBack.setImageDrawable(artworkDrawable);
+ }
+
+ if (mBackdropFront.getVisibility() == View.VISIBLE) {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
+ + mBackdropFront.getDrawable()
+ + " to "
+ + mBackdropBack.getDrawable());
+ }
+ mBackdropFront.animate()
+ .setDuration(250)
+ .alpha(0f).withEndAction(mHideBackdropFront);
+ }
+ }
+ } else {
+ // need to hide the album art, either because we are unlocked, on AOD
+ // or because the metadata isn't there to support it
+ if (mBackdrop.getVisibility() != View.GONE) {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
+ }
+ boolean cannotAnimateDoze = getShadeController() != null
+ && getShadeController().isDozing()
+ && !ScrimState.AOD.getAnimateChange();
+ if (mBiometricUnlockController != null && mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ || hideBecauseOccluded || cannotAnimateDoze) {
+
+ // We are unlocking directly - no animation!
+ mBackdrop.setVisibility(View.GONE);
+ mBackdropBack.setImageDrawable(null);
+ if (getWindowController() != null) {
+ getWindowController().setBackdropShowing(false);
+ }
+ } else {
+ if (getWindowController() != null) {
+ getWindowController().setBackdropShowing(false);
+ }
+ mBackdrop.animate()
+ .alpha(0)
+ .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
+ .setDuration(300)
+ .setStartDelay(0)
+ .withEndAction(() -> {
+ mBackdrop.setVisibility(View.GONE);
+ mBackdropFront.animate().cancel();
+ mBackdropBack.setImageDrawable(null);
+ mHandler.post(mHideBackdropFront);
+ });
+ if (mKeyguardMonitor.isKeyguardFadingAway()) {
+ mBackdrop.animate()
+ // Make it disappear faster, as the focus should be on the activity
+ // behind.
+ .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+ .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
+ .setInterpolator(Interpolators.LINEAR)
+ .start();
+ }
+ }
+ }
+ }
+ Trace.endSection();
+ }
+
+ public void setup(BackDropView backdrop, ImageView backdropFront, ImageView backdropBack,
+ BiometricUnlockController biometricUnlockController, ScrimController scrimController,
+ LockscreenWallpaper lockscreenWallpaper) {
+ mBackdrop = backdrop;
+ mBackdropFront = backdropFront;
+ mBackdropBack = backdropBack;
+ mBiometricUnlockController = biometricUnlockController;
+ mScrimController = scrimController;
+ mLockscreenWallpaper = lockscreenWallpaper;
+ }
+
+ /**
+ * Hide the album artwork that is fading out and release its bitmap.
+ */
+ protected final Runnable mHideBackdropFront = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
+ }
+ mBackdropFront.setVisibility(View.INVISIBLE);
+ mBackdropFront.animate().cancel();
+ mBackdropFront.setImageDrawable(null);
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index c58eb80..5c8f4cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -19,6 +19,7 @@
import android.os.Handler;
import android.view.View;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -31,9 +32,7 @@
* for affecting the state of the system (e.g. starting an intent, given that the presenter may
* want to perform some action before doing so).
*/
-public interface NotificationPresenter extends NotificationData.Environment,
- NotificationRemoteInputManager.Callback,
- ExpandableNotificationRow.OnExpandClickListener,
+public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener,
ActivatableNotificationView.OnActivatedListener,
NotificationEntryManager.Callback {
/**
@@ -43,59 +42,23 @@
boolean isPresenterFullyCollapsed();
/**
- * Returns true if the presenter is locked. For example, if the keyguard is active.
- */
- boolean isPresenterLocked();
-
- /**
* 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);
/**
- * Returns the Handler for NotificationPresenter.
- */
- Handler getHandler();
-
- /**
* Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
*/
void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation);
/**
- * Called when the locked status of the device is changed for a work profile.
- */
- void onWorkChallengeChanged();
-
- /**
* Called when the current user changes.
* @param newUserId new user id
*/
void onUserSwitched(int newUserId);
/**
- * Gets the NotificationLockscreenUserManager for this Presenter.
- */
- NotificationLockscreenUserManager getNotificationLockscreenUserManager();
-
- /**
- * Wakes the device up if dozing.
- *
- * @param time the time when the request to wake up was issued
- * @param where which view caused this wake up request
- */
- void wakeUpIfDozing(long time, View where);
-
- /**
- * True if the device currently requires a PIN, pattern, or password to unlock.
- *
- * @param userId user id to query about
- * @return true iff the device is locked
- */
- boolean isDeviceLocked(int userId);
-
- /**
* @return true iff the device is in vr mode
*/
boolean isDeviceInVrMode();
@@ -114,7 +77,36 @@
int getMaxNotificationsWhileLocked(boolean recompute);
/**
- * Called when the row states are updated by NotificationViewHierarchyManager.
+ * True if the presenter
+ * @return
+ */
+ default boolean isPresenterLocked() { return false; }
+
+ /**
+ * Called when the row states are updated by {@link NotificationViewHierarchyManager}.
*/
void onUpdateRowStates();
+
+ /**
+ * @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;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index ea7e03e..f30377e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
@@ -46,9 +47,11 @@
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
+import com.android.systemui.InitController;
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.phone.ShadeController;
import com.android.systemui.statusbar.policy.RemoteInputView;
import java.io.FileDescriptor;
@@ -97,13 +100,18 @@
Dependency.get(NotificationLockscreenUserManager.class);
protected final SmartReplyController mSmartReplyController =
Dependency.get(SmartReplyController.class);
+ private final NotificationEntryManager mEntryManager
+ = Dependency.get(NotificationEntryManager.class);
+
+ // Lazy
+ private ShadeController mShadeController;
protected final Context mContext;
private final UserManager mUserManager;
+ private final KeyguardManager mKeyguardManager;
protected RemoteInputController mRemoteInputController;
protected NotificationPresenter mPresenter;
- protected NotificationEntryManager mEntryManager;
protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
mNotificationLifetimeFinishedCallback;
protected IStatusBarService mBarService;
@@ -115,7 +123,7 @@
@Override
public boolean onClickHandler(
final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
- mPresenter.wakeUpIfDozing(SystemClock.uptimeMillis(), view);
+ getShadeController().wakeUpIfDozing(SystemClock.uptimeMillis(), view);
if (handleRemoteInput(view, pendingIntent)) {
return true;
@@ -240,7 +248,7 @@
return true;
}
if (mUserManager.getUserInfo(userId).isManagedProfile()
- && mPresenter.isDeviceLocked(userId)) {
+ && mKeyguardManager.isDeviceLocked(userId)) {
mCallback.onLockedWorkRemoteInput(userId, row, view);
return true;
}
@@ -291,20 +299,26 @@
}
};
+ private ShadeController getShadeController() {
+ if (mShadeController == null) {
+ mShadeController = Dependency.get(ShadeController.class);
+ }
+ return mShadeController;
+ }
+
public NotificationRemoteInputManager(Context context) {
mContext = context;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
addLifetimeExtenders();
+ mKeyguardManager = context.getSystemService(KeyguardManager.class);
}
public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationEntryManager entryManager,
Callback callback,
RemoteInputController.Delegate delegate) {
mPresenter = presenter;
- mEntryManager = entryManager;
mCallback = callback;
mRemoteInputController = new RemoteInputController(delegate);
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@@ -318,7 +332,7 @@
// view it is already canceled, so we'll need to cancel it on the apps behalf
// after sending - unless the app posts an update in the mean time, so wait a
// bit.
- mPresenter.getHandler().postDelayed(() -> {
+ Dependency.get(Dependency.MAIN_HANDLER).postDelayed(() -> {
if (mEntriesKeptForRemoteInputActive.remove(entry)) {
mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 1495abf..cd3da123 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -34,6 +34,7 @@
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -103,7 +104,8 @@
}
@Override
- protected void onFinishInflate() {
+ @VisibleForTesting
+ public void onFinishInflate() {
super.onFinishInflate();
mShelfIcons = findViewById(R.id.content);
mShelfIcons.setClipChildren(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 5b3082b..92765bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -24,6 +24,7 @@
import android.view.ViewGroup;
import com.android.systemui.Dependency;
+import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -31,6 +32,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
import java.util.ArrayList;
import java.util.HashMap;
@@ -57,6 +59,13 @@
Dependency.get(NotificationGroupManager.class);
protected final VisualStabilityManager mVisualStabilityManager =
Dependency.get(VisualStabilityManager.class);
+ private final StatusBarStateController mStatusBarStateController =
+ Dependency.get(StatusBarStateController.class);
+ private final NotificationEntryManager mEntryManager =
+ Dependency.get(NotificationEntryManager.class);
+
+ // Lazy
+ private ShadeController mShadeController;
/**
* {@code true} if notifications not part of a group should by default be rendered in their
@@ -66,9 +75,15 @@
private final boolean mAlwaysExpandNonGroupedNotification;
private NotificationPresenter mPresenter;
- private NotificationEntryManager mEntryManager;
private NotificationListContainer mListContainer;
+ private ShadeController getShadeController() {
+ if (mShadeController == null) {
+ mShadeController = Dependency.get(ShadeController.class);
+ }
+ return mShadeController;
+ }
+
public NotificationViewHierarchyManager(Context context) {
Resources res = context.getResources();
mAlwaysExpandNonGroupedNotification =
@@ -76,9 +91,8 @@
}
public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationEntryManager entryManager, NotificationListContainer listContainer) {
+ NotificationListContainer listContainer) {
mPresenter = presenter;
- mEntryManager = entryManager;
mListContainer = listContainer;
}
@@ -291,9 +305,9 @@
final int N = mListContainer.getContainerChildCount();
int visibleNotifications = 0;
- boolean isLocked = mPresenter.isPresenterLocked();
+ boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
int maxNotifications = -1;
- if (isLocked) {
+ if (onKeyguard) {
maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
}
mListContainer.setMaxDisplayedNotifications(maxNotifications);
@@ -311,9 +325,9 @@
boolean isChildNotification =
mGroupManager.isChildInGroupWithSummary(entry.notification);
- row.setOnKeyguard(isLocked);
+ row.setOnKeyguard(onKeyguard);
- if (!isLocked) {
+ if (!onKeyguard) {
// If mAlwaysExpandNonGroupedNotification is false, then only expand the
// very first notification and if it's not a child of grouped notifications.
row.setSystemExpanded(mAlwaysExpandNonGroupedNotification
@@ -321,7 +335,7 @@
&& !row.isLowPriority()));
}
- entry.row.setOnAmbient(mPresenter.isDozing());
+ entry.row.setOnAmbient(getShadeController().isDozing());
int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.row.isRemoved();
@@ -340,7 +354,7 @@
}
if (suppressedSummary
|| mLockscreenUserManager.shouldHideNotifications(userId)
- || (isLocked && !showOnKeyguard)) {
+ || (onKeyguard && !showOnKeyguard)) {
entry.row.setVisibility(View.GONE);
} else {
boolean wasGone = entry.row.getVisibility() == View.GONE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index 78a5817..12c0fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -44,6 +44,7 @@
private int mState;
private int mLastState;
private boolean mLeaveOpenOnKeyguardHide;
+ private boolean mKeyguardRequested;
// TODO: b/115739177 (remove this explicit ordering if we can)
@Retention(SOURCE)
@@ -173,6 +174,14 @@
}
}
+ public void setKeyguardRequested(boolean keyguardRequested) {
+ mKeyguardRequested = keyguardRequested;
+ }
+
+ public boolean isKeyguardRequested() {
+ return mKeyguardRequested;
+ }
+
public static String describe(int state) {
return StatusBarState.toShortString(state);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 24665ea..8799341 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -525,12 +525,6 @@
}
@Override
- public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
- // Do nothing, we don't want to display media art in the lock screen for a car.
- }
-
-
- @Override
public void animateExpandNotificationsPanel() {
// Because space is usually constrained in the auto use-case, there should not be a
// pinned notification when the shade has been expanded. Ensure this by removing all heads-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java
index 8cae806..9e99fbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AppOpsListener.java
@@ -33,10 +33,11 @@
// Dependencies:
private final ForegroundServiceController mFsc =
Dependency.get(ForegroundServiceController.class);
+ private final NotificationEntryManager mEntryManager =
+ Dependency.get(NotificationEntryManager.class);
private final Context mContext;
protected NotificationPresenter mPresenter;
- protected NotificationEntryManager mEntryManager;
protected final AppOpsManager mAppOps;
protected static final int[] OPS = new int[] {AppOpsManager.OP_CAMERA,
@@ -48,10 +49,8 @@
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
- public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationEntryManager entryManager) {
+ public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
- mEntryManager = entryManager;
mAppOps.startWatchingActive(OPS, this);
}
@@ -62,7 +61,7 @@
@Override
public void onOpActiveChanged(int code, int uid, String packageName, boolean active) {
mFsc.onAppOpChanged(code, uid, packageName, active);
- mPresenter.getHandler().post(() -> {
+ Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index fbf12ed..3539fff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -51,21 +51,22 @@
import android.view.View;
import android.widget.ImageView;
-import androidx.annotation.Nullable;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.ZenModeController;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -74,16 +75,23 @@
import java.util.List;
import java.util.Objects;
+import androidx.annotation.Nullable;
+
/**
* The list of currently displaying notifications.
*/
public class NotificationData {
- private final Environment mEnvironment;
- private HeadsUpManager mHeadsUpManager;
+ /**
+ * These dependencies are late init-ed
+ */
+ private KeyguardEnvironment mEnvironment;
+ private ShadeController mShadeController;
+ private NotificationMediaManager mMediaManager;
+ private ForegroundServiceController mFsc;
+ private NotificationLockscreenUserManager mUserManager;
- final ZenModeController mZen = Dependency.get(ZenModeController.class);
- final ForegroundServiceController mFsc = Dependency.get(ForegroundServiceController.class);
+ private HeadsUpManager mHeadsUpManager;
public static final class Entry {
private static final long LAUNCH_COOLDOWN = 2000;
@@ -375,7 +383,8 @@
private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
private final ArrayList<Entry> mFilteredForUser = new ArrayList<>();
- private NotificationGroupManager mGroupManager;
+ private final NotificationGroupManager mGroupManager
+ = Dependency.get(NotificationGroupManager.class);
private RankingMap mRankingMap;
private final Ranking mTmpRanking = new Ranking();
@@ -407,7 +416,7 @@
bRank = mRankingB.getRank();
}
- String mediaNotification = mEnvironment.getCurrentMediaNotificationKey();
+ String mediaNotification = getMediaManager().getMediaNotificationKey();
// IMPORTANCE_MIN media streams are allowed to drift to the bottom
final boolean aMedia = a.key.equals(mediaNotification)
@@ -442,13 +451,43 @@
}
};
- public NotificationData(Environment environment) {
- mEnvironment = environment;
- mGroupManager = environment.getGroupManager();
+ private KeyguardEnvironment getEnvironment() {
+ if (mEnvironment == null) {
+ mEnvironment = Dependency.get(KeyguardEnvironment.class);
+ }
+ return mEnvironment;
+ }
+
+ private ShadeController getShadeController() {
+ if (mShadeController == null) {
+ mShadeController = Dependency.get(ShadeController.class);
+ }
+ return mShadeController;
+ }
+
+ private NotificationMediaManager getMediaManager() {
+ if (mMediaManager == null) {
+ mMediaManager = Dependency.get(NotificationMediaManager.class);
+ }
+ return mMediaManager;
+ }
+
+ private ForegroundServiceController getFsc() {
+ if (mFsc == null) {
+ mFsc = Dependency.get(ForegroundServiceController.class);
+ }
+ return mFsc;
+ }
+
+ private NotificationLockscreenUserManager getUserManager() {
+ if (mUserManager == null) {
+ mUserManager = Dependency.get(NotificationLockscreenUserManager.class);
+ }
+ return mUserManager;
}
/**
- * Returns the sorted list of active notifications (depending on {@link Environment}
+ * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
*
* <p>
* This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
@@ -468,7 +507,7 @@
for (int i = 0; i < N; i++) {
Entry entry = mEntries.valueAt(i);
final StatusBarNotification sbn = entry.notification;
- if (!mEnvironment.isNotificationForCurrentProfiles(sbn)) {
+ if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
continue;
}
mFilteredForUser.add(entry);
@@ -719,27 +758,27 @@
*/
public boolean shouldFilterOut(Entry entry) {
final StatusBarNotification sbn = entry.notification;
- if (!(mEnvironment.isDeviceProvisioned() ||
+ if (!(getEnvironment().isDeviceProvisioned() ||
showNotificationEvenIfUnprovisioned(sbn))) {
return true;
}
- if (!mEnvironment.isNotificationForCurrentProfiles(sbn)) {
+ if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
return true;
}
- if (mEnvironment.isSecurelyLocked(sbn.getUserId()) &&
+ if (getUserManager().isLockscreenPublicMode(sbn.getUserId()) &&
(sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
- || mEnvironment.shouldHideNotifications(sbn.getUserId())
- || mEnvironment.shouldHideNotifications(sbn.getKey()))) {
+ || getUserManager().shouldHideNotifications(sbn.getUserId())
+ || getUserManager().shouldHideNotifications(sbn.getKey()))) {
return true;
}
- if (mEnvironment.isDozing() && shouldSuppressAmbient(entry)) {
+ if (getShadeController().isDozing() && shouldSuppressAmbient(entry)) {
return true;
}
- if (!mEnvironment.isDozing() && shouldSuppressNotificationList(entry)) {
+ if (!getShadeController().isDozing() && shouldSuppressNotificationList(entry)) {
return true;
}
@@ -752,15 +791,16 @@
return true;
}
- if (mFsc.isDungeonNotification(sbn) && !mFsc.isDungeonNeededForUser(sbn.getUserId())) {
+ if (getFsc().isDungeonNotification(sbn)
+ && !getFsc().isDungeonNeededForUser(sbn.getUserId())) {
// this is a foreground-service disclosure for a user that does not need to show one
return true;
}
- if (mFsc.isSystemAlertNotification(sbn)) {
+ if (getFsc().isSystemAlertNotification(sbn)) {
final String[] apps = sbn.getNotification().extras.getStringArray(
Notification.EXTRA_FOREGROUND_APPS);
if (apps != null && apps.length >= 1) {
- if (!mFsc.isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) {
+ if (!getFsc().isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) {
return true;
}
}
@@ -838,18 +878,8 @@
/**
* Provides access to keyguard state and user settings dependent data.
*/
- public interface Environment {
- public boolean isSecurelyLocked(int userId);
- public boolean shouldHideNotifications(int userid);
- public boolean shouldHideNotifications(String key);
- public boolean isDeviceProvisioned();
- public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
- public String getCurrentMediaNotificationKey();
- public NotificationGroupManager getGroupManager();
-
- /**
- * @return true iff the device is dozing
- */
- boolean isDozing();
+ public interface KeyguardEnvironment {
+ boolean isDeviceProvisioned();
+ boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 28d339a..d136c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -62,6 +62,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
@@ -74,13 +75,15 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -110,33 +113,31 @@
protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>();
protected final NotificationClicker mNotificationClicker = new NotificationClicker();
- // Dependencies:
- protected final NotificationLockscreenUserManager mLockscreenUserManager =
- Dependency.get(NotificationLockscreenUserManager.class);
- protected final NotificationGroupManager mGroupManager =
+ private final NotificationGroupManager mGroupManager =
Dependency.get(NotificationGroupManager.class);
- protected final NotificationGutsManager mGutsManager =
+ private final NotificationGutsManager mGutsManager =
Dependency.get(NotificationGutsManager.class);
- protected final NotificationRemoteInputManager mRemoteInputManager =
- Dependency.get(NotificationRemoteInputManager.class);
- protected final NotificationMediaManager mMediaManager =
- Dependency.get(NotificationMediaManager.class);
- protected final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
- protected final DeviceProvisionedController mDeviceProvisionedController =
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ private final DeviceProvisionedController mDeviceProvisionedController =
Dependency.get(DeviceProvisionedController.class);
- protected final VisualStabilityManager mVisualStabilityManager =
+ private final VisualStabilityManager mVisualStabilityManager =
Dependency.get(VisualStabilityManager.class);
- protected final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
- protected final ForegroundServiceController mForegroundServiceController =
+ private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+ private final ForegroundServiceController mForegroundServiceController =
Dependency.get(ForegroundServiceController.class);
- protected final NotificationListener mNotificationListener =
- Dependency.get(NotificationListener.class);
- protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
+ private final AmbientPulseManager mAmbientPulseManager =
+ Dependency.get(AmbientPulseManager.class);
+
+ // Lazily retrieved dependencies
+ private NotificationRemoteInputManager mRemoteInputManager;
+ private NotificationMediaManager mMediaManager;
+ private NotificationListener mNotificationListener;
+ private ShadeController mShadeController;
protected IDreamManager mDreamManager;
protected IStatusBarService mBarService;
- protected NotificationPresenter mPresenter;
- protected Callback mCallback;
+ private NotificationPresenter mPresenter;
+ private Callback mCallback;
protected PowerManager mPowerManager;
protected NotificationListenerService.RankingMap mLatestRankingMap;
protected HeadsUpManager mHeadsUpManager;
@@ -149,7 +150,6 @@
= new ArrayList<>();
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
-
private final class NotificationClicker implements View.OnClickListener {
@Override
@@ -159,7 +159,7 @@
return;
}
- mPresenter.wakeUpIfDozing(SystemClock.uptimeMillis(), v);
+ getShadeController().wakeUpIfDozing(SystemClock.uptimeMillis(), v);
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
final StatusBarNotification sbn = row.getStatusBarNotification();
@@ -232,20 +232,55 @@
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.checkService(DreamService.DREAM_SERVICE));
mMessagingUtil = new NotificationMessagingUtil(context);
+ mNotificationData = new NotificationData();
+ Dependency.get(InitController.class).addPostInitTask(this::onPostInit);
+ }
+
+ private void onPostInit() {
mGroupManager.setPendingEntries(mPendingNotifications);
}
+ /**
+ * Our dependencies can have cyclic references, so some need to be lazy
+ */
+ private NotificationRemoteInputManager getRemoteInputManager() {
+ if (mRemoteInputManager == null) {
+ mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
+ }
+ return mRemoteInputManager;
+ }
+
+ private NotificationMediaManager getMediaManager() {
+ if (mMediaManager == null) {
+ mMediaManager = Dependency.get(NotificationMediaManager.class);
+ }
+ return mMediaManager;
+ }
+
+ private NotificationListener getNotificationListener() {
+ if (mNotificationListener == null) {
+ mNotificationListener = Dependency.get(NotificationListener.class);
+ }
+ return mNotificationListener;
+ }
+
+ private ShadeController getShadeController() {
+ if (mShadeController == null) {
+ mShadeController = Dependency.get(ShadeController.class);
+ }
+ return mShadeController;
+ }
+
public void setUpWithPresenter(NotificationPresenter presenter,
NotificationListContainer listContainer, Callback callback,
HeadsUpManager headsUpManager) {
mPresenter = presenter;
mCallback = callback;
- mNotificationData = new NotificationData(presenter);
mHeadsUpManager = headsUpManager;
mNotificationData.setHeadsUpManager(mHeadsUpManager);
mListContainer = listContainer;
- mHeadsUpObserver = new ContentObserver(mPresenter.getHandler()) {
+ mHeadsUpObserver = new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
@Override
public void onChange(boolean selfChange) {
boolean wasUsing = mUseHeadsUp;
@@ -278,7 +313,7 @@
mNotificationLifetimeExtenders.add(mHeadsUpManager);
mNotificationLifetimeExtenders.add(mAmbientPulseManager);
mNotificationLifetimeExtenders.add(mGutsManager);
- mNotificationLifetimeExtenders.addAll(mRemoteInputManager.getLifetimeExtenders());
+ mNotificationLifetimeExtenders.addAll(getRemoteInputManager().getLifetimeExtenders());
for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
extender.setCallback(key -> removeNotification(key, mLatestRankingMap));
@@ -294,6 +329,14 @@
return mNotificationData;
}
+ protected Context getContext() {
+ return mContext;
+ }
+
+ protected NotificationPresenter getPresenter() {
+ return mPresenter;
+ }
+
public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
return mGutsManager::openGuts;
}
@@ -348,7 +391,7 @@
row.setInflationCallback(this);
row.setLongPressListener(getNotificationLongClicker());
mListContainer.bindRow(row);
- mRemoteInputManager.bindRow(row);
+ getRemoteInputManager().bindRow(row);
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
@@ -387,7 +430,7 @@
true);
NotificationData.Entry entry = mNotificationData.get(n.getKey());
- mRemoteInputManager.onPerformRemoveNotification(n, entry);
+ getRemoteInputManager().onPerformRemoveNotification(n, entry);
final String pkg = n.getPackageName();
final String tag = n.getTag();
final int id = n.getId();
@@ -512,7 +555,7 @@
// sending look longer than it takes.
// Also we should not defer the removal if reordering isn't allowed since otherwise
// some notifications can't disappear before the panel is closed.
- boolean ignoreEarliestRemovalTime = mRemoteInputManager.getController().isSpinning(key)
+ boolean ignoreEarliestRemovalTime = getRemoteInputManager().getController().isSpinning(key)
&& !FORCE_REMOTE_INPUT_HISTORY
|| !mVisualStabilityManager.isReorderingAllowed();
mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
@@ -547,7 +590,7 @@
extender.setShouldManageLifetime(entry, false /* shouldManage */);
}
- mMediaManager.onNotificationRemoved(key);
+ getMediaManager().onNotificationRemoved(key);
mForegroundServiceController.removeNotification(entry.notification);
if (entry.row != null) {
@@ -602,8 +645,8 @@
boolean isForeground = (row.getStatusBarNotification().getNotification().flags
& Notification.FLAG_FOREGROUND_SERVICE) != 0;
boolean keepForReply =
- mRemoteInputManager.shouldKeepForRemoteInputHistory(childEntry)
- || mRemoteInputManager.shouldKeepForSmartReplyHistory(childEntry);
+ getRemoteInputManager().shouldKeepForRemoteInputHistory(childEntry)
+ || getRemoteInputManager().shouldKeepForSmartReplyHistory(childEntry);
if (isForeground || keepForReply) {
// the child is a foreground service notification which we can't remove or it's
// a child we're keeping around for reply!
@@ -633,7 +676,8 @@
protected void updateNotification(NotificationData.Entry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row) {
- row.setNeedsRedaction(mLockscreenUserManager.needsRedaction(entry));
+ row.setNeedsRedaction(
+ Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry));
boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
boolean isUpdate = mNotificationData.get(entry.key) != null;
boolean wasLowPriority = row.isLowPriority();
@@ -818,7 +862,7 @@
mNotificationData.getImportance(key));
boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
- if (mPresenter.isDozing()) {
+ if (getShadeController().isDozing()) {
updateAlertState(entry, shouldPulse(entry), alertAgain, mAmbientPulseManager);
} else {
updateAlertState(entry, shouldHeadsUp(entry), alertAgain, mHeadsUpManager);
@@ -833,7 +877,8 @@
if (DEBUG) {
// Is this for you?
- boolean isForCurrentUser = mPresenter.isNotificationForCurrentProfiles(notification);
+ boolean isForCurrentUser = Dependency.get(KeyguardEnvironment.class)
+ .isNotificationForCurrentProfiles(notification);
Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
}
@@ -917,7 +962,7 @@
public boolean shouldHeadsUp(NotificationData.Entry entry) {
StatusBarNotification sbn = entry.notification;
- if (mPresenter.isDozing()) {
+ if (getShadeController().isDozing()) {
if (DEBUG) {
Log.d(TAG, "No heads up: device is dozing: " + sbn.getKey());
}
@@ -998,7 +1043,7 @@
protected boolean shouldPulse(NotificationData.Entry entry) {
StatusBarNotification sbn = entry.notification;
- if (!mPresenter.isDozing()) {
+ if (!getShadeController().isDozing()) {
if (DEBUG) {
Log.d(TAG, "No pulsing: not dozing: " + sbn.getKey());
}
@@ -1076,7 +1121,7 @@
protected void setNotificationsShown(String[] keys) {
try {
- mNotificationListener.setNotificationsShown(keys);
+ getNotificationListener().setNotificationsShown(keys);
} catch (RuntimeException e) {
Log.d(TAG, "failed setNotificationsShown: ", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index e96e176..b5fbde1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -56,8 +56,9 @@
private final NotificationListenerService mNotificationListener =
Dependency.get(NotificationListener.class);
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+ protected NotificationEntryManager mEntryManager
+ = Dependency.get(NotificationEntryManager.class);
- protected NotificationEntryManager mEntryManager;
protected Handler mHandler = new Handler();
protected IStatusBarService mBarService;
private long mLastVisibilityReportUptimeMs;
@@ -147,9 +148,7 @@
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
- public void setUpWithEntryManager(NotificationEntryManager entryManager,
- NotificationListContainer listContainer) {
- mEntryManager = entryManager;
+ public void setUpWithContainer(NotificationListContainer listContainer) {
mListContainer = listContainer;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index f4ef0f8..2499952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
@@ -41,15 +42,23 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -71,14 +80,20 @@
// Dependencies:
private final NotificationLockscreenUserManager mLockscreenUserManager =
Dependency.get(NotificationLockscreenUserManager.class);
+ private final StatusBarStateController mStatusBarStateController =
+ 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 final IStatusBarService mBarService;
private NotificationGuts mNotificationGutsExposed;
private NotificationMenuRowPlugin.MenuItem mGutsMenuItem;
- private NotificationPresenter mPresenter;
private NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
+ private NotificationPresenter mPresenter;
private NotificationListContainer mListContainer;
- private NotificationInfo.CheckSaveListener mCheckSaveListener;
+ private CheckSaveListener mCheckSaveListener;
private OnSettingsClickListener mOnSettingsClickListener;
@VisibleForTesting
protected String mKeyToRemoveOnGutsClosed;
@@ -89,16 +104,17 @@
mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
public void setUpWithPresenter(NotificationPresenter presenter,
NotificationListContainer listContainer,
- NotificationInfo.CheckSaveListener checkSaveListener,
- OnSettingsClickListener onSettingsClickListener) {
+ CheckSaveListener checkSave, OnSettingsClickListener onSettingsClick) {
mPresenter = presenter;
mListContainer = listContainer;
- mCheckSaveListener = checkSaveListener;
- mOnSettingsClickListener = onSettingsClickListener;
+ mCheckSaveListener = checkSave;
+ mOnSettingsClickListener = onSettingsClick;
}
public void onDensityOrFontScaleChanged(ExpandableNotificationRow row) {
@@ -264,7 +280,7 @@
onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
guts.resetFalsingCheck();
- mOnSettingsClickListener.onClick(sbn.getKey());
+ mOnSettingsClickListener.onSettingsClick(sbn.getKey());
startAppNotificationSettingsActivity(packageName, appUid, channel, row);
};
}
@@ -279,7 +295,7 @@
mCheckSaveListener,
onSettingsClick,
onAppSettingsClick,
- mPresenter.isDeviceProvisioned(),
+ mDeviceProvisionedController.isDeviceProvisioned(),
row.getIsNonblockable(),
isForBlockingHelper,
row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE);
@@ -317,6 +333,10 @@
mNotificationGutsExposed = guts;
}
+ public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
+ return this::openGuts;
+ }
+
/**
* Opens guts on the given ExpandableNotificationRow {@code view}. This handles opening guts for
* the normal half-swipe and long-press use cases via a circular reveal. When the blocking
@@ -385,7 +405,7 @@
guts.setVisibility(View.VISIBLE);
final boolean needsFalsingProtection =
- (mPresenter.isPresenterLocked() &&
+ (mStatusBarStateController.getState() == StatusBarState.KEYGUARD &&
!mAccessibilityManager.isTouchExplorationEnabled());
guts.openControls(
@@ -442,6 +462,6 @@
}
public interface OnSettingsClickListener {
- void onClick(String key);
+ public void onSettingsClick(String key);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 659f6c7..c9cbb40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -44,7 +44,6 @@
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -88,33 +87,33 @@
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.EmptyShadeView;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
+import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.FakeShadowView;
-import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.notification.ShadeViewRefactor;
-import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
-import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
@@ -125,6 +124,7 @@
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -435,6 +435,8 @@
private float mVerticalPanelTranslation;
private final NotificationLockscreenUserManager mLockscreenUserManager =
Dependency.get(NotificationLockscreenUserManager.class);
+ protected final NotificationGutsManager mGutsManager =
+ Dependency.get(NotificationGutsManager.class);
private final Rect mTmpRect = new Rect();
private final NotificationEntryManager mEntryManager =
Dependency.get(NotificationEntryManager.class);
@@ -454,6 +456,7 @@
private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private NotificationPanelView mNotificationPanel;
+ private final ShadeController mShadeController = Dependency.get(ShadeController.class);
private final NotificationGutsManager
mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
@@ -4740,7 +4743,8 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void setStatusBarState(int statusBarState) {
+ @VisibleForTesting
+ protected void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
}
@@ -4942,7 +4946,7 @@
return;
}
- mStatusBar.addPostCollapseAction(() -> {
+ mShadeController.addPostCollapseAction(() -> {
setDismissAllInProgress(false);
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
if (canChildBeDismissed(rowToRemove)) {
@@ -5042,6 +5046,10 @@
mNotificationPanel = notificationPanelView;
}
+ public void updateIconAreaViews() {
+ mIconAreaController.updateNotificationIcons();
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -5662,7 +5670,7 @@
if (mNotificationPanel.onDraggedDown() || startingChild != null) {
// We have notifications, go to locked shade.
- mStatusBar.goToLockedShade(startingChild);
+ mShadeController.goToLockedShade(startingChild);
if (startingChild instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
row.onExpandedByGesture(true /* drag down is always an open */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index c094669..8325bf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -32,6 +32,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.NotificationMediaManager;
import java.io.PrintWriter;
@@ -95,6 +96,8 @@
*/
private static final float BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
+ private final NotificationMediaManager mMediaManager =
+ Dependency.get(NotificationMediaManager.class);
private PowerManager mPowerManager;
private Handler mHandler = new Handler();
private PowerManager.WakeLock mWakeLock;
@@ -264,7 +267,7 @@
case MODE_WAKE_AND_UNLOCK:
if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
- mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
+ mMediaManager.updateMediaMetaData(false /* metaDataChanged */,
true /* allowEnterAnimation */);
} else if (mMode == MODE_WAKE_AND_UNLOCK){
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index a781be6..fa63831 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -64,11 +64,12 @@
private StatusBar mStatusBarComponent;
private DarkIconManager mDarkIconManager;
private View mOperatorNameFrame;
+ private CommandQueue mCommandQueue;
private SignalCallback mSignalCallback = new SignalCallback() {
@Override
public void setIsAirplaneMode(NetworkController.IconState icon) {
- mStatusBarComponent.recomputeDisableFlags(true /* animate */);
+ mCommandQueue.recomputeDisableFlags(true /* animate */);
}
};
@@ -78,6 +79,7 @@
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mNetworkController = Dependency.get(NetworkController.class);
mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
+ mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
}
@Override
@@ -116,13 +118,13 @@
@Override
public void onResume() {
super.onResume();
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+ mCommandQueue.addCallbacks(this);
}
@Override
public void onPause() {
super.onPause();
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
+ mCommandQueue.removeCallbacks(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 072343a..32c9301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -787,6 +787,10 @@
mIndicationController = keyguardIndicationController;
}
+ public void showTransientIndication(int id) {
+ mIndicationController.showTransientIndication(id);
+ }
+
public void updateLeftAffordance() {
updateLeftAffordanceIcon();
updateLeftPreview();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 8ac8677..235629b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.phone;
-import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
index 76ddca4..6111178 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -16,9 +16,7 @@
package com.android.systemui.statusbar.phone;
-import android.annotation.Nullable;
-
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
/** Executes actions that require the screen to be unlocked. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index d676692..462201c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -18,7 +18,7 @@
import android.util.Log;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
/**
* Executes actions that require the screen to be unlocked. Delegates the actual handling to an
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
new file mode 100644
index 0000000..b3423a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -0,0 +1,57 @@
+/*
+ * 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.statusbar.phone.StatusBar.DEBUG;
+import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
+
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
+
+ private static final String TAG = "KeyguardEnvironmentImpl";
+
+ private final NotificationLockscreenUserManager mLockscreenUserManager =
+ Dependency.get(NotificationLockscreenUserManager.class);
+ private final DeviceProvisionedController mDeviceProvisionedController =
+ Dependency.get(DeviceProvisionedController.class);
+ private final NotificationMediaManager mMediaManager =
+ Dependency.get(NotificationMediaManager.class);
+
+ public KeyguardEnvironmentImpl() {
+ }
+
+ @Override // NotificationData.KeyguardEnvironment
+ public boolean isDeviceProvisioned() {
+ return mDeviceProvisionedController.isDeviceProvisioned();
+ }
+
+ @Override // NotificationData.KeyguardEnvironment
+ public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
+ final int notificationUserId = n.getUserId();
+ if (DEBUG && MULTIUSER_DEBUG) {
+ Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
+ mLockscreenUserManager.getCurrentUserId(), notificationUserId));
+ }
+ return mLockscreenUserManager.isCurrentProfile(notificationUserId);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 40ddf5b..673cdb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -40,6 +40,8 @@
import android.util.Log;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NotificationMediaManager;
import libcore.io.IoUtils;
@@ -52,6 +54,9 @@
private static final String TAG = "LockscreenWallpaper";
+ private final NotificationMediaManager mMediaManager =
+ Dependency.get(NotificationMediaManager.class);
+
private final StatusBar mBar;
private final WallpaperManager mWallpaperManager;
private final Handler mH;
@@ -193,7 +198,7 @@
mCached = true;
mCache = result.bitmap;
mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
- mBar.updateMediaMetaData(
+ mMediaManager.updateMediaMetaData(
true /* metaDataChanged */, true /* allowEnterAnimation */);
}
mLoader = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 80f3506..f105f612 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -95,6 +95,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -126,6 +127,9 @@
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
+ private final DeviceProvisionedController mDeviceProvisionedController =
+ Dependency.get(DeviceProvisionedController.class);
+
protected NavigationBarView mNavigationBarView = null;
protected AssistManager mAssistManager;
@@ -725,7 +729,7 @@
}
private boolean shouldDisableNavbarGestures() {
- return !mStatusBar.isDeviceProvisioned()
+ return !mDeviceProvisionedController.isDeviceProvisioned()
|| (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index e92656ae..a2bd00e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -350,7 +350,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
shouldDeadZoneConsumeTouchEvents(event);
- if (mGestureHelper.onTouchEvent(event)) {
+ if (mGestureHelper != null && mGestureHelper.onTouchEvent(event)) {
return true;
}
return super.onTouchEvent(event);
@@ -680,7 +680,9 @@
}
public void onNavigationButtonLongPress(View v) {
- mGestureHelper.onNavigationButtonLongPress(v);
+ if (mGestureHelper != null) {
+ mGestureHelper.onNavigationButtonLongPress(v);
+ }
}
public void onPanelExpandedChange(boolean expanded) {
@@ -807,7 +809,9 @@
@Override
protected void onDraw(Canvas canvas) {
- mGestureHelper.onDraw(canvas);
+ if (mGestureHelper != null) {
+ mGestureHelper.onDraw(canvas);
+ }
mDeadZone.onDraw(canvas);
super.onDraw(canvas);
}
@@ -819,7 +823,9 @@
updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
updateButtonLocationOnScreen(getRecentsButton(), mRecentsButtonBounds);
updateButtonLocationOnScreen(getRotateSuggestionButton(), mRotationButtonBounds);
- mGestureHelper.onLayout(changed, left, top, right, bottom);
+ if (mGestureHelper != null) {
+ mGestureHelper.onLayout(changed, left, top, right, bottom);
+ }
mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
}
@@ -1117,7 +1123,9 @@
pw.println(" }");
mContextualButtonGroup.dump(pw);
- mGestureHelper.dump(pw);
+ if (mGestureHelper != null) {
+ mGestureHelper.dump(pw);
+ }
mRecentsOnboarding.dump(pw);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index e31bad65..5ee0823 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.SysUiServiceProvider.getComponent;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
.ExpandAnimationParameters;
@@ -65,10 +66,12 @@
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSFragment;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
@@ -337,6 +340,11 @@
Dependency.get(NotificationEntryManager.class);
private final StateListener mListener = this::setBarState;
+ private final CommandQueue mCommandQueue;
+ private final NotificationLockscreenUserManager mLockscreenUserManager =
+ Dependency.get(NotificationLockscreenUserManager.class);
+ private final ShadeController mShadeController =
+ Dependency.get(ShadeController.class);
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -347,6 +355,7 @@
setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
setPanelAlpha(255, false /* animate */);
+ mCommandQueue = getComponent(context, CommandQueue.class);
}
private void setStatusBar(StatusBar bar) {
@@ -630,7 +639,7 @@
if (suppressedSummary) {
continue;
}
- if (!mStatusBar.getNotificationLockscreenUserManager().shouldShowOnKeyguard(
+ if (!mLockscreenUserManager.shouldShowOnKeyguard(
row.getStatusBarNotification())) {
continue;
}
@@ -2414,7 +2423,7 @@
return true;
case StatusBarState.SHADE_LOCKED:
if (!mQsExpanded) {
- mStatusBar.goToKeyguard();
+ mShadeController.goToKeyguard();
}
return true;
case StatusBarState.SHADE:
@@ -2617,7 +2626,7 @@
}
if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
mShowIconsWhenExpanded = showIconsWhenExpanded;
- mStatusBar.recomputeDisableFlags(false);
+ mCommandQueue.recomputeDisableFlags(false);
}
}
@@ -2904,7 +2913,7 @@
if (hideIcons != mHideIconsDuringNotificationLaunch) {
mHideIconsDuringNotificationLaunch = hideIcons;
if (!hideIcons) {
- mStatusBar.recomputeDisableFlags(true /* animate */);
+ mCommandQueue.recomputeDisableFlags(true /* animate */);
}
}
}
@@ -2972,6 +2981,7 @@
mNotificationStackScroller.updateSpeedBumpIndex();
mNotificationStackScroller.updateFooter();
updateShowEmptyShadeView();
+ mNotificationStackScroller.updateIconAreaViews();
}
public void onUpdateRowStates() {
@@ -3019,6 +3029,10 @@
updateShowEmptyShadeView();
}
+ public void showTransientIndication(int id) {
+ mKeyguardBottomArea.showTransientIndication(id);
+ }
+
/**
* Whenever a user drags down on the empty area (pulling down the shade and clock) and lets go.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 59863ec..2129835 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -19,6 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
+import static com.android.systemui.SysUiServiceProvider.getComponent;
import android.annotation.Nullable;
import android.content.Context;
@@ -42,6 +43,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
@@ -52,6 +54,7 @@
private static final boolean DEBUG = StatusBar.DEBUG;
private static final boolean DEBUG_GESTURES = false;
private static final int NO_VALUE = Integer.MIN_VALUE;
+ private final CommandQueue mCommandQueue;
StatusBar mBar;
@@ -82,6 +85,7 @@
super(context, attrs);
mBarTransitions = new PhoneStatusBarTransitions(this);
+ mCommandQueue = getComponent(context, CommandQueue.class);
}
public BarTransitions getBarTransitions() {
@@ -166,7 +170,7 @@
@Override
public boolean panelEnabled() {
- return mBar.panelsEnabled();
+ return mCommandQueue.panelsEnabled();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
new file mode 100644
index 0000000..e546119
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -0,0 +1,147 @@
+/*
+ * 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 android.view.View;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+
+/**
+ * {@link ShadeController} is an abstraction of the work that used to be hard-coded in
+ * {@link StatusBar}. The shade itself represents the concept of the status bar window state, and
+ * can be in multiple states: dozing, locked, showing the bouncer, occluded, etc. All/some of these
+ * are coordinated with {@link StatusBarKeyguardViewManager} via
+ * {@link com.android.systemui.keyguard.KeyguardViewMediator} and others.
+ */
+public interface ShadeController {
+
+ /**
+ * Shows the keyguard bouncer - the password challenge on the lock screen
+ *
+ * @param scrimmed true when the bouncer should show scrimmed, false when the user will be
+ * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
+ */
+ void showBouncer(boolean scrimmed);
+
+ /**
+ * Make our window larger and the panel expanded
+ */
+ void instantExpandNotificationsPanel();
+
+ /**
+ * If the notifications panel is not fully expanded, collapse it animated.
+ *
+ * @return Seems to always return false
+ */
+ boolean closeShadeIfOpen();
+
+ /**
+ * Add a runnable for NotificationPanelView to post when the panel is expanded.
+ *
+ * @param action the action to post
+ */
+ void postOnShadeExpanded(Runnable action);
+
+ /**
+ * Add a runnable to be executed after the shade collapses. Post-collapse runnables are
+ * aggregated and run serially.
+ *
+ * @param action the action to execute
+ */
+ void addPostCollapseAction(Runnable action);
+
+ /**
+ * Ask shade controller to set the state to {@link StatusBarState#KEYGUARD}, but only from
+ * {@link StatusBarState#SHADE_LOCKED}
+ */
+ void goToKeyguard();
+
+ /**
+ * When the keyguard is showing and covered by something (bouncer, keyguard activity, etc.) it
+ * is occluded. This is controlled by {@link com.android.server.policy.PhoneWindowManager}
+ *
+ * @return whether the keyguard is currently occluded
+ */
+ boolean isOccluded();
+
+ /**
+ * Notify the shade controller that the current user changed
+ *
+ * @param newUserId userId of the new user
+ */
+ void setLockscreenUser(int newUserId);
+
+ /**
+ * Dozing is when the screen is in AOD or asleep
+ *
+ * @return true if we are dozing
+ */
+ boolean isDozing();
+
+ /**
+ * Ask the display to wake up if currently dozing, else do nothing
+ *
+ * @param time when to wake up
+ * @param view the view requesting the wakeup
+ */
+ void wakeUpIfDozing(long time, View view);
+
+ /**
+ * If secure with redaction: Show bouncer, go to unlocked shade.
+ *
+ * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
+ *
+ * @param startingChild The view to expand after going to the shade.
+ */
+ void goToLockedShade(View startingChild);
+
+ /**
+ * Adds a {@param runnable} to be executed after Keyguard is gone.
+ */
+ void addAfterKeyguardGoneRunnable(Runnable runnable);
+
+ /**
+ * Close the shade if it was open
+ *
+ * @return true if the shade was open, else false
+ */
+ boolean collapsePanel();
+
+ /**
+ * If {@param animate}, does the same as {@link #collapsePanel()}. Otherwise, instantly collapse
+ * the panel. Post collapse runnables will be executed
+ *
+ * @param animate
+ */
+ void collapsePanel(boolean animate);
+
+ /**
+ * Callback to tell the shade controller that an activity launch animation was canceled
+ */
+ void onLaunchAnimationCancelled();
+
+ /**
+ * When notifications update, give the shade controller a chance to do thing in response to
+ * the new data set
+ */
+ void updateAreThereNotifications();
+
+ /**
+ * Callback to notify the shade controller that a {@link ActivatableNotificationView} has become
+ * inactive
+ */
+ void onActivationReset();
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 56e5a1e..f56e219 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -26,10 +26,8 @@
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;
-import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
-import static com.android.systemui.statusbar.NotificationLockscreenUserManager
- .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.NotificationMediaManager.DEBUG_MEDIA;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
@@ -54,7 +52,6 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
-import android.app.TaskStackBuilder;
import android.app.UiModeManager;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
@@ -65,31 +62,21 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IntentSender;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.PointF;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
import android.media.AudioAttributes;
-import android.media.MediaMetadata;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -105,14 +92,10 @@
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
-import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
import android.view.Display;
import android.view.IWindowManager;
import android.view.KeyEvent;
@@ -122,7 +105,6 @@
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -130,19 +112,15 @@
import android.view.animation.AccelerateInterpolator;
import android.widget.DateTimeView;
import android.widget.ImageView;
-import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.MessagingGroup;
import com.android.internal.widget.MessagingMessage;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
@@ -152,11 +130,11 @@
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
+import com.android.systemui.InitController;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
-import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
@@ -185,38 +163,34 @@
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
-import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
-import com.android.systemui.statusbar.notification.AppOpsListener;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.row.NotificationInfo;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.AppOpsListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
@@ -230,7 +204,6 @@
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
@@ -253,9 +226,9 @@
public class StatusBar extends SystemUI implements DemoMode,
ActivityStarter, OnUnlockMethodChangedListener,
OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
- ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter,
- StatusBarStateController.StateListener, AmbientPulseManager.OnAmbientChangedListener,
- ActivityLaunchAnimator.Callback {
+ ColorExtractor.OnColorsChangedListener, ConfigurationListener,
+ StatusBarStateController.StateListener, ShadeController,
+ ActivityLaunchAnimator.Callback, AmbientPulseManager.OnAmbientChangedListener {
public static final boolean MULTIUSER_DEBUG = false;
public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -324,10 +297,10 @@
/** If true, the system is in the half-boot-to-decryption-screen state.
* Prudently disable QS and notifications. */
- private static final boolean ONLY_CORE_APPS;
+ public static final boolean ONLY_CORE_APPS;
/** If true, the lockscreen will show a distinct wallpaper */
- private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
+ public static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
static {
boolean onlyCoreApps;
@@ -376,7 +349,6 @@
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
- private TextView mNotificationPanelDebugText;
// settings
private QSPanel mQSPanel;
@@ -385,15 +357,12 @@
// RemoteInputView to be activated after unlock
private View mPendingRemoteInputView;
- private View mPendingWorkRemoteInputView;
private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
Dependency.get(RemoteInputQuickSettingsDisabler.class);
private View mReportRejectedTouch;
- private int mMaxAllowedKeyguardNotifications;
-
private boolean mExpandedVisible;
private final int[] mAbsPos = new int[2];
@@ -460,7 +429,6 @@
private int mInteractingWindows;
private boolean mAutohideSuspended;
private int mStatusBarMode;
- private int mMaxKeyguardNotifications;
private ViewMediatorCallback mKeyguardViewMediatorCallback;
protected ScrimController mScrimController;
@@ -479,9 +447,6 @@
protected BackDropView mBackdrop;
protected ImageView mBackdropFront, mBackdropBack;
- protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
- protected final PorterDuffXfermode mSrcOverXferMode =
- new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
private NotificationMediaManager mMediaManager;
protected NotificationLockscreenUserManager mLockscreenUserManager;
@@ -524,7 +489,6 @@
private boolean mIsOccluded;
private boolean mWereIconsJustHidden;
private boolean mBouncerWasShowingWhenHidden;
- private boolean mIsCollapsingToShowActivityOverLockscreen;
// Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
// this animation is tied to the scrim for historic reasons.
@@ -557,13 +521,9 @@
private BatteryController mBatteryController;
protected boolean mPanelExpanded;
private UiModeManager mUiModeManager;
- private boolean mKeyguardRequested;
private boolean mIsKeyguard;
private LogMaker mStatusBarStateLog;
- private final LockscreenGestureLogger mLockscreenGestureLogger =
- Dependency.get(LockscreenGestureLogger.class);
protected NotificationIconAreaController mNotificationIconAreaController;
- private boolean mReinflateNotificationsOnUserSwitched;
@Nullable private View mAmbientIndicationContainer;
private SysuiColorExtractor mColorExtractor;
private ScreenLifecycle mScreenLifecycle;
@@ -598,10 +558,10 @@
private NavigationBarFragment mNavigationBar;
private View mNavigationBarView;
- protected ActivityLaunchAnimator mActivityLaunchAnimator;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private boolean mVibrateOnOpening;
private VibratorHelper mVibratorHelper;
+ protected NotificationPresenter mPresenter;
@Override
public void start() {
@@ -626,11 +586,11 @@
mEntryManager = Dependency.get(NotificationEntryManager.class);
mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
mAppOpsListener = Dependency.get(AppOpsListener.class);
- mAppOpsListener.setUpWithPresenter(this, mEntryManager);
mZenController = Dependency.get(ZenModeController.class);
mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
-
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+ mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+
mColorExtractor.addOnColorsChangedListener(this);
mStatusBarStateController.addListener(this, StatusBarStateController.RANK_STATUS_BAR);
@@ -659,17 +619,12 @@
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
-
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mRecents = getComponent(Recents.class);
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mLockPatternUtils = new LockPatternUtils(mContext);
-
- mMediaManager.setUpWithPresenter(this, mEntryManager);
// Connect in to the status bar manager service
mCommandQueue = getComponent(CommandQueue.class);
@@ -696,7 +651,6 @@
wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
mWallpaperChangedReceiver.onReceive(mContext, null);
- mLockscreenUserManager.setUpWithPresenter(this, mEntryManager);
mCommandQueue.disable(switches[0], switches[6], false /* animate */);
setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
fullscreenStackBounds, dockedStackBounds);
@@ -711,7 +665,16 @@
}
// Set up the initial notification state.
- mNotificationListener.setUpWithPresenter(this, mEntryManager);
+ mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
+ mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
+ mScrimController, this);
+ mAppOpsListener.setUpWithPresenter(mPresenter);
+ mNotificationListener.setUpWithPresenter(mPresenter);
+ mNotificationShelf.setOnActivatedListener(mPresenter);
+ mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
+
+ // set the initial view visibility
+ Dependency.get(InitController.class).addPostInitTask(this::updateAreThereNotifications);
if (DEBUG) {
Log.d(TAG, String.format(
@@ -724,24 +687,12 @@
));
}
- setHeadsUpUser(mLockscreenUserManager.getCurrentUserId());
-
IntentFilter internalFilter = new IntentFilter();
internalFilter.addAction(BANNER_ACTION_CANCEL);
internalFilter.addAction(BANNER_ACTION_SETUP);
mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
null);
- IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
- Context.VR_SERVICE));
- if (vrManager != null) {
- try {
- vrManager.registerListener(mVrStateCallbacks);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to register VR mode state listener: " + e);
- }
- }
-
IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
ServiceManager.getService(Context.WALLPAPER_SERVICE));
try {
@@ -788,24 +739,9 @@
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
- NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller;
mZenController.addCallback(this);
- mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
- this,
- mNotificationPanel,
- notifListContainer);
- mGutsManager.setUpWithPresenter(this, notifListContainer, mCheckSaveListener,
- key -> {
- try {
- mBarService.onNotificationSettingsViewed(key);
- } catch (RemoteException e) {
- // if we're here we're dead
- }
- });
- mNotificationLogger.setUpWithEntryManager(mEntryManager, notifListContainer);
- mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
- mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
- R.id.notification_container_parent));
+ NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller;
+ mNotificationLogger.setUpWithContainer(notifListContainer);
mNotificationIconAreaController = SystemUIFactory.getInstance()
.createNotificationIconAreaController(context, this);
@@ -850,7 +786,7 @@
mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
mHeadsUpAppearanceController.readFrom(oldController);
mStatusBarWindow.setStatusBarView(mStatusBarView);
- setAreThereNotifications();
+ updateAreThereNotifications();
checkBarModes();
}).getFragmentManager()
.beginTransaction()
@@ -872,13 +808,6 @@
mGroupManager.setHeadsUpManager(mHeadsUpManager);
putComponent(HeadsUpManager.class, mHeadsUpManager);
- mEntryManager.setUpWithPresenter(this, notifListContainer, this, mHeadsUpManager);
- mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, notifListContainer);
-
- if (MULTIUSER_DEBUG) {
- mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
- mNotificationPanelDebugText.setVisibility(View.VISIBLE);
- }
try {
boolean showNav = mWindowManagerService.hasNavigationBar();
@@ -890,14 +819,16 @@
// no window manager? good luck with that
}
- mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
- mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
- mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
-
if (ENABLE_LOCKSCREEN_WALLPAPER) {
mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
}
+ mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
+ mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
+ mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
+ mMediaManager.setup(mBackdrop, mBackdropFront, mBackdropBack, mBiometricUnlockController,
+ mScrimController, mLockscreenWallpaper);
+
mKeyguardIndicationController =
SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
@@ -908,9 +839,6 @@
mAmbientIndicationContainer = mStatusBarWindow.findViewById(
R.id.ambient_indication_container);
- // set the initial view visibility
- setAreThereNotifications();
-
// TODO: Find better place for this callback.
mBatteryController.addCallback(new BatteryStateChangeCallback() {
@Override
@@ -1053,6 +981,30 @@
ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
}
+ @Override
+ public void addAfterKeyguardGoneRunnable(Runnable runnable) {
+ mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
+ }
+
+ @Override
+ public boolean isDozing() {
+ return mDozing && mNotificationPanel.isFullyDark();
+ }
+
+ @Override
+ public void wakeUpIfDozing(long time, View where) {
+ if (mDozing) {
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ pm.wakeUp(time, "com.android.systemui:NODOZE");
+ mWakeUpComingFromTouch = true;
+ where.getLocationInWindow(mTmpInt2);
+ mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
+ mTmpInt2[1] + where.getHeight() / 2);
+ mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
+ mFalsingManager.onScreenOnFromTouch();
+ }
+ }
+
protected void createNavigationBar() {
mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
mNavigationBar = (NavigationBarFragment) fragment;
@@ -1084,7 +1036,6 @@
mNotificationShelf =
(NotificationShelf) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_shelf, mStackScroller, false);
- mNotificationShelf.setOnActivatedListener(this);
mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
}
@@ -1092,13 +1043,6 @@
public void onDensityOrFontScaleChanged() {
MessagingMessage.dropCache();
MessagingGroup.dropCache();
- // start old BaseStatusBar.onDensityOrFontScaleChanged().
- if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
- mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
- } else {
- mReinflateNotificationsOnUserSwitched = true;
- }
- // end old BaseStatusBar.onDensityOrFontScaleChanged().
// TODO: Remove this.
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onDensityOrFontScaleChanged();
@@ -1169,8 +1113,6 @@
mScrimController, this, UnlockMethodCache.getInstance(mContext));
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
getBouncerContainer(), mNotificationPanel, mBiometricUnlockController);
- //TODO: Can we put the keyguard view manager in Dependency?
- mLockscreenUserManager.setKeyguardViewManager(mStatusBarKeyguardViewManager);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -1234,73 +1176,13 @@
return true;
}
- @Override
- public void onPerformRemoveNotification(StatusBarNotification n) {
- if (mNotificationPanel.hasPulsingNotifications() &&
- !mAmbientPulseManager.hasNotifications()) {
- // We were showing a pulse for a notification, but no notifications are pulsing anymore.
- // Finish the pulse.
- mDozeScrimController.pulseOutNow();
- }
- }
-
- @Override
- public void updateNotificationViews() {
- // The function updateRowStates depends on both of these being non-null, so check them here.
- // We may be called before they are set from DeviceProvisionedController's callback.
- if (mScrimController == null) return;
-
- // Do not modify the notifications during collapse.
- if (isCollapsing()) {
- addPostCollapseAction(this::updateNotificationViews);
- return;
- }
-
- mViewHierarchyManager.updateNotificationViews();
-
- mNotificationPanel.updateNotificationViews();
-
- updateQsExpansionEnabled();
-
- // Let's also update the icons
- mNotificationIconAreaController.updateNotificationIcons();
- }
-
- @Override
- public void onNotificationAdded(Entry shadeEntry) {
- // Recalculate the position of the sliding windows and the titles.
- setAreThereNotifications();
- }
-
- @Override
- public void onNotificationUpdated(StatusBarNotification notification) {
- setAreThereNotifications();
- }
-
- @Override
- public void onNotificationRemoved(String key, StatusBarNotification old) {
- if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
-
- if (old != null) {
- if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
- && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
- if (mState == StatusBarState.SHADE) {
- animateCollapsePanels();
- } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
- goToKeyguard();
- }
- }
- }
- setAreThereNotifications();
- }
-
/**
* Disable QS if device not provisioned.
* If the user switcher is simple then disable QS during setup because
* the user intends to use the lock screen user switcher, QS in not needed.
*/
private void updateQsExpansionEnabled() {
- mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
+ mNotificationPanel.setQsExpansionEnabled(mDeviceProvisionedController.isDeviceProvisioned()
&& (mUserSetup || mUserSwitcherController == null
|| !mUserSwitcherController.isSimpleUserSwitcher())
&& ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0)
@@ -1337,12 +1219,11 @@
mEntryManager.updateNotifications();
}
- protected void setAreThereNotifications() {
-
+ public void updateAreThereNotifications() {
if (SPEW) {
final boolean clearable = hasActiveNotifications() &&
mNotificationPanel.hasActiveClearableNotifications();
- Log.d(TAG, "setAreThereNotifications: N=" +
+ Log.d(TAG, "updateAreThereNotifications: N=" +
mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" +
hasActiveNotifications() + " clearable=" + clearable);
}
@@ -1368,192 +1249,9 @@
.start();
}
}
-
mMediaManager.findAndUpdateMediaNotifications();
}
-
- /**
- * Hide the album artwork that is fading out and release its bitmap.
- */
- protected final Runnable mHideBackdropFront = new Runnable() {
- @Override
- public void run() {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
- }
- mBackdropFront.setVisibility(View.INVISIBLE);
- mBackdropFront.animate().cancel();
- mBackdropFront.setImageDrawable(null);
- }
- };
-
- // TODO: Move this to NotificationMediaManager.
- /**
- * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
- */
- @Override
- public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
- Trace.beginSection("StatusBar#updateMediaMetaData");
- if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
- Trace.endSection();
- return;
- }
-
- if (mBackdrop == null) {
- Trace.endSection();
- return; // called too early
- }
-
- boolean wakeAndUnlock = mBiometricUnlockController != null
- && mBiometricUnlockController.isWakeAndUnlock();
- if (mLaunchTransitionFadingAway || wakeAndUnlock) {
- mBackdrop.setVisibility(View.INVISIBLE);
- Trace.endSection();
- return;
- }
-
- MediaMetadata mediaMetadata = mMediaManager.getMediaMetadata();
-
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
- + mMediaManager.getMediaNotificationKey()
- + " metadata=" + mediaMetadata
- + " metaDataChanged=" + metaDataChanged
- + " state=" + mState);
- }
-
- Drawable artworkDrawable = null;
- if (mediaMetadata != null) {
- Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
- if (artworkBitmap == null) {
- artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- // might still be null
- }
- if (artworkBitmap != null) {
- artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
- }
- }
- boolean allowWhenShade = false;
- if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
- Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
- if (lockWallpaper != null) {
- artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
- mBackdropBack.getResources(), lockWallpaper);
- // We're in the SHADE mode on the SIM screen - yet we still need to show
- // the lockscreen wallpaper in that mode.
- allowWhenShade = mStatusBarKeyguardViewManager != null
- && mStatusBarKeyguardViewManager.isShowing();
- }
- }
-
- boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
- && mStatusBarKeyguardViewManager.isOccluded();
-
- final boolean hasArtwork = artworkDrawable != null;
- mColorExtractor.setHasBackdrop(hasArtwork);
- if (mScrimController != null) {
- mScrimController.setHasBackdrop(hasArtwork);
- }
-
- if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
- && (mState != StatusBarState.SHADE || allowWhenShade)
- && mBiometricUnlockController.getMode()
- != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
- && !hideBecauseOccluded) {
- // time to show some art!
- if (mBackdrop.getVisibility() != View.VISIBLE) {
- mBackdrop.setVisibility(View.VISIBLE);
- if (allowEnterAnimation) {
- mBackdrop.setAlpha(0);
- mBackdrop.animate().alpha(1f);
- } else {
- mBackdrop.animate().cancel();
- mBackdrop.setAlpha(1f);
- }
- mStatusBarWindowController.setBackdropShowing(true);
- metaDataChanged = true;
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
- }
- }
- if (metaDataChanged) {
- if (mBackdropBack.getDrawable() != null) {
- Drawable drawable =
- mBackdropBack.getDrawable().getConstantState()
- .newDrawable(mBackdropFront.getResources()).mutate();
- mBackdropFront.setImageDrawable(drawable);
- mBackdropFront.setAlpha(1f);
- mBackdropFront.setVisibility(View.VISIBLE);
- } else {
- mBackdropFront.setVisibility(View.INVISIBLE);
- }
-
- if (DEBUG_MEDIA_FAKE_ARTWORK) {
- final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
- Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
- mBackdropBack.setBackgroundColor(0xFFFFFFFF);
- mBackdropBack.setImageDrawable(new ColorDrawable(c));
- } else {
- mBackdropBack.setImageDrawable(artworkDrawable);
- }
-
- if (mBackdropFront.getVisibility() == View.VISIBLE) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
- + mBackdropFront.getDrawable()
- + " to "
- + mBackdropBack.getDrawable());
- }
- mBackdropFront.animate()
- .setDuration(250)
- .alpha(0f).withEndAction(mHideBackdropFront);
- }
- }
- } else {
- // need to hide the album art, either because we are unlocked, on AOD
- // or because the metadata isn't there to support it
- if (mBackdrop.getVisibility() != View.GONE) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
- }
- boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
- if (mBiometricUnlockController.getMode()
- == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
- || hideBecauseOccluded || cannotAnimateDoze) {
-
- // We are unlocking directly - no animation!
- mBackdrop.setVisibility(View.GONE);
- mBackdropBack.setImageDrawable(null);
- mStatusBarWindowController.setBackdropShowing(false);
- } else {
- mStatusBarWindowController.setBackdropShowing(false);
- mBackdrop.animate()
- .alpha(0)
- .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
- .setDuration(300)
- .setStartDelay(0)
- .withEndAction(() -> {
- mBackdrop.setVisibility(View.GONE);
- mBackdropFront.animate().cancel();
- mBackdropBack.setImageDrawable(null);
- mHandler.post(mHideBackdropFront);
- });
- if (mKeyguardMonitor.isKeyguardFadingAway()) {
- mBackdrop.animate()
- // Make it disappear faster, as the focus should be on the activity
- // behind.
- .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
- .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
- .setInterpolator(Interpolators.LINEAR)
- .start();
- }
- }
- }
- }
- Trace.endSection();
- }
-
private void updateReportRejectedTouchVisibility() {
if (mReportRejectedTouch == null) {
return;
@@ -1646,15 +1344,6 @@
}
}
- /**
- * Reapplies the disable flags as last requested by StatusBarManager.
- *
- * This needs to be called if state used by adjustDisableFlags changes.
- */
- public void recomputeDisableFlags(boolean animate) {
- mCommandQueue.recomputeDisableFlags(animate);
- }
-
protected H createHandler() {
return new StatusBar.H();
}
@@ -1695,53 +1384,6 @@
return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
}
- @Override
- public boolean isDozing() {
- return mDozing && mNotificationPanel.isFullyDark();
- }
-
- @Override
- public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
- if (isDozing()) {
- return false;
- }
-
- if (mIsOccluded) {
- boolean devicePublic = mLockscreenUserManager.
- isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
- boolean userPublic = devicePublic
- || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
- boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
- if (userPublic && needsRedaction) {
- return false;
- }
- }
-
- if (!panelsEnabled()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
- }
- return false;
- }
-
- if (sbn.getNotification().fullScreenIntent != null) {
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
- return false;
- } else {
- // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
- return !mStatusBarKeyguardViewManager.isShowing()
- || mStatusBarKeyguardViewManager.isOccluded();
- }
- }
- return true;
- }
-
- @Override // NotificationData.Environment
- public String getCurrentMediaNotificationKey() {
- return mMediaManager.getMediaNotificationKey();
- }
-
/**
* To be called when there's a state change in StatusBarKeyguardViewManager.
*/
@@ -1815,12 +1457,6 @@
}
}
- protected void setHeadsUpUser(int newUserId) {
- if (mHeadsUpManager != null) {
- mHeadsUpManager.setUser(newUserId);
- }
- }
-
public boolean isKeyguardCurrentlySecure() {
return !mUnlockMethodCache.canSkipBouncer();
}
@@ -1868,6 +1504,11 @@
return mAmbientIndicationContainer;
}
+ @Override
+ public boolean isOccluded() {
+ return mIsOccluded;
+ }
+
public void setOccluded(boolean occluded) {
mIsOccluded = occluded;
mScrimController.setKeyguardOccluded(occluded);
@@ -1901,10 +1542,10 @@
mWereIconsJustHidden = true;
mHandler.postDelayed(() -> {
mWereIconsJustHidden = false;
- recomputeDisableFlags(true);
+ mCommandQueue.recomputeDisableFlags(true);
}, 500);
} else {
- recomputeDisableFlags(animate);
+ mCommandQueue.recomputeDisableFlags(animate);
}
}
if (shouldHideIconsForBouncer) {
@@ -1912,20 +1553,21 @@
}
}
- @Override
- public void onLaunchAnimationCancelled() {
- if (!isCollapsing()) {
- onClosingFinished();
- }
- }
-
public boolean isHeadsUpShouldBeVisible() {
return mHeadsUpAppearanceController.shouldBeVisible();
}
+ //TODO: These can / should probably be moved to NotificationPresenter or ShadeController
+ @Override
+ public void onLaunchAnimationCancelled() {
+ if (!mPresenter.isCollapsing()) {
+ onClosingFinished();
+ }
+ }
+
@Override
public void onExpandAnimationFinished(boolean launchIsFullScreen) {
- if (!isCollapsing()) {
+ if (!mPresenter.isCollapsing()) {
onClosingFinished();
}
if (launchIsFullScreen) {
@@ -1935,8 +1577,9 @@
@Override
public void onExpandAnimationTimedOut() {
- if (isPresenterFullyCollapsed() && !isCollapsing()
- && !mActivityLaunchAnimator.isLaunchForActivity()) {
+ ActivityLaunchAnimator animator = mPresenter.getActivityLaunchAnimator();
+ if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing()
+ && animator != null && !animator.isLaunchForActivity()) {
onClosingFinished();
} else {
collapsePanel(true /* animate */);
@@ -1948,6 +1591,14 @@
return mState == StatusBarState.SHADE;
}
+ public boolean isDeviceInVrMode() {
+ return mPresenter.isDeviceInVrMode();
+ }
+
+ public NotificationPresenter getPresenter() {
+ return mPresenter;
+ }
+
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
@@ -2005,7 +1656,7 @@
@Override
public void handleSystemKey(int key) {
if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
- if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
+ if (!mCommandQueue.panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
|| mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
return;
}
@@ -2047,15 +1698,9 @@
}
}
- boolean panelsEnabled() {
- return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0
- && (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
- && !ONLY_CORE_APPS;
- }
-
void makeExpandedVisible(boolean force) {
if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
- if (!force && (mExpandedVisible || !panelsEnabled())) {
+ if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
return;
}
@@ -2066,7 +1711,7 @@
mStatusBarWindowController.setPanelVisible(true);
visibilityChanged(true);
- recomputeDisableFlags(!force /* animate */);
+ mCommandQueue.recomputeDisableFlags(!force /* animate */);
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
@@ -2099,12 +1744,12 @@
}
}
- @Override
public void animateCollapsePanels(int flags) {
animateCollapsePanels(flags, false /* force */, false /* delayed */,
1.0f /* speedUpFactor */);
}
+ @Override
public void animateCollapsePanels(int flags, boolean force) {
animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
}
@@ -2155,7 +1800,7 @@
}
public void dispatchNotificationsPanelTouchEvent(MotionEvent ev) {
- if (!panelsEnabled()) {
+ if (!mCommandQueue.panelsEnabled()) {
return;
}
mNotificationPanel.dispatchTouchEvent(ev);
@@ -2173,7 +1818,7 @@
@Override
public void animateExpandNotificationsPanel() {
if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
- if (!panelsEnabled()) {
+ if (!mCommandQueue.panelsEnabled()) {
return ;
}
@@ -2185,7 +1830,7 @@
@Override
public void animateExpandSettingsPanel(@Nullable String subPanel) {
if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
- if (!panelsEnabled()) {
+ if (!mCommandQueue.panelsEnabled()) {
return;
}
@@ -2233,12 +1878,13 @@
runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
- if (!mIsCollapsingToShowActivityOverLockscreen) {
+ if (!mPresenter.isCollapsingToShowActivityOverLockscreen()) {
showBouncerIfKeyguard();
} else if (DEBUG) {
Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
}
- recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
+ mCommandQueue.recomputeDisableFlags(
+ mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
// the bouncer appear animation.
@@ -2330,7 +1976,7 @@
// update low profile
if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
- setAreThereNotifications();
+ updateAreThereNotifications();
}
// ready to unhide
@@ -2703,9 +2349,6 @@
private void addStatusBarWindow() {
makeStatusBarView();
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
- mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,
- mNotificationPanel.createRemoteInputDelegate());
- mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());
}
@@ -2750,7 +2393,7 @@
public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
final Callback callback, int flags) {
- if (onlyProvisioned && !isDeviceProvisioned()) return;
+ if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return;
final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, mLockscreenUserManager.getCurrentUserId());
@@ -2888,7 +2531,7 @@
}
} else if (ACTION_FAKE_ARTWORK.equals(action)) {
if (DEBUG_MEDIA_FAKE_ARTWORK) {
- updateMediaMetaData(true, true);
+ mPresenter.updateMediaMetaData(true, true);
}
}
}
@@ -2917,7 +2560,8 @@
dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
}
- private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
+ @Override
+ public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
boolean afterKeyguardGone) {
if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
&& mUnlockMethodCache.canSkipBouncer()
@@ -2951,38 +2595,10 @@
}
@Override
- public void onUserSwitched(int newUserId) {
- // Begin old BaseStatusBar.userSwitched
- setHeadsUpUser(newUserId);
- // End old BaseStatusBar.userSwitched
- if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
- animateCollapsePanels();
- if (mReinflateNotificationsOnUserSwitched) {
- mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
- mReinflateNotificationsOnUserSwitched = false;
- }
- updateNotificationViews();
- mMediaManager.clearCurrentMediaNotification();
- setLockscreenUser(newUserId);
- mWallpaperChangedReceiver.onReceive(mContext, null);
- }
-
- @Override
- public NotificationLockscreenUserManager getNotificationLockscreenUserManager() {
- return mLockscreenUserManager;
- }
-
- @Override
- public void onBindRow(Entry entry, PackageManager pmUser,
- StatusBarNotification sbn, ExpandableNotificationRow row) {
- row.setAboveShelfChangedListener(mAboveShelfObserver);
- row.setSecureStateProvider(this::isKeyguardCurrentlySecure);
- }
-
- protected void setLockscreenUser(int newUserId) {
+ public void setLockscreenUser(int newUserId) {
mLockscreenWallpaper.setCurrentUser(newUserId);
mScrimController.setCurrentUser(newUserId);
- updateMediaMetaData(true, false);
+ mWallpaperChangedReceiver.onReceive(mContext, null);
}
/**
@@ -3020,8 +2636,6 @@
if (mStatusBarWindowController != null && mNaturalBarHeight != oldBarHeight) {
mStatusBarWindowController.setBarHeight(mNaturalBarHeight);
}
- mMaxAllowedKeyguardNotifications = res.getInteger(
- R.integer.keyguard_max_notification_count);
if (DEBUG) Log.v(TAG, "defineSlots");
}
@@ -3058,12 +2672,12 @@
if (visibleToUser) {
boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
boolean clearNotificationEffects =
- !isPresenterFullyCollapsed() &&
+ !mPresenter.isPresenterFullyCollapsed() &&
(mState == StatusBarState.SHADE
|| mState == StatusBarState.SHADE_LOCKED);
int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications()
.size();
- if (pinnedHeadsUp && isPresenterFullyCollapsed()) {
+ if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
notificationLoad = 1;
}
final int finalNotificationLoad = notificationLoad;
@@ -3298,13 +2912,8 @@
}
}
- @Override
- public boolean isPresenterFullyCollapsed() {
- return mNotificationPanel.isFullyCollapsed();
- }
-
public void showKeyguard() {
- mKeyguardRequested = true;
+ mStatusBarStateController.setKeyguardRequested(true);
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
mPendingRemoteInputView = null;
updateIsKeyguard();
@@ -3312,11 +2921,12 @@
}
public boolean hideKeyguard() {
- mKeyguardRequested = false;
+ mStatusBarStateController.setKeyguardRequested(false);
return updateIsKeyguard();
}
/**
+ * stop(tag)
* @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
*/
public boolean isFullScreenUserSwitcherState() {
@@ -3333,7 +2943,8 @@
// turned off fully.
boolean keyguardForDozing = mDozingRequested &&
(!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
- boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking;
+ boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
+ || keyguardForDozing) && !wakeAndUnlocking;
if (keyguardForDozing) {
updatePanelExpansionForKeyguard();
}
@@ -3385,13 +2996,7 @@
releaseGestureWakeLock();
runLaunchTransitionEndRunnable();
mLaunchTransitionFadingAway = false;
- updateMediaMetaData(true /* metaDataChanged */, true);
- }
-
- public boolean isCollapsing() {
- return mNotificationPanel.isCollapsing()
- || mActivityLaunchAnimator.isAnimationPending()
- || mActivityLaunchAnimator.isAnimationRunning();
+ mPresenter.updateMediaMetaData(true /* metaDataChanged */, true);
}
public void addPostCollapseAction(Runnable r) {
@@ -3415,12 +3020,13 @@
mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
mLaunchTransitionEndRunnable = endRunnable;
Runnable hideRunnable = () -> {
+ mKeyguardMonitor.setLaunchTransitionFadingAway(true);
mLaunchTransitionFadingAway = true;
if (beforeFading != null) {
beforeFading.run();
}
updateScrimController();
- updateMediaMetaData(false, true);
+ mPresenter.updateMediaMetaData(false, true);
mNotificationPanel.setAlpha(1);
mNotificationPanel.animate()
.alpha(0)
@@ -3505,9 +3111,8 @@
mLockscreenUserManager.updatePublicMode();
mEntryManager.updateNotifications();
}
- View viewToClick = null;
if (mStatusBarStateController.leaveOpenOnKeyguardHide()) {
- if (!mKeyguardRequested) {
+ if (!mStatusBarStateController.isKeyguardRequested()) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
}
long delay = mKeyguardMonitor.calculateGoingToFullShadeDelay();
@@ -3516,10 +3121,6 @@
mDraggedDownRow.setUserLocked(false);
mDraggedDownRow = null;
}
- if (!mKeyguardRequested) {
- viewToClick = mPendingRemoteInputView;
- mPendingRemoteInputView = null;
- }
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
@@ -3530,10 +3131,6 @@
instantCollapseNotificationPanel();
}
- if (viewToClick != null && viewToClick.isAttachedToWindow()) {
- viewToClick.callOnClick();
- }
-
// Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
// visibilities so next time we open the panel we know the correct height already.
if (mQSPanel != null) {
@@ -3575,7 +3172,7 @@
mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
- LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
- recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
+ mCommandQueue.recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
mCommandQueue.appTransitionStarting(
startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
@@ -3697,15 +3294,43 @@
}
}
- protected void showBouncer(boolean scrimmed) {
+ @Override
+ public void showBouncer(boolean scrimmed) {
mStatusBarKeyguardViewManager.showBouncer(scrimmed);
}
- private void instantExpandNotificationsPanel() {
+ @Override
+ public void instantExpandNotificationsPanel() {
// Make our window larger and the panel expanded.
makeExpandedVisible(true);
mNotificationPanel.expand(false /* animate */);
- recomputeDisableFlags(false /* animate */);
+ mCommandQueue.recomputeDisableFlags(false /* animate */);
+ }
+
+ @Override
+ public boolean closeShadeIfOpen() {
+ if (!mNotificationPanel.isFullyCollapsed()) {
+ mCommandQueue.animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+ visibilityChanged(false);
+ mAssistManager.hideAssist();
+ }
+ return false;
+ }
+
+ @Override
+ public void postOnShadeExpanded(Runnable executable) {
+ mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (getStatusBarWindow().getHeight() != getStatusBarHeight()) {
+ mNotificationPanel.getViewTreeObserver()
+ .removeOnGlobalLayoutListener(this);
+ mNotificationPanel.post(executable);
+ }
+ }
+ });
}
private void instantCollapseNotificationPanel() {
@@ -3714,25 +3339,7 @@
}
@Override
- public void onActivated(ActivatableNotificationView view) {
- onActivated((View) view);
- mNotificationPanel.setActivatedChild(view);
- }
-
- public void onActivated(View view) {
- mLockscreenGestureLogger.write(
- MetricsEvent.ACTION_LS_NOTE,
- 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
- mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
- ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
- if (previousView != null) {
- previousView.makeInactive(true /* animate */);
- }
- }
-
- @Override
public void onStatePreChange(int oldState, int newState) {
-
// If we're visible and switched to SHADE_LOCKED (the user dragged
// down on the lockscreen), clear notification LED, vibration,
// ringing.
@@ -3780,7 +3387,7 @@
updateDozingState();
checkBarModes();
updateScrimController();
- updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
+ mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
mUnlockMethodCache.isMethodSecure(),
mStatusBarKeyguardViewManager.isOccluded());
@@ -3797,6 +3404,7 @@
&& DozeParameters.getInstance(mContext).shouldControlScreenOff();
mNotificationPanel.resetViews(dozingAnimated);
+ updateQsExpansionEnabled();
mKeyguardViewMediator.setAodShowing(mDozing);
//TODO: make these folks listeners of StatusBarStateController.onDozingChanged
@@ -3828,15 +3436,7 @@
mStatusBarStateController.setIsDozing(dozing);
}
- @Override
- public void onActivationReset(ActivatableNotificationView view) {
- if (view == mNotificationPanel.getActivatedChild()) {
- mNotificationPanel.setActivatedChild(null);
- onActivationReset((View)view);
- }
- }
-
- public void onActivationReset(View view) {
+ public void onActivationReset() {
mKeyguardIndicationController.hideTransientIndication();
}
@@ -3846,7 +3446,7 @@
public void onClosingFinished() {
runPostCollapseRunnables();
- if (!isPresenterFullyCollapsed()) {
+ if (!mPresenter.isPresenterFullyCollapsed()) {
// if we set it not to be focusable when collapsing, we have to undo it when we aborted
// the closing
mStatusBarWindowController.setStatusBarFocusable(true);
@@ -3886,22 +3486,6 @@
}
}
- @Override
- public int getMaxNotificationsWhileLocked(boolean recompute) {
- if (recompute) {
- mMaxKeyguardNotifications = Math.max(1,
- mNotificationPanel.computeMaxKeyguardNotifications(
- mMaxAllowedKeyguardNotifications));
- return mMaxKeyguardNotifications;
- }
- return mMaxKeyguardNotifications;
- }
-
- @Override
- public void onUpdateRowStates() {
- mNotificationPanel.onUpdateRowStates();
- }
-
// TODO: Figure out way to remove these.
public NavigationBarView getNavigationBarView() {
return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null);
@@ -3958,184 +3542,6 @@
}
}
- public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
- mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
- dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
- }
-
- @Override
- public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
- mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
- showBouncer(true /* scrimmed */);
- mPendingRemoteInputView = clicked;
- }
-
- @Override
- public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
- View clickedView) {
- if (isKeyguardShowing()) {
- onLockedRemoteInput(row, clickedView);
- } else {
- row.setUserExpanded(true);
- row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
- }
- }
-
- @Override
- public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) {
- // Skip remote input as doing so will expand the notification shade.
- return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
- }
-
- @Override
- public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
- Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) {
- final boolean isActivity = pendingIntent.isActivity();
- if (isActivity) {
- final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
- mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
- dismissKeyguardThenExecute(() -> {
- try {
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
-
- boolean handled = defaultHandler.handleClick();
-
- // close the shade if it was open
- if (handled && !mNotificationPanel.isFullyCollapsed()) {
- animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
- visibilityChanged(false);
- mAssistManager.hideAssist();
-
- // Wait for activity start.
- return true;
- } else {
- return false;
- }
-
- }, afterKeyguardGone);
- return true;
- } else {
- return defaultHandler.handleClick();
- }
- }
-
- protected 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
- mPendingWorkRemoteInputView = null;
- // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
- final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
- null, userId);
- if (newIntent == null) {
- return false;
- }
- final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
- callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
- callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
- callBackIntent.setPackage(mContext.getPackageName());
-
- PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
- mContext,
- 0,
- callBackIntent,
- PendingIntent.FLAG_CANCEL_CURRENT |
- PendingIntent.FLAG_ONE_SHOT |
- PendingIntent.FLAG_IMMUTABLE);
- newIntent.putExtra(
- Intent.EXTRA_INTENT,
- callBackPendingIntent.getIntentSender());
- try {
- ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
- null /*options*/);
- } catch (RemoteException ex) {
- // ignore
- }
- return true;
- // End old BaseStatusBar.startWorkChallengeIfNecessary.
- }
-
- @Override
- public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
- View clicked) {
- // Collapse notification and show work challenge
- animateCollapsePanels();
- startWorkChallengeIfNecessary(userId, null, null);
- // Add pending remote input view after starting work challenge, as starting work challenge
- // will clear all previous pending review view
- mPendingWorkRemoteInputView = clicked;
- }
-
- @Override
- public void onWorkChallengeChanged() {
- if (mPendingWorkRemoteInputView != null
- && !mLockscreenUserManager.isAnyProfilePublicMode()) {
- // Expand notification panel and the notification row, then click on remote input view
- final Runnable clickPendingViewRunnable = () -> {
- final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
- if (pendingWorkRemoteInputView == null) {
- return;
- }
-
- // Climb up the hierarchy until we get to the container for this row.
- ViewParent p = pendingWorkRemoteInputView.getParent();
- while (!(p instanceof ExpandableNotificationRow)) {
- if (p == null) {
- return;
- }
- p = p.getParent();
- }
-
- final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
- ViewParent viewParent = row.getParent();
- if (viewParent instanceof NotificationStackScrollLayout) {
- final NotificationStackScrollLayout scrollLayout =
- (NotificationStackScrollLayout) viewParent;
- row.makeActionsVisibile();
- row.post(() -> {
- final Runnable finishScrollingCallback = () -> {
- mPendingWorkRemoteInputView.callOnClick();
- mPendingWorkRemoteInputView = null;
- scrollLayout.setFinishScrollingCallback(null);
- };
- if (scrollLayout.scrollTo(row)) {
- // It scrolls! So call it when it's finished.
- scrollLayout.setFinishScrollingCallback(finishScrollingCallback);
- } else {
- // It does not scroll, so call it now!
- finishScrollingCallback.run();
- }
- });
- }
- };
- mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (mNotificationPanel.mStatusBar.getStatusBarWindow()
- .getHeight() != mNotificationPanel.mStatusBar
- .getStatusBarHeight()) {
- mNotificationPanel.getViewTreeObserver()
- .removeOnGlobalLayoutListener(this);
- mNotificationPanel.post(clickPendingViewRunnable);
- }
- }
- });
- instantExpandNotificationsPanel();
- }
- }
-
- @Override
- public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
- mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
- if (mState == StatusBarState.KEYGUARD && nowExpanded) {
- goToLockedShade(clickedEntry.row);
- }
- }
-
/**
* Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
*/
@@ -4149,7 +3555,7 @@
mBouncerShowing = bouncerShowing;
if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
updateHideIconsForBouncer(true /* animate */);
- recomputeDisableFlags(true /* animate */);
+ mCommandQueue.recomputeDisableFlags(true /* animate */);
updateScrimController();
}
@@ -4273,25 +3679,6 @@
}
@Override
- public void wakeUpIfDozing(long time, View where) {
- if (mDozing) {
- PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- pm.wakeUp(time, "com.android.systemui:NODOZE");
- mWakeUpComingFromTouch = true;
- where.getLocationInWindow(mTmpInt2);
- mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
- mTmpInt2[1] + where.getHeight() / 2);
- mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
- mFalsingManager.onScreenOnFromTouch();
- }
- }
-
- @Override
- public boolean isDeviceLocked(int userId) {
- return mKeyguardManager.isDeviceLocked(userId);
- }
-
- @Override
public void appTransitionCancelled() {
getComponent(Divider.class).onAppTransitionFinished();
}
@@ -4669,8 +4056,6 @@
protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
- private AboveShelfObserver mAboveShelfObserver;
-
// handling reordering
protected VisualStabilityManager mVisualStabilityManager;
@@ -4688,7 +4073,6 @@
protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
protected KeyguardManager mKeyguardManager;
- private LockPatternUtils mLockPatternUtils;
private DeviceProvisionedController mDeviceProvisionedController
= Dependency.get(DeviceProvisionedController.class);
@@ -4707,28 +4091,10 @@
protected AssistManager mAssistManager;
- protected boolean mVrMode;
-
public boolean isDeviceInteractive() {
return mDeviceInteractive;
}
- @Override // NotificationData.Environment
- public boolean isDeviceProvisioned() {
- return mDeviceProvisionedController.isDeviceProvisioned();
- }
-
- private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
- @Override
- public void onVrStateChanged(boolean enabled) {
- mVrMode = enabled;
- }
- };
-
- public boolean isDeviceInVrMode() {
- return mVrMode;
- }
-
private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -4754,182 +4120,13 @@
};
@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 = mIsOccluded;
- boolean showOverLockscreen = mStatusBarKeyguardViewManager.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).getStatusBarNotification();
- 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 (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) {
- addPostCollapseAction(runnable);
- collapsePanel(true /* animate */);
- } else if (mStatusBarKeyguardViewManager.isShowing()
- && mStatusBarKeyguardViewManager.isOccluded()) {
- mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
- collapsePanel(true /* animate */);
- } else {
- new Thread(runnable).start();
- }
-
- return !mNotificationPanel.isFullyCollapsed();
- };
- if (showOverLockscreen) {
- mIsCollapsingToShowActivityOverLockscreen = true;
- postKeyguardAction.onDismiss();
- } else {
- dismissKeyguardThenExecute(postKeyguardAction, afterKeyguardGone);
- }
- }
-
- private void collapseOnMainThread() {
- if (Looper.getMainLooper().isCurrentThread()) {
- collapsePanel();
- } else {
- Dependency.get(Dependency.MAIN_HANDLER).post(this::collapsePanel);
- }
- }
-
- private boolean shouldCollapse() {
- return mState != StatusBarState.SHADE || !mActivityLaunchAnimator.isAnimationPending();
- }
-
public void collapsePanel(boolean animate) {
if (animate) {
boolean willCollapse = collapsePanel();
if (!willCollapse) {
runPostCollapseRunnables();
}
- } else if (!isPresenterFullyCollapsed()) {
+ } else if (!mPresenter.isPresenterFullyCollapsed()) {
instantCollapseNotificationPanel();
visibilityChanged(false);
} else {
@@ -4937,7 +4134,8 @@
}
}
- private boolean collapsePanel() {
+ @Override
+ public boolean collapsePanel() {
if (!mNotificationPanel.isFullyCollapsed()) {
// close the shade if it was open
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
@@ -4950,59 +4148,8 @@
}
}
- private void removeNotification(StatusBarNotification notification) {
- // We have to post it to the UI thread for synchronization
- mHandler.post(() -> {
- Runnable removeRunnable =
- () -> mEntryManager.performRemoveNotification(notification);
- if (isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade was collapsed
- addPostCollapseAction(removeRunnable);
- } else {
- removeRunnable.run();
- }
- });
- }
-
protected NotificationListener mNotificationListener;
- @Override // NotificationData.Environment
- public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
- final int notificationUserId = n.getUserId();
- if (DEBUG && MULTIUSER_DEBUG) {
- Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
- mLockscreenUserManager.getCurrentUserId(), notificationUserId));
- }
- return mLockscreenUserManager.isCurrentProfile(notificationUserId);
- }
-
- @Override
- public NotificationGroupManager getGroupManager() {
- return mGroupManager;
- }
-
- @Override
- public void startNotificationGutsIntent(final Intent intent, final int appUid,
- ExpandableNotificationRow row) {
- dismissKeyguardThenExecute(() -> {
- AsyncTask.execute(() -> {
- int launchResult = TaskStackBuilder.create(mContext)
- .addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(
- mActivityLaunchAnimator.getLaunchAnimation(row, mIsOccluded)),
- new UserHandle(UserHandle.getUserId(appUid)));
- mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
- if (shouldCollapse()) {
- // Putting it back on the main thread, since we're touching views
- mStatusBarWindow.post(() -> animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
- }
- });
- return true;
- }, false /* afterKeyguardGone */);
- }
-
public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
if (snoozeOption.getSnoozeCriterion() != null) {
mNotificationListener.snoozeNotification(sbn.getKey(),
@@ -5063,7 +4210,7 @@
// Immediately update the icon hidden state, since that should only apply if we're
// staying fullscreen.
mWereIconsJustHidden = false;
- recomputeDisableFlags(true);
+ mCommandQueue.recomputeDisableFlags(true);
}
updateHideIconsForBouncer(true /* animate */);
}
@@ -5076,24 +4223,6 @@
KeyboardShortcuts.dismiss();
}
- @Override // NotificationData.Environment
- public boolean shouldHideNotifications(int userId) {
- return mLockscreenUserManager.shouldHideNotifications(userId);
- }
-
- @Override // NotificationDate.Environment
- public boolean shouldHideNotifications(String key) {
- return mLockscreenUserManager.shouldHideNotifications(key);
- }
-
- /**
- * Returns true if we're on a secure lockscreen.
- */
- @Override // NotificationData.Environment
- public boolean isSecurelyLocked(int userId) {
- return mLockscreenUserManager.isLockscreenPublicMode(userId);
- }
-
/**
* Called when the notification panel layouts
*/
@@ -5105,8 +4234,8 @@
if (mState == StatusBarState.KEYGUARD) {
// Since the number of notifications is determined based on the height of the view, we
// need to update them.
- int maxBefore = getMaxNotificationsWhileLocked(false /* recompute */);
- int maxNotifications = getMaxNotificationsWhileLocked(true /* recompute */);
+ int maxBefore = mPresenter.getMaxNotificationsWhileLocked(false /* recompute */);
+ int maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
if (maxBefore != maxNotifications) {
mViewHierarchyManager.updateRowStates();
}
@@ -5114,7 +4243,7 @@
}
public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
- if (!isDeviceProvisioned()) return;
+ if (!mDeviceProvisionedController.isDeviceProvisioned()) return;
final boolean afterKeyguardGone = intent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
@@ -5148,18 +4277,7 @@
}, afterKeyguardGone);
}
- private 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;
- }
-
- protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
+ public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
ActivityOptions options;
if (animationAdapter != null) {
options = ActivityOptions.makeRemoteAnimation(animationAdapter);
@@ -5276,28 +4394,4 @@
public NotificationGutsManager getGutsManager() {
return mGutsManager;
}
-
- @Override
- public boolean isPresenterLocked() {
- return mState == StatusBarState.KEYGUARD;
- }
-
- @Override
- public Handler getHandler() {
- return mHandler;
- }
-
- private final NotificationInfo.CheckSaveListener mCheckSaveListener =
- (Runnable saveImportance, StatusBarNotification sbn) -> {
- // If the user has security enabled, show challenge if the setting is changed.
- if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
- && mKeyguardManager.isKeyguardLocked()) {
- onLockedNotificationImportanceChange(() -> {
- saveImportance.run();
- return true;
- });
- } else {
- saveImportance.run();
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index ac3608b..c560301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.phone;
-import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
@@ -43,6 +43,7 @@
import com.android.systemui.SystemUIFactory;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
@@ -124,6 +125,8 @@
// Dismiss action to be launched when we stop dozing or the keyguard is gone.
private DismissWithActionRequest mPendingWakeupAction;
private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+ private final NotificationMediaManager mMediaManager =
+ Dependency.get(NotificationMediaManager.class);
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@@ -381,7 +384,7 @@
boolean isOccluding = !mOccluded && occluded;
mOccluded = occluded;
if (mShowing) {
- mStatusBar.updateMediaMetaData(false, animate && !occluded);
+ mMediaManager.updateMediaMetaData(false, animate && !occluded);
}
mStatusBarWindowController.setKeyguardOccluded(occluded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
new file mode 100644
index 0000000..635ffc7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -0,0 +1,672 @@
+/*
+ * 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.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;
+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;
+import com.android.systemui.statusbar.CommandQueue;
+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;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+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 {
+
+ private final LockscreenGestureLogger mLockscreenGestureLogger =
+ Dependency.get(LockscreenGestureLogger.class);
+
+ private static final String TAG = "StatusBarNotificationPresenter";
+
+ 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);
+ private final NotificationLockscreenUserManager mLockscreenUserManager =
+ Dependency.get(NotificationLockscreenUserManager.class);
+ private final StatusBarStateController mStatusBarStateController =
+ Dependency.get(StatusBarStateController.class);
+ private final NotificationEntryManager mEntryManager =
+ 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;
+ private final HeadsUpManagerPhone mHeadsUpManager;
+ private final AboveShelfObserver mAboveShelfObserver;
+ private final DozeScrimController mDozeScrimController;
+ private final ScrimController mScrimController;
+ private final Context mContext;
+ private final CommandQueue mCommandQueue;
+
+ private final AccessibilityManager mAccessibilityManager;
+ private final LockPatternUtils mLockPatternUtils;
+ private final KeyguardManager mKeyguardManager;
+ private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final int mMaxAllowedKeyguardNotifications;
+ private final IStatusBarService mBarService;
+ private boolean mReinflateNotificationsOnUserSwitched;
+ private final UnlockMethodCache mUnlockMethodCache;
+ private TextView mNotificationPanelDebugText;
+
+ protected boolean mVrMode;
+ private int mMaxKeyguardNotifications;
+ private boolean mIsCollapsingToShowActivityOverLockscreen;
+
+ public StatusBarNotificationPresenter(Context context, NotificationPanelView panel,
+ HeadsUpManagerPhone headsUp, StatusBarWindowView statusBarWindow,
+ ViewGroup stackScroller, DozeScrimController dozeScrimController,
+ ScrimController scrimController,
+ ActivityLaunchAnimator.Callback launchAnimatorCallback) {
+ mContext = context;
+ mNotificationPanel = panel;
+ mHeadsUpManager = headsUp;
+ mCommandQueue = getComponent(context, CommandQueue.class);
+ mAboveShelfObserver = new AboveShelfObserver(stackScroller);
+ 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);
+ mNotificationPanelDebugText.setVisibility(View.VISIBLE);
+ }
+
+ IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
+ Context.VR_SERVICE));
+ if (vrManager != null) {
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
+ }
+ mRemoteInputManager.setUpWithPresenter(this,
+ Dependency.get(NotificationRemoteInputManager.Callback.class),
+ mNotificationPanel.createRemoteInputDelegate());
+ mRemoteInputManager.getController().addCallback(
+ Dependency.get(StatusBarWindowController.class));
+
+ NotificationListContainer notifListContainer = (NotificationListContainer) stackScroller;
+ Dependency.get(InitController.class).addPostInitTask(() -> {
+ mViewHierarchyManager.setUpWithPresenter(this, notifListContainer);
+ mEntryManager.setUpWithPresenter(this, notifListContainer, this, mHeadsUpManager);
+ mLockscreenUserManager.setUpWithPresenter(this);
+ mMediaManager.setUpWithPresenter(this);
+ Dependency.get(NotificationGutsManager.class).setUpWithPresenter(this,
+ notifListContainer, mCheckSaveListener, mOnSettingsClickListener);
+
+ onUserSwitched(mLockscreenUserManager.getCurrentUserId());
+ });
+ }
+
+ public void onDensityOrFontScaleChanged() {
+ if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
+ mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
+ } else {
+ mReinflateNotificationsOnUserSwitched = true;
+ }
+ }
+
+ @Override
+ public ActivityLaunchAnimator getActivityLaunchAnimator() {
+ return mActivityLaunchAnimator;
+ }
+
+ @Override
+ public boolean isCollapsing() {
+ return mNotificationPanel.isCollapsing()
+ || mActivityLaunchAnimator.isAnimationPending()
+ || mActivityLaunchAnimator.isAnimationRunning();
+ }
+
+ @Override
+ public boolean isCollapsingToShowActivityOverLockscreen() {
+ return mIsCollapsingToShowActivityOverLockscreen;
+ }
+
+ @Override
+ public void onPerformRemoveNotification(StatusBarNotification n) {
+ if (mNotificationPanel.hasPulsingNotifications() &&
+ !mAmbientPulseManager.hasNotifications()) {
+ // We were showing a pulse for a notification, but no notifications are pulsing anymore.
+ // Finish the pulse.
+ mDozeScrimController.pulseOutNow();
+ }
+ }
+
+ @Override
+ public void updateNotificationViews() {
+ // The function updateRowStates depends on both of these being non-null, so check them here.
+ // We may be called before they are set from DeviceProvisionedController's callback.
+ if (mScrimController == null) return;
+
+ // Do not modify the notifications during collapse.
+ if (isCollapsing()) {
+ mShadeController.addPostCollapseAction(this::updateNotificationViews);
+ return;
+ }
+
+ mViewHierarchyManager.updateNotificationViews();
+
+ mNotificationPanel.updateNotificationViews();
+ }
+
+ @Override
+ public void onNotificationAdded(Entry shadeEntry) {
+ // Recalculate the position of the sliding windows and the titles.
+ mShadeController.updateAreThereNotifications();
+ }
+
+ @Override
+ public void onNotificationUpdated(StatusBarNotification notification) {
+ mShadeController.updateAreThereNotifications();
+ }
+
+ @Override
+ public void onNotificationRemoved(String key, StatusBarNotification old) {
+ if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
+
+ if (old != null) {
+ if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
+ && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
+ if (mStatusBarStateController.getState() == StatusBarState.SHADE) {
+ mCommandQueue.animateCollapsePanels();
+ } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
+ && !isCollapsing()) {
+ mShadeController.goToKeyguard();
+ }
+ }
+ }
+ mShadeController.updateAreThereNotifications();
+ }
+
+ public boolean hasActiveNotifications() {
+ return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+ }
+
+ @Override
+ public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
+ if (!mShadeController.isDozing()) {
+ return false;
+ }
+
+ if (mShadeController.isOccluded()) {
+ boolean devicePublic = mLockscreenUserManager.
+ isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
+ boolean userPublic = devicePublic
+ || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
+ boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
+ if (userPublic && needsRedaction) {
+ return false;
+ }
+ }
+
+ if (!mCommandQueue.panelsEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (sbn.getNotification().fullScreenIntent != null) {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
+ return false;
+ } else {
+ // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
+ return !mKeyguardMonitor.isShowing()
+ || mShadeController.isOccluded();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onUserSwitched(int newUserId) {
+ // Begin old BaseStatusBar.userSwitched
+ mHeadsUpManager.setUser(newUserId);
+ // End old BaseStatusBar.userSwitched
+ if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
+ mCommandQueue.animateCollapsePanels();
+ if (mReinflateNotificationsOnUserSwitched) {
+ mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
+ mReinflateNotificationsOnUserSwitched = false;
+ }
+ updateNotificationViews();
+ mMediaManager.clearCurrentMediaNotification();
+ mShadeController.setLockscreenUser(newUserId);
+ updateMediaMetaData(true, false);
+ }
+
+ @Override
+ public void onBindRow(Entry entry, PackageManager pmUser,
+ StatusBarNotification sbn, ExpandableNotificationRow row) {
+ row.setAboveShelfChangedListener(mAboveShelfObserver);
+ row.setSecureStateProvider(mUnlockMethodCache::canSkipBouncer);
+ }
+
+ @Override
+ public boolean isPresenterFullyCollapsed() {
+ return mNotificationPanel.isFullyCollapsed();
+ }
+
+ @Override
+ public void onActivated(ActivatableNotificationView view) {
+ onActivated();
+ if (view != null) mNotificationPanel.setActivatedChild(view);
+ }
+
+ public void onActivated() {
+ mLockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_NOTE,
+ 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+ mNotificationPanel.showTransientIndication(R.string.notification_tap_again);
+ ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
+ if (previousView != null) {
+ previousView.makeInactive(true /* animate */);
+ }
+ }
+
+ @Override
+ public void onActivationReset(ActivatableNotificationView view) {
+ if (view == mNotificationPanel.getActivatedChild()) {
+ mNotificationPanel.setActivatedChild(null);
+ mShadeController.onActivationReset();
+ }
+ }
+
+ @Override
+ public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
+ 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).getStatusBarNotification();
+ 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) {
+ mMaxKeyguardNotifications = Math.max(1,
+ mNotificationPanel.computeMaxKeyguardNotifications(
+ mMaxAllowedKeyguardNotifications));
+ return mMaxKeyguardNotifications;
+ }
+ return mMaxKeyguardNotifications;
+ }
+
+ @Override
+ public void onUpdateRowStates() {
+ mNotificationPanel.onUpdateRowStates();
+ }
+
+ @Override
+ public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
+ mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
+ if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
+ mShadeController.goToLockedShade(clickedEntry.row);
+ }
+ }
+
+ @Override
+ public boolean isDeviceInVrMode() {
+ 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) {
+ mVrMode = enabled;
+ }
+ };
+
+ 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()) {
+ onLockedNotificationImportanceChange(() -> {
+ saveImportance.run();
+ return true;
+ });
+ } else {
+ saveImportance.run();
+ }
+ }
+ };
+
+ private final OnSettingsClickListener mOnSettingsClickListener = new OnSettingsClickListener() {
+ @Override
+ public void onSettingsClick(String key) {
+ try {
+ mBarService.onNotificationSettingsViewed(key);
+ } catch (RemoteException e) {
+ // if we're here we're dead
+ }
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
new file mode 100644
index 0000000..06f9658
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -0,0 +1,252 @@
+/*
+ * 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 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 android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+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;
+
+public class StatusBarRemoteInputCallback implements Callback, Callbacks {
+
+ private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+ private final StatusBarStateController mStatusBarStateController
+ = Dependency.get(StatusBarStateController.class);
+ private final NotificationLockscreenUserManager mLockscreenUserManager
+ = Dependency.get(NotificationLockscreenUserManager.class);
+ private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
+ private final Context mContext;
+ private View mPendingWorkRemoteInputView;
+ private final StatusBarStateController.StateListener mStateListener = this::setStatusBarState;
+ private View mPendingRemoteInputView;
+ private final ShadeController mShadeController = Dependency.get(ShadeController.class);
+ private KeyguardManager mKeyguardManager;
+ private final CommandQueue mCommandQueue;
+ private int mDisabled2;
+ protected BroadcastReceiver mChallengeReceiver = new ChallengeReceiver();
+
+ public StatusBarRemoteInputCallback(Context context) {
+ mContext = context;
+ mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
+ new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
+ mStatusBarStateController.addListener(mStateListener);
+ mKeyguardManager = context.getSystemService(KeyguardManager.class);
+ mCommandQueue = getComponent(context, CommandQueue.class);
+ mCommandQueue.addCallbacks(this);
+ }
+
+ private void setStatusBarState(int state) {
+ if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
+ if (!mStatusBarStateController.isKeyguardRequested()) {
+ if (mPendingRemoteInputView != null
+ && mPendingRemoteInputView.isAttachedToWindow()) {
+ mPendingRemoteInputView.post(mPendingRemoteInputView::callOnClick);
+ }
+ mPendingRemoteInputView = null;
+ }
+ }
+ }
+
+ @Override
+ public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
+ mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+ mShadeController.showBouncer(true /* scrimmed */);
+ mPendingRemoteInputView = clicked;
+ }
+
+ protected void onWorkChallengeChanged() {
+ if (mPendingWorkRemoteInputView != null
+ && !mLockscreenUserManager.isAnyProfilePublicMode()) {
+ // Expand notification panel and the notification row, then click on remote input view
+ final Runnable clickPendingViewRunnable = () -> {
+ final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
+ if (pendingWorkRemoteInputView == null) {
+ return;
+ }
+
+ // Climb up the hierarchy until we get to the container for this row.
+ ViewParent p = pendingWorkRemoteInputView.getParent();
+ while (!(p instanceof ExpandableNotificationRow)) {
+ if (p == null) {
+ return;
+ }
+ p = p.getParent();
+ }
+
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
+ ViewParent viewParent = row.getParent();
+ if (viewParent instanceof NotificationStackScrollLayout) {
+ final NotificationStackScrollLayout scrollLayout =
+ (NotificationStackScrollLayout) viewParent;
+ row.makeActionsVisibile();
+ row.post(() -> {
+ final Runnable finishScrollingCallback = () -> {
+ mPendingWorkRemoteInputView.callOnClick();
+ mPendingWorkRemoteInputView = null;
+ scrollLayout.setFinishScrollingCallback(null);
+ };
+ if (scrollLayout.scrollTo(row)) {
+ // It scrolls! So call it when it's finished.
+ scrollLayout.setFinishScrollingCallback(finishScrollingCallback);
+ } else {
+ // It does not scroll, so call it now!
+ finishScrollingCallback.run();
+ }
+ });
+ }
+ };
+ mShadeController.postOnShadeExpanded(clickPendingViewRunnable);
+ mShadeController.instantExpandNotificationsPanel();
+ }
+ }
+
+ @Override
+ public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
+ View clickedView) {
+ if (mKeyguardMonitor.isShowing()) {
+ onLockedRemoteInput(row, clickedView);
+ } else {
+ row.setUserExpanded(true);
+ row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
+ }
+ }
+
+ @Override
+ public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
+ View clicked) {
+ // Collapse notification and show work challenge
+ mCommandQueue.animateCollapsePanels();
+ startWorkChallengeIfNecessary(userId, null, null);
+ // Add pending remote input view after starting work challenge, as starting work challenge
+ // will clear all previous pending review view
+ mPendingWorkRemoteInputView = clicked;
+ }
+
+ protected 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
+ mPendingWorkRemoteInputView = null;
+ // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
+ final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
+ null, userId);
+ if (newIntent == null) {
+ return false;
+ }
+ final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
+ callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
+ callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
+ callBackIntent.setPackage(mContext.getPackageName());
+
+ PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ callBackIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT |
+ PendingIntent.FLAG_ONE_SHOT |
+ PendingIntent.FLAG_IMMUTABLE);
+ newIntent.putExtra(
+ Intent.EXTRA_INTENT,
+ callBackPendingIntent.getIntentSender());
+ try {
+ ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
+ null /*options*/);
+ } catch (RemoteException ex) {
+ // ignore
+ }
+ return true;
+ // End old BaseStatusBar.startWorkChallengeIfNecessary.
+ }
+
+ @Override
+ public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) {
+ // Skip remote input as doing so will expand the notification shade.
+ return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
+ }
+
+ @Override
+ public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
+ Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) {
+ final boolean isActivity = pendingIntent.isActivity();
+ if (isActivity) {
+ final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
+ mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
+ mActivityStarter.dismissKeyguardThenExecute(() -> {
+ try {
+ ActivityManager.getService().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+
+ boolean handled = defaultHandler.handleClick();
+
+ // close the shade if it was open and maybe wait for activity start.
+ return handled && mShadeController.closeShadeIfOpen();
+ }, null, afterKeyguardGone);
+ return true;
+ } else {
+ return defaultHandler.handleClick();
+ }
+ }
+
+ @Override
+ public void disable(int state1, int state2, boolean animate) {
+ mDisabled2 = state2;
+ }
+
+ protected class ChallengeReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
+ if (userId != mLockscreenUserManager.getCurrentUserId()
+ && mLockscreenUserManager.isCurrentProfile(userId)) {
+ onWorkChallengeChanged();
+ }
+ }
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 7b42dd4..aba2377 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -24,6 +24,7 @@
boolean isOccluded();
boolean isKeyguardFadingAway();
boolean isKeyguardGoingAway();
+ boolean isLaunchTransitionFadingAway();
long getKeyguardFadingAwayDuration();
long getKeyguardFadingAwayDelay();
long calculateGoingToFullShadeDelay();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 10cb09b..5eb0fb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -28,7 +28,7 @@
public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
implements KeyguardMonitor {
- private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private final Context mContext;
private final CurrentUserTracker mUserTracker;
@@ -45,6 +45,7 @@
private long mKeyguardFadingAwayDelay;
private long mKeyguardFadingAwayDuration;
private boolean mKeyguardGoingAway;
+ private boolean mLaunchTransitionFadingAway;
public KeyguardMonitorImpl(Context context) {
mContext = context;
@@ -123,7 +124,7 @@
private void notifyKeyguardChanged() {
// Copy the list to allow removal during callback.
- new ArrayList<Callback>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
+ new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
}
public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
@@ -165,4 +166,13 @@
public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
mKeyguardGoingAway = keyguardGoingAway;
}
+
+ public void setLaunchTransitionFadingAway(boolean fadingAway) {
+ mLaunchTransitionFadingAway = fadingAway;
+ }
+
+ @Override
+ public boolean isLaunchTransitionFadingAway() {
+ return mLaunchTransitionFadingAway;
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index dd03162..aa4782f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -28,7 +28,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ContrastColorUtil;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;