diff options
43 files changed, 655 insertions, 346 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java index 517e3ce39d7e..31c92ba5e207 100644 --- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java @@ -70,6 +70,9 @@ public class ZipFilePerfTest { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { ZipFile zf = new ZipFile(mFile); + state.pauseTiming(); + zf.close(); + state.resumeTiming(); } } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9e9e985d27de..802458b1793c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5894,16 +5894,16 @@ public final class ActivityThread extends ClientTransactionHandler final boolean movedToDifferentDisplay = isDifferentDisplay(activity.getDisplayId(), displayId); - final Configuration currentConfig = activity.mCurrentConfig; - final int diff = currentConfig.diffPublicOnly(newConfig); - final boolean hasPublicConfigChange = diff != 0; + final Configuration currentResConfig = activity.getResources().getConfiguration(); + final int diff = currentResConfig.diffPublicOnly(newConfig); + final boolean hasPublicResConfigChange = diff != 0; final ActivityClientRecord r = getActivityClient(activityToken); // TODO(b/173090263): Use diff instead after the improvement of AssetManager and // ResourcesImpl constructions. - final boolean shouldUpdateResources = hasPublicConfigChange - || shouldUpdateResources(activityToken, currentConfig, newConfig, amOverrideConfig, - movedToDifferentDisplay, hasPublicConfigChange); - final boolean shouldReportChange = shouldReportChange(diff, currentConfig, newConfig, + final boolean shouldUpdateResources = hasPublicResConfigChange + || shouldUpdateResources(activityToken, currentResConfig, newConfig, + amOverrideConfig, movedToDifferentDisplay, hasPublicResConfigChange); + final boolean shouldReportChange = shouldReportChange(activity.mCurrentConfig, newConfig, r != null ? r.mSizeConfigurations : null, activity.mActivityInfo.getRealConfigChanged()); // Nothing significant, don't proceed with updating and reporting. @@ -5927,9 +5927,6 @@ public final class ActivityThread extends ClientTransactionHandler amOverrideConfig, contextThemeWrapperOverrideConfig); mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig, displayId); - activity.mConfigChangeFlags = 0; - activity.mCurrentConfig = new Configuration(newConfig); - // Apply the ContextThemeWrapper override if necessary. // NOTE: Make sure the configurations are not modified, as they are treated as immutable // in many places. @@ -5940,8 +5937,10 @@ public final class ActivityThread extends ClientTransactionHandler activity.dispatchMovedToDisplay(displayId, configToReport); } + activity.mConfigChangeFlags = 0; if (shouldReportChange) { activity.mCalled = false; + activity.mCurrentConfig = new Configuration(newConfig); activity.onConfigurationChanged(configToReport); if (!activity.mCalled) { throw new SuperNotCalledException("Activity " + activity.getLocalClassName() + @@ -5956,8 +5955,6 @@ public final class ActivityThread extends ClientTransactionHandler * Returns {@code true} if {@link Activity#onConfigurationChanged(Configuration)} should be * dispatched. * - * @param publicDiff Usually computed by {@link Configuration#diffPublicOnly(Configuration)}. - * This parameter is to prevent we compute it again. * @param currentConfig The current configuration cached in {@link Activity#mCurrentConfig}. * It is {@code null} before the first config update from the server side. * @param newConfig The updated {@link Configuration} @@ -5966,9 +5963,10 @@ public final class ActivityThread extends ClientTransactionHandler * @return {@code true} if the config change should be reported to the Activity */ @VisibleForTesting - public static boolean shouldReportChange(int publicDiff, @Nullable Configuration currentConfig, + public static boolean shouldReportChange(@Nullable Configuration currentConfig, @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets sizeBuckets, int handledConfigChanges) { + final int publicDiff = currentConfig.diffPublicOnly(newConfig); // Don't report the change if there's no public diff between current and new config. if (publicDiff == 0) { return false; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 6829f3da5717..98d4c5976adc 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -4503,10 +4503,13 @@ public class BatteryStatsImpl extends BatteryStats { for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) { entry.setValue(entry.getValue() | TAG_FIRST_OCCURRENCE_FLAG); } + // Make a copy of mHistoryCur. + HistoryItem copy = new HistoryItem(); + copy.setTo(cur); + // startRecordingHistory will reset mHistoryCur. startRecordingHistory(elapsedRealtimeMs, uptimeMs, false); - HistoryItem newItem = new HistoryItem(); - newItem.setTo(cur); - addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, newItem); + // Add the copy into history buffer. + addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, copy); return; } diff --git a/core/proto/android/server/windowmanagertransitiontrace.proto b/core/proto/android/server/windowmanagertransitiontrace.proto index 9429127b2f6e..4161f6554fb6 100644 --- a/core/proto/android/server/windowmanagertransitiontrace.proto +++ b/core/proto/android/server/windowmanagertransitiontrace.proto @@ -58,6 +58,8 @@ message Transition { State state = 5; int32 flags = 6; repeated ChangeInfo change = 7; + uint64 start_transaction_id = 8; + uint64 finish_transaction_id = 9; } message ChangeInfo { diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java index 385879210d4a..dd0e9ff8b5e8 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java @@ -154,19 +154,21 @@ public class BatteryStatsHistoryIteratorTest { for (int i = 0; i < eventCount; i++) { String name = "a" + (i % 10); - assertThat(iterator.next(item)).isTrue(); - // Skip a blank event inserted at the start of every buffer - if (item.eventCode == BatteryStats.HistoryItem.EVENT_NONE) { + do { assertThat(iterator.next(item)).isTrue(); - } + // Skip a blank event inserted at the start of every buffer + } while (item.cmd != BatteryStats.HistoryItem.CMD_UPDATE + || item.eventCode == BatteryStats.HistoryItem.EVENT_NONE); + assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START); assertThat(item.eventTag.string).isEqualTo(name); - assertThat(iterator.next(item)).isTrue(); - if (item.eventCode == BatteryStats.HistoryItem.EVENT_NONE) { + do { assertThat(iterator.next(item)).isTrue(); - } + } while (item.cmd != BatteryStats.HistoryItem.CMD_UPDATE + || item.eventCode == BatteryStats.HistoryItem.EVENT_NONE); + assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH); assertThat(item.eventTag.string).isEqualTo(name); diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 8d3751e6ad6c..47f70ddf2d42 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -207,8 +207,8 @@ public class ActivityThreadClientTest { final Configuration currentConfig = new Configuration(); assertFalse("Must not report change if no public diff", - shouldReportChange(0 /* publicDiff */, currentConfig, newConfig, - null /* sizeBuckets */, 0 /* handledConfigChanges */)); + shouldReportChange(currentConfig, newConfig, null /* sizeBuckets */, + 0 /* handledConfigChanges */)); final int[] verticalThresholds = {100, 400}; final SizeConfigurationBuckets buckets = new SizeConfigurationBuckets( @@ -221,25 +221,25 @@ public class ActivityThreadClientTest { newConfig.screenHeightDp = 300; assertFalse("Must not report changes if the diff is small and not handled", - shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig, - newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */)); + shouldReportChange(currentConfig, newConfig, buckets, + CONFIG_FONT_SCALE /* handledConfigChanges */)); assertTrue("Must report changes if the small diff is handled", - shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig, newConfig, - buckets, CONFIG_SCREEN_SIZE /* handledConfigChanges */)); + shouldReportChange(currentConfig, newConfig, buckets, + CONFIG_SCREEN_SIZE /* handledConfigChanges */)); currentConfig.fontScale = 0.8f; newConfig.fontScale = 1.2f; assertTrue("Must report handled changes regardless of small unhandled change", - shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */, - currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */)); + shouldReportChange(currentConfig, newConfig, buckets, + CONFIG_FONT_SCALE /* handledConfigChanges */)); newConfig.screenHeightDp = 500; assertFalse("Must not report changes if there's unhandled big changes", - shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */, - currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */)); + shouldReportChange(currentConfig, newConfig, buckets, + CONFIG_FONT_SCALE /* handledConfigChanges */)); } private void recreateAndVerifyNoRelaunch(ActivityThread activityThread, TestActivity activity) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 172418057b86..920dcc70ad46 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -216,24 +216,24 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange /** Applies new configuration, returns {@code false} if there's no effect to the layout. */ public boolean updateConfiguration(Configuration configuration) { - // Always update configuration after orientation changed to make sure to render divider bar - // with proper resources that matching screen orientation. - final int orientation = configuration.orientation; - if (mOrientation != orientation) { - mContext = mContext.createConfigurationContext(configuration); - mSplitWindowManager.setConfiguration(configuration); - mOrientation = orientation; - } - // Update the split bounds when necessary. Besides root bounds changed, split bounds need to // be updated when the rotation changed to cover the case that users rotated the screen 180 // degrees. + // Make sure to render the divider bar with proper resources that matching the screen + // orientation. final int rotation = configuration.windowConfiguration.getRotation(); final Rect rootBounds = configuration.windowConfiguration.getBounds(); - if (mRotation == rotation && mRootBounds.equals(rootBounds)) { + final int orientation = configuration.orientation; + + if (mOrientation == orientation + && mRotation == rotation + && mRootBounds.equals(rootBounds)) { return false; } + mContext = mContext.createConfigurationContext(configuration); + mSplitWindowManager.setConfiguration(configuration); + mOrientation = orientation; mTempRect.set(mRootBounds); mRootBounds.set(rootBounds); mRotation = rotation; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java index 3dd43866e465..f9fc1f3ca184 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; -import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationListener.NotificationHandler; @@ -33,13 +32,10 @@ import java.util.List; import java.util.Set; import java.util.concurrent.Executor; -import javax.inject.Inject; - /*** * {@link DreamOverlayNotificationCountProvider} provides the current notification count to * registered callbacks. Ongoing notifications are not included in the count. */ -@SysUISingleton public class DreamOverlayNotificationCountProvider implements CallbackController<DreamOverlayNotificationCountProvider.Callback> { private final Set<String> mNotificationKeys = new HashSet<>(); @@ -82,7 +78,6 @@ public class DreamOverlayNotificationCountProvider } }; - @Inject public DreamOverlayNotificationCountProvider( NotificationListener notificationListener, @Background Executor bgExecutor) { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java index e878b22f61ed..250313d0aae8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java @@ -49,6 +49,7 @@ import com.android.systemui.util.time.DateFormatUtil; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -65,7 +66,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve private final Resources mResources; private final DateFormatUtil mDateFormatUtil; private final IndividualSensorPrivacyController mSensorPrivacyController; - private final DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider; + private final Optional<DreamOverlayNotificationCountProvider> + mDreamOverlayNotificationCountProvider; private final ZenModeController mZenModeController; private final Executor mMainExecutor; @@ -125,7 +127,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve NextAlarmController nextAlarmController, DateFormatUtil dateFormatUtil, IndividualSensorPrivacyController sensorPrivacyController, - DreamOverlayNotificationCountProvider dreamOverlayNotificationCountProvider, + Optional<DreamOverlayNotificationCountProvider> dreamOverlayNotificationCountProvider, ZenModeController zenModeController, StatusBarWindowStateController statusBarWindowStateController) { super(view); @@ -161,7 +163,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mZenModeController.addCallback(mZenModeCallback); updatePriorityModeStatusIcon(); - mDreamOverlayNotificationCountProvider.addCallback(mNotificationCountCallback); + mDreamOverlayNotificationCountProvider.ifPresent( + provider -> provider.addCallback(mNotificationCountCallback)); + mTouchInsetSession.addViewToTracking(mView); } @@ -171,7 +175,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mSensorPrivacyController.removeCallback(mSensorCallback); mNextAlarmController.removeCallback(mNextAlarmCallback); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); - mDreamOverlayNotificationCountProvider.removeCallback(mNotificationCountCallback); + mDreamOverlayNotificationCountProvider.ifPresent( + provider -> provider.removeCallback(mNotificationCountCallback)); mTouchInsetSession.clear(); mIsAttached = false; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java index cd23f149cf7d..2dd2098a78b9 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java @@ -20,9 +20,13 @@ import android.content.Context; import android.content.res.Resources; import com.android.settingslib.dream.DreamBackend; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dreams.DreamOverlayNotificationCountProvider; import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule; +import java.util.Optional; + import javax.inject.Named; import dagger.Module; @@ -50,6 +54,18 @@ public interface DreamModule { return DreamBackend.getInstance(context); } + /** + * Provides an instance of a {@link DreamOverlayNotificationCountProvider}. + */ + @SysUISingleton + @Provides + static Optional<DreamOverlayNotificationCountProvider> + providesDreamOverlayNotificationCountProvider() { + // If we decide to bring this back, we should gate it on a config that can be changed in + // an overlay. + return Optional.empty(); + } + /** */ @Provides @Named(DREAM_ONLY_ENABLED_FOR_SYSTEM_USER) diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index f86541a90109..47c678b4b8cf 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -45,9 +45,6 @@ public class Flags { /***************************************/ // 100 - notification - public static final BooleanFlag NEW_NOTIFICATION_PIPELINE_RENDERING = - new BooleanFlag(101, true); - public static final BooleanFlag NOTIFICATION_PIPELINE_DEVELOPER_LOGGING = new BooleanFlag(103, false); @@ -194,6 +191,8 @@ public class Flags { public static final SysPropBooleanFlag WM_ALWAYS_ENFORCE_PREDICTIVE_BACK = new SysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", false); + public static final BooleanFlag NEW_BACK_AFFORDANCE = new BooleanFlag(1203, true); + // Pay no attention to the reflection behind the curtain. // ========================== Curtain ========================== // | | diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index c5f6b7831ecf..d29655a5408d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -486,6 +486,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ private IRemoteAnimationRunner mKeyguardExitAnimationRunner; + private CentralSurfaces mCentralSurfaces; + private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override @@ -846,6 +848,13 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, + mOccluded); } + @Override + public void onLaunchAnimationEnd(boolean launchIsFullScreen) { + if (launchIsFullScreen) { + mCentralSurfaces.instantCollapseNotificationPanel(); + } + } + @NonNull @Override public ViewGroup getLaunchContainer() { @@ -2853,6 +2862,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Nullable PanelExpansionStateManager panelExpansionStateManager, BiometricUnlockController biometricUnlockController, View notificationContainer, KeyguardBypassController bypassController) { + mCentralSurfaces = centralSurfaces; mKeyguardViewControllerLazy.get().registerCentralSurfaces( centralSurfaces, panelView, diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 05da4bb4d1ad..90cca15ddf21 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -52,7 +52,7 @@ public class LogModule { return factory.create("NotifLog", 1000 /* maxSize */, false /* systrace */); } - /** Provides a logging buffer for all logs related to the data layer of notifications. */ + /** Provides a logging buffer for logs related to heads up presentation of notifications. */ @Provides @SysUISingleton @NotificationHeadsUpLog @@ -60,6 +60,14 @@ public class LogModule { return factory.create("NotifHeadsUpLog", 1000); } + /** Provides a logging buffer for notification interruption calculations. */ + @Provides + @SysUISingleton + @NotificationInterruptLog + public static LogBuffer provideNotificationInterruptLogBuffer(LogBufferFactory factory) { + return factory.create("NotifInterruptLog", 100); + } + /** Provides a logging buffer for all logs for lockscreen to shade transition events. */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java new file mode 100644 index 000000000000..760fbf3928b6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationInterruptLog.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 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.log.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.android.systemui.log.LogBuffer; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Qualifier; + +/** A {@link LogBuffer} for notification interruption logging. */ +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface NotificationInterruptLog { +} diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index d41837b7cf4d..e210d685a370 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -234,7 +234,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private boolean mIsBackGestureAllowed; private boolean mGestureBlockingActivityRunning; private boolean mIsInPipMode; - private boolean mIsPredictiveBackAnimEnabled; + private boolean mIsNewBackAffordanceEnabled; private InputMonitor mInputMonitor; private InputChannelCompat.InputEventReceiver mInputEventReceiver; @@ -524,8 +524,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker Choreographer.getInstance(), this::onInputEvent); // Add a nav bar panel window - mIsPredictiveBackAnimEnabled = - mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_ANIM); + mIsNewBackAffordanceEnabled = mFeatureFlags.isEnabled(Flags.NEW_BACK_AFFORDANCE); resetEdgeBackPlugin(); mPluginManager.addPluginListener( this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false); @@ -545,7 +544,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker } private void resetEdgeBackPlugin() { - if (mIsPredictiveBackAnimEnabled) { + if (mIsNewBackAffordanceEnabled) { setEdgeBackPlugin( mBackPanelControllerFactory.create(mContext, mBackAnimation)); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt index f6a55e6b75c6..478f7aa8ce09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt @@ -48,8 +48,7 @@ class NotifPipelineFlags @Inject constructor( fun assertLegacyPipelineEnabled(): Unit = check(!isNewPipelineEnabled()) { "Old pipeline code running w/ new pipeline enabled" } - fun isNewPipelineEnabled(): Boolean = - featureFlags.isEnabled(Flags.NEW_NOTIFICATION_PIPELINE_RENDERING) + fun isNewPipelineEnabled(): Boolean = true fun isDevLoggingEnabled(): Boolean = featureFlags.isEnabled(Flags.NOTIFICATION_PIPELINE_DEVELOPER_LOGGING) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS new file mode 100644 index 000000000000..63c37e9584d6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS @@ -0,0 +1,12 @@ +set noparent + +# Bug component: 78010 + +aaliomer@google.com +aroederer@google.com +jeffdq@google.com +juliacr@google.com +juliatuttle@google.com +lynhan@google.com +steell@google.com +yurilin@google.com
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java index e98ae8db4122..792ff8d20b97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java @@ -115,6 +115,7 @@ public class ListDumper { ) { sb.append(indent) .append("[").append(index).append("] ") + .append(index.length() == 1 ? " " : "") .append(entry.getKey()); if (includeParent) { @@ -192,7 +193,7 @@ public class ListDumper { if (notifEntry.getAttachState().getSuppressedChanges().getSection() != null) { rksb.append("suppressedSection=") .append(notifEntry.getAttachState().getSuppressedChanges() - .getSection()) + .getSection().getLabel()) .append(" "); } 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 410593ac5493..ecce1ba25702 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 @@ -104,6 +104,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -829,11 +830,9 @@ public class NotifCollection implements Dumpable { @Override public void dump(PrintWriter pw, @NonNull String[] args) { final List<NotificationEntry> entries = new ArrayList<>(getAllNotifs()); + entries.sort(Comparator.comparing(NotificationEntry::getKey)); - pw.println("\t" + TAG + " unsorted/unfiltered notifications:"); - if (entries.size() == 0) { - pw.println("\t\t None"); - } + pw.println("\t" + TAG + " unsorted/unfiltered notifications: " + entries.size()); pw.println( ListDumper.dumpList( entries, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt index 6c99e3adb73e..1d18ca3dfade 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt @@ -20,16 +20,14 @@ import android.service.notification.StatusBarNotification import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.dagger.NotificationHeadsUpLog -import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.log.dagger.NotificationInterruptLog import javax.inject.Inject class NotificationInterruptLogger @Inject constructor( - @NotificationLog val notifBuffer: LogBuffer, - @NotificationHeadsUpLog val hunBuffer: LogBuffer + @NotificationInterruptLog val buffer: LogBuffer ) { fun logHeadsUpFeatureChanged(useHeadsUp: Boolean) { - hunBuffer.log(TAG, INFO, { + buffer.log(TAG, INFO, { bool1 = useHeadsUp }, { "heads up is enabled=$bool1" @@ -37,14 +35,14 @@ class NotificationInterruptLogger @Inject constructor( } fun logWillDismissAll() { - hunBuffer.log(TAG, INFO, { + buffer.log(TAG, INFO, { }, { "dismissing any existing heads up notification on disable event" }) } fun logNoBubbleNotAllowed(sbn: StatusBarNotification) { - notifBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No bubble up: not allowed to bubble: $str1" @@ -52,7 +50,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoBubbleNoMetadata(sbn: StatusBarNotification) { - notifBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No bubble up: notification: $str1 doesn't have valid metadata" @@ -60,14 +58,14 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoHeadsUpFeatureDisabled() { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { }, { "No heads up: no huns" }) } fun logNoHeadsUpPackageSnoozed(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No alerting: snoozed package: $str1" @@ -75,7 +73,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoHeadsUpAlreadyBubbled(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No heads up: in unlocked shade where notification is shown as a bubble: $str1" @@ -83,7 +81,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoHeadsUpSuppressedByDnd(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No heads up: suppressed by DND: $str1" @@ -91,7 +89,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoHeadsUpNotImportant(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No heads up: unimportant notification: $str1" @@ -99,7 +97,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoHeadsUpNotInUse(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No heads up: not in use: $str1" @@ -110,7 +108,7 @@ class NotificationInterruptLogger @Inject constructor( sbn: StatusBarNotification, suppressor: NotificationInterruptSuppressor ) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key str2 = suppressor.name }, { @@ -119,7 +117,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logHeadsUp(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "Heads up: $str1" @@ -127,7 +125,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoAlertingFilteredOut(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No alerting: filtered notification: $str1" @@ -135,7 +133,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoAlertingGroupAlertBehavior(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No alerting: suppressed due to group alert behavior: $str1" @@ -147,7 +145,7 @@ class NotificationInterruptLogger @Inject constructor( suppressor: NotificationInterruptSuppressor, awake: Boolean ) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key str2 = suppressor.name bool1 = awake @@ -157,7 +155,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoAlertingRecentFullscreen(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No alerting: recent fullscreen: $str1" @@ -165,7 +163,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoPulsingSettingDisabled(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No pulsing: disabled by setting: $str1" @@ -173,7 +171,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoPulsingBatteryDisabled(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No pulsing: disabled by battery saver: $str1" @@ -181,7 +179,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoPulsingNoAlert(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No pulsing: notification shouldn't alert: $str1" @@ -189,7 +187,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoPulsingNoAmbientEffect(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No pulsing: ambient effect suppressed: $str1" @@ -197,7 +195,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logNoPulsingNotImportant(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "No pulsing: not important enough: $str1" @@ -205,7 +203,7 @@ class NotificationInterruptLogger @Inject constructor( } fun logPulsing(sbn: StatusBarNotification) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = sbn.key }, { "Pulsing: $str1" @@ -213,7 +211,7 @@ class NotificationInterruptLogger @Inject constructor( } fun keyguardHideNotification(key: String) { - hunBuffer.log(TAG, DEBUG, { + buffer.log(TAG, DEBUG, { str1 = key }, { "Keyguard Hide Notification: $str1" 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 b785435f41f2..cd4a44e1c6e0 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 @@ -141,7 +141,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f; private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30); - private boolean mUpdateBackgroundOnUpdate; + private boolean mUpdateSelfBackgroundOnUpdate; private boolean mNotificationTranslationFinished = false; private boolean mIsSnoozed; private boolean mIsFaded; @@ -553,9 +553,28 @@ public class ExpandableNotificationRow extends ActivatableNotificationView updateLimits(); updateShelfIconColor(); updateRippleAllowed(); - if (mUpdateBackgroundOnUpdate) { - mUpdateBackgroundOnUpdate = false; - updateBackgroundColors(); + if (mUpdateSelfBackgroundOnUpdate) { + // Because this is triggered by UiMode change which we already propagated to children, + // we know that child rows will receive the same event, and will update their own + // backgrounds when they finish inflating, so propagating again would be redundant. + mUpdateSelfBackgroundOnUpdate = false; + updateBackgroundColorsOfSelf(); + } + } + + private void updateBackgroundColorsOfSelf() { + super.updateBackgroundColors(); + } + + @Override + public void updateBackgroundColors() { + // Because this call is made by the NSSL only on attached rows at the moment of the + // UiMode or Theme change, we have to propagate to our child views. + updateBackgroundColorsOfSelf(); + if (mIsSummaryWithChildren) { + for (ExpandableNotificationRow child : mChildrenContainer.getAttachedChildren()) { + child.updateBackgroundColors(); + } } } @@ -1242,7 +1261,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public void onUiModeChanged() { - mUpdateBackgroundOnUpdate = true; + mUpdateSelfBackgroundOnUpdate = true; reInflateViews(); if (mChildrenContainer != null) { for (ExpandableNotificationRow child : mChildrenContainer.getAttachedChildren()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 8c6176408821..5181af773d9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1597,7 +1597,7 @@ public class CentralSurfacesImpl extends CoreStartable implements } } }); - mStatusBarKeyguardViewManager.registerCentralSurfaces( + mKeyguardViewMediator.registerCentralSurfaces( /* statusBar= */ this, mNotificationPanelViewController, mPanelExpansionStateManager, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS new file mode 100644 index 000000000000..18f0fb38999c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS @@ -0,0 +1,3 @@ +per-file *Notification* = set noparent +per-file *Notification* = file:../notification/OWNERS +per-file NotificationIcon* = ccassidy@google.com, evanlaird@google.com, pixel@google.com
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java index 313d56febb75..4e9030f8045c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java +++ b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java @@ -16,17 +16,17 @@ package com.android.systemui.util.condition; +import android.util.ArraySet; import android.util.Log; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.statusbar.policy.CallbackController; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; +import java.util.Collections; +import java.util.HashMap; import java.util.Set; import java.util.concurrent.Executor; import java.util.stream.Collectors; @@ -37,154 +37,200 @@ import javax.inject.Inject; * {@link Monitor} takes in a set of conditions, monitors whether all of them have * been fulfilled, and informs any registered listeners. */ -public class Monitor implements CallbackController<Monitor.Callback> { +public class Monitor { private final String mTag = getClass().getSimpleName(); + private final Executor mExecutor; - private final ArrayList<Callback> mCallbacks = new ArrayList<>(); + private final HashMap<Condition, ArraySet<Subscription.Token>> mConditions = new HashMap<>(); + private final HashMap<Subscription.Token, SubscriptionState> mSubscriptions = new HashMap<>(); - // Set of all conditions that need to be monitored. - private final Set<Condition> mConditions; - private final Executor mExecutor; + private static class SubscriptionState { + private final Subscription mSubscription; + private Boolean mAllConditionsMet; - // Whether all conditions have been met. - private boolean mAllConditionsMet = false; + SubscriptionState(Subscription subscription) { + mSubscription = subscription; + } + + public Set<Condition> getConditions() { + return mSubscription.mConditions; + } - // Whether the monitor has started listening for all the conditions. - private boolean mHaveConditionsStarted = false; + public void update() { + // Overriding conditions do not override each other + final Collection<Condition> overridingConditions = mSubscription.mConditions.stream() + .filter(Condition::isOverridingCondition).collect(Collectors.toSet()); + + final Collection<Condition> targetCollection = overridingConditions.isEmpty() + ? mSubscription.mConditions : overridingConditions; + + final boolean newAllConditionsMet = targetCollection.isEmpty() ? true : targetCollection + .stream() + .map(Condition::isConditionMet) + .allMatch(conditionMet -> conditionMet); + + if (mAllConditionsMet != null && newAllConditionsMet == mAllConditionsMet) { + return; + } + + mAllConditionsMet = newAllConditionsMet; + mSubscription.mCallback.onConditionsChanged(mAllConditionsMet); + } + } // Callback for when each condition has been updated. private final Condition.Callback mConditionCallback = new Condition.Callback() { @Override public void onConditionChanged(Condition condition) { - mExecutor.execute(() -> updateConditionMetState()); + mExecutor.execute(() -> updateConditionMetState(condition)); } }; @Inject - public Monitor(@Main Executor executor, Set<Condition> conditions) { - mConditions = new HashSet<>(); + public Monitor(@Main Executor executor) { mExecutor = executor; - - if (conditions != null) { - mConditions.addAll(conditions); - } } - private void updateConditionMetState() { - // Overriding conditions do not override each other - final Collection<Condition> overridingConditions = mConditions.stream() - .filter(Condition::isOverridingCondition).collect(Collectors.toSet()); - - final Collection<Condition> targetCollection = overridingConditions.isEmpty() - ? mConditions : overridingConditions; - - final boolean newAllConditionsMet = targetCollection.isEmpty() ? true : targetCollection - .stream() - .map(Condition::isConditionMet) - .allMatch(conditionMet -> conditionMet); + private void updateConditionMetState(Condition condition) { + mConditions.get(condition).stream().forEach(token -> mSubscriptions.get(token).update()); + } - if (newAllConditionsMet == mAllConditionsMet) { - return; - } + /** + * Registers a callback and the set of conditions to trigger it. + * @param subscription A {@link Subscription} detailing the desired conditions and callback. + * @return A {@link Subscription.Token} that can be used to remove the subscription. + */ + public Subscription.Token addSubscription(@NotNull Subscription subscription) { + final Subscription.Token token = new Subscription.Token(); + final SubscriptionState state = new SubscriptionState(subscription); - if (shouldLog()) Log.d(mTag, "all conditions met: " + newAllConditionsMet); - mAllConditionsMet = newAllConditionsMet; - - // Updates all callbacks. - final Iterator<Callback> iterator = mCallbacks.iterator(); - while (iterator.hasNext()) { - final Callback callback = iterator.next(); - if (callback == null) { - iterator.remove(); - } else { - callback.onConditionsChanged(mAllConditionsMet); - } - } - } + mExecutor.execute(() -> { + mSubscriptions.put(token, state); - private void addConditionLocked(@NotNull Condition condition) { - mConditions.add(condition); + // Add and associate conditions. + subscription.getConditions().stream().forEach(condition -> { + if (!mConditions.containsKey(condition)) { + mConditions.put(condition, new ArraySet<>()); + condition.addCallback(mConditionCallback); + } - if (!mHaveConditionsStarted) { - return; - } + mConditions.get(condition).add(token); + }); - condition.addCallback(mConditionCallback); - updateConditionMetState(); - } + // Update subscription state. + state.update(); - /** - * Adds a condition for the monitor to listen to and consider when determining whether the - * overall condition state is met. - */ - public void addCondition(@NotNull Condition condition) { - mExecutor.execute(() -> addConditionLocked(condition)); + }); + return token; } /** - * Removes a condition from further consideration. + * Removes a subscription from participating in future callbacks. + * @param token The {@link Subscription.Token} returned when the {@link Subscription} was + * originally added. */ - public void removeCondition(@NotNull Condition condition) { + public void removeSubscription(@NotNull Subscription.Token token) { mExecutor.execute(() -> { - mConditions.remove(condition); - - if (!mHaveConditionsStarted) { + if (shouldLog()) Log.d(mTag, "removing callback"); + if (!mSubscriptions.containsKey(token)) { + Log.e(mTag, "subscription not present:" + token); return; } - condition.removeCallback(mConditionCallback); - updateConditionMetState(); + mSubscriptions.remove(token).getConditions().forEach(condition -> { + if (!mConditions.containsKey(condition)) { + Log.e(mTag, "condition not present:" + condition); + return; + + } + final Set<Subscription.Token> conditionSubscriptions = mConditions.get(condition); + + conditionSubscriptions.remove(token); + if (conditionSubscriptions.isEmpty()) { + condition.removeCallback(mConditionCallback); + mConditions.remove(condition); + } + }); }); } - private void addCallbackLocked(@NotNull Callback callback) { - if (mCallbacks.contains(callback)) { - return; - } + private boolean shouldLog() { + return Log.isLoggable(mTag, Log.DEBUG); + } - if (shouldLog()) Log.d(mTag, "adding callback"); - mCallbacks.add(callback); + /** + * A {@link Subscription} represents a set of conditions and a callback that is informed when + * these conditions change. + */ + public static class Subscription { + private final Set<Condition> mConditions; + private final Callback mCallback; + + /** */ + public Subscription(Set<Condition> conditions, Callback callback) { + this.mConditions = Collections.unmodifiableSet(conditions); + this.mCallback = callback; + } - // Updates the callback immediately. - callback.onConditionsChanged(mAllConditionsMet); + public Set<Condition> getConditions() { + return mConditions; + } - if (!mHaveConditionsStarted) { - if (shouldLog()) Log.d(mTag, "starting all conditions"); - mConditions.forEach(condition -> condition.addCallback(mConditionCallback)); - updateConditionMetState(); - mHaveConditionsStarted = true; + public Callback getCallback() { + return mCallback; } - } - @Override - public void addCallback(@NotNull Callback callback) { - mExecutor.execute(() -> addCallbackLocked(callback)); - } + /** + * A {@link Token} is an identifier that is associated with a {@link Subscription} which is + * registered with a {@link Monitor}. + */ + public static class Token { + } - @Override - public void removeCallback(@NotNull Callback callback) { - mExecutor.execute(() -> { - if (shouldLog()) Log.d(mTag, "removing callback"); - final Iterator<Callback> iterator = mCallbacks.iterator(); - while (iterator.hasNext()) { - final Callback cb = iterator.next(); - if (cb == null || cb == callback) { - iterator.remove(); - } + /** + * {@link Builder} is a helper class for constructing a {@link Subscription}. + */ + public static class Builder { + private final Callback mCallback; + private final ArraySet<Condition> mConditions; + + /** + * Default constructor specifying the {@link Callback} for the {@link Subscription}. + * @param callback + */ + public Builder(Callback callback) { + mCallback = callback; + mConditions = new ArraySet<>(); } - if (mCallbacks.isEmpty() && mHaveConditionsStarted) { - if (shouldLog()) Log.d(mTag, "stopping all conditions"); - mConditions.forEach(condition -> condition.removeCallback(mConditionCallback)); + /** + * Adds a {@link Condition} to be associated with the {@link Subscription}. + * @param condition + * @return The updated {@link Builder}. + */ + public Builder addCondition(Condition condition) { + mConditions.add(condition); + return this; + } - mAllConditionsMet = false; - mHaveConditionsStarted = false; + /** + * Adds a set of {@link Condition} to be associated with the {@link Subscription}. + * @param condition + * @return The updated {@link Builder}. + */ + public Builder addConditions(Set<Condition> condition) { + mConditions.addAll(condition); + return this; } - }); - } - private boolean shouldLog() { - return Log.isLoggable(mTag, Log.DEBUG); + /** + * Builds the {@link Subscription}. + * @return The resulting {@link Subscription}. + */ + public Subscription build() { + return new Subscription(mConditions, mCallback); + } + } } /** @@ -192,6 +238,13 @@ public class Monitor implements CallbackController<Monitor.Callback> { */ public interface Callback { /** + * Returns the conditions associated with this callback. + */ + default ArrayList<Condition> getConditions() { + return new ArrayList<>(); + } + + /** * Triggered when the fulfillment of all conditions have been met. * * @param allConditionsMet True if all conditions have been fulfilled. False if none or diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java b/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java deleted file mode 100644 index 8e739d61b4f2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/util/condition/dagger/MonitorComponent.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.condition.dagger; - -import com.android.systemui.util.condition.Condition; -import com.android.systemui.util.condition.Monitor; - -import java.util.Set; - -import dagger.BindsInstance; -import dagger.Subcomponent; - -/** - * Component for {@link Monitor}. - */ -@Subcomponent -public interface MonitorComponent { - /** - * Factory for {@link MonitorComponent}. - */ - @Subcomponent.Factory - interface Factory { - MonitorComponent create(@BindsInstance Set<Condition> conditions); - } - - /** - * Provides {@link Monitor}. - * @return - */ - Monitor getMonitor(); -} diff --git a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java index 7892d6eec98d..981bf01164e3 100644 --- a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java +++ b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java @@ -18,7 +18,6 @@ package com.android.systemui.util.dagger; import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.RingerModeTrackerImpl; -import com.android.systemui.util.condition.dagger.MonitorComponent; import com.android.systemui.util.wrapper.UtilWrapperModule; import dagger.Binds; @@ -27,9 +26,6 @@ import dagger.Module; /** Dagger Module for code in the util package. */ @Module(includes = { UtilWrapperModule.class - }, - subcomponents = { - MonitorComponent.class, }) public interface UtilModule { /** */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java index 3c28d48c2eb5..d334694805fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java @@ -57,6 +57,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; import java.util.concurrent.Executor; @SmallTest @@ -115,7 +116,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { mNextAlarmController, mDateFormatUtil, mSensorPrivacyController, - mDreamOverlayNotificationCountProvider, + Optional.of(mDreamOverlayNotificationCountProvider), mZenModeController, mStatusBarWindowStateController); } @@ -231,6 +232,26 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { } @Test + public void testNotificationsIconNotShownWhenCountProviderAbsent() { + DreamOverlayStatusBarViewController controller = new DreamOverlayStatusBarViewController( + mView, + mResources, + mMainExecutor, + mConnectivityManager, + mTouchSession, + mAlarmManager, + mNextAlarmController, + mDateFormatUtil, + mSensorPrivacyController, + Optional.empty(), + mZenModeController, + mStatusBarWindowStateController); + controller.onViewAttached(); + verify(mView, never()).showIcon( + eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any()); + } + + @Test public void testOnViewAttachedShowsPriorityModeIconWhenEnabled() { when(mZenModeController.getZen()).thenReturn( Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index b1bf971c52fc..f8b39e8cff71 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -43,6 +43,7 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.NotificationChannel; +import android.graphics.Color; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -110,6 +111,28 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { } @Test + public void testUpdateBackgroundColors_isRecursive() { + mGroupRow.setTintColor(Color.RED); + mGroupRow.getChildNotificationAt(0).setTintColor(Color.GREEN); + mGroupRow.getChildNotificationAt(1).setTintColor(Color.BLUE); + + assertThat(mGroupRow.getCurrentBackgroundTint()).isEqualTo(Color.RED); + assertThat(mGroupRow.getChildNotificationAt(0).getCurrentBackgroundTint()) + .isEqualTo(Color.GREEN); + assertThat(mGroupRow.getChildNotificationAt(1).getCurrentBackgroundTint()) + .isEqualTo(Color.BLUE); + + mGroupRow.updateBackgroundColors(); + + int resetTint = mGroupRow.getCurrentBackgroundTint(); + assertThat(resetTint).isNotEqualTo(Color.RED); + assertThat(mGroupRow.getChildNotificationAt(0).getCurrentBackgroundTint()) + .isEqualTo(resetTint); + assertThat(mGroupRow.getChildNotificationAt(1).getCurrentBackgroundTint()) + .isEqualTo(resetTint); + } + + @Test public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws InterruptedException { // GIVEN a sensitive notification row that's currently redacted measureAndLayout(mNotifRow); diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java index 758961658f2a..1e35b0f0e68a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java @@ -65,7 +65,12 @@ public class ConditionMonitorTest extends SysuiTestCase { mCondition3 = spy(new FakeCondition()); mConditions = new HashSet<>(Arrays.asList(mCondition1, mCondition2, mCondition3)); - mConditionMonitor = new Monitor(mExecutor, mConditions); + mConditionMonitor = new Monitor(mExecutor); + } + + public Monitor.Subscription.Builder getDefaultBuilder(Monitor.Callback callback) { + return new Monitor.Subscription.Builder(callback) + .addConditions(mConditions); } @Test @@ -74,11 +79,19 @@ public class ConditionMonitorTest extends SysuiTestCase { final Condition regularCondition = Mockito.mock(Condition.class); final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class); - final Monitor monitor = new Monitor( - mExecutor, - new HashSet<>(Arrays.asList(overridingCondition, regularCondition))); + final Monitor.Callback referenceCallback = Mockito.mock(Monitor.Callback.class); + + final Monitor monitor = new Monitor(mExecutor); + + monitor.addSubscription(getDefaultBuilder(callback) + .addCondition(overridingCondition) + .addCondition(regularCondition) + .build()); + + monitor.addSubscription(getDefaultBuilder(referenceCallback) + .addCondition(regularCondition) + .build()); - monitor.addCallback(callback); mExecutor.runAllReady(); when(overridingCondition.isOverridingCondition()).thenReturn(true); @@ -94,7 +107,9 @@ public class ConditionMonitorTest extends SysuiTestCase { mExecutor.runAllReady(); verify(callback).onConditionsChanged(eq(true)); + verify(referenceCallback).onConditionsChanged(eq(false)); Mockito.clearInvocations(callback); + Mockito.clearInvocations(referenceCallback); when(regularCondition.isConditionMet()).thenReturn(true); when(overridingCondition.isConditionMet()).thenReturn(false); @@ -103,12 +118,7 @@ public class ConditionMonitorTest extends SysuiTestCase { mExecutor.runAllReady(); verify(callback).onConditionsChanged(eq(false)); - - clearInvocations(callback); - monitor.removeCondition(overridingCondition); - mExecutor.runAllReady(); - - verify(callback).onConditionsChanged(eq(true)); + verify(referenceCallback, never()).onConditionsChanged(anyBoolean()); } /** @@ -122,11 +132,13 @@ public class ConditionMonitorTest extends SysuiTestCase { final Condition regularCondition = Mockito.mock(Condition.class); final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class); - final Monitor monitor = new Monitor( - mExecutor, - new HashSet<>(Arrays.asList(overridingCondition, overridingCondition2, - regularCondition))); - monitor.addCallback(callback); + final Monitor monitor = new Monitor(mExecutor); + + monitor.addSubscription(getDefaultBuilder(callback) + .addCondition(overridingCondition) + .addCondition(overridingCondition2) + .build()); + mExecutor.runAllReady(); when(overridingCondition.isOverridingCondition()).thenReturn(true); @@ -151,13 +163,13 @@ public class ConditionMonitorTest extends SysuiTestCase { public void addCallback_addFirstCallback_addCallbackToAllConditions() { final Monitor.Callback callback1 = mock(Monitor.Callback.class); - mConditionMonitor.addCallback(callback1); + mConditionMonitor.addSubscription(getDefaultBuilder(callback1).build()); mExecutor.runAllReady(); mConditions.forEach(condition -> verify(condition).addCallback(any())); final Monitor.Callback callback2 = mock(Monitor.Callback.class); - mConditionMonitor.addCallback(callback2); + mConditionMonitor.addSubscription(getDefaultBuilder(callback2).build()); mExecutor.runAllReady(); mConditions.forEach(condition -> verify(condition, times(1)).addCallback(any())); } @@ -166,7 +178,7 @@ public class ConditionMonitorTest extends SysuiTestCase { public void addCallback_addFirstCallback_reportWithDefaultValue() { final Monitor.Callback callback = mock(Monitor.Callback.class); - mConditionMonitor.addCallback(callback); + mConditionMonitor.addSubscription(getDefaultBuilder(callback).build()); mExecutor.runAllReady(); verify(callback).onConditionsChanged(false); } @@ -177,66 +189,65 @@ public class ConditionMonitorTest extends SysuiTestCase { mock(Monitor.Callback.class); final Condition condition = mock(Condition.class); when(condition.isConditionMet()).thenReturn(true); - final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition))); - monitor.addCallback(callback1); + final Monitor monitor = new Monitor(mExecutor); + monitor.addSubscription(new Monitor.Subscription.Builder(callback1) + .addCondition(condition) + .build()); final Monitor.Callback callback2 = mock(Monitor.Callback.class); - monitor.addCallback(callback2); + monitor.addSubscription(new Monitor.Subscription.Builder(callback2) + .addCondition(condition) + .build()); mExecutor.runAllReady(); verify(callback2).onConditionsChanged(eq(true)); } @Test public void addCallback_noConditions_reportAllConditionsMet() { - final Monitor monitor = new Monitor(mExecutor, new HashSet<>()); + final Monitor monitor = new Monitor(mExecutor); final Monitor.Callback callback = mock(Monitor.Callback.class); - monitor.addCallback(callback); + monitor.addSubscription(new Monitor.Subscription.Builder(callback).build()); mExecutor.runAllReady(); verify(callback).onConditionsChanged(true); } @Test - public void addCallback_withMultipleInstancesOfTheSameCallback_registerOnlyOne() { - final Monitor monitor = new Monitor(mExecutor, new HashSet<>()); - final Monitor.Callback callback = mock(Monitor.Callback.class); - - // Adds the same instance multiple times. - monitor.addCallback(callback); - monitor.addCallback(callback); - monitor.addCallback(callback); + public void removeCallback_noFailureOnDoubleRemove() { + final Condition condition = mock(Condition.class); + final Monitor monitor = new Monitor(mExecutor); + final Monitor.Callback callback = + mock(Monitor.Callback.class); + final Monitor.Subscription.Token token = monitor.addSubscription( + new Monitor.Subscription.Builder(callback).addCondition(condition).build() + ); + monitor.removeSubscription(token); + mExecutor.runAllReady(); + // Ensure second removal doesn't cause an exception. + monitor.removeSubscription(token); mExecutor.runAllReady(); - - // Callback should only be triggered once. - verify(callback, times(1)).onConditionsChanged(true); } @Test public void removeCallback_shouldNoLongerReceiveUpdate() { final Condition condition = mock(Condition.class); - final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition))); + final Monitor monitor = new Monitor(mExecutor); final Monitor.Callback callback = mock(Monitor.Callback.class); - monitor.addCallback(callback); - monitor.removeCallback(callback); + final Monitor.Subscription.Token token = monitor.addSubscription( + new Monitor.Subscription.Builder(callback).addCondition(condition).build() + ); + monitor.removeSubscription(token); mExecutor.runAllReady(); clearInvocations(callback); final ArgumentCaptor<Condition.Callback> conditionCallbackCaptor = ArgumentCaptor.forClass(Condition.Callback.class); verify(condition).addCallback(conditionCallbackCaptor.capture()); - final Condition.Callback conditionCallback = conditionCallbackCaptor.getValue(); - - when(condition.isConditionMet()).thenReturn(true); - conditionCallback.onConditionChanged(condition); - mExecutor.runAllReady(); - verify(callback, never()).onConditionsChanged(true); - when(condition.isConditionMet()).thenReturn(false); - conditionCallback.onConditionChanged(condition); - mExecutor.runAllReady(); - verify(callback, never()).onConditionsChanged(false); + final Condition.Callback conditionCallback = conditionCallbackCaptor.getValue(); + verify(condition).removeCallback(conditionCallback); } @Test @@ -245,14 +256,16 @@ public class ConditionMonitorTest extends SysuiTestCase { mock(Monitor.Callback.class); final Monitor.Callback callback2 = mock(Monitor.Callback.class); - mConditionMonitor.addCallback(callback1); - mConditionMonitor.addCallback(callback2); + final Monitor.Subscription.Token subscription1 = + mConditionMonitor.addSubscription(getDefaultBuilder(callback1).build()); + final Monitor.Subscription.Token subscription2 = + mConditionMonitor.addSubscription(getDefaultBuilder(callback2).build()); - mConditionMonitor.removeCallback(callback1); + mConditionMonitor.removeSubscription(subscription1); mExecutor.runAllReady(); mConditions.forEach(condition -> verify(condition, never()).removeCallback(any())); - mConditionMonitor.removeCallback(callback2); + mConditionMonitor.removeSubscription(subscription2); mExecutor.runAllReady(); mConditions.forEach(condition -> verify(condition).removeCallback(any())); } @@ -261,7 +274,7 @@ public class ConditionMonitorTest extends SysuiTestCase { public void updateCallbacks_allConditionsMet_reportTrue() { final Monitor.Callback callback = mock(Monitor.Callback.class); - mConditionMonitor.addCallback(callback); + mConditionMonitor.addSubscription(getDefaultBuilder(callback).build()); clearInvocations(callback); mCondition1.fakeUpdateCondition(true); @@ -276,7 +289,7 @@ public class ConditionMonitorTest extends SysuiTestCase { public void updateCallbacks_oneConditionStoppedMeeting_reportFalse() { final Monitor.Callback callback = mock(Monitor.Callback.class); - mConditionMonitor.addCallback(callback); + mConditionMonitor.addSubscription(getDefaultBuilder(callback).build()); mCondition1.fakeUpdateCondition(true); mCondition2.fakeUpdateCondition(true); @@ -292,7 +305,7 @@ public class ConditionMonitorTest extends SysuiTestCase { public void updateCallbacks_shouldOnlyUpdateWhenValueChanges() { final Monitor.Callback callback = mock(Monitor.Callback.class); - mConditionMonitor.addCallback(callback); + mConditionMonitor.addSubscription(getDefaultBuilder(callback).build()); mExecutor.runAllReady(); verify(callback).onConditionsChanged(false); clearInvocations(callback); diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index 03e18a04c2d5..8e00ccf68fb1 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -40,6 +40,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; +import android.os.SystemProperties; +import android.os.Trace; import android.util.Slog; import android.util.SparseArray; @@ -144,15 +146,30 @@ public final class DeviceStateManagerService extends SystemService { private Set<Integer> mDeviceStatesAvailableForAppRequests; + @VisibleForTesting + interface SystemPropertySetter { + void setDebugTracingDeviceStateProperty(String value); + } + @NonNull + private final SystemPropertySetter mSystemPropertySetter; + public DeviceStateManagerService(@NonNull Context context) { this(context, DeviceStatePolicy.Provider .fromResources(context.getResources()) .instantiate(context)); } + private DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) { + this(context, policy, (value) -> { + SystemProperties.set("debug.tracing.device_state", value); + }); + } + @VisibleForTesting - DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) { + DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy, + @NonNull SystemPropertySetter systemPropertySetter) { super(context); + mSystemPropertySetter = systemPropertySetter; // We use the DisplayThread because this service indirectly drives // display (on/off) and window (position) events through its callbacks. DisplayThread displayThread = DisplayThread.get(); @@ -462,6 +479,10 @@ public final class DeviceStateManagerService extends SystemService { FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_STATE_CHANGED, newState.getIdentifier(), !mCommittedState.isPresent()); + String traceString = newState.getIdentifier() + ":" + newState.getName(); + Trace.instantForTrack( + Trace.TRACE_TAG_SYSTEM_SERVER, "DeviceStateChanged", traceString); + mSystemPropertySetter.setDebugTracingDeviceStateProperty(traceString); mCommittedState = Optional.of(newState); mPendingState = Optional.empty(); diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index cf63b69254f8..6fd88411593f 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -1057,7 +1057,17 @@ class AutomaticBrightnessController { public void recalculateSplines(boolean applyAdjustment, float[] adjustment) { mCurrentBrightnessMapper.recalculateSplines(applyAdjustment, adjustment); - updateAutoBrightness(true /*sendUpdate*/, false /*isManuallySet*/); + + // If rbc is turned on, off or there is a change in strength, we want to reset the short + // term model. Since the nits range at which brightness now operates has changed due to + // RBC/strength change, any short term model based on the previous range should be + // invalidated. + resetShortTermModel(); + + // When rbc is turned on, we want to accommodate this change in the short term model. + if (applyAdjustment) { + setScreenBrightnessByUser(getAutomaticScreenBrightness()); + } } private final class AutomaticBrightnessHandler extends Handler { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index a5bb716e67b7..d05a902c6593 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -657,12 +657,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } mIsRbcActive = mCdsi.isReduceBrightColorsActivated(); mAutomaticBrightnessController.recalculateSplines(mIsRbcActive, adjustedNits); - - // If rbc is turned on, off or there is a change in strength, we want to reset the short - // term model. Since the nits range at which brightness now operates has changed due to - // RBC/strength change, any short term model based on the previous range should be - // invalidated. - mAutomaticBrightnessController.resetShortTermModel(); } /** diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java index dd0ec948aa3a..43d62aaa120a 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java @@ -21,6 +21,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.os.AsyncTask; +import android.os.Trace; import android.os.UserHandle; import android.util.Slog; import android.webkit.UserPackage; @@ -265,10 +266,12 @@ class WebViewUpdateServiceImpl { // Either the current relro creation isn't done yet, or the new relro creatioin // hasn't kicked off yet (the last relro creation used an out-of-date WebView). webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO; - Slog.e(TAG, "Timed out waiting for relro creation, relros started " + String timeoutError = "Timed out waiting for relro creation, relros started " + mNumRelroCreationsStarted + " relros finished " + mNumRelroCreationsFinished - + " package dirty? " + mWebViewPackageDirty); + + " package dirty? " + mWebViewPackageDirty; + Slog.e(TAG, timeoutError); + Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, timeoutError); } } if (!webViewReady) Slog.w(TAG, "creating relro file timed out"); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 3f31ad503c01..53f2c7146656 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -314,6 +314,10 @@ public class AppTransition implements Dump { setAppTransitionState(APP_STATE_TIMEOUT); } + @ColorInt int getNextAppTransitionBackgroundColor() { + return mNextAppTransitionBackgroundColor; + } + HardwareBuffer getAppTransitionThumbnailHeader(WindowContainer container) { AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get( container.hashCode()); diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java index fd0631320520..7ca38b8fcc00 100644 --- a/services/core/java/com/android/server/wm/DisplayFrames.java +++ b/services/core/java/com/android/server/wm/DisplayFrames.java @@ -99,19 +99,28 @@ public class DisplayFrames { state.setRoundedCorners(roundedCorners); state.setPrivacyIndicatorBounds(indicatorBounds); state.getDisplayCutoutSafe(safe); - if (!cutout.isEmpty()) { + if (safe.left > unrestricted.left) { state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame( unrestricted.left, unrestricted.top, safe.left, unrestricted.bottom); + } else { + state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT); + } + if (safe.top > unrestricted.top) { state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame( unrestricted.left, unrestricted.top, unrestricted.right, safe.top); + } else { + state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT); + } + if (safe.right < unrestricted.right) { state.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame( safe.right, unrestricted.top, unrestricted.right, unrestricted.bottom); + } else { + state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT); + } + if (safe.bottom < unrestricted.bottom) { state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame( unrestricted.left, safe.bottom, unrestricted.right, unrestricted.bottom); } else { - state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT); - state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT); - state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT); state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT); } return true; diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 878413cb9d78..ad158c7b45b9 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -22,6 +22,7 @@ import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Point; @@ -431,6 +432,7 @@ class RemoteAnimationController implements DeathRecipient { final WindowContainer mWindowContainer; final Rect mStartBounds; final boolean mShowBackdrop; + @ColorInt int mBackdropColor = 0; private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING; RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds, @@ -456,6 +458,10 @@ class RemoteAnimationController implements DeathRecipient { } } + void setBackDropColor(@ColorInt int backdropColor) { + mBackdropColor = backdropColor; + } + RemoteAnimationTarget createRemoteAnimationTarget() { if (mAdapter == null || mAdapter.mCapturedFinishCallback == null @@ -510,6 +516,12 @@ class RemoteAnimationController implements DeathRecipient { } @Override + @ColorInt + public int getBackgroundColor() { + return mRecord.mBackdropColor; + } + + @Override public boolean getShowBackground() { return mShowBackdrop; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index fc1b89348c25..3a272859c70c 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4427,13 +4427,13 @@ class Task extends TaskFragment { : WINDOWING_MODE_FULLSCREEN; } if (currentMode == WINDOWING_MODE_PINNED) { + // In the case that we've disabled affecting the SysUI flags as a part of seamlessly + // transferring the transform on the leash to the task, reset this state once we're + // moving out of pip + setCanAffectSystemUiFlags(true); mRootWindowContainer.notifyActivityPipModeChanged(this, null); } if (likelyResolvedMode == WINDOWING_MODE_PINNED) { - // In the case that we've disabled affecting the SysUI flags as a part of seamlessly - // transferring the transform on the leash to the task, reset this state once we've - // actually entered pip - setCanAffectSystemUiFlags(true); if (taskDisplayArea.getRootPinnedTask() != null) { // Can only have 1 pip at a time, so replace an existing pip taskDisplayArea.getRootPinnedTask().dismissPip(); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index d8404a79e794..3c0cac0079e8 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -305,6 +305,16 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe return mFlags; } + @VisibleForTesting + SurfaceControl.Transaction getStartTransaction() { + return mStartTransaction; + } + + @VisibleForTesting + SurfaceControl.Transaction getFinishTransaction() { + return mFinishTransaction; + } + /** Starts collecting phase. Once this starts, all relevant surface operations are sync. */ void startCollecting(long timeoutMs) { if (mState != STATE_PENDING) { @@ -771,6 +781,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } mState = STATE_PLAYING; + mStartTransaction = transaction; + mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get(); mController.moveToPlaying(this); if (dc.isKeyguardLocked()) { @@ -856,8 +868,6 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (controller != null && mTargets.contains(dc)) { controller.setupStartTransaction(transaction); } - mStartTransaction = transaction; - mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get(); buildFinishTransaction(mFinishTransaction, info.getRootLeash()); if (mController.getTransitionPlayer() != null) { mController.dispatchLegacyAppTransitionStarting(info); diff --git a/services/core/java/com/android/server/wm/TransitionTracer.java b/services/core/java/com/android/server/wm/TransitionTracer.java index 192b9abc62a7..b1951e038177 100644 --- a/services/core/java/com/android/server/wm/TransitionTracer.java +++ b/services/core/java/com/android/server/wm/TransitionTracer.java @@ -23,8 +23,10 @@ import static com.android.server.wm.shell.ChangeInfo.HAS_CHANGED; import static com.android.server.wm.shell.ChangeInfo.TRANSIT_MODE; import static com.android.server.wm.shell.ChangeInfo.WINDOW_IDENTIFIER; import static com.android.server.wm.shell.Transition.CHANGE; +import static com.android.server.wm.shell.Transition.FINISH_TRANSACTION_ID; import static com.android.server.wm.shell.Transition.FLAGS; import static com.android.server.wm.shell.Transition.ID; +import static com.android.server.wm.shell.Transition.START_TRANSACTION_ID; import static com.android.server.wm.shell.Transition.STATE; import static com.android.server.wm.shell.Transition.TIMESTAMP; import static com.android.server.wm.shell.Transition.TRANSITION_TYPE; @@ -82,6 +84,13 @@ public class TransitionTracer { outputStream.write(TRANSITION_TYPE, transition.mType); outputStream.write(STATE, transition.getState()); outputStream.write(FLAGS, transition.getFlags()); + if (transition.getStartTransaction() != null) { + outputStream.write(START_TRANSACTION_ID, transition.getStartTransaction().getId()); + } + if (transition.getFinishTransaction() != null) { + outputStream.write(FINISH_TRANSACTION_ID, + transition.getFinishTransaction().getId()); + } for (int i = 0; i < transition.mChanges.size(); ++i) { final WindowContainer window = transition.mChanges.keyAt(i); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index cfc4db969a6f..59aed833f3f3 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2949,11 +2949,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) { // Here we load App XML in order to read com.android.R.styleable#Animation_showBackdrop. boolean showBackdrop = false; + // Optionally set backdrop color if App explicitly provides it through + // {@link Activity#overridePendingTransition(int, int, int)}. + @ColorInt int backdropColor = 0; if (controller.isFromActivityEmbedding()) { final int animAttr = AppTransition.mapOpenCloseTransitTypes(transit, enter); final Animation a = animAttr != 0 ? appTransition.loadAnimationAttr(lp, animAttr, transit) : null; showBackdrop = a != null && a.getShowBackdrop(); + backdropColor = appTransition.getNextAppTransitionBackgroundColor(); } final Rect localBounds = new Rect(mTmpRect); localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y); @@ -2961,6 +2965,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< controller.createRemoteAnimationRecord( this, mTmpPoint, localBounds, screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null), showBackdrop); + if (backdropColor != 0) { + adapters.setBackDropColor(backdropColor); + } if (!isChanging) { adapters.setMode(enter ? RemoteAnimationTarget.MODE_OPENING diff --git a/services/proguard.flags b/services/proguard.flags index bad02b47031c..c648f7d3ac45 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -68,6 +68,9 @@ # TODO(b/210510433): Revisit and consider generating from frameworks/base/core/res/res/values/config.xml. -keep,allowoptimization,allowaccessmodification public class com.android.server.notification.** implements com.android.server.notification.NotificationSignalExtractor +# OEM provided DisplayAreaPolicy.Provider defined in frameworks/base/core/res/res/values/config.xml. +-keep,allowoptimization,allowaccessmodification class com.android.server.wm.** implements com.android.server.wm.DisplayAreaPolicy$Provider + # JNI keep rules # TODO(b/210510433): Revisit and fix with @Keep, or consider auto-generating from # frameworks/base/services/core/jni/onload.cpp. diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java index fe3034dc569d..038cbc032375 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java @@ -76,12 +76,15 @@ public final class DeviceStateManagerServiceTest { private TestDeviceStatePolicy mPolicy; private TestDeviceStateProvider mProvider; private DeviceStateManagerService mService; + private TestSystemPropertySetter mSysPropSetter; @Before public void setup() { mProvider = new TestDeviceStateProvider(); mPolicy = new TestDeviceStatePolicy(mProvider); - mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy); + mSysPropSetter = new TestSystemPropertySetter(); + mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy, + mSysPropSetter); // Necessary to allow us to check for top app process id in tests mService.mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); @@ -107,6 +110,8 @@ public final class DeviceStateManagerServiceTest { public void baseStateChanged() { assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -115,6 +120,8 @@ public final class DeviceStateManagerServiceTest { flushHandler(); assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -128,6 +135,8 @@ public final class DeviceStateManagerServiceTest { flushHandler(); assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -136,6 +145,8 @@ public final class DeviceStateManagerServiceTest { flushHandler(); assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -157,6 +168,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -170,6 +183,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -182,6 +197,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE); @@ -193,6 +210,8 @@ public final class DeviceStateManagerServiceTest { // supported. assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE); @@ -211,6 +230,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE); @@ -223,6 +244,8 @@ public final class DeviceStateManagerServiceTest { // supported. assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE); @@ -315,6 +338,8 @@ public final class DeviceStateManagerServiceTest { TestDeviceStateManagerCallback.STATUS_ACTIVE); // Committed state changes as there is a requested override. assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), @@ -333,6 +358,8 @@ public final class DeviceStateManagerServiceTest { TestDeviceStateManagerCallback.STATUS_CANCELED); // Committed state is set back to the requested state once the override is cleared. assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertFalse(mService.getOverrideState().isPresent()); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), @@ -385,9 +412,10 @@ public final class DeviceStateManagerServiceTest { // callback. assertEquals(callback.getLastNotifiedStatus(secondRequestToken), TestDeviceStateManagerCallback.STATUS_UNKNOWN); - assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -397,6 +425,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -412,6 +442,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -458,6 +490,8 @@ public final class DeviceStateManagerServiceTest { // Committed state changes as there is a requested override. assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName()); assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -471,6 +505,8 @@ public final class DeviceStateManagerServiceTest { // Committed state is set back to the requested state once the override is cleared. assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName()); assertFalse(mService.getOverrideState().isPresent()); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -495,6 +531,8 @@ public final class DeviceStateManagerServiceTest { TestDeviceStateManagerCallback.STATUS_ACTIVE); // Committed state changes as there is a requested override. assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), @@ -509,6 +547,8 @@ public final class DeviceStateManagerServiceTest { // Committed state is set back to the requested state as the override state is no longer // supported. assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mSysPropSetter.getValue(), + DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName()); assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertFalse(mService.getOverrideState().isPresent()); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), @@ -673,4 +713,18 @@ public final class DeviceStateManagerServiceTest { return mLastNotifiedStatus.getOrDefault(requestToken, STATUS_UNKNOWN); } } + + private static final class TestSystemPropertySetter implements + DeviceStateManagerService.SystemPropertySetter { + private String mValue; + + @Override + public void setDebugTracingDeviceStateProperty(String value) { + mValue = value; + } + + public String getValue() { + return mValue; + } + } } diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java index b0c52f1fdbb8..9d82f1a90c77 100644 --- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyFloat; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -258,29 +259,36 @@ public class AutomaticBrightnessControllerTest { @Test public void testRecalculateSplines() throws Exception { // Enabling the light sensor, and setting the ambient lux to 1000 + int currentLux = 1000; ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); SensorEventListener listener = listenerCaptor.getValue(); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, currentLux)); - //Setting the brightnessFloat to 0.5f - float currentBrightnessFloat = 0.5f; - when(mBrightnessMappingStrategy.getBrightness(1000, - null, ApplicationInfo.CATEGORY_UNDEFINED)).thenReturn(currentBrightnessFloat); + // User sets brightness to 0.5f + when(mBrightnessMappingStrategy.getBrightness(currentLux, + null, ApplicationInfo.CATEGORY_UNDEFINED)).thenReturn(0.5f); mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */, - currentBrightnessFloat /* brightness */, false /* userChangedBrightness */, - 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT); + 0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */, + false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT); - // Adjusting spline, and accordingly remapping the current 0.5f brightnessFloat to 0.3f - float updatedBrightnessFloat = 0.3f; - when(mBrightnessMappingStrategy.getBrightness(1000, - null, ApplicationInfo.CATEGORY_UNDEFINED)).thenReturn(updatedBrightnessFloat); - float[] adjustments = new float[]{0.2f, 0.5f}; + //Recalculating the spline with RBC enabled, verifying that the short term model is reset, + //and the interaction is learnt in short term model + float[] adjustments = new float[]{0.2f, 0.6f}; mController.recalculateSplines(true, adjustments); + verify(mBrightnessMappingStrategy).clearUserDataPoints(); verify(mBrightnessMappingStrategy).recalculateSplines(true, adjustments); - assertEquals(mController.getAutomaticScreenBrightness(), updatedBrightnessFloat, EPSILON); + verify(mBrightnessMappingStrategy, times(2)).addUserDataPoint(currentLux, 0.5f); + + clearInvocations(mBrightnessMappingStrategy); + + // Verify short term model is not learnt when RBC is disabled + mController.recalculateSplines(false, adjustments); + verify(mBrightnessMappingStrategy).clearUserDataPoints(); + verify(mBrightnessMappingStrategy).recalculateSplines(false, adjustments); + verifyNoMoreInteractions(mBrightnessMappingStrategy); } @Test |