Merge "Do not use shared lib resources" into sc-v2-dev
diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
index a630873..e1c13f7 100644
--- a/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
+++ b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
@@ -29,4 +29,6 @@
in String callingPackage,
in IFindDeviceCallback findCallback,
in AndroidFuture<Association> serviceCallback);
+
+ void onAssociationCreated();
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 42b4380..20515e7 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -516,12 +516,8 @@
// Skipping containers that do not have any activities to report.
continue;
}
- ActivityStack primaryContainer =
- new ActivityStack(
- container.getPrimaryContainer().collectActivities());
- ActivityStack secondaryContainer =
- new ActivityStack(
- container.getSecondaryContainer().collectActivities());
+ ActivityStack primaryContainer = container.getPrimaryContainer().toActivityStack();
+ ActivityStack secondaryContainer = container.getSecondaryContainer().toActivityStack();
SplitInfo splitState = new SplitInfo(primaryContainer,
secondaryContainer,
// Splits that are not showing side-by-side are reported as having 0 split
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 54e44a7..80d9c2c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -109,6 +109,10 @@
return allActivities;
}
+ ActivityStack toActivityStack() {
+ return new ActivityStack(collectActivities(), mInfo.getRunningActivityCount() == 0);
+ }
+
void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
mPendingAppearedActivities.add(pendingAppearedActivity);
}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 4f36c9c..830d13d 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index b4cafd8..edbfd2a 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -254,8 +254,14 @@
Log.i(LOG_TAG, "onDeviceConfirmed(selectedDevice = " + selectedDevice + ")");
getService().onDeviceSelected(
getCallingPackage(), getDeviceMacAddress(selectedDevice.device));
+ }
+
+ void setResultAndFinish() {
+ Log.i(LOG_TAG, "setResultAndFinish(selectedDevice = "
+ + getService().mSelectedDevice.device + ")");
setResult(RESULT_OK,
- new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice.device));
+ new Intent().putExtra(
+ CompanionDeviceManager.EXTRA_DEVICE, getService().mSelectedDevice.device));
finish();
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index c24782e..5df8e3c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -117,6 +117,11 @@
CompanionDeviceDiscoveryService::startDiscovery,
CompanionDeviceDiscoveryService.this, request));
}
+
+ @Override
+ public void onAssociationCreated() {
+ Handler.getMain().post(CompanionDeviceDiscoveryService.this::onAssociationCreated);
+ }
};
private ScanCallback mBLEScanCallback;
@@ -222,6 +227,11 @@
SCAN_TIMEOUT);
}
+ @MainThread
+ private void onAssociationCreated() {
+ mActivity.setResultAndFinish();
+ }
+
private boolean shouldScan(List<? extends DeviceFilter> mediumSpecificFilters) {
return !isEmpty(mediumSpecificFilters) || isEmpty(mFilters);
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c6cca5a..721b432 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -52,12 +52,18 @@
filegroup {
name: "ReleaseJavaFiles",
- srcs: ["src/com/android/systemui/flags/FeatureFlagManager.java"],
+ srcs: [
+ "src-release/**/*.kt",
+ "src-release/**/*.java",
+ ],
}
filegroup {
name: "DebugJavaFiles",
- srcs: ["src-debug/com/android/systemui/flags/FeatureFlagManager.java"],
+ srcs: [
+ "src-debug/**/*.kt",
+ "src-debug/**/*.java",
+ ],
}
android_library {
@@ -66,6 +72,8 @@
"src/**/*.kt",
"src/**/*.java",
"src/**/I*.aidl",
+ "src-release/**/*.kt",
+ "src-release/**/*.java",
],
product_variables: {
debuggable: {
@@ -159,6 +167,8 @@
"src/**/*.kt",
"src/**/*.java",
"src/**/I*.aidl",
+ "src-release/**/*.kt",
+ "src-release/**/*.java",
],
static_libs: [
"SystemUIAnimationLib",
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index 5389d9b..c949ba0 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -21,6 +21,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="5dp"
>
<LinearLayout
android:id="@+id/ongoing_call_chip_background"
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index ab159e1..040df86 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -32,4 +32,6 @@
<!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
<bool name="config_skinnyNotifsInLandscape">false</bool>
+
+ <dimen name="keyguard_indication_margin_bottom">25dp</dimen>
</resources>
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
index 3a8ee29..1eeb516 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
@@ -75,6 +75,7 @@
}
/** Return a {@link BooleanFlag}'s value. */
+ @Override
public boolean isEnabled(int id, boolean defaultValue) {
if (!mBooleanFlagCache.containsKey(id)) {
Boolean result = isEnabledInternal(id);
@@ -105,6 +106,7 @@
}
/** Set whether a given {@link BooleanFlag} is enabled or not. */
+ @Override
public void setEnabled(int id, boolean value) {
Boolean currentValue = isEnabledInternal(id);
if (currentValue != null && currentValue == value) {
@@ -136,8 +138,10 @@
Log.i(TAG, "Erase id " + id);
}
+ @Override
public void addListener(Listener run) {}
+ @Override
public void removeListener(Listener run) {}
private void restartSystemUI() {
@@ -198,6 +202,7 @@
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("can override: true");
ArrayList<String> flagStrings = new ArrayList<>(mBooleanFlagCache.size());
for (Map.Entry<Integer, Boolean> entry : mBooleanFlagCache.entrySet()) {
flagStrings.add(" sysui_flag_" + entry.getKey() + ": " + entry.getValue());
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/flags/FeatureFlagManager.java
rename to packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
index 78f0b5f..e501a07 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagManager.java
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.flags;
+import android.content.Context;
import android.util.SparseBooleanArray;
import androidx.annotation.NonNull;
@@ -39,21 +40,21 @@
public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
SparseBooleanArray mAccessedFlags = new SparseBooleanArray();
@Inject
- public FeatureFlagManager(DumpManager dumpManager) {
+ public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper, Context context,
+ DumpManager dumpManager) {
dumpManager.registerDumpable("SysUIFlags", this);
}
- public boolean isEnabled(String key, boolean defaultValue) {
- return defaultValue;
- }
+ @Override
public boolean isEnabled(int key, boolean defaultValue) {
mAccessedFlags.append(key, defaultValue);
return defaultValue;
}
- public void setEnabled(String key, boolean value) {}
+ @Override
public void setEnabled(int key, boolean value) {}
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("can override: false");
int size = mAccessedFlags.size();
for (int i = 0; i < size; i++) {
pw.println(" sysui_flag_" + mAccessedFlags.keyAt(i)
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
index 947a39a..48bb281 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -18,6 +18,8 @@
import android.content.Context;
import android.util.FeatureFlagUtils;
+import android.util.Log;
+import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
@@ -86,6 +88,22 @@
}
}
+ public void assertLegacyPipelineEnabled() {
+ if (isNewNotifPipelineRenderingEnabled()) {
+ throw new IllegalStateException("Old pipeline code running w/ new pipeline enabled");
+ }
+ }
+
+ public boolean checkLegacyPipelineEnabled() {
+ if (!isNewNotifPipelineRenderingEnabled()) {
+ return true;
+ }
+ Log.d("NotifPipeline", "Old pipeline code running w/ new pipeline enabled",
+ new Exception());
+ Toast.makeText(mContext, "Old pipeline code running!", Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
public boolean isNewNotifPipelineEnabled() {
return isEnabled(Flags.NEW_NOTIFICATION_PIPELINE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 4f87cad..98b9146 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -72,12 +72,6 @@
private var listening: Boolean = false
var expanded = false
- set(value) {
- if (field != value) {
- field = value
- updateView()
- }
- }
private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button)
private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container)
@@ -176,8 +170,7 @@
}
private fun updateView() {
- mView.updateEverything(buttonsVisible(), isTunerEnabled(),
- multiUserSwitchController.isMultiUserEnabled)
+ mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
}
override fun onViewDetached() {
@@ -191,14 +184,14 @@
this.listening = listening
if (this.listening) {
userInfoController.addCallback(onUserInfoChangedListener)
+ updateView()
} else {
userInfoController.removeCallback(onUserInfoChangedListener)
}
}
fun disable(state2: Int) {
- mView.disable(buttonsVisible(), state2, isTunerEnabled(),
- multiUserSwitchController.isMultiUserEnabled)
+ mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
}
fun setExpansion(headerExpansionFraction: Float) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
index 941e54a..f81f7bf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
@@ -107,7 +107,6 @@
}
fun disable(
- buttonsVisible: Boolean,
state2: Int,
isTunerEnabled: Boolean,
multiUserEnabled: Boolean
@@ -115,16 +114,15 @@
val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
if (disabled == qsDisabled) return
qsDisabled = disabled
- updateEverything(buttonsVisible, isTunerEnabled, multiUserEnabled)
+ updateEverything(isTunerEnabled, multiUserEnabled)
}
fun updateEverything(
- buttonsVisible: Boolean,
isTunerEnabled: Boolean,
multiUserEnabled: Boolean
) {
post {
- updateVisibilities(buttonsVisible, isTunerEnabled, multiUserEnabled)
+ updateVisibilities(isTunerEnabled, multiUserEnabled)
updateClickabilities()
isClickable = false
}
@@ -137,15 +135,14 @@
}
private fun updateVisibilities(
- buttonsVisible: Boolean,
isTunerEnabled: Boolean,
multiUserEnabled: Boolean
) {
settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE
- multiUserSwitch.visibility = if (buttonsVisible && multiUserEnabled) VISIBLE else GONE
+ multiUserSwitch.visibility = if (multiUserEnabled) VISIBLE else GONE
val isDemo = UserManager.isDeviceInDemoMode(context)
- settingsButton.visibility = if (isDemo || !buttonsVisible) INVISIBLE else VISIBLE
+ settingsButton.visibility = if (isDemo) INVISIBLE else VISIBLE
}
fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 7e5ff8a..1784f73 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -112,6 +112,16 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ // Pass configuration change to non-attached pages as well. Some config changes will cause
+ // QS to recreate itself (as determined in FragmentHostManager), but in order to minimize
+ // those, make sure that all get passed to all pages.
+ int numPages = mPages.size();
+ for (int i = 0; i < numPages; i++) {
+ View page = mPages.get(i);
+ if (page.getParent() == null) {
+ page.dispatchConfigurationChanged(newConfig);
+ }
+ }
if (mLayoutOrientation != newConfig.orientation) {
mLayoutOrientation = newConfig.orientation;
mDistributeTiles = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 396d86b..464b2b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -27,6 +27,7 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
@@ -72,6 +73,7 @@
// Dependencies:
private final DynamicChildBindController mDynamicChildBindController;
+ private final FeatureFlags mFeatureFlags;
protected final NotificationLockscreenUserManager mLockscreenUserManager;
protected final NotificationGroupManagerLegacy mGroupManager;
protected final VisualStabilityManager mVisualStabilityManager;
@@ -107,6 +109,7 @@
public NotificationViewHierarchyManager(
Context context,
@Main Handler mainHandler,
+ FeatureFlags featureFlags,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGroupManagerLegacy groupManager,
VisualStabilityManager visualStabilityManager,
@@ -121,6 +124,7 @@
AssistantFeedbackController assistantFeedbackController) {
mContext = context;
mHandler = mainHandler;
+ mFeatureFlags = featureFlags;
mLockscreenUserManager = notificationLockscreenUserManager;
mBypassController = bypassController;
mGroupManager = groupManager;
@@ -142,7 +146,9 @@
NotificationListContainer listContainer) {
mPresenter = presenter;
mListContainer = listContainer;
- mDynamicPrivacyController.addListener(this);
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mDynamicPrivacyController.addListener(this);
+ }
}
/**
@@ -151,6 +157,10 @@
//TODO: Rewrite this to focus on Entries, or some other data object instead of views
public void updateNotificationViews() {
Assert.isMainThread();
+ if (!mFeatureFlags.checkLegacyPipelineEnabled()) {
+ return;
+ }
+
beginUpdate();
List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
@@ -425,6 +435,10 @@
*/
public void updateRowStates() {
Assert.isMainThread();
+ if (!mFeatureFlags.checkLegacyPipelineEnabled()) {
+ return;
+ }
+
beginUpdate();
updateRowStatesInternal();
endUpdate();
@@ -510,6 +524,7 @@
@Override
public void onDynamicPrivacyChanged() {
+ mFeatureFlags.assertLegacyPipelineEnabled();
if (mPerformingUpdate) {
Log.w(TAG, "onDynamicPrivacyChanged made a re-entrant call");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index d297d95..1c9174a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -184,6 +184,7 @@
static NotificationViewHierarchyManager provideNotificationViewHierarchyManager(
Context context,
@Main Handler mainHandler,
+ FeatureFlags featureFlags,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGroupManagerLegacy groupManager,
VisualStabilityManager visualStabilityManager,
@@ -199,6 +200,7 @@
return new NotificationViewHierarchyManager(
context,
mainHandler,
+ featureFlags,
notificationLockscreenUserManager,
groupManager,
visualStabilityManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index dfdc548..b36b7c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -48,6 +48,7 @@
import android.annotation.UserIdInt;
import android.app.Notification;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
@@ -512,6 +513,7 @@
}
private void dispatchEventsAndRebuildList() {
+ Trace.beginSection("NotifCollection.dispatchEventsAndRebuildList");
mAmDispatchingToOtherCode = true;
while (!mEventQueue.isEmpty()) {
mEventQueue.remove().dispatchTo(mNotifCollectionListeners);
@@ -521,6 +523,7 @@
if (mBuildListener != null) {
mBuildListener.onBuildList(mReadOnlyNotificationSet);
}
+ Trace.endSection();
}
private void onEndLifetimeExtension(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 47939f0..5777925 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -23,6 +23,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
@@ -216,6 +217,11 @@
mShadeListBuilder.addOnBeforeRenderListListener(listener);
}
+ /** Registers an invalidator that can be used to invalidate the entire notif list. */
+ public void addPreRenderInvalidator(Invalidator invalidator) {
+ mShadeListBuilder.addPreRenderInvalidator(invalidator);
+ }
+
/**
* Returns a read-only view in to the current shade list, i.e. the list of notifications that
* are currently present in the shade. If this method is called during pipeline execution it
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 3730524..6d38389 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -30,6 +30,7 @@
import android.annotation.MainThread;
import android.annotation.Nullable;
+import android.os.Trace;
import android.util.ArrayMap;
import androidx.annotation.NonNull;
@@ -45,6 +46,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState;
import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeListBuilderLogger;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
@@ -174,6 +176,13 @@
mOnBeforeRenderListListeners.add(listener);
}
+ void addPreRenderInvalidator(Invalidator invalidator) {
+ Assert.isMainThread();
+
+ mPipelineState.requireState(STATE_IDLE);
+ invalidator.setInvalidationListener(this::onPreRenderInvalidated);
+ }
+
void addPreGroupFilter(NotifFilter filter) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
@@ -256,6 +265,14 @@
}
};
+ private void onPreRenderInvalidated(Invalidator invalidator) {
+ Assert.isMainThread();
+
+ mLogger.logPreRenderInvalidated(invalidator.getName(), mPipelineState.getState());
+
+ rebuildListIfBefore(STATE_FINALIZING);
+ }
+
private void onPreGroupFilterInvalidated(NotifFilter filter) {
Assert.isMainThread();
@@ -316,6 +333,7 @@
* if we detect that behavior, we should crash instantly.
*/
private void buildList() {
+ Trace.beginSection("ShadeListBuilder.buildList");
mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
mPipelineState.setState(STATE_BUILD_STARTED);
@@ -369,9 +387,11 @@
// Step 8: Dispatch the new list, first to any listeners and then to the view layer
dispatchOnBeforeRenderList(mReadOnlyNotifList);
+ Trace.beginSection("ShadeListBuilder.onRenderList");
if (mOnRenderListListener != null) {
mOnRenderListListener.onRenderList(mReadOnlyNotifList);
}
+ Trace.endSection();
// Step 9: We're done!
mLogger.logEndBuildList(
@@ -383,9 +403,11 @@
}
mPipelineState.setState(STATE_IDLE);
mIterationCount++;
+ Trace.endSection();
}
private void notifySectionEntriesUpdated() {
+ Trace.beginSection("ShadeListBuilder.notifySectionEntriesUpdated");
NotifSection currentSection = null;
mTempSectionMembers.clear();
for (int i = 0; i < mNotifList.size(); i++) {
@@ -399,6 +421,7 @@
}
mTempSectionMembers.add(currentEntry);
}
+ Trace.endSection();
}
/**
@@ -440,6 +463,7 @@
Collection<? extends ListEntry> entries,
List<ListEntry> out,
List<NotifFilter> filters) {
+ Trace.beginSection("ShadeListBuilder.filterNotifs");
final long now = mSystemClock.uptimeMillis();
for (ListEntry entry : entries) {
if (entry instanceof GroupEntry) {
@@ -471,9 +495,11 @@
}
}
}
+ Trace.endSection();
}
private void groupNotifs(List<ListEntry> entries, List<ListEntry> out) {
+ Trace.beginSection("ShadeListBuilder.groupNotifs");
for (ListEntry listEntry : entries) {
// since grouping hasn't happened yet, all notifs are NotificationEntries
NotificationEntry entry = (NotificationEntry) listEntry;
@@ -529,12 +555,14 @@
}
}
}
+ Trace.endSection();
}
private void stabilizeGroupingNotifs(List<ListEntry> topLevelList) {
if (mNotifStabilityManager == null) {
return;
}
+ Trace.beginSection("ShadeListBuilder.stabilizeGroupingNotifs");
for (int i = 0; i < topLevelList.size(); i++) {
final ListEntry tle = topLevelList.get(i);
@@ -560,6 +588,7 @@
}
}
}
+ Trace.endSection();
}
/**
@@ -592,6 +621,7 @@
}
private void promoteNotifs(List<ListEntry> list) {
+ Trace.beginSection("ShadeListBuilder.promoteNotifs");
for (int i = 0; i < list.size(); i++) {
final ListEntry tle = list.get(i);
@@ -610,9 +640,11 @@
});
}
}
+ Trace.endSection();
}
private void pruneIncompleteGroups(List<ListEntry> shadeList) {
+ Trace.beginSection("ShadeListBuilder.pruneIncompleteGroups");
for (int i = 0; i < shadeList.size(); i++) {
final ListEntry tle = shadeList.get(i);
@@ -667,6 +699,7 @@
}
}
}
+ Trace.endSection();
}
/**
@@ -733,6 +766,7 @@
}
private void sortListAndNotifySections() {
+ Trace.beginSection("ShadeListBuilder.sortListAndNotifySections");
// Assign sections to top-level elements and sort their children
for (ListEntry entry : mNotifList) {
NotifSection section = applySections(entry);
@@ -750,6 +784,7 @@
// notify sections since the list is sorted now
notifySectionEntriesUpdated();
+ Trace.endSection();
}
private void freeEmptyGroups() {
@@ -1000,27 +1035,35 @@
}
private void dispatchOnBeforeTransformGroups(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeTransformGroups");
for (int i = 0; i < mOnBeforeTransformGroupsListeners.size(); i++) {
mOnBeforeTransformGroupsListeners.get(i).onBeforeTransformGroups(entries);
}
+ Trace.endSection();
}
private void dispatchOnBeforeSort(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeSort");
for (int i = 0; i < mOnBeforeSortListeners.size(); i++) {
mOnBeforeSortListeners.get(i).onBeforeSort(entries);
}
+ Trace.endSection();
}
private void dispatchOnBeforeFinalizeFilter(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeFinalizeFilter");
for (int i = 0; i < mOnBeforeFinalizeFilterListeners.size(); i++) {
mOnBeforeFinalizeFilterListeners.get(i).onBeforeFinalizeFilter(entries);
}
+ Trace.endSection();
}
private void dispatchOnBeforeRenderList(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeRenderList");
for (int i = 0; i < mOnBeforeRenderListListeners.size(); i++) {
mOnBeforeRenderListListeners.get(i).onBeforeRenderList(entries);
}
+ Trace.endSection();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 301b185..3a39c39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -23,11 +23,11 @@
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
@@ -48,7 +48,7 @@
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender
*/
-@SysUISingleton
+@CoordinatorScope
public class AppOpsCoordinator implements Coordinator {
private static final String TAG = "AppOpsCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 29a030f..15f0d88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -16,10 +16,10 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
@@ -53,7 +53,7 @@
* respond to app-cancellations (ie: remove the bubble if the app cancels the notification).
*
*/
-@SysUISingleton
+@CoordinatorScope
public class BubbleCoordinator implements Coordinator {
private static final String TAG = "BubbleCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index c385836..e59f4a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -16,10 +16,10 @@
package com.android.systemui.statusbar.notification.collection.coordinator
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.render.NodeController
@@ -34,7 +34,7 @@
* - Elevates important conversation notifications
* - Puts conversations into its own people section. @see [NotifCoordinators] for section ordering.
*/
-@SysUISingleton
+@CoordinatorScope
class ConversationCoordinator @Inject constructor(
private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
@PeopleHeader peopleHeaderController: NodeController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index 47928b4..e865249 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -23,9 +23,9 @@
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -36,7 +36,7 @@
* Special notifications with extra permissions and tags won't be filtered out even when the
* device is unprovisioned.
*/
-@SysUISingleton
+@CoordinatorScope
public class DeviceProvisionedCoordinator implements Coordinator {
private static final String TAG = "DeviceProvisionedCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
index 8948969..dbecf1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
@@ -17,17 +17,17 @@
import android.util.ArraySet
import com.android.systemui.Dumpable
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
-import com.android.systemui.statusbar.notification.row.NotificationGuts
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
+import com.android.systemui.statusbar.notification.row.NotificationGuts
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager
import java.io.FileDescriptor
import java.io.PrintWriter
import javax.inject.Inject
@@ -38,7 +38,7 @@
* Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline.
* Specifically, this just adds the lifetime extension necessary to keep guts from disappearing.
*/
-@SysUISingleton
+@CoordinatorScope
class GutsCoordinator @Inject constructor(
private val notifGutsViewManager: NotifGutsViewManager,
private val logger: GutsCoordinatorLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index 8c8a8a9..f8b4274 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -22,11 +22,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -57,7 +57,7 @@
*
* Note: The inflation callback in {@link PreparationCoordinator} handles showing HUNs.
*/
-@SysUISingleton
+@CoordinatorScope
public class HeadsUpCoordinator implements Coordinator {
private static final String TAG = "HeadsUpCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
index 0059e7b..6684237 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
@@ -20,13 +20,21 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import javax.inject.Inject;
+
/**
* Filters out notifications that have been dismissed locally (by the user) but that system server
* hasn't yet confirmed the removal of.
*/
+@CoordinatorScope
public class HideLocallyDismissedNotifsCoordinator implements Coordinator {
+
+ @Inject
+ HideLocallyDismissedNotifsCoordinator() { }
+
@Override
public void attach(NotifPipeline pipeline) {
pipeline.addPreGroupFilter(mFilter);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
index e595dd4..7b5cf85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
@@ -23,6 +23,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import javax.inject.Inject;
@@ -37,6 +38,7 @@
* TODO: The NotificationLockscreenUserManager currently maintains the list of active user profiles.
* We should spin that off into a standalone section at some point.
*/
+@CoordinatorScope
public class HideNotifsForOtherUsersCoordinator implements Coordinator {
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final SharedCoordinatorLogger mLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 23d5369..fe1cd7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -34,13 +34,13 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -50,7 +50,7 @@
/**
* Filters low priority and privacy-sensitive notifications from the lockscreen.
*/
-@SysUISingleton
+@CoordinatorScope
public class KeyguardCoordinator implements Coordinator {
private static final String TAG = "KeyguardCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
index 026a3ff..8769969 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -21,6 +21,7 @@
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import javax.inject.Inject;
@@ -28,6 +29,7 @@
/**
* Coordinates hiding (filtering) of media notifications.
*/
+@CoordinatorScope
public class MediaCoordinator implements Coordinator {
private static final String TAG = "MediaCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
deleted file mode 100644
index 9305900..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.coordinator;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * Handles the attachment of {@link Coordinator}s to the {@link NotifPipeline} so that the
- * Coordinators can register their respective callbacks.
- */
-@SysUISingleton
-public class NotifCoordinators implements Dumpable {
- private static final String TAG = "NotifCoordinators";
- private final List<Coordinator> mCoordinators = new ArrayList<>();
- private final List<NotifSectioner> mOrderedSections = new ArrayList<>();
-
- /**
- * Creates all the coordinators.
- */
- @Inject
- public NotifCoordinators(
- DumpManager dumpManager,
- FeatureFlags featureFlags,
- HideNotifsForOtherUsersCoordinator hideNotifsForOtherUsersCoordinator,
- KeyguardCoordinator keyguardCoordinator,
- RankingCoordinator rankingCoordinator,
- AppOpsCoordinator appOpsCoordinator,
- DeviceProvisionedCoordinator deviceProvisionedCoordinator,
- BubbleCoordinator bubbleCoordinator,
- HeadsUpCoordinator headsUpCoordinator,
- GutsCoordinator gutsCoordinator,
- ConversationCoordinator conversationCoordinator,
- PreparationCoordinator preparationCoordinator,
- MediaCoordinator mediaCoordinator,
- ShadeEventCoordinator shadeEventCoordinator,
- SmartspaceDedupingCoordinator smartspaceDedupingCoordinator,
- ViewConfigCoordinator viewConfigCoordinator,
- VisualStabilityCoordinator visualStabilityCoordinator) {
- dumpManager.registerDumpable(TAG, this);
-
- mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
- mCoordinators.add(hideNotifsForOtherUsersCoordinator);
- mCoordinators.add(keyguardCoordinator);
- mCoordinators.add(rankingCoordinator);
- mCoordinators.add(appOpsCoordinator);
- mCoordinators.add(deviceProvisionedCoordinator);
- mCoordinators.add(bubbleCoordinator);
- mCoordinators.add(conversationCoordinator);
- mCoordinators.add(mediaCoordinator);
- mCoordinators.add(shadeEventCoordinator);
- mCoordinators.add(viewConfigCoordinator);
- mCoordinators.add(visualStabilityCoordinator);
-
- if (featureFlags.isSmartspaceDedupingEnabled()) {
- mCoordinators.add(smartspaceDedupingCoordinator);
- }
-
- if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
- mCoordinators.add(headsUpCoordinator);
- mCoordinators.add(gutsCoordinator);
- mCoordinators.add(preparationCoordinator);
- }
-
- // Manually add Ordered Sections
- // HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
- if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
- mOrderedSections.add(headsUpCoordinator.getSectioner()); // HeadsUp
- }
- mOrderedSections.add(appOpsCoordinator.getSectioner()); // ForegroundService
- mOrderedSections.add(conversationCoordinator.getSectioner()); // People
- mOrderedSections.add(rankingCoordinator.getAlertingSectioner()); // Alerting
- mOrderedSections.add(rankingCoordinator.getSilentSectioner()); // Silent
- }
-
- /**
- * Sends the pipeline to each coordinator when the pipeline is ready to accept
- * {@link Pluggable}s, {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s.
- */
- public void attach(NotifPipeline pipeline) {
- for (Coordinator c : mCoordinators) {
- c.attach(pipeline);
- }
-
- pipeline.setSections(mOrderedSections);
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println();
- pw.println(TAG + ":");
- for (Coordinator c : mCoordinators) {
- pw.println("\t" + c.getClass());
- }
-
- for (NotifSectioner s : mOrderedSections) {
- pw.println("\t" + s.getName());
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
new file mode 100644
index 0000000..66290bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.util.ArrayList
+import javax.inject.Inject
+
+/**
+ * Handles the attachment of [Coordinator]s to the [NotifPipeline] so that the
+ * Coordinators can register their respective callbacks.
+ */
+interface NotifCoordinators : Coordinator, Dumpable
+
+@CoordinatorScope
+class NotifCoordinatorsImpl @Inject constructor(
+ dumpManager: DumpManager,
+ featureFlags: FeatureFlags,
+ hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
+ hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
+ keyguardCoordinator: KeyguardCoordinator,
+ rankingCoordinator: RankingCoordinator,
+ appOpsCoordinator: AppOpsCoordinator,
+ deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
+ bubbleCoordinator: BubbleCoordinator,
+ headsUpCoordinator: HeadsUpCoordinator,
+ gutsCoordinator: GutsCoordinator,
+ conversationCoordinator: ConversationCoordinator,
+ preparationCoordinator: PreparationCoordinator,
+ mediaCoordinator: MediaCoordinator,
+ shadeEventCoordinator: ShadeEventCoordinator,
+ smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
+ viewConfigCoordinator: ViewConfigCoordinator,
+ visualStabilityCoordinator: VisualStabilityCoordinator,
+ sensitiveContentCoordinator: SensitiveContentCoordinator
+) : NotifCoordinators {
+
+ private val mCoordinators: MutableList<Coordinator> = ArrayList()
+ private val mOrderedSections: MutableList<NotifSectioner> = ArrayList()
+
+ /**
+ * Creates all the coordinators.
+ */
+ init {
+ dumpManager.registerDumpable(TAG, this)
+ mCoordinators.add(hideLocallyDismissedNotifsCoordinator)
+ mCoordinators.add(hideNotifsForOtherUsersCoordinator)
+ mCoordinators.add(keyguardCoordinator)
+ mCoordinators.add(rankingCoordinator)
+ mCoordinators.add(appOpsCoordinator)
+ mCoordinators.add(deviceProvisionedCoordinator)
+ mCoordinators.add(bubbleCoordinator)
+ mCoordinators.add(conversationCoordinator)
+ mCoordinators.add(mediaCoordinator)
+ mCoordinators.add(shadeEventCoordinator)
+ mCoordinators.add(viewConfigCoordinator)
+ mCoordinators.add(visualStabilityCoordinator)
+ mCoordinators.add(sensitiveContentCoordinator)
+ if (featureFlags.isSmartspaceDedupingEnabled) {
+ mCoordinators.add(smartspaceDedupingCoordinator)
+ }
+ if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ mCoordinators.add(headsUpCoordinator)
+ mCoordinators.add(gutsCoordinator)
+ mCoordinators.add(preparationCoordinator)
+ }
+
+ // Manually add Ordered Sections
+ // HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
+ if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp
+ }
+ mOrderedSections.add(appOpsCoordinator.sectioner) // ForegroundService
+ mOrderedSections.add(conversationCoordinator.sectioner) // People
+ mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting
+ mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent
+ }
+
+ /**
+ * Sends the pipeline to each coordinator when the pipeline is ready to accept
+ * [Pluggable]s, [NotifCollectionListener]s and [NotifLifetimeExtender]s.
+ */
+ override fun attach(pipeline: NotifPipeline) {
+ for (c in mCoordinators) {
+ c.attach(pipeline)
+ }
+ pipeline.setSections(mOrderedSections)
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+ pw.println()
+ pw.println("$TAG:")
+ for (c in mCoordinators) {
+ pw.println("\t${c.javaClass}")
+ }
+ for (s in mOrderedSections) {
+ pw.println("\t${s.name}")
+ }
+ }
+
+ companion object {
+ private const val TAG = "NotifCoordinators"
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 31826c7..afdfb3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -57,6 +57,7 @@
* If a notification was uninflated, this coordinator will filter the notification out from the
* {@link ShadeListBuilder} until it is inflated.
*/
+// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
public class PreparationCoordinator implements Coordinator {
private static final String TAG = "PreparationCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index 1a6a63a..2ab2dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -19,11 +19,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
@@ -44,7 +44,7 @@
* - whether the notification's app is suspended or hiding its notifications
* - whether DND settings are hiding notifications from ambient display or the notification list
*/
-@SysUISingleton
+@CoordinatorScope
public class RankingCoordinator implements Coordinator {
public static final boolean SHOW_ALL_SECTIONS = false;
private final StatusBarStateController mStatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
new file mode 100644
index 0000000..a115e04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import android.os.UserHandle
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.notification.DynamicPrivacyController
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
+import dagger.Module
+import dagger.Provides
+
+@Module
+object SensitiveContentCoordinatorModule {
+ @Provides
+ @JvmStatic
+ @CoordinatorScope
+ fun provideCoordinator(
+ dynamicPrivacyController: DynamicPrivacyController,
+ lockscreenUserManager: NotificationLockscreenUserManager
+ ): SensitiveContentCoordinator =
+ SensitiveContentCoordinatorImpl(dynamicPrivacyController, lockscreenUserManager)
+}
+
+/** Coordinates re-inflation and post-processing of sensitive notification content. */
+interface SensitiveContentCoordinator : Coordinator
+
+private class SensitiveContentCoordinatorImpl(
+ private val dynamicPrivacyController: DynamicPrivacyController,
+ private val lockscreenUserManager: NotificationLockscreenUserManager
+) : Invalidator("SensitiveContentInvalidator"),
+ SensitiveContentCoordinator,
+ DynamicPrivacyController.Listener,
+ OnBeforeRenderListListener {
+
+ override fun attach(pipeline: NotifPipeline) {
+ dynamicPrivacyController.addListener(this)
+ pipeline.addOnBeforeRenderListListener(this)
+ pipeline.addPreRenderInvalidator(this)
+ }
+
+ override fun onDynamicPrivacyChanged(): Unit = invalidateList()
+
+ override fun onBeforeRenderList(entries: List<ListEntry>) {
+ val currentUserId = lockscreenUserManager.currentUserId
+ val devicePublic = lockscreenUserManager.isLockscreenPublicMode(currentUserId)
+ val deviceSensitive = devicePublic &&
+ !lockscreenUserManager.userAllowsPrivateNotificationsInPublic(currentUserId)
+ val dynamicallyUnlocked = dynamicPrivacyController.isDynamicallyUnlocked
+ for (entry in extractAllRepresentativeEntries(entries).filter { it.rowExists() }) {
+ val notifUserId = entry.sbn.user.identifier
+ val userLockscreen = devicePublic ||
+ lockscreenUserManager.isLockscreenPublicMode(notifUserId)
+ val userPublic = when {
+ // if we're not on the lockscreen, we're definitely private
+ !userLockscreen -> false
+ // we are on the lockscreen, so unless we're dynamically unlocked, we're
+ // definitely public
+ !dynamicallyUnlocked -> true
+ // we're dynamically unlocked, but check if the notification needs
+ // a separate challenge if it's from a work profile
+ else -> when (notifUserId) {
+ currentUserId -> false
+ UserHandle.USER_ALL -> false
+ else -> lockscreenUserManager.needsSeparateWorkChallenge(notifUserId)
+ }
+ }
+ val needsRedaction = lockscreenUserManager.needsRedaction(entry)
+ val isSensitive = userPublic && needsRedaction
+ entry.setSensitive(isSensitive, deviceSensitive)
+ }
+ }
+}
+
+private fun extractAllRepresentativeEntries(
+ entries: List<ListEntry>
+): Sequence<NotificationEntry> =
+ entries.asSequence().flatMap(::extractAllRepresentativeEntries)
+
+private fun extractAllRepresentativeEntries(listEntry: ListEntry): Sequence<NotificationEntry> =
+ sequence {
+ listEntry.representativeEntry?.let { yield(it) }
+ if (listEntry is GroupEntry) {
+ yieldAll(extractAllRepresentativeEntries(listEntry.children))
+ }
+ }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt
index f9648a0..2d5c331 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt
@@ -29,6 +29,7 @@
* A coordinator which provides callbacks to a view surfaces for various events relevant to the
* shade, such as when the user removes a notification, or when the shade is emptied.
*/
+// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
class ShadeEventCoordinator @Inject internal constructor(
private val mLogger: ShadeEventCoordinatorLogger
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
index 442d9d2..519d75f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
@@ -18,7 +18,6 @@
import android.app.smartspace.SmartspaceTarget
import android.os.Parcelable
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -28,6 +27,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -45,7 +45,7 @@
*/
// This class is a singleton so that the same instance can be accessed by both the old and new
// pipelines
-@SysUISingleton
+@CoordinatorScope
class SmartspaceDedupingCoordinator @Inject constructor(
private val statusBarStateController: SysuiStatusBarStateController,
private val smartspaceController: LockscreenSmartspaceController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index df1132b..5b86de2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -19,11 +19,11 @@
import com.android.internal.widget.MessagingGroup
import com.android.internal.widget.MessagingMessage
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl
import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.row.NotificationGutsManager
import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
@@ -33,7 +33,7 @@
* for the current uiMode and screen properties; additionally deferring those changes when a user
* change is in progress until that process has completed.
*/
-@SysUISingleton
+@CoordinatorScope
class ViewConfigCoordinator @Inject internal constructor(
configurationController: ConfigurationController,
lockscreenUserManager: NotificationLockscreenUserManagerImpl,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 5d6c043..5ba4c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -50,6 +50,7 @@
* This is now integrated in the data-layer via
* {@link com.android.systemui.statusbar.notification.collection.ShadeListBuilder}.
*/
+// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
public class VisualStabilityCoordinator implements Coordinator {
private final DelayableExecutor mDelayableExecutor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
new file mode 100644
index 0000000..a26d50d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator.dagger
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators
+import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl
+import com.android.systemui.statusbar.notification.collection.coordinator.SensitiveContentCoordinatorModule
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.Subcomponent
+import javax.inject.Qualifier
+import javax.inject.Scope
+
+@Module(subcomponents = [CoordinatorsSubcomponent::class])
+object CoordinatorsModule {
+ @SysUISingleton
+ @JvmStatic
+ @Provides
+ fun notifCoordinators(factory: CoordinatorsSubcomponent.Factory): NotifCoordinators =
+ factory.create().notifCoordinators
+}
+
+@CoordinatorScope
+@Subcomponent(modules = [InternalCoordinatorsModule::class])
+interface CoordinatorsSubcomponent {
+ @get:Internal val notifCoordinators: NotifCoordinators
+
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(): CoordinatorsSubcomponent
+ }
+}
+
+@Module(includes = [SensitiveContentCoordinatorModule::class])
+private abstract class InternalCoordinatorsModule {
+ @Binds
+ @Internal
+ abstract fun bindNotifCoordinators(impl: NotifCoordinatorsImpl): NotifCoordinators
+}
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+private annotation class Internal
+
+@Scope
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class CoordinatorScope
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index 5a35127..8fff905 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -47,6 +47,15 @@
})
}
+ fun logPreRenderInvalidated(filterName: String, pipelineState: Int) {
+ buffer.log(TAG, DEBUG, {
+ str1 = filterName
+ int1 = pipelineState
+ }, {
+ """Pre-render Invalidator "$str1" invalidated; pipeline state is $int1"""
+ })
+ }
+
fun logPreGroupFilterInvalidated(filterName: String, pipelineState: Int) {
buffer.log(TAG, DEBUG, {
str1 = filterName
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java
new file mode 100644
index 0000000..d7092ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
+
+/** A {@link Pluggable} that can only invalidate. */
+public abstract class Invalidator extends Pluggable<Invalidator> {
+ protected Invalidator(String name) {
+ super(name);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
index 8e4fb75..b981a96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
import android.annotation.Nullable;
+import android.os.Trace;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -50,7 +51,9 @@
*/
public final void invalidateList() {
if (mListener != null) {
+ Trace.beginSection("Pluggable<" + mName + ">.invalidateList");
mListener.onPluggableInvalidated((This) this);
+ Trace.endSection();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
index 9b8ac72..010b6f80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -20,6 +20,7 @@
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
+import com.android.systemui.util.traceSection
/**
* Converts a notif list (the output of the ShadeListBuilder) into a NodeSpec, an abstract
@@ -36,7 +37,7 @@
fun buildNodeSpec(
rootController: NodeController,
notifList: List<ListEntry>
- ): NodeSpec {
+ ): NodeSpec = traceSection("NodeSpecBuilder.buildNodeSpec") {
val root = NodeSpecImpl(null, rootController)
var currentSection: NotifSection? = null
val prevSections = mutableSetOf<NotifSection?>()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 7babbb4..6d4ae4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -19,6 +19,7 @@
import android.annotation.MainThread
import android.view.View
import com.android.systemui.util.kotlin.transform
+import com.android.systemui.util.traceSection
/**
* Given a "spec" that describes a "tree" of views, adds and removes views from the
@@ -47,7 +48,7 @@
* provided [spec]. The root node of the spec must match the root controller passed to the
* differ's constructor.
*/
- fun applySpec(spec: NodeSpec) {
+ fun applySpec(spec: NodeSpec) = traceSection("ShadeViewDiffer.applySpec") {
val specMap = treeToMap(spec)
if (spec.controller != rootNode.controller) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index a2c7aa5..b582a24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -18,10 +18,13 @@
import android.content.Context
import android.view.View
+import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.util.traceSection
import javax.inject.Inject
/**
@@ -32,7 +35,7 @@
context: Context,
listContainer: NotificationListContainer,
logger: ShadeViewDifferLogger,
- viewBarn: NotifViewBarn,
+ private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
// We pass a shim view here because the listContainer may not actually have a view associated
@@ -45,8 +48,21 @@
listBuilder.setOnRenderListListener(::onNewNotifTree)
private fun onNewNotifTree(notifList: List<ListEntry>) {
- viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
- notificationIconAreaController.updateNotificationIcons(notifList)
+ traceSection("ShadeViewManager.onNewNotifTree") {
+ viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
+ updateGroupCounts(notifList)
+ notificationIconAreaController.updateNotificationIcons(notifList)
+ }
+ }
+
+ private fun updateGroupCounts(notifList: List<ListEntry>) {
+ traceSection("ShadeViewManager.updateGroupCounts") {
+ notifList.asSequence().filterIsInstance<GroupEntry>().forEach { groupEntry ->
+ val controller = viewBarn.requireView(checkNotNull(groupEntry.summary))
+ val row = controller.view as ExpandableNotificationRow
+ row.setUntruncatedChildCount(groupEntry.untruncatedChildCount)
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 540216c..1eb007e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -47,6 +47,7 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.coordinator.ShadeEventCoordinator;
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorsModule;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl;
@@ -93,7 +94,10 @@
/**
* Dagger Module for classes found within the com.android.systemui.statusbar.notification package.
*/
-@Module(includes = {NotificationSectionHeadersModule.class})
+@Module(includes = {
+ NotificationSectionHeadersModule.class,
+ CoordinatorsModule.class
+})
public interface NotificationsModule {
@Binds
StackScrollAlgorithm.SectionProvider bindSectionProvider(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 02b1210..ccd4843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -107,6 +107,7 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
+import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.wmshell.BubblesManager;
import java.io.FileDescriptor;
@@ -3305,40 +3306,45 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- super.dump(fd, pw, args);
- pw.println(" Notification: " + mEntry.getKey());
- pw.print(" visibility: " + getVisibility());
- pw.print(", alpha: " + getAlpha());
- pw.print(", translation: " + getTranslation());
- pw.print(", removed: " + isRemoved());
- pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
- NotificationContentView showingLayout = getShowingLayout();
- pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
- pw.println();
- showingLayout.dump(fd, pw, args);
- pw.print(" ");
- if (getViewState() != null) {
- getViewState().dump(fd, pw, args);
- } else {
- pw.print("no viewState!!!");
- }
- pw.println();
- pw.println();
- if (mIsSummaryWithChildren) {
- pw.print(" ChildrenContainer");
- pw.print(" visibility: " + mChildrenContainer.getVisibility());
- pw.print(", alpha: " + mChildrenContainer.getAlpha());
- pw.print(", translationY: " + mChildrenContainer.getTranslationY());
- pw.println();
- List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
- pw.println(" Children: " + notificationChildren.size());
- pw.println(" {");
- for(ExpandableNotificationRow child : notificationChildren) {
- child.dump(fd, pw, args);
+ // Skip super call; dump viewState ourselves
+ pw.println("Notification: " + mEntry.getKey());
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ ipw.print("visibility: " + getVisibility());
+ ipw.print(", alpha: " + getAlpha());
+ ipw.print(", translation: " + getTranslation());
+ ipw.print(", removed: " + isRemoved());
+ ipw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
+ NotificationContentView showingLayout = getShowingLayout();
+ ipw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
+ ipw.println();
+ showingLayout.dump(fd, ipw, args);
+
+ if (getViewState() != null) {
+ getViewState().dump(fd, ipw, args);
+ ipw.println();
+ } else {
+ ipw.println("no viewState!!!");
}
- pw.println(" }");
- pw.println();
- }
+
+ if (mIsSummaryWithChildren) {
+ ipw.println();
+ ipw.print("ChildrenContainer");
+ ipw.print(" visibility: " + mChildrenContainer.getVisibility());
+ ipw.print(", alpha: " + mChildrenContainer.getAlpha());
+ ipw.print(", translationY: " + mChildrenContainer.getTranslationY());
+ ipw.println();
+ List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
+ ipw.println("Children: " + notificationChildren.size());
+ ipw.print("{");
+ ipw.increaseIndent();
+ for (ExpandableNotificationRow child : notificationChildren) {
+ ipw.println();
+ child.dump(fd, ipw, args);
+ }
+ ipw.decreaseIndent();
+ ipw.println("}");
+ }
+ });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 8b0764b..fa2c1ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -34,6 +34,7 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.util.DumpUtilsKt;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -743,6 +744,16 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(getClass().getSimpleName());
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ ExpandableViewState viewState = getViewState();
+ if (viewState == null) {
+ ipw.println("no viewState!!!");
+ } else {
+ viewState.dump(fd, ipw, args);
+ ipw.println();
+ }
+ });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 9eb95c4..b27a40a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -25,6 +25,10 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.util.DumpUtilsKt;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
public class FooterView extends StackScrollerDecorView {
private FooterViewButton mDismissButton;
@@ -45,6 +49,19 @@
}
@Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dump(fd, pw, args);
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ ipw.println("visibility: " + DumpUtilsKt.visibilityString(getVisibility()));
+ ipw.println("manageButton showHistory: " + mShowHistory);
+ ipw.println("manageButton visibility: "
+ + DumpUtilsKt.visibilityString(mDismissButton.getVisibility()));
+ ipw.println("dismissButton visibility: "
+ + DumpUtilsKt.visibilityString(mDismissButton.getVisibility()));
+ });
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
mDismissButton = (FooterViewButton) findSecondaryView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 4f54e4f..df484dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1253,7 +1253,7 @@
}
if (hasRemoteInput) {
existing.setWrapper(wrapper);
- existing.setOnVisibilityChangedListener(this::setRemoteInputVisible);
+ existing.addOnVisibilityChangedListener(this::setRemoteInputVisible);
if (existingPendingIntent != null || existing.isActive()) {
// The current action could be gone, or the pending intent no longer valid.
@@ -1938,7 +1938,6 @@
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print(" ");
pw.print("contentView visibility: " + getVisibility());
pw.print(", alpha: " + getAlpha());
pw.print(", clipBounds: " + getClipBounds());
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 6aa5f07..6a12710 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
@@ -109,6 +109,7 @@
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.DumpUtilsKt;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -4899,54 +4900,42 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(String.format("[%s: pulsing=%s visibility=%s"
- + " alpha=%f scrollY:%d maxTopPadding=%d showShelfOnly=%s"
- + " qsExpandFraction=%f"
- + " hideAmount=%f]",
- this.getClass().getSimpleName(),
- mPulsing ? "T" : "f",
- getVisibility() == View.VISIBLE ? "visible"
- : getVisibility() == View.GONE ? "gone"
- : "invisible",
- getAlpha(),
- mAmbientState.getScrollY(),
- mMaxTopPadding,
- mShouldShowShelfOnly ? "T" : "f",
- mQsExpansionFraction,
- mAmbientState.getHideAmount()));
- int childCount = getChildCount();
- pw.println(" Number of children: " + childCount);
- pw.println();
+ StringBuilder sb = new StringBuilder("[")
+ .append(this.getClass().getSimpleName()).append(":")
+ .append(" pulsing=").append(mPulsing ? "T" : "f")
+ .append(" visibility=").append(DumpUtilsKt.visibilityString(getVisibility()))
+ .append(" alpha=").append(getAlpha())
+ .append(" scrollY=").append(mAmbientState.getScrollY())
+ .append(" maxTopPadding=").append(mMaxTopPadding)
+ .append(" showShelfOnly=").append(mShouldShowShelfOnly ? "T" : "f")
+ .append(" qsExpandFraction=").append(mQsExpansionFraction)
+ .append(" isCurrentUserSetup=").append(mIsCurrentUserSetup)
+ .append(" hideAmount=").append(mAmbientState.getHideAmount())
+ .append("]");
+ pw.println(sb.toString());
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ int childCount = getChildCount();
+ ipw.println("Number of children: " + childCount);
+ ipw.println();
- for (int i = 0; i < childCount; i++) {
- ExpandableView child = (ExpandableView) getChildAt(i);
- child.dump(fd, pw, args);
- if (!(child instanceof ExpandableNotificationRow)) {
- pw.println(" " + child.getClass().getSimpleName());
- // Notifications dump it's viewstate as part of their dump to support children
- ExpandableViewState viewState = child.getViewState();
- if (viewState == null) {
- pw.println(" no viewState!!!");
- } else {
- pw.print(" ");
- viewState.dump(fd, pw, args);
- pw.println();
- pw.println();
- }
+ for (int i = 0; i < childCount; i++) {
+ ExpandableView child = (ExpandableView) getChildAt(i);
+ child.dump(fd, ipw, args);
+ ipw.println();
}
- }
- int transientViewCount = getTransientViewCount();
- pw.println(" Transient Views: " + transientViewCount);
- for (int i = 0; i < transientViewCount; i++) {
- ExpandableView child = (ExpandableView) getTransientView(i);
- child.dump(fd, pw, args);
- }
- View swipedView = mSwipeHelper.getSwipedView();
- pw.println(" Swiped view: " + swipedView);
- if (swipedView instanceof ExpandableView) {
- ExpandableView expandableView = (ExpandableView) swipedView;
- expandableView.dump(fd, pw, args);
- }
+ int transientViewCount = getTransientViewCount();
+ pw.println("Transient Views: " + transientViewCount);
+ for (int i = 0; i < transientViewCount; i++) {
+ ExpandableView child = (ExpandableView) getTransientView(i);
+ child.dump(fd, pw, args);
+ }
+ View swipedView = mSwipeHelper.getSwipedView();
+ pw.println("Swiped view: " + swipedView);
+ if (swipedView instanceof ExpandableView) {
+ ExpandableView expandableView = (ExpandableView) swipedView;
+ expandableView.dump(fd, pw, args);
+ }
+ });
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 6516abd..fbe59a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -6,6 +6,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Trace;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
@@ -336,12 +337,14 @@
}
private void updateNotificationIcons() {
+ Trace.beginSection("NotificationIconAreaController.updateNotificationIcons");
updateStatusBarIcons();
updateShelfIcons();
updateCenterIcon();
updateAodNotificationIcons();
applyNotificationIconsTint();
+ Trace.endSection();
}
private void updateShelfIcons() {
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 4ad2af4..711e941 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -129,7 +129,6 @@
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.AutoReinflateContainer;
import com.android.systemui.DejankUtils;
-import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
import com.android.systemui.InitController;
import com.android.systemui.Prefs;
@@ -235,6 +234,7 @@
import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
+import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.util.WallpaperController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.MessageRouter;
@@ -936,8 +936,6 @@
data -> mCommandQueueCallbacks.animateExpandSettingsPanel(data.mSubpanel));
mMessageRouter.subscribeTo(MSG_LAUNCH_TRANSITION_TIMEOUT,
id -> onLaunchTransitionTimeout());
-
- dumpManager.registerDumpable(this);
}
@Override
@@ -2445,8 +2443,14 @@
}
pw.println(" mStackScroller: ");
if (mStackScroller != null) {
- pw.print (" ");
- ((Dumpable) mStackScroller).dump(fd, pw, args);
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ // Triple indent until we rewrite the rest of this dump()
+ ipw.increaseIndent();
+ ipw.increaseIndent();
+ mStackScroller.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ });
}
pw.println(" Theme:");
String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + "";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index cf9b2c6..ecd5c98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -314,9 +314,7 @@
mShadeController.addPostCollapseAction(() -> updateNotificationViews(reason));
return;
}
-
mViewHierarchyManager.updateNotificationViews();
-
mNotificationPanel.updateNotificationViews(reason);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 5d7d480..aa8d95f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -108,36 +108,36 @@
private final SendButtonTextWatcher mTextWatcher;
private final TextView.OnEditorActionListener mEditorActionHandler;
- private final UiEventLogger mUiEventLogger;
- private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
- private final List<OnFocusChangeListener> mEditTextFocusChangeListeners = new ArrayList<>();
- private final List<OnSendRemoteInputListener> mOnSendListeners = new ArrayList<>();
+ private final ArrayList<OnSendRemoteInputListener> mOnSendListeners = new ArrayList<>();
+ private final ArrayList<Consumer<Boolean>> mOnVisibilityChangedListeners = new ArrayList<>();
+ private final ArrayList<OnFocusChangeListener> mEditTextFocusChangeListeners =
+ new ArrayList<>();
+
private RemoteEditText mEditText;
private ImageButton mSendButton;
private GradientDrawable mContentBackground;
private ProgressBar mProgressBar;
- private PendingIntent mPendingIntent;
- private RemoteInput[] mRemoteInputs;
- private RemoteInput mRemoteInput;
- private RemoteInputController mController;
-
- private NotificationEntry mEntry;
-
- private boolean mRemoved;
-
+ private ImageView mDelete;
+ private ImageView mDeleteBg;
+ // TODO(b/193539698): remove reveal param fields, turn them into parameters where needed
private int mRevealCx;
private int mRevealCy;
private int mRevealR;
-
private boolean mColorized;
private int mTint;
-
private boolean mResetting;
- private NotificationViewWrapper mWrapper;
- private Consumer<Boolean> mOnVisibilityChangedListener;
+
+ // TODO(b/193539698): move these to a Controller
+ private RemoteInputController mController;
+ private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+ private final UiEventLogger mUiEventLogger;
+ private NotificationEntry mEntry;
+ private PendingIntent mPendingIntent;
+ private RemoteInput mRemoteInput;
+ private RemoteInput[] mRemoteInputs;
private NotificationRemoteInputManager.BouncerChecker mBouncerChecker;
- private ImageView mDelete;
- private ImageView mDeleteBg;
+ private boolean mRemoved;
+ private NotificationViewWrapper mWrapper;
/**
* Enum for logged notification remote input UiEvents.
@@ -382,7 +382,7 @@
private void sendRemoteInput(Intent intent) {
if (mBouncerChecker != null && mBouncerChecker.showBouncerIfNecessary()) {
mEditText.hideIme();
- for (OnSendRemoteInputListener listener : mOnSendListeners) {
+ for (OnSendRemoteInputListener listener : new ArrayList<>(mOnSendListeners)) {
listener.onSendRequestBounced();
}
return;
@@ -399,7 +399,7 @@
mController.remoteInputSent(mEntry);
mEntry.setHasSentReply();
- for (OnSendRemoteInputListener listener : mOnSendListeners) {
+ for (OnSendRemoteInputListener listener : new ArrayList<>(mOnSendListeners)) {
listener.onSendRemoteInput();
}
@@ -760,15 +760,32 @@
mWrapper = wrapper;
}
- public void setOnVisibilityChangedListener(Consumer<Boolean> visibilityChangedListener) {
- mOnVisibilityChangedListener = visibilityChangedListener;
+ /**
+ * Register a listener to be notified when this view's visibility changes.
+ *
+ * Specifically, the passed {@link Consumer} will receive {@code true} when
+ * {@link #getVisibility()} would return {@link View#VISIBLE}, and {@code false} it would return
+ * any other value.
+ */
+ public void addOnVisibilityChangedListener(Consumer<Boolean> listener) {
+ mOnVisibilityChangedListeners.add(listener);
+ }
+
+ /**
+ * Unregister a listener previously registered via
+ * {@link #addOnVisibilityChangedListener(Consumer)}.
+ */
+ public void removeOnVisibilityChangedListener(Consumer<Boolean> listener) {
+ mOnVisibilityChangedListeners.remove(listener);
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
- if (changedView == this && mOnVisibilityChangedListener != null) {
- mOnVisibilityChangedListener.accept(visibility == VISIBLE);
+ if (changedView == this) {
+ for (Consumer<Boolean> listener : new ArrayList<>(mOnVisibilityChangedListeners)) {
+ listener.accept(visibility == VISIBLE);
+ }
// Hide soft-keyboard when the input view became invisible
// (i.e. The notification shade collapsed by pressing the home key)
if (visibility != VISIBLE && !mEditText.isVisibleToUser()
diff --git a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
new file mode 100644
index 0000000..9f33c27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 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.util
+
+import android.util.IndentingPrintWriter
+import android.view.View
+import java.io.PrintWriter
+import java.util.function.Consumer
+
+/**
+ * Run some code that will print to an [IndentingPrintWriter] that wraps the given [PrintWriter].
+ *
+ * If the given [PrintWriter] is an [IndentingPrintWriter], the block will be passed that same
+ * instance with [IndentingPrintWriter.increaseIndent] having been called, and calling
+ * [IndentingPrintWriter.decreaseIndent] after completion of the block, so the passed [PrintWriter]
+ * should not be used before the block completes.
+ */
+inline fun PrintWriter.withIndenting(block: (IndentingPrintWriter) -> Unit) {
+ if (this is IndentingPrintWriter) {
+ this.withIncreasedIndent { block(this) }
+ } else {
+ block(IndentingPrintWriter(this))
+ }
+}
+
+/**
+ * Run some code that will print to an [IndentingPrintWriter] that wraps the given [PrintWriter].
+ *
+ * If the given [PrintWriter] is an [IndentingPrintWriter], the block will be passed that same
+ * instance with [IndentingPrintWriter.increaseIndent] having been called, and calling
+ * [IndentingPrintWriter.decreaseIndent] after completion of the block, so the passed [PrintWriter]
+ * should not be used before the block completes.
+ */
+fun PrintWriter.withIndenting(consumer: Consumer<IndentingPrintWriter>) {
+ if (this is IndentingPrintWriter) {
+ this.withIncreasedIndent { consumer.accept(this) }
+ } else {
+ consumer.accept(IndentingPrintWriter(this))
+ }
+}
+
+/**
+ * Run some code inside a block, with [IndentingPrintWriter.increaseIndent] having been called on
+ * the given argument, and calling [IndentingPrintWriter.decreaseIndent] after completion.
+ */
+inline fun IndentingPrintWriter.withIncreasedIndent(block: () -> Unit) {
+ this.increaseIndent()
+ try {
+ block()
+ } finally {
+ this.decreaseIndent()
+ }
+}
+
+/** Return a readable string for the visibility */
+fun visibilityString(@View.Visibility visibility: Int): String = when (visibility) {
+ View.GONE -> "gone"
+ View.VISIBLE -> "visible"
+ View.INVISIBLE -> "invisible"
+ else -> "unknown:$visibility"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
new file mode 100644
index 0000000..5b16ae9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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.util
+
+import android.os.Trace
+
+/**
+ * Run a block within a [Trace] section.
+ * Calls [Trace.beginSection] before and [Trace.endSection] after the passed block.
+ */
+inline fun <T> traceSection(tag: String, block: () -> T): T {
+ Trace.beginSection(tag)
+ try {
+ return block()
+ } finally {
+ Trace.endSection()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
index e639313a..5568f64 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
@@ -17,6 +17,7 @@
package com.android.systemui.util.sensors;
import android.hardware.SensorManager;
+import android.os.Build;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -56,7 +57,7 @@
*/
class ProximitySensorImpl implements ProximitySensor {
private static final String TAG = "ProxSensor";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Build.IS_DEBUGGABLE;
private static final long SECONDARY_PING_INTERVAL_MS = 5000;
ThresholdSensor mPrimaryThresholdSensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
index b3c098c..8243be8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
@@ -20,13 +20,21 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.content.Context;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -36,17 +44,33 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+/**
+ * NOTE: This test is for the version of FeatureFlagManager in src-release, which should not allow
+ * overriding, and should never return any value other than the one provided as the default.
+ */
@SmallTest
public class FeatureFlagManagerTest extends SysuiTestCase {
FeatureFlagManager mFeatureFlagManager;
+ @Mock private SystemPropertiesHelper mProps;
+ @Mock private Context mContext;
@Mock private DumpManager mDumpManager;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mFeatureFlagManager = new FeatureFlagManager(mDumpManager);
+ mFeatureFlagManager = new FeatureFlagManager(mProps, mContext, mDumpManager);
+ }
+
+ @After
+ public void onFinished() {
+ // SystemPropertiesHelper and Context are provided for constructor consistency with the
+ // debug version of the FeatureFlagManager, but should never be used.
+ verifyZeroInteractions(mProps, mContext);
+ // The dump manager should be registered with even for the release version, but that's it.
+ verify(mDumpManager).registerDumpable(anyString(), any());
+ verifyNoMoreInteractions(mDumpManager);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index e54a6ec..d2bba36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -1,7 +1,9 @@
package com.android.systemui.qs
-import com.android.systemui.R
import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.ViewUtils
import android.view.LayoutInflater
import android.view.View
import androidx.test.filters.SmallTest
@@ -9,6 +11,7 @@
import com.android.internal.logging.UiEventLogger
import com.android.internal.logging.testing.FakeMetricsLogger
import com.android.systemui.Dependency
+import com.android.systemui.R
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.globalactions.GlobalActionsDialogLite
import com.android.systemui.plugins.ActivityStarter
@@ -19,8 +22,11 @@
import com.android.systemui.tuner.TunerService
import com.android.systemui.utils.leaks.FakeTunerService
import com.android.systemui.utils.leaks.LeakCheckedTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Mock
@@ -30,6 +36,8 @@
import org.mockito.Mockito.`when` as whenever
@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
class FooterActionsControllerTest : LeakCheckedTest() {
@Mock
private lateinit var userManager: UserManager
@@ -53,10 +61,12 @@
private val metricsLogger: MetricsLogger = FakeMetricsLogger()
private lateinit var view: FooterActionsView
private val falsingManager: FalsingManagerFake = FalsingManagerFake()
+ private lateinit var testableLooper: TestableLooper
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
@@ -69,7 +79,14 @@
globalActionsDialog, uiEventLogger, showPMLiteButton = true,
buttonsVisibleState = ExpansionState.EXPANDED)
controller.init()
- controller.onViewAttached()
+ ViewUtils.attachView(view)
+ // View looper is the testable looper associated with the test
+ testableLooper.processAllMessages()
+ }
+
+ @After
+ fun tearDown() {
+ ViewUtils.detachView(view)
}
@Test
@@ -90,4 +107,19 @@
// Verify Settings wasn't launched.
verify<ActivityStarter>(activityStarter, Mockito.never()).startActivity(any(), anyBoolean())
}
+
+ @Test
+ fun testMultiUserSwitchUpdatedWhenExpansionStarts() {
+ // When expansion starts, listening is set to true
+ val multiUserSwitch = view.requireViewById<View>(R.id.multi_user_switch)
+
+ assertThat(multiUserSwitch.visibility).isNotEqualTo(View.VISIBLE)
+
+ whenever(multiUserSwitchController.isMultiUserEnabled).thenReturn(true)
+
+ controller.setListening(true)
+ testableLooper.processAllMessages()
+
+ assertThat(multiUserSwitch.visibility).isEqualTo(View.VISIBLE)
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 7fb7b86..cf58c63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -36,6 +36,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
@@ -75,6 +76,7 @@
@Spy private FakeListContainer mListContainer = new FakeListContainer();
// Dependency mocks:
+ @Mock private FeatureFlags mFeatureFlags;
@Mock private NotificationEntryManager mEntryManager;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGroupManagerLegacy mGroupManager;
@@ -101,10 +103,14 @@
when(mVisualStabilityManager.areGroupChangesAllowed()).thenReturn(true);
when(mVisualStabilityManager.isReorderingAllowed()).thenReturn(true);
+ when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
+ when(mFeatureFlags.checkLegacyPipelineEnabled()).thenReturn(true);
+
mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
- mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
+ mHandler, mFeatureFlags, mLockscreenUserManager, mGroupManager,
+ mVisualStabilityManager,
mock(StatusBarStateControllerImpl.class), mEntryManager,
mock(KeyguardBypassController.class),
Optional.of(mock(Bubbles.class)),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index e9e6718..190c352 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeListBuilderLogger;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
@@ -847,11 +848,13 @@
NotifPromoter idPromoter = new IdPromoter(4);
NotifSectioner section = new PackageSectioner(PACKAGE_1);
NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
+ Invalidator preRenderInvalidator = new Invalidator("PreRenderInvalidator") {};
mListBuilder.addPreGroupFilter(packageFilter);
mListBuilder.addPromoter(idPromoter);
mListBuilder.setSectioners(singletonList(section));
mListBuilder.setComparators(singletonList(hypeComparator));
+ mListBuilder.addPreRenderInvalidator(preRenderInvalidator);
// GIVEN a set of random notifs
addNotif(0, PACKAGE_1);
@@ -876,6 +879,10 @@
clearInvocations(mOnRenderListListener);
hypeComparator.invalidateList();
verify(mOnRenderListListener).onRenderList(anyList());
+
+ clearInvocations(mOnRenderListListener);
+ preRenderInvalidator.invalidateList();
+ verify(mOnRenderListListener).onRenderList(anyList());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
new file mode 100644
index 0000000..5fd4174
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import android.os.UserHandle
+import android.service.notification.StatusBarNotification
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.notification.DynamicPrivacyController
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.mockito.mock
+import org.junit.Test
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+class SensitiveContentCoordinatorTest : SysuiTestCase() {
+
+ val dynamicPrivacyController: DynamicPrivacyController = mock()
+ val lockscreenUserManager: NotificationLockscreenUserManager = mock()
+ val pipeline: NotifPipeline = mock()
+
+ val coordinator: SensitiveContentCoordinator = SensitiveContentCoordinatorModule
+ .provideCoordinator(dynamicPrivacyController, lockscreenUserManager)
+
+ @Test
+ fun onDynamicPrivacyChanged_invokeInvalidationListener() {
+ coordinator.attach(pipeline)
+ val invalidator = withArgCaptor<Invalidator> {
+ verify(pipeline).addPreRenderInvalidator(capture())
+ }
+ val dynamicPrivacyListener = withArgCaptor<DynamicPrivacyController.Listener> {
+ verify(dynamicPrivacyController).addListener(capture())
+ }
+
+ val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>()
+ invalidator.setInvalidationListener(invalidationListener)
+
+ dynamicPrivacyListener.onDynamicPrivacyChanged()
+
+ verify(invalidationListener).onPluggableInvalidated(invalidator)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, false)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, false)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, false)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, false)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, false)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, false)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, true)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(true, true)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
+ val entry = fakeNotification(1, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, true)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
+ whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true)
+
+ val entry = fakeNotification(2, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(true, true)
+ }
+
+ private fun fakeNotification(notifUserId: Int, needsRedaction: Boolean): ListEntry {
+ val mockUserHandle = mock<UserHandle>().apply {
+ whenever(identifier).thenReturn(notifUserId)
+ }
+ val mockSbn: StatusBarNotification = mock<StatusBarNotification>().apply {
+ whenever(user).thenReturn(mockUserHandle)
+ }
+ val mockEntry = mock<NotificationEntry>().apply {
+ whenever(sbn).thenReturn(mockSbn)
+ }
+ whenever(lockscreenUserManager.needsRedaction(mockEntry)).thenReturn(needsRedaction)
+ whenever(mockEntry.rowExists()).thenReturn(true)
+ return object : ListEntry("key", 0) {
+ override fun getRepresentativeEntry(): NotificationEntry = mockEntry
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index dd8354d..97e1edb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -205,7 +205,7 @@
ExpandableNotificationRow row = helper.createRow();
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
- view.setOnVisibilityChangedListener(null);
+ view.addOnVisibilityChangedListener(null);
view.setVisibility(View.INVISIBLE);
view.setVisibility(View.VISIBLE);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 4748a86..2028766 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -457,6 +457,9 @@
}, FgThread.getExecutor()).whenComplete(uncheckExceptions((association, err) -> {
if (err == null) {
addAssociation(association, userId);
+ mServiceConnectors.forUser(userId).post(service -> {
+ service.onAssociationCreated();
+ });
} else {
Slog.e(LOG_TAG, "Failed to discover device(s)", err);
callback.onFailure("No devices found: " + err.getMessage());
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index e890acb..9572154 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -36,6 +36,7 @@
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -152,16 +153,9 @@
throw new RuntimeException(
"Failed to find NetworkScanInfo with id " + message.arg2);
}
- NetworkScanCallback callback = nsi.mCallback;
- Executor executor = nsi.mExecutor;
- if (callback == null) {
- throw new RuntimeException(
- "Failed to find NetworkScanCallback with id " + message.arg2);
- }
- if (executor == null) {
- throw new RuntimeException(
- "Failed to find Executor with id " + message.arg2);
- }
+
+ final NetworkScanCallback callback = nsi.mCallback;
+ final Executor executor = nsi.mExecutor;
switch (message.what) {
case CALLBACK_RESTRICTED_SCAN_RESULTS:
@@ -246,17 +240,24 @@
NetworkScanRequest request, Executor executor, NetworkScanCallback callback,
String callingPackage, @Nullable String callingFeatureId) {
try {
+ Objects.requireNonNull(request, "Request was null");
+ Objects.requireNonNull(callback, "Callback was null");
+ Objects.requireNonNull(executor, "Executor was null");
final ITelephony telephony = getITelephony();
if (telephony == null) return null;
- int scanId = telephony.requestNetworkScan(
- subId, request, mMessenger, new Binder(), callingPackage,
- callingFeatureId);
- if (scanId == INVALID_SCAN_ID) {
- Rlog.e(TAG, "Failed to initiate network scan");
- return null;
- }
+ // The lock must be taken before calling requestNetworkScan because the resulting
+ // scanId can be invoked asynchronously on another thread at any time after
+ // requestNetworkScan invoked, leaving a critical section between that call and adding
+ // the record to the ScanInfo cache.
synchronized (mScanInfo) {
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage,
+ callingFeatureId);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
// We link to death whenever a scan is started to ensure that we are linked
// at the point that phone process death might matter.
// We never unlink because: