From 3582d26e2aee4f4b43238864ff5f41bf8e9c7fb9 Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Fri, 23 Jul 2021 15:43:22 -0700 Subject: [PATCH 01/12] Early exit if the target region is empty Bug: 193849901 Test: atest StaticLayoutBidiTouchTest Change-Id: I55f04068a6e5b353867d50742356c272d28886b3 --- core/java/android/text/TextLine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 1f11d10052fee..1a7ec7f99c954 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -782,7 +782,7 @@ public class TextLine { int spanStart = runStart; int spanLimit; - if (mSpanned == null) { + if (mSpanned == null || runStart == runLimit) { spanLimit = runLimit; } else { int target = after ? offset + 1 : offset; From b696fd0bcfb962ff76a288f1417f11d9ed88e0a0 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Tue, 7 Sep 2021 19:55:59 +0200 Subject: [PATCH 02/12] Protect LE Audio Broadcasts Test: compilation Bug: 196858567 Bug: 196858999 Change-Id: I5208554b4e39306810da6df718e5365a5a03e755 --- core/res/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index bad79eb137492..e6462413201c2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -247,6 +247,8 @@ android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" /> + + From 42e8c45e8c48530d7d0b4624add65c72b9961485 Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Fri, 17 Sep 2021 16:32:58 -0400 Subject: [PATCH 03/12] Do not show the notification footer until the user is set up. Bug: 193149550 Test: follow repro steps Merged-In: I49e2b8bcec7b2ce0a9776ff30a64c07f24949da7 Change-Id: I49e2b8bcec7b2ce0a9776ff30a64c07f24949da7 --- .../stack/NotificationStackScrollLayout.java | 39 +++++++++++++++++++ .../NotificationStackScrollLayoutTest.java | 33 ++++++++++++++-- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index a4a58194a46b0..6986ad754596b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -157,6 +157,8 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.ScrollAdapter; import com.android.systemui.statusbar.policy.ZenModeController; @@ -300,6 +302,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean mExpandedInThisMotion; private boolean mShouldShowShelfOnly; protected boolean mScrollingEnabled; + private boolean mIsCurrentUserSetup; protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; private boolean mDismissAllInProgress; @@ -508,6 +511,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private final NotifPipeline mNotifPipeline; private final NotifCollection mNotifCollection; private final NotificationEntryManager mEntryManager; + private final DeviceProvisionedController mDeviceProvisionedController = + Dependency.get(DeviceProvisionedController.class); private final IStatusBarService mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); @VisibleForTesting @@ -648,6 +653,29 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd }, HIGH_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL, Settings.Secure.NOTIFICATION_HISTORY_ENABLED); + mDeviceProvisionedController.addCallback( + new DeviceProvisionedListener() { + @Override + public void onDeviceProvisionedChanged() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSwitched() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSetupChanged() { + updateCurrentUserIsSetup(); + } + + private void updateCurrentUserIsSetup() { + setCurrentUserSetup(mDeviceProvisionedController.isCurrentUserSetup()); + } + }); + + mFeatureFlags = featureFlags; mNotifPipeline = notifPipeline; mEntryManager = entryManager; @@ -772,6 +800,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL); boolean showFooterView = (showDismissView || hasActiveNotifications()) + && mIsCurrentUserSetup // see: b/193149550 && mStatusBarState != StatusBarState.KEYGUARD && !mRemoteInputManager.getController().isRemoteInputActive(); boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(), @@ -5923,6 +5952,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return MathUtils.smoothStep(0, totalDistance, dragDownAmount); } + /** + * Sets whether the current user is set up, which is required to show the footer (b/193149550) + */ + public void setCurrentUserSetup(boolean isCurrentUserSetup) { + if (mIsCurrentUserSetup != isCurrentUserSetup) { + mIsCurrentUserSetup = isCurrentUserSetup; + updateFooter(); + } + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 2ae4caeca9633..710a6c84a63ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -110,8 +110,6 @@ import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; -import dagger.Lazy; - /** * Tests for {@link NotificationStackScrollLayout}. */ @@ -143,7 +141,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationSection mNotificationSection; @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private FeatureFlags mFeatureFlags; - @Mock private Lazy mBubbleControllerLazy; + @Mock private BubbleController mBubbleController; private UserChangedListener mUserChangedListener; private NotificationEntryManager mEntryManager; private int mOriginalInterruptionModelSetting; @@ -194,7 +192,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { () -> mock(NotificationRowBinder.class), () -> mRemoteInputManager, mock(LeakDetector.class), - mBubbleControllerLazy, + () -> mBubbleController, mock(ForegroundServiceDismissalFeatureController.class) ); mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class)); @@ -354,6 +352,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_noNotifications() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); assertEquals(0, mEntryManager.getActiveNotificationsCount()); FooterView view = mock(FooterView.class); @@ -365,6 +364,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_remoteInput() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); + ArrayList entries = new ArrayList<>(); entries.add(new NotificationEntryBuilder().build()); addEntriesToEntryManager(entries); @@ -384,6 +385,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ArrayList entries = new ArrayList<>(); entries.add(new NotificationEntryBuilder().build()); @@ -400,9 +402,30 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mStackScroller).updateFooterView(true, true, true); } + @Test + public void testUpdateFooter_oneClearableNotification_beforeUserSetup() { + setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(false); + + ArrayList entries = new ArrayList<>(); + entries.add(new NotificationEntryBuilder().build()); + addEntriesToEntryManager(entries); + + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + when(row.canViewBeDismissed()).thenReturn(true); + when(mStackScroller.getChildCount()).thenReturn(1); + when(mStackScroller.getChildAt(anyInt())).thenReturn(row); + + FooterView view = mock(FooterView.class); + mStackScroller.setFooterView(view); + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(false, true, true); + } + @Test public void testUpdateFooter_oneNonClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ArrayList entries = new ArrayList<>(); entries.add(new NotificationEntryBuilder().build()); @@ -416,6 +439,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_atEnd() { + mStackScroller.setCurrentUserSetup(true); + // add footer mStackScroller.inflateFooterView(); From 73c3c0a7d649b725da0459cc55c6418e0f2ba175 Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Fri, 17 Sep 2021 16:32:58 -0400 Subject: [PATCH 04/12] Do not show the notification footer until the user is set up. Bug: 193149550 Test: follow repro steps Merged-In: I49e2b8bcec7b2ce0a9776ff30a64c07f24949da7 Change-Id: I49e2b8bcec7b2ce0a9776ff30a64c07f24949da7 --- .../stack/NotificationStackScrollLayout.java | 39 +++++++++++++++++++ .../NotificationStackScrollLayoutTest.java | 27 +++++++++++++ 2 files changed, 66 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index b9d31a93f408a..9ce31a129afe8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -157,6 +157,8 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.ScrollAdapter; import com.android.systemui.statusbar.policy.ZenModeController; @@ -300,6 +302,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean mExpandedInThisMotion; private boolean mShouldShowShelfOnly; protected boolean mScrollingEnabled; + private boolean mIsCurrentUserSetup; protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; private boolean mDismissAllInProgress; @@ -508,6 +511,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private final NotifPipeline mNotifPipeline; private final NotifCollection mNotifCollection; private final NotificationEntryManager mEntryManager; + private final DeviceProvisionedController mDeviceProvisionedController = + Dependency.get(DeviceProvisionedController.class); private final IStatusBarService mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); @VisibleForTesting @@ -648,6 +653,29 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd }, HIGH_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL, Settings.Secure.NOTIFICATION_HISTORY_ENABLED); + mDeviceProvisionedController.addCallback( + new DeviceProvisionedListener() { + @Override + public void onDeviceProvisionedChanged() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSwitched() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSetupChanged() { + updateCurrentUserIsSetup(); + } + + private void updateCurrentUserIsSetup() { + setCurrentUserSetup(mDeviceProvisionedController.isCurrentUserSetup()); + } + }); + + mFeatureFlags = featureFlags; mNotifPipeline = notifPipeline; mEntryManager = entryManager; @@ -772,6 +800,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL); boolean showFooterView = (showDismissView || hasActiveNotifications()) + && mIsCurrentUserSetup // see: b/193149550 && mStatusBarState != StatusBarState.KEYGUARD && !mRemoteInputManager.getController().isRemoteInputActive(); boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(), @@ -5923,6 +5952,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return MathUtils.smoothStep(0, totalDistance, dragDownAmount); } + /** + * Sets whether the current user is set up, which is required to show the footer (b/193149550) + */ + public void setCurrentUserSetup(boolean isCurrentUserSetup) { + if (mIsCurrentUserSetup != isCurrentUserSetup) { + mIsCurrentUserSetup = isCurrentUserSetup; + updateFooter(); + } + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index b286f9486e13c..796793d216f73 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -349,6 +349,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_noNotifications() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); assertEquals(0, mEntryManager.getActiveNotificationsCount()); FooterView view = mock(FooterView.class); @@ -360,6 +361,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_remoteInput() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); + ArrayList entries = new ArrayList<>(); entries.add(new NotificationEntryBuilder().build()); addEntriesToEntryManager(entries); @@ -379,6 +382,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ArrayList entries = new ArrayList<>(); entries.add(new NotificationEntryBuilder().build()); @@ -395,9 +399,30 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mStackScroller).updateFooterView(true, true, true); } + @Test + public void testUpdateFooter_oneClearableNotification_beforeUserSetup() { + setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(false); + + ArrayList entries = new ArrayList<>(); + entries.add(new NotificationEntryBuilder().build()); + addEntriesToEntryManager(entries); + + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + when(row.canViewBeDismissed()).thenReturn(true); + when(mStackScroller.getChildCount()).thenReturn(1); + when(mStackScroller.getChildAt(anyInt())).thenReturn(row); + + FooterView view = mock(FooterView.class); + mStackScroller.setFooterView(view); + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(false, true, true); + } + @Test public void testUpdateFooter_oneNonClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ArrayList entries = new ArrayList<>(); entries.add(new NotificationEntryBuilder().build()); @@ -411,6 +436,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_atEnd() { + mStackScroller.setCurrentUserSetup(true); + // add footer mStackScroller.inflateFooterView(); From 33b92965da7608bf78037b1ddf23468211c2d176 Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Fri, 17 Sep 2021 16:32:58 -0400 Subject: [PATCH 05/12] Do not show the notification footer until the user is set up. Bug: 193149550 Test: follow repro steps Change-Id: I49e2b8bcec7b2ce0a9776ff30a64c07f24949da7 --- .../stack/NotificationStackScrollLayout.java | 12 ++++++++ ...tificationStackScrollLayoutController.java | 30 +++++++++++++++++++ .../NotificationStackScrollLayoutTest.java | 23 ++++++++++++++ ...tificationStackScrollerControllerTest.java | 3 ++ 4 files changed, 68 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index a771274e34331..f121b585a2234 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -260,6 +260,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private boolean mExpandedInThisMotion; private boolean mShouldShowShelfOnly; protected boolean mScrollingEnabled; + private boolean mIsCurrentUserSetup; protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; private boolean mDismissAllInProgress; @@ -686,6 +687,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mController.hasActiveClearableNotifications(ROWS_ALL); RemoteInputController remoteInputController = mRemoteInputManager.getController(); boolean showFooterView = (showDismissView || getVisibleNotificationCount() > 0) + && mIsCurrentUserSetup // see: b/193149550 && mStatusBarState != StatusBarState.KEYGUARD && !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying() && (remoteInputController == null || !remoteInputController.isRemoteInputActive()); @@ -5597,6 +5599,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mAnimateNextTopPaddingChange = true; } + /** + * Sets whether the current user is set up, which is required to show the footer (b/193149550) + */ + public void setCurrentUserSetup(boolean isCurrentUserSetup) { + if (mIsCurrentUserSetup != isCurrentUserSetup) { + mIsCurrentUserSetup = isCurrentUserSetup; + updateFooter(); + } + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index faba48f82cb3b..1773416f40ff9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -117,6 +117,8 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; @@ -144,6 +146,7 @@ public class NotificationStackScrollLayoutController { private final HeadsUpManagerPhone mHeadsUpManager; private final NotificationRoundnessManager mNotificationRoundnessManager; private final TunerService mTunerService; + private final DeviceProvisionedController mDeviceProvisionedController; private final DynamicPrivacyController mDynamicPrivacyController; private final ConfigurationController mConfigurationController; private final ZenModeController mZenModeController; @@ -218,6 +221,28 @@ public class NotificationStackScrollLayoutController { } }; + private final DeviceProvisionedListener mDeviceProvisionedListener = + new DeviceProvisionedListener() { + @Override + public void onDeviceProvisionedChanged() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSwitched() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSetupChanged() { + updateCurrentUserIsSetup(); + } + + private void updateCurrentUserIsSetup() { + mView.setCurrentUserSetup(mDeviceProvisionedController.isCurrentUserSetup()); + } + }; + private final DynamicPrivacyController.Listener mDynamicPrivacyControllerListener = () -> { if (mView.isExpanded()) { // The bottom might change because we're using the final actual height of the view @@ -587,6 +612,7 @@ public class NotificationStackScrollLayoutController { HeadsUpManagerPhone headsUpManager, NotificationRoundnessManager notificationRoundnessManager, TunerService tunerService, + DeviceProvisionedController deviceProvisionedController, DynamicPrivacyController dynamicPrivacyController, ConfigurationController configurationController, SysuiStatusBarStateController statusBarStateController, @@ -623,6 +649,7 @@ public class NotificationStackScrollLayoutController { mHeadsUpManager = headsUpManager; mNotificationRoundnessManager = notificationRoundnessManager; mTunerService = tunerService; + mDeviceProvisionedController = deviceProvisionedController; mDynamicPrivacyController = dynamicPrivacyController; mConfigurationController = configurationController; mStatusBarStateController = statusBarStateController; @@ -759,6 +786,9 @@ public class NotificationStackScrollLayoutController { return Unit.INSTANCE; }); + // callback is invoked synchronously, updating mView immediately + mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); + if (mView.isAttachedToWindow()) { mOnAttachStateChangeListener.onViewAttachedToWindow(mView); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index b03df880f0baa..4151ab2044f4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -290,6 +290,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_noNotifications() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); + FooterView view = mock(FooterView.class); mStackScroller.setFooterView(view); mStackScroller.updateFooter(); @@ -299,6 +301,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_remoteInput() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); when(row.canViewBeDismissed()).thenReturn(true); @@ -318,6 +321,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); when(mEmptyShadeView.getVisibility()).thenReturn(GONE); when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL)) @@ -330,9 +334,26 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mStackScroller).updateFooterView(true, true, true); } + @Test + public void testUpdateFooter_oneClearableNotification_beforeUserSetup() { + setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(false); + + when(mEmptyShadeView.getVisibility()).thenReturn(GONE); + when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL)) + .thenReturn(true); + when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true); + + FooterView view = mock(FooterView.class); + mStackScroller.setFooterView(view); + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(false, true, true); + } + @Test public void testUpdateFooter_oneNonClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); when(row.canViewBeDismissed()).thenReturn(false); @@ -351,6 +372,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_atEnd() { + mStackScroller.setCurrentUserSetup(true); + // add footer mStackScroller.inflateFooterView(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java index f376e88b2cb12..42f38891b1bbd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java @@ -74,6 +74,7 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; @@ -98,6 +99,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; @Mock private TunerService mTunerService; + @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private DynamicPrivacyController mDynamicPrivacyController; @Mock private ConfigurationController mConfigurationController; @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; @@ -153,6 +155,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { mHeadsUpManager, mNotificationRoundnessManager, mTunerService, + mDeviceProvisionedController, mDynamicPrivacyController, mConfigurationController, mSysuiStatusBarStateController, From e4d9de5961d9ec2fa9dc7103e4eb652e60d624c3 Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Fri, 17 Sep 2021 16:32:58 -0400 Subject: [PATCH 06/12] Do not show the notification footer until the user is set up. Bug: 193149550 Test: follow repro steps Merged-In: I49e2b8bcec7b2ce0a9776ff30a64c07f24949da7 Change-Id: I49e2b8bcec7b2ce0a9776ff30a64c07f24949da7 --- .../stack/NotificationStackScrollLayout.java | 12 ++++++++ ...tificationStackScrollLayoutController.java | 30 +++++++++++++++++++ .../NotificationStackScrollLayoutTest.java | 23 ++++++++++++++ ...tificationStackScrollerControllerTest.java | 3 ++ 4 files changed, 68 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 0660daab3720c..ae852053f0c55 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -256,6 +256,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private boolean mExpandedInThisMotion; private boolean mShouldShowShelfOnly; protected boolean mScrollingEnabled; + private boolean mIsCurrentUserSetup; protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; private boolean mDismissAllInProgress; @@ -683,6 +684,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mController.hasActiveClearableNotifications(ROWS_ALL); RemoteInputController remoteInputController = mRemoteInputManager.getController(); boolean showFooterView = (showDismissView || getVisibleNotificationCount() > 0) + && mIsCurrentUserSetup // see: b/193149550 && mStatusBarState != StatusBarState.KEYGUARD && !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying() && (remoteInputController == null || !remoteInputController.isRemoteInputActive()); @@ -5566,6 +5568,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mAnimateNextTopPaddingChange = true; } + /** + * Sets whether the current user is set up, which is required to show the footer (b/193149550) + */ + public void setCurrentUserSetup(boolean isCurrentUserSetup) { + if (mIsCurrentUserSetup != isCurrentUserSetup) { + mIsCurrentUserSetup = isCurrentUserSetup; + updateFooter(); + } + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 9e4adce47e0c2..3ceb655b1c0c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -117,6 +117,8 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; @@ -144,6 +146,7 @@ public class NotificationStackScrollLayoutController { private final HeadsUpManagerPhone mHeadsUpManager; private final NotificationRoundnessManager mNotificationRoundnessManager; private final TunerService mTunerService; + private final DeviceProvisionedController mDeviceProvisionedController; private final DynamicPrivacyController mDynamicPrivacyController; private final ConfigurationController mConfigurationController; private final ZenModeController mZenModeController; @@ -218,6 +221,28 @@ public class NotificationStackScrollLayoutController { } }; + private final DeviceProvisionedListener mDeviceProvisionedListener = + new DeviceProvisionedListener() { + @Override + public void onDeviceProvisionedChanged() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSwitched() { + updateCurrentUserIsSetup(); + } + + @Override + public void onUserSetupChanged() { + updateCurrentUserIsSetup(); + } + + private void updateCurrentUserIsSetup() { + mView.setCurrentUserSetup(mDeviceProvisionedController.isCurrentUserSetup()); + } + }; + private final DynamicPrivacyController.Listener mDynamicPrivacyControllerListener = () -> { if (mView.isExpanded()) { // The bottom might change because we're using the final actual height of the view @@ -587,6 +612,7 @@ public class NotificationStackScrollLayoutController { HeadsUpManagerPhone headsUpManager, NotificationRoundnessManager notificationRoundnessManager, TunerService tunerService, + DeviceProvisionedController deviceProvisionedController, DynamicPrivacyController dynamicPrivacyController, ConfigurationController configurationController, SysuiStatusBarStateController statusBarStateController, @@ -623,6 +649,7 @@ public class NotificationStackScrollLayoutController { mHeadsUpManager = headsUpManager; mNotificationRoundnessManager = notificationRoundnessManager; mTunerService = tunerService; + mDeviceProvisionedController = deviceProvisionedController; mDynamicPrivacyController = dynamicPrivacyController; mConfigurationController = configurationController; mStatusBarStateController = statusBarStateController; @@ -759,6 +786,9 @@ public class NotificationStackScrollLayoutController { return Unit.INSTANCE; }); + // callback is invoked synchronously, updating mView immediately + mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); + if (mView.isAttachedToWindow()) { mOnAttachStateChangeListener.onViewAttachedToWindow(mView); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index b03df880f0baa..4151ab2044f4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -290,6 +290,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_noNotifications() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); + FooterView view = mock(FooterView.class); mStackScroller.setFooterView(view); mStackScroller.updateFooter(); @@ -299,6 +301,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_remoteInput() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); when(row.canViewBeDismissed()).thenReturn(true); @@ -318,6 +321,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); when(mEmptyShadeView.getVisibility()).thenReturn(GONE); when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL)) @@ -330,9 +334,26 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mStackScroller).updateFooterView(true, true, true); } + @Test + public void testUpdateFooter_oneClearableNotification_beforeUserSetup() { + setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(false); + + when(mEmptyShadeView.getVisibility()).thenReturn(GONE); + when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL)) + .thenReturn(true); + when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true); + + FooterView view = mock(FooterView.class); + mStackScroller.setFooterView(view); + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(false, true, true); + } + @Test public void testUpdateFooter_oneNonClearableNotification() { setBarStateForTest(StatusBarState.SHADE); + mStackScroller.setCurrentUserSetup(true); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); when(row.canViewBeDismissed()).thenReturn(false); @@ -351,6 +372,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_atEnd() { + mStackScroller.setCurrentUserSetup(true); + // add footer mStackScroller.inflateFooterView(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java index f376e88b2cb12..42f38891b1bbd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java @@ -74,6 +74,7 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; @@ -98,6 +99,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; @Mock private TunerService mTunerService; + @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private DynamicPrivacyController mDynamicPrivacyController; @Mock private ConfigurationController mConfigurationController; @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; @@ -153,6 +155,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { mHeadsUpManager, mNotificationRoundnessManager, mTunerService, + mDeviceProvisionedController, mDynamicPrivacyController, mConfigurationController, mSysuiStatusBarStateController, From a49b90befed61e22f382ce320df13cb6cc3031ed Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Fri, 17 Sep 2021 15:29:49 -0700 Subject: [PATCH 07/12] Change DisplayModeDirector's brightness source to DisplayListener Currently, DisplayModeDirector listens to brightness changes from Settings. However, brightness value in Settings is overridden for various reasons inside DisplayPowerController before being propagated to HALs. As a result, the brightness value that DisplayModeDirector is acting on isn't always the brightness value that gets applied to the display. This change, - Changes DisplayPowerController so that the final brightness value (after all modifications) is saved. - Changes DisplayModeDirector to use DisplayManager.DisplayListener to observe brightness changes and then retrieve and act on the final brightness value saved in DisplayPowerController. Bug: 199955532 Test: atest DisplayModeDirectorTest Change-Id: Ia6dd7d194b6913d2942bea9c29a2011b8058beef --- .../hardware/display/BrightnessInfo.java | 11 +++ .../server/display/DisplayModeDirector.java | 91 ++++++++----------- .../display/DisplayPowerController.java | 26 +++++- .../display/DisplayModeDirectorTest.java | 79 ++++++++-------- 4 files changed, 114 insertions(+), 93 deletions(-) diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java index c5d37c2d0b906..6a2b900eea591 100644 --- a/core/java/android/hardware/display/BrightnessInfo.java +++ b/core/java/android/hardware/display/BrightnessInfo.java @@ -60,6 +60,9 @@ public final class BrightnessInfo implements Parcelable { /** Brightness */ public final float brightness; + /** Brightness after {@link DisplayPowerController} adjustments */ + public final float adjustedBrightness; + /** Current minimum supported brightness. */ public final float brightnessMinimum; @@ -74,7 +77,13 @@ public final class BrightnessInfo implements Parcelable { public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum, @HighBrightnessMode int highBrightnessMode) { + this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode); + } + + public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum, + float brightnessMaximum, @HighBrightnessMode int highBrightnessMode) { this.brightness = brightness; + this.adjustedBrightness = adjustedBrightness; this.brightnessMinimum = brightnessMinimum; this.brightnessMaximum = brightnessMaximum; this.highBrightnessMode = highBrightnessMode; @@ -103,6 +112,7 @@ public final class BrightnessInfo implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeFloat(brightness); + dest.writeFloat(adjustedBrightness); dest.writeFloat(brightnessMinimum); dest.writeFloat(brightnessMaximum); dest.writeInt(highBrightnessMode); @@ -123,6 +133,7 @@ public final class BrightnessInfo implements Parcelable { private BrightnessInfo(Parcel source) { brightness = source.readFloat(); + adjustedBrightness = source.readFloat(); brightnessMinimum = source.readFloat(); brightnessMaximum = source.readFloat(); highBrightnessMode = source.readInt(); diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 5fc301e60b9d7..ee6df426c82d8 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -17,6 +17,7 @@ package com.android.server.display; import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE; +import static android.os.PowerManager.BRIGHTNESS_INVALID; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,6 +41,7 @@ import android.os.IThermalEventListener; import android.os.IThermalService; import android.os.Looper; import android.os.Message; +import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -60,6 +62,7 @@ import android.view.DisplayInfo; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; import com.android.server.display.utils.AmbientFilter; @@ -155,7 +158,7 @@ public class DisplayModeDirector { mAppRequestObserver = new AppRequestObserver(); mSettingsObserver = new SettingsObserver(context, handler); mDisplayObserver = new DisplayObserver(context, handler); - mBrightnessObserver = new BrightnessObserver(context, handler); + mBrightnessObserver = new BrightnessObserver(context, handler, injector); mUdfpsObserver = new UdfpsObserver(); final BallotBox ballotBox = (displayId, priority, vote) -> { synchronized (mLock) { @@ -1427,8 +1430,6 @@ public class DisplayModeDirector { @Override public void onDisplayChanged(int displayId) { updateDisplayModes(displayId); - // TODO: Break the coupling between DisplayObserver and BrightnessObserver. - mBrightnessObserver.onDisplayChanged(displayId); } private void updateDisplayModes(int displayId) { @@ -1465,7 +1466,7 @@ public class DisplayModeDirector { * {@link R.array#config_ambientThresholdsOfPeakRefreshRate}. */ @VisibleForTesting - public class BrightnessObserver extends ContentObserver { + public class BrightnessObserver implements DisplayManager.DisplayListener { private final static int LIGHT_SENSOR_RATE_MS = 250; private int[] mLowDisplayBrightnessThresholds; private int[] mLowAmbientBrightnessThresholds; @@ -1488,6 +1489,8 @@ public class DisplayModeDirector { private int mBrightness = -1; private final Context mContext; + private final Injector mInjector; + private final Handler mHandler; // Enable light sensor only when mShouldObserveAmbientLowChange is true or // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate @@ -1500,9 +1503,11 @@ public class DisplayModeDirector { private int mRefreshRateInLowZone; private int mRefreshRateInHighZone; - BrightnessObserver(Context context, Handler handler) { - super(handler); + BrightnessObserver(Context context, Handler handler, Injector injector) { mContext = context; + mHandler = handler; + mInjector = injector; + mLowDisplayBrightnessThresholds = context.getResources().getIntArray( R.array.config_brightnessThresholdsOfPeakRefreshRate); mLowAmbientBrightnessThresholds = context.getResources().getIntArray( @@ -1569,8 +1574,7 @@ public class DisplayModeDirector { public void observe(SensorManager sensorManager) { mSensorManager = sensorManager; final ContentResolver cr = mContext.getContentResolver(); - mBrightness = Settings.System.getIntForUser(cr, - Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId()); + mBrightness = getBrightness(Display.DEFAULT_DISPLAY); // DeviceConfig is accessible after system ready. int[] lowDisplayBrightnessThresholds = @@ -1603,6 +1607,10 @@ public class DisplayModeDirector { restartObserver(); mDeviceConfigDisplaySettings.startListening(); + + mInjector.registerDisplayListener(this, mHandler, + DisplayManager.EVENT_FLAG_DISPLAY_CHANGED | + DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); } public void setLoggingEnabled(boolean loggingEnabled) { @@ -1718,28 +1726,30 @@ public class DisplayModeDirector { } } + @Override + public void onDisplayAdded(int displayId) {} + + @Override + public void onDisplayRemoved(int displayId) {} + + @Override public void onDisplayChanged(int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { updateDefaultDisplayState(); - } - } - @Override - public void onChange(boolean selfChange, Uri uri, int userId) { - synchronized (mLock) { - final ContentResolver cr = mContext.getContentResolver(); - int brightness = Settings.System.getIntForUser(cr, - Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId()); - if (brightness != mBrightness) { - mBrightness = brightness; - onBrightnessChangedLocked(); + // We don't support multiple display blocking zones yet, so only handle + // brightness changes for the default display for now. + int brightness = getBrightness(displayId); + synchronized (mLock) { + if (brightness != mBrightness) { + mBrightness = brightness; + onBrightnessChangedLocked(); + } } } } private void restartObserver() { - final ContentResolver cr = mContext.getContentResolver(); - if (mRefreshRateInLowZone > 0) { mShouldObserveDisplayLowChange = hasValidThreshold( mLowDisplayBrightnessThresholds); @@ -1760,15 +1770,6 @@ public class DisplayModeDirector { mShouldObserveAmbientHighChange = false; } - if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) { - // Content Service does not check if an listener has already been registered. - // To ensure only one listener is registered, force an unregistration first. - mInjector.unregisterBrightnessObserver(cr, this); - mInjector.registerBrightnessObserver(cr, this); - } else { - mInjector.unregisterBrightnessObserver(cr, this); - } - if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) { Resources resources = mContext.getResources(); String lightSensorType = resources.getString( @@ -1968,6 +1969,15 @@ public class DisplayModeDirector { return mDefaultDisplayState == Display.STATE_ON; } + private int getBrightness(int displayId) { + final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); + if (info != null) { + return BrightnessSynchronizer.brightnessFloatToInt(info.adjustedBrightness); + } + + return BRIGHTNESS_INVALID; + } + private final class LightSensorEventListener implements SensorEventListener { final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS; private float mLastSensorData; @@ -2630,19 +2640,11 @@ public class DisplayModeDirector { } interface Injector { - // TODO: brightnessfloat: change this to the float setting - Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); @NonNull DeviceConfigInterface getDeviceConfig(); - void registerBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer); - - void unregisterBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer); - void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer); @@ -2671,19 +2673,6 @@ public class DisplayModeDirector { return DeviceConfigInterface.REAL; } - @Override - public void registerBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/, - observer, UserHandle.USER_SYSTEM); - } - - @Override - public void unregisterBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - cr.unregisterContentObserver(observer); - } - @Override public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index abbe13ac260f8..25afc3f8b2135 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1259,10 +1259,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call putScreenBrightnessSetting(brightnessState, /* updateCurrent */ true); } - // We save the brightness info *after* the brightness setting has been changed so that - // the brightness info reflects the latest value. - saveBrightnessInfo(getScreenBrightnessSetting()); - // Apply dimming by at least some minimum amount when user activity // timeout is about to expire. if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) { @@ -1393,6 +1389,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call hadUserBrightnessPoint); } + // We save the brightness info *after* the brightness setting has been changed and + // adjustments made so that the brightness info reflects the latest value. + saveBrightnessInfo(getScreenBrightnessSetting(), animateValue); + } else { + saveBrightnessInfo(getScreenBrightnessSetting()); } // Log any changes to what is currently driving the brightness setting. @@ -1509,6 +1510,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call synchronized (mCachedBrightnessInfo) { return new BrightnessInfo( mCachedBrightnessInfo.brightness, + mCachedBrightnessInfo.adjustedBrightness, mCachedBrightnessInfo.brightnessMin, mCachedBrightnessInfo.brightnessMax, mCachedBrightnessInfo.hbmMode); @@ -1516,8 +1518,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void saveBrightnessInfo(float brightness) { + saveBrightnessInfo(brightness, brightness); + } + + private void saveBrightnessInfo(float brightness, float adjustedBrightness) { synchronized (mCachedBrightnessInfo) { mCachedBrightnessInfo.brightness = brightness; + mCachedBrightnessInfo.adjustedBrightness = adjustedBrightness; mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin(); mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax(); mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode(); @@ -2195,6 +2202,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp); pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig); pw.println(" mColorFadeEnabled=" + mColorFadeEnabled); + synchronized (mCachedBrightnessInfo) { + pw.println(" mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness); + pw.println(" mCachedBrightnessInfo.adjustedBrightness=" + + mCachedBrightnessInfo.adjustedBrightness); + pw.println(" mCachedBrightnessInfo.brightnessMin=" + + mCachedBrightnessInfo.brightnessMin); + pw.println(" mCachedBrightnessInfo.brightnessMax=" + + mCachedBrightnessInfo.brightnessMax); + pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode); + } pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig); pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig); @@ -2606,6 +2623,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call static class CachedBrightnessInfo { public float brightness; + public float adjustedBrightness; public float brightnessMin; public float brightnessMax; public int hbmMode; diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 0dd5c61121dbf..511687bf2d232 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -74,6 +74,7 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.util.Preconditions; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProviderRule; @@ -751,19 +752,27 @@ public class DisplayModeDirectorTest { director.start(sensorManager); - ArgumentCaptor listenerCaptor = + ArgumentCaptor displayListenerCaptor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), + any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + DisplayListener displayListener = displayListenerCaptor.getValue(); + + ArgumentCaptor sensorListenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1))) .registerListener( - listenerCaptor.capture(), + sensorListenerCaptor.capture(), eq(lightSensor), anyInt(), any(Handler.class)); - SensorEventListener listener = listenerCaptor.getValue(); + SensorEventListener sensorListener = sensorListenerCaptor.getValue(); - setBrightness(10); + setBrightness(10, 10, displayListener); // Sensor reads 20 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/)); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertVoteForRefreshRate(vote, 90 /*fps*/); @@ -771,9 +780,11 @@ public class DisplayModeDirectorTest { assertThat(vote).isNotNull(); assertThat(vote.disableRefreshRateSwitching).isTrue(); - setBrightness(125); + // We expect DisplayModeDirector to act on BrightnessInfo.adjustedBrightness; set only this + // parameter to the necessary threshold + setBrightness(10, 125, displayListener); // Sensor reads 1000 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/)); vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertThat(vote).isNull(); @@ -799,6 +810,14 @@ public class DisplayModeDirectorTest { director.start(sensorManager); + ArgumentCaptor displayListenerCaptor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), + any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + DisplayListener displayListener = displayListenerCaptor.getValue(); + ArgumentCaptor listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1))) @@ -807,20 +826,22 @@ public class DisplayModeDirectorTest { eq(lightSensor), anyInt(), any(Handler.class)); - SensorEventListener listener = listenerCaptor.getValue(); + SensorEventListener sensorListener = listenerCaptor.getValue(); - setBrightness(100); + setBrightness(100, 100, displayListener); // Sensor reads 2000 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000)); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertThat(vote).isNull(); vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH); assertThat(vote).isNull(); - setBrightness(255); + // We expect DisplayModeDirector to act on BrightnessInfo.adjustedBrightness; set only this + // parameter to the necessary threshold + setBrightness(100, 255, displayListener); // Sensor reads 9000 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000)); vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertVoteForRefreshRate(vote, 60 /*fps*/); @@ -1834,11 +1855,14 @@ public class DisplayModeDirectorTest { } } - private void setBrightness(int brightness) { - Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, - brightness); - mInjector.notifyBrightnessChanged(); - waitForIdleSync(); + private void setBrightness(int brightness, int adjustedBrightness, DisplayListener listener) { + float floatBri = BrightnessSynchronizer.brightnessIntToFloat(brightness); + float floatAdjBri = BrightnessSynchronizer.brightnessIntToFloat(adjustedBrightness); + + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(floatBri, floatAdjBri, 0.0f, 1.0f, + BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + listener.onDisplayChanged(DISPLAY_ID); } private void setPeakRefreshRate(float fps) { @@ -1901,27 +1925,6 @@ public class DisplayModeDirectorTest { return mDeviceConfig; } - @Override - public void registerBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - if (mBrightnessObserver != null) { - throw new IllegalStateException("Tried to register a second brightness observer"); - } - mBrightnessObserver = observer; - } - - @Override - public void unregisterBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - mBrightnessObserver = null; - } - - void notifyBrightnessChanged() { - if (mBrightnessObserver != null) { - mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI); - } - } - @Override public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer) { From 49cd1ddff21a7f25ed91ac26af74d8873e4eeda8 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 1 Oct 2021 21:52:16 +0000 Subject: [PATCH 08/12] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I16d9a6d095235020a1b698f49218b14aba4cbe1e --- packages/SystemUI/res/values-te/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 18fb714d1fc6a..8649ce4bde606 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -100,7 +100,7 @@ "స్క్రీన్ రికార్డింగ్ అవుతోంది" "స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్‌గోయింగ్ నోటిఫికేషన్" "రికార్డింగ్‌ను ప్రారంభించాలా?" - "రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నైనా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, ఆడియో ఉంటాయి." + "రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నయినా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, ఆడియో కూడా ఉంటాయి." "ఆడియోను రికార్డ్ చేయి" "పరికరం ఆడియో" "మీ పరికరం నుండి వచ్చే సంగీతం, కాల్స్‌, రింగ్‌టోన్‌ల వంటి ధ్వనులు" @@ -506,7 +506,7 @@ "బ్యాటరీ సేవర్ ఆన్‌లో ఉంది" "పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది" "బ్యాటరీ సేవర్‌ను ఆఫ్ చేయండి" - "రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, %s యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, చెల్లింపు వివరాలు, ఫోటోలు, మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి." + "రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, %s యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి." "రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్‌ను అందిస్తున్న సర్వీస్ యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి." "రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?" "%sతో రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?" @@ -1144,7 +1144,7 @@ "కంటెంట్ త్వరలో కనిపిస్తుంది" "మిస్డ్ కాల్" "%d+" - "ఇటీవలి మెసేజ్‌లు, మిస్డ్ కాల్స్‌, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి" + "ఇటీవలి మెసేజ్‌లు, మిస్స్‌డ్‌ కాల్స్‌, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి" "సంభాషణ" "అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది" "%1$s మెసేజ్‌ను పంపారు: %2$s" From 13d3dffa6655c1610d3485227037867439f0403c Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Fri, 24 Sep 2021 17:44:00 -0700 Subject: [PATCH 09/12] Make DisplayModeDirector aware of whether HBM is active Currently DisplayModeDirector casts Vote.PRIORITY_HIGH_BRIGHTNESS_MODE based on whether High Brightness Mode (HBM) is allowed, rather than based on whether HBM is actually active. This can lead to cases where the HBM refresh rate vote is cast when HBM is allowed but not actually used. This change corrects this behavior, and makes DisplayModeDirector check that HBM is both allowed (enabled) and actually in use (active). Bug: 200851199 Test: atest DisplayModeDirectorTest BrightnessLevelPreferenceControllerTest HighBrightnessModeControllerTest Change-Id: I8cb8f023a6bca11de976866259032143f43d9a4f --- .../hardware/display/BrightnessInfo.java | 14 +- .../server/display/DisplayModeDirector.java | 54 ++++--- .../display/DisplayPowerController.java | 8 +- .../display/HighBrightnessModeController.java | 11 ++ .../display/DisplayModeDirectorTest.java | 141 ++++++++++++++++-- .../HighBrightnessModeControllerTest.java | 4 + 6 files changed, 197 insertions(+), 35 deletions(-) diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java index 6a2b900eea591..0dc8f92967fb9 100644 --- a/core/java/android/hardware/display/BrightnessInfo.java +++ b/core/java/android/hardware/display/BrightnessInfo.java @@ -69,6 +69,9 @@ public final class BrightnessInfo implements Parcelable { /** Current maximum supported brightness. */ public final float brightnessMaximum; + /** Brightness values greater than this point are only used in High Brightness Mode. */ + public final float highBrightnessTransitionPoint; + /** * Current state of high brightness mode. * Can be any of HIGH_BRIGHTNESS_MODE_* values. @@ -76,17 +79,20 @@ public final class BrightnessInfo implements Parcelable { public final int highBrightnessMode; public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum, - @HighBrightnessMode int highBrightnessMode) { - this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode); + @HighBrightnessMode int highBrightnessMode, float highBrightnessTransitionPoint) { + this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode, + highBrightnessTransitionPoint); } public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum, - float brightnessMaximum, @HighBrightnessMode int highBrightnessMode) { + float brightnessMaximum, @HighBrightnessMode int highBrightnessMode, + float highBrightnessTransitionPoint) { this.brightness = brightness; this.adjustedBrightness = adjustedBrightness; this.brightnessMinimum = brightnessMinimum; this.brightnessMaximum = brightnessMaximum; this.highBrightnessMode = highBrightnessMode; + this.highBrightnessTransitionPoint = highBrightnessTransitionPoint; } /** @@ -116,6 +122,7 @@ public final class BrightnessInfo implements Parcelable { dest.writeFloat(brightnessMinimum); dest.writeFloat(brightnessMaximum); dest.writeInt(highBrightnessMode); + dest.writeFloat(highBrightnessTransitionPoint); } public static final @android.annotation.NonNull Creator CREATOR = @@ -137,6 +144,7 @@ public final class BrightnessInfo implements Parcelable { brightnessMinimum = source.readFloat(); brightnessMaximum = source.readFloat(); highBrightnessMode = source.readInt(); + highBrightnessTransitionPoint = source.readFloat(); } } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index ee6df426c82d8..0a22f2fdfdf8e 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -2293,6 +2293,7 @@ public class DisplayModeDirector { private final BallotBox mBallotBox; private final Handler mHandler; private final SparseIntArray mHbmMode = new SparseIntArray(); + private final SparseBooleanArray mHbmActive = new SparseBooleanArray(); private final Injector mInjector; private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; private int mRefreshRateInHbmSunlight; @@ -2361,6 +2362,7 @@ public class DisplayModeDirector { public void onDisplayRemoved(int displayId) { mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null); mHbmMode.delete(displayId); + mHbmActive.delete(displayId); } @Override @@ -2370,12 +2372,17 @@ public class DisplayModeDirector { // Display no longer there. Assume we'll get an onDisplayRemoved very soon. return; } + final int hbmMode = info.highBrightnessMode; - if (hbmMode == mHbmMode.get(displayId)) { + final boolean isHbmActive = hbmMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF && + info.adjustedBrightness > info.highBrightnessTransitionPoint; + if (hbmMode == mHbmMode.get(displayId) && + isHbmActive == mHbmActive.get(displayId)) { // no change, ignore. return; } mHbmMode.put(displayId, hbmMode); + mHbmActive.put(displayId, isHbmActive); recalculateVotesForDisplay(displayId); } @@ -2389,28 +2396,36 @@ public class DisplayModeDirector { } private void recalculateVotesForDisplay(int displayId) { - final int hbmMode = mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); Vote vote = null; - if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) { - // Device resource properties take priority over DisplayDeviceConfig - if (mRefreshRateInHbmSunlight > 0) { - vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight, - mRefreshRateInHbmSunlight); - } else { - final List limits = - mDisplayManagerInternal.getRefreshRateLimitations(displayId); - for (int i = 0; limits != null && i < limits.size(); i++) { - final RefreshRateLimitation limitation = limits.get(i); - if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { - vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max); - break; + if (mHbmActive.get(displayId, false)) { + final int hbmMode = + mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); + if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) { + // Device resource properties take priority over DisplayDeviceConfig + if (mRefreshRateInHbmSunlight > 0) { + vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight, + mRefreshRateInHbmSunlight); + } else { + final List limits = + mDisplayManagerInternal.getRefreshRateLimitations(displayId); + for (int i = 0; limits != null && i < limits.size(); i++) { + final RefreshRateLimitation limitation = limits.get(i); + if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { + vote = Vote.forRefreshRates(limitation.range.min, + limitation.range.max); + break; + } } } + } else if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR && + mRefreshRateInHbmHdr > 0) { + // HBM for HDR vote isn't supported through DisplayDeviceConfig yet, so look for + // a vote from Device properties + vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr); + } else { + Slog.w(TAG, "Unexpected HBM mode " + hbmMode + " for display ID " + displayId); } - } - if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR - && mRefreshRateInHbmHdr > 0) { - vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr); + } mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote); } @@ -2418,6 +2433,7 @@ public class DisplayModeDirector { void dumpLocked(PrintWriter pw) { pw.println(" HbmObserver"); pw.println(" mHbmMode: " + mHbmMode); + pw.println(" mHbmActive: " + mHbmActive); pw.println(" mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight); pw.println(" mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 25afc3f8b2135..34b635b75151d 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1513,7 +1513,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mCachedBrightnessInfo.adjustedBrightness, mCachedBrightnessInfo.brightnessMin, mCachedBrightnessInfo.brightnessMax, - mCachedBrightnessInfo.hbmMode); + mCachedBrightnessInfo.hbmMode, + mCachedBrightnessInfo.highBrightnessTransitionPoint); } } @@ -1528,6 +1529,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin(); mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax(); mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode(); + mCachedBrightnessInfo.highBrightnessTransitionPoint = + mHbmController.getTransitionPoint(); } } @@ -2211,6 +2214,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mCachedBrightnessInfo.brightnessMax=" + mCachedBrightnessInfo.brightnessMax); pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode); + pw.println(" mCachedBrightnessInfo.highBrightnessTransitionPoint=" + + mCachedBrightnessInfo.highBrightnessTransitionPoint); } pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig); pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig); @@ -2627,5 +2632,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call public float brightnessMin; public float brightnessMax; public int hbmMode; + public float highBrightnessTransitionPoint; } } diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java index 2791f6a409be3..1e1cfeb5b9dde 100644 --- a/services/core/java/com/android/server/display/HighBrightnessModeController.java +++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java @@ -59,6 +59,9 @@ class HighBrightnessModeController { private static final float HDR_PERCENT_OF_SCREEN_REQUIRED = 0.50f; + @VisibleForTesting + static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY; + private final float mBrightnessMin; private final float mBrightnessMax; private final Handler mHandler; @@ -214,6 +217,14 @@ class HighBrightnessModeController { return mHbmMode; } + float getTransitionPoint() { + if (deviceSupportsHbm()) { + return mHbmData.transitionPoint; + } else { + return HBM_TRANSITION_POINT_INVALID; + } + } + void stop() { registerHdrListener(null /*displayToken*/); mSkinThermalStatusObserver.stopObserving(); diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 511687bf2d232..418831f47c1ae 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -26,6 +26,7 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_R import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE; import static com.android.server.display.DisplayModeDirector.Vote.INVALID_SIZE; +import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID; import static com.google.common.truth.Truth.assertThat; @@ -111,6 +112,7 @@ public class DisplayModeDirectorTest { private static final boolean DEBUG = false; private static final float FLOAT_TOLERANCE = 0.01f; private static final int DISPLAY_ID = 0; + private static final float TRANSITION_POINT = 0.763f; private Context mContext; private FakesInjector mInjector; @@ -1456,16 +1458,58 @@ public class DisplayModeDirectorTest { Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertNull(vote); - // Turn on HBM + // Turn on HBM, with brightness in the HBM range when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR)); + new BrightnessInfo(TRANSITION_POINT + FLOAT_TOLERANCE, 0.0f, 1.0f, + BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, hbmRefreshRate); + + // Turn on HBM, with brightness below the HBM range + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(TRANSITION_POINT - FLOAT_TOLERANCE, 0.0f, 1.0f, + BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HBM, with brightness in the HBM range + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(TRANSITION_POINT + FLOAT_TOLERANCE, 0.0f, 1.0f, + BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertVoteForRefreshRate(vote, hbmRefreshRate); // Turn off HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HBM, with brightness below the HBM range + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(TRANSITION_POINT - FLOAT_TOLERANCE, 0.0f, 1.0f, + BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertNull(vote); @@ -1535,7 +1579,8 @@ public class DisplayModeDirectorTest { // Turn on HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertVoteForRefreshRate(vote, initialRefreshRate); @@ -1552,14 +1597,16 @@ public class DisplayModeDirectorTest { // Turn off HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertNull(vote); // Turn HBM on again and ensure the updated vote value stuck when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertVoteForRefreshRate(vote, updatedRefreshRate); @@ -1574,7 +1621,8 @@ public class DisplayModeDirectorTest { // Turn off HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertNull(vote); @@ -1605,14 +1653,82 @@ public class DisplayModeDirectorTest { // Turn on HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertNull(vote); // Turn off HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + } + + @Test + public void testHbmVoting_HbmUnsupported() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + director.start(createMockSensorManager()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + DisplayListener listener = captor.getValue(); + + // Specify Limitation + when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn( + List.of(new RefreshRateLimitation( + DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, + 60.0f, 60.0f))); + + // Verify that there is no HBM vote initially + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HBM when HBM is supported; expect a valid transition point and a vote. + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, 60.0f); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on Sunlight HBM when HBM is unsupported; expect an invalid transition point and + // no vote. + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + HBM_TRANSITION_POINT_INVALID)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HDR HBM when HBM is unsupported; expect an invalid transition point and + // no vote. + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, + HBM_TRANSITION_POINT_INVALID)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertNull(vote); @@ -1621,7 +1737,7 @@ public class DisplayModeDirectorTest { private void setHbmAndAssertRefreshRate( DisplayModeDirector director, DisplayListener listener, int mode, float rr) { when(mInjector.getBrightnessInfo(DISPLAY_ID)) - .thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode)); + .thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode, TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); final Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); @@ -1700,7 +1816,8 @@ public class DisplayModeDirectorTest { // Turn on HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( - new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, + TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); assertVoteForRefreshRate(vote, 60.f); @@ -1861,7 +1978,7 @@ public class DisplayModeDirectorTest { when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( new BrightnessInfo(floatBri, floatAdjBri, 0.0f, 1.0f, - BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, TRANSITION_POINT)); listener.onDisplayChanged(DISPLAY_ID); } diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java index cc3591c895605..aca863299b33a 100644 --- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java @@ -20,6 +20,8 @@ import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR; import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT; +import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.spy; @@ -124,6 +126,7 @@ public class HighBrightnessModeControllerTest { mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF); + assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f); } @Test @@ -135,6 +138,7 @@ public class HighBrightnessModeControllerTest { hbmc.setAutoBrightnessEnabled(true); hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF); + assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f); } @Test From da4272ecaa8c740a1ab6aa944e106d5a75034a90 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 4 Oct 2021 21:31:28 +0800 Subject: [PATCH 10/12] Align the duration of task exit animation to enter animation Now they are both 500ms. Otherwise if the duration of exit animation is longer, it may cover the entering task. Bug: 201998178 Test: Back from a task in a different orientation, the exiting task should not flash on screen. Merged-In: Iefa134e4217ba35d33801225368b7a5df60d932c Change-Id: Iefa134e4217ba35d33801225368b7a5df60d932c --- core/res/res/anim-ldrtl/task_close_exit.xml | 7 +------ core/res/res/anim-ldrtl/task_open_exit.xml | 7 +------ core/res/res/anim/task_close_exit.xml | 7 +------ core/res/res/anim/task_open_exit.xml | 7 +------ 4 files changed, 4 insertions(+), 24 deletions(-) diff --git a/core/res/res/anim-ldrtl/task_close_exit.xml b/core/res/res/anim-ldrtl/task_close_exit.xml index 76fbdffd1760d..0887019ca608b 100644 --- a/core/res/res/anim-ldrtl/task_close_exit.xml +++ b/core/res/res/anim-ldrtl/task_close_exit.xml @@ -28,9 +28,4 @@ android:startOffset="0" android:duration="500"/> - - - \ No newline at end of file + diff --git a/core/res/res/anim-ldrtl/task_open_exit.xml b/core/res/res/anim-ldrtl/task_open_exit.xml index beb6fca5632a0..88cdcceae4150 100644 --- a/core/res/res/anim-ldrtl/task_open_exit.xml +++ b/core/res/res/anim-ldrtl/task_open_exit.xml @@ -28,9 +28,4 @@ android:startOffset="0" android:duration="500"/> - - - \ No newline at end of file + diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml index 736f3f2083e57..3a8dd934cd17a 100644 --- a/core/res/res/anim/task_close_exit.xml +++ b/core/res/res/anim/task_close_exit.xml @@ -30,9 +30,4 @@ android:startOffset="0" android:duration="500"/> - - - \ No newline at end of file + diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml index d1703170e16f0..21fec7f694bf6 100644 --- a/core/res/res/anim/task_open_exit.xml +++ b/core/res/res/anim/task_open_exit.xml @@ -30,9 +30,4 @@ android:startOffset="0" android:duration="500"/> - - - \ No newline at end of file + From b5997d47aef24642c86120d8cb6190434561978f Mon Sep 17 00:00:00 2001 From: Joshua Mccloskey Date: Mon, 13 Sep 2021 12:24:02 -0700 Subject: [PATCH 11/12] Fixed NPE in FingerprintAuthClient Test: It builds. Bug: 193883067 Change-Id: I3c310ab6a631750377a069e926567279bedc9d3b Merged-In: I3c310ab6a631750377a069e926567279bedc9d3b (cherry picked from commit 78893c23173aea599c3cadd6a4ab7506ae3919ac) DO NOT MERGE --- .../aidl/FingerprintAuthenticationClient.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 37ee76adeecef..4400834efb3f3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -164,13 +164,17 @@ class FingerprintAuthenticationClient extends AuthenticationClient imp @Override protected void stopHalOperation() { UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController); - try { - mCancellationSignal.cancel(); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - mCallback.onClientFinished(this, false /* success */); + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + } else { + Slog.e(TAG, "cancellation signal was null"); } } From 9d347aa9d58ab69870d1a575100e087ddefc8830 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Tue, 5 Oct 2021 02:27:17 +0000 Subject: [PATCH 12/12] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: If41a14538101c6b39535fce97e478da8f9aba9fa --- core/res/res/values-mcc334-mnc020-as/strings.xml | 9 +++------ core/res/res/values-mcc334-mnc020-bn/strings.xml | 9 +++------ core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml | 9 +++------ core/res/res/values-mcc334-mnc020-gu/strings.xml | 9 +++------ core/res/res/values-mcc334-mnc020-ur/strings.xml | 9 +++------ core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml | 9 +++------ 6 files changed, 18 insertions(+), 36 deletions(-) diff --git a/core/res/res/values-mcc334-mnc020-as/strings.xml b/core/res/res/values-mcc334-mnc020-as/strings.xml index 25b074eec1451..43f5fb1effa2d 100644 --- a/core/res/res/values-mcc334-mnc020-as/strings.xml +++ b/core/res/res/values-mcc334-mnc020-as/strings.xml @@ -20,10 +20,7 @@ - - - - - - + "বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ বিফল হৈছে -29-" + "সেৱাটো ছাবস্ক্ৰাইব কৰা নাই -33-" + "এটা APNৰ বাবে একাধিক PDN সংযোগৰ অনুমতি নাই -55-" diff --git a/core/res/res/values-mcc334-mnc020-bn/strings.xml b/core/res/res/values-mcc334-mnc020-bn/strings.xml index 25b074eec1451..f58aea71bddeb 100644 --- a/core/res/res/values-mcc334-mnc020-bn/strings.xml +++ b/core/res/res/values-mcc334-mnc020-bn/strings.xml @@ -20,10 +20,7 @@ - - - - - - + "যাচাই করা যায়নি -29-" + "পরিষেবা সাবস্ক্রাইব করা হয়নি -33-" + "নির্দিষ্ট কোনও APN-এর জন্য একাধিক PDN কানেকশন অনুমোদিত নয় -55-" diff --git a/core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml b/core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml index 25b074eec1451..19794dafb6c81 100644 --- a/core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml +++ b/core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml @@ -20,10 +20,7 @@ - - - - - - + "ÉCHEC DE L\'AUTHENTIFICATION -29-" + "NON ABONNÉ AU SERVICE -33-" + "Connexions PDN multiples interdites pour un APN donné -55-" diff --git a/core/res/res/values-mcc334-mnc020-gu/strings.xml b/core/res/res/values-mcc334-mnc020-gu/strings.xml index 25b074eec1451..5faef6f13a26d 100644 --- a/core/res/res/values-mcc334-mnc020-gu/strings.xml +++ b/core/res/res/values-mcc334-mnc020-gu/strings.xml @@ -20,10 +20,7 @@ - - - - - - + "પ્રમાણીકરણ નિષ્ફળ થયું -29-" + "સેવા સબ્સ્ક્રાઇબ કરી નથી -33-" + "આપેલા APN માટે એક કરતાં વધારે PDN કનેક્શનની મંજૂરી નથી -55-" diff --git a/core/res/res/values-mcc334-mnc020-ur/strings.xml b/core/res/res/values-mcc334-mnc020-ur/strings.xml index 25b074eec1451..bab5589eeadb7 100644 --- a/core/res/res/values-mcc334-mnc020-ur/strings.xml +++ b/core/res/res/values-mcc334-mnc020-ur/strings.xml @@ -20,10 +20,7 @@ - - - - - - + "توثیق کی ناکامی -29-" + "سروس کو سبسکرائب نہیں کیا -33-" + "‏ایک دیئے گئے APN کے لیے متعدد PDN کنکشنز کی اجازت نہیں ہے -55-" diff --git a/core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml b/core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml index 25b074eec1451..a8fbe74cd3ab2 100644 --- a/core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml +++ b/core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml @@ -20,10 +20,7 @@ - - - - - - + "身份验证失败 -29-" + "未订阅服务 -33-" + "指定的 APN 不能有多个 PDN 连接 -55-"