From 5b5a16e90073f7d4e75dfb7743838c6f26f17d42 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Mon, 10 Jan 2022 12:01:04 -0500 Subject: [PATCH] Sysui changes to support vibrate icon setting - Add a listener for the new setting Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON - Rebuild any IconManager that receives an updated blocklist - Assert that any blocklist changes come in on the main thread Test: atest CollapsedStatusBarFragmentTest Bug: 220144337 Change-Id: I667b5c57ef646c57a2f6912df7d233b1b5c0f89d Merged-In: I667b5c57ef646c57a2f6912df7d233b1b5c0f89d --- core/java/android/provider/Settings.java | 7 +++ .../settings/backup/SecureSettings.java | 1 + .../validators/SecureSettingsValidators.java | 1 + .../phone/StatusBarIconController.java | 18 +++++-- .../phone/StatusBarIconControllerImpl.java | 7 +++ .../phone/dagger/StatusBarViewModule.java | 11 +++- .../fragment/CollapsedStatusBarFragment.java | 51 +++++++++++++++++-- .../CollapsedStatusBarFragmentTest.java | 45 +++++++++++++++- .../leaks/FakeStatusBarIconController.java | 4 ++ 9 files changed, 132 insertions(+), 13 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 97a380effc8d4..a1b4deae0989f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9663,6 +9663,13 @@ public final class Settings { public static final String LOCKSCREEN_USE_DOUBLE_LINE_CLOCK = "lockscreen_use_double_line_clock"; + /** + * Whether to show the vibrate icon in the Status Bar (default off) + * + * @hide + */ + public static final String STATUS_BAR_SHOW_VIBRATE_ICON = "status_bar_show_vibrate_icon"; + /** * Specifies whether the web action API is enabled. * diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 77fff0f08d4cd..a150dbf18a498 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -192,5 +192,6 @@ public class SecureSettings { Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, Settings.Secure.LOCKSCREEN_SHOW_WALLET, Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, + Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 9f883960981b3..1e8e05f025c74 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -151,6 +151,7 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.LOCKSCREEN_SHOW_CONTROLS, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_WALLET, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.STATUS_BAR_SHOW_VIBRATE_ICON, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_ALWAYS_ON, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_PICK_UP_GESTURE, BOOLEAN_VALIDATOR); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 48fe77482340b..fd435d45934a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.StatusIconDisplayable; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; +import com.android.systemui.util.Assert; import java.util.ArrayList; import java.util.List; @@ -65,6 +66,8 @@ public interface StatusBarIconController { void addIconGroup(IconManager iconManager); /** */ void removeIconGroup(IconManager iconManager); + /** Refresh the state of an IconManager by recreating the views */ + void refreshIconGroup(IconManager iconManager); /** */ void setExternalIcon(String slot); /** */ @@ -242,6 +245,7 @@ public interface StatusBarIconController { protected final int mIconSize; // Whether or not these icons show up in dumpsys protected boolean mShouldLog = false; + private StatusBarIconController mController; // Enables SystemUI demo mode to take effect in this group protected boolean mDemoable = true; @@ -266,13 +270,17 @@ public interface StatusBarIconController { mDemoable = demoable; } - public void setBlockList(@Nullable List blockList) { - mBlockList.clear(); - if (blockList == null || blockList.isEmpty()) { - return; - } + void setController(StatusBarIconController controller) { + mController = controller; + } + public void setBlockList(@Nullable List blockList) { + Assert.isMainThread(); + mBlockList.clear(); mBlockList.addAll(blockList); + if (mController != null) { + mController.refreshIconGroup(this); + } } public void setShouldLog(boolean should) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index 88a7dc7bcd75e..d6cf80ec70aa1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -99,6 +99,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu } } + group.setController(this); mIconGroups.add(group); List allSlots = getSlots(); for (int i = 0; i < allSlots.size(); i++) { @@ -114,6 +115,12 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu } } + @Override + public void refreshIconGroup(IconManager iconManager) { + removeIconGroup(iconManager); + addIconGroup(iconManager); + } + private void refreshIconGroups() { for (int i = mIconGroups.size() - 1; i >= 0; --i) { IconManager group = mIconGroups.get(i); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index 14cca13b396b3..8750845e57a80 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -60,6 +60,9 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.tuner.TunerService; +import com.android.systemui.util.settings.SecureSettings; + +import java.util.concurrent.Executor; import javax.inject.Named; @@ -257,7 +260,9 @@ public abstract class StatusBarViewModule { StatusBarStateController statusBarStateController, CommandQueue commandQueue, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, - OperatorNameViewController.Factory operatorNameViewControllerFactory + OperatorNameViewController.Factory operatorNameViewControllerFactory, + SecureSettings secureSettings, + @Main Executor mainExecutor ) { return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory, ongoingCallController, @@ -274,6 +279,8 @@ public abstract class StatusBarViewModule { statusBarStateController, commandQueue, collapsedStatusBarFragmentLogger, - operatorNameViewControllerFactory); + operatorNameViewControllerFactory, + secureSettings, + mainExecutor); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index d6ba6f3ff97a2..1a2f8a8e5db7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -29,8 +29,10 @@ import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Fragment; +import android.database.ContentObserver; import android.os.Bundle; import android.os.Parcelable; +import android.provider.Settings; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; @@ -38,8 +40,11 @@ import android.view.ViewGroup; import android.view.ViewStub; import android.widget.LinearLayout; +import androidx.annotation.VisibleForTesting; + import com.android.systemui.R; import com.android.systemui.animation.Interpolators; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; @@ -65,11 +70,13 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.EncryptionHelper; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.settings.SecureSettings; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; import javax.inject.Inject; @@ -113,6 +120,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private final PanelExpansionStateManager mPanelExpansionStateManager; private final StatusBarIconController mStatusBarIconController; private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; + private final SecureSettings mSecureSettings; + private final Executor mMainExecutor; private List mBlockedIcons = new ArrayList<>(); @@ -148,7 +157,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue StatusBarStateController statusBarStateController, CommandQueue commandQueue, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, - OperatorNameViewController.Factory operatorNameViewControllerFactory + OperatorNameViewController.Factory operatorNameViewControllerFactory, + SecureSettings secureSettings, + @Main Executor mainExecutor ) { mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory; mOngoingCallController = ongoingCallController; @@ -166,6 +177,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mCommandQueue = commandQueue; mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger; mOperatorNameViewControllerFactory = operatorNameViewControllerFactory; + mSecureSettings = secureSettings; + mMainExecutor = mainExecutor; } @Override @@ -190,10 +203,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags); mDarkIconManager.setShouldLog(true); - mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume)); - mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock)); - mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength)); - mDarkIconManager.setBlockList(mBlockedIcons); + updateBlockedIcons(); mStatusBarIconController.addIconGroup(mDarkIconManager); mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area); mClockView = mStatusBar.findViewById(R.id.clock); @@ -206,6 +216,24 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mAnimationScheduler.addCallback(this); } + @VisibleForTesting + void updateBlockedIcons() { + mBlockedIcons.clear(); + + if (mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0) { + mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume)); + } + mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock)); + mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength)); + + mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons)); + } + + @VisibleForTesting + List getBlockedIcons() { + return mBlockedIcons; + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -220,6 +248,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mCommandQueue.addCallback(this); mStatusBarStateController.addCallback(this); initOngoingCallChip(); + + mSecureSettings.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON), + false, + mVolumeSettingObserver); } @Override @@ -228,6 +261,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mCommandQueue.removeCallback(this); mStatusBarStateController.removeCallback(this); mOngoingCallController.removeCallback(mOngoingCallListener); + mSecureSettings.unregisterContentObserver(mVolumeSettingObserver); } @Override @@ -597,6 +631,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin); } + private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + updateBlockedIcons(); + } + }; + // Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot private View.OnLayoutChangeListener mStatusBarLayoutListener = (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index b97f053b24b53..cf9fbe06ef472 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone.fragment; import static android.view.Display.DEFAULT_DISPLAY; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeast; @@ -27,6 +29,7 @@ import android.app.Fragment; import android.app.StatusBarManager; import android.content.Context; import android.os.Bundle; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.View; @@ -58,6 +61,7 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; @@ -85,6 +89,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { private final CommandQueue mCommandQueue = mock(CommandQueue.class); private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; private OperatorNameViewController mOperatorNameViewController; + private SecureSettings mSecureSettings; + private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); @Mock private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory; @@ -299,6 +305,40 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { assertEquals(mStatusBarFragmentComponent, fragment.getStatusBarFragmentComponent()); } + @Test + public void testBlockedIcons_obeysSettingForVibrateIcon_settingOff() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + String str = mContext.getString(com.android.internal.R.string.status_bar_volume); + + // GIVEN the setting is off + when(mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0)) + .thenReturn(0); + + // WHEN CollapsedStatusBarFragment builds the blocklist + fragment.updateBlockedIcons(); + + // THEN status_bar_volume SHOULD be present in the list + boolean contains = fragment.getBlockedIcons().contains(str); + assertTrue(contains); + } + + @Test + public void testBlockedIcons_obeysSettingForVibrateIcon_settingOn() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + String str = mContext.getString(com.android.internal.R.string.status_bar_volume); + + // GIVEN the setting is ON + when(mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0)) + .thenReturn(1); + + // WHEN CollapsedStatusBarFragment builds the blocklist + fragment.updateBlockedIcons(); + + // THEN status_bar_volume SHOULD NOT be present in the list + boolean contains = fragment.getBlockedIcons().contains(str); + assertFalse(contains); + } + @Override protected Fragment instantiate(Context context, String className, Bundle arguments) { MockitoAnnotations.initMocks(this); @@ -314,6 +354,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class); when(mOperatorNameViewControllerFactory.create(any())) .thenReturn(mOperatorNameViewController); + mSecureSettings = mock(SecureSettings.class); setUpNotificationIconAreaController(); return new CollapsedStatusBarFragment( @@ -336,7 +377,9 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { new LogBuffer("TEST", 1, 1, mock(LogcatEchoTracker.class)), new DisableFlagsLogger() ), - mOperatorNameViewControllerFactory); + mOperatorNameViewControllerFactory, + mSecureSettings, + mExecutor); } private void setUpDaggerComponent() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java index 8ad6271bfc7e8..2be67edfc9466 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java @@ -42,6 +42,10 @@ public class FakeStatusBarIconController extends BaseLeakChecker removeCallback(iconManager); } + @Override + public void refreshIconGroup(IconManager iconManager) { + } + @Override public void setExternalIcon(String slot) {