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
This commit is contained in:
Evan Laird
2022-01-10 12:01:04 -05:00
parent 404db92194
commit 225052be27
9 changed files with 134 additions and 13 deletions

View File

@@ -9964,6 +9964,13 @@ public final class Settings {
public static final String LOCKSCREEN_USE_DOUBLE_LINE_CLOCK = public static final String LOCKSCREEN_USE_DOUBLE_LINE_CLOCK =
"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. * Specifies whether the web action API is enabled.
* *

View File

@@ -196,5 +196,6 @@ public class SecureSettings {
Settings.Secure.LOCKSCREEN_SHOW_WALLET, Settings.Secure.LOCKSCREEN_SHOW_WALLET,
Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER,
Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON
}; };
} }

View File

@@ -155,6 +155,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.LOCKSCREEN_SHOW_WALLET, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_WALLET, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 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_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DOZE_ALWAYS_ON, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_ALWAYS_ON, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DOZE_PICK_UP_GESTURE, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_PICK_UP_GESTURE, BOOLEAN_VALIDATOR);

View File

@@ -48,6 +48,7 @@ import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.util.Assert;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -66,6 +67,8 @@ public interface StatusBarIconController {
void addIconGroup(IconManager iconManager); void addIconGroup(IconManager iconManager);
/** */ /** */
void removeIconGroup(IconManager iconManager); void removeIconGroup(IconManager iconManager);
/** Refresh the state of an IconManager by recreating the views */
void refreshIconGroup(IconManager iconManager);
/** */ /** */
void setExternalIcon(String slot); void setExternalIcon(String slot);
/** */ /** */
@@ -243,6 +246,7 @@ public interface StatusBarIconController {
protected final int mIconSize; protected final int mIconSize;
// Whether or not these icons show up in dumpsys // Whether or not these icons show up in dumpsys
protected boolean mShouldLog = false; protected boolean mShouldLog = false;
private StatusBarIconController mController;
// Enables SystemUI demo mode to take effect in this group // Enables SystemUI demo mode to take effect in this group
protected boolean mDemoable = true; protected boolean mDemoable = true;
@@ -267,13 +271,17 @@ public interface StatusBarIconController {
mDemoable = demoable; mDemoable = demoable;
} }
public void setBlockList(@Nullable List<String> blockList) { void setController(StatusBarIconController controller) {
mBlockList.clear(); mController = controller;
if (blockList == null || blockList.isEmpty()) { }
return;
}
public void setBlockList(@Nullable List<String> blockList) {
Assert.isMainThread();
mBlockList.clear();
mBlockList.addAll(blockList); mBlockList.addAll(blockList);
if (mController != null) {
mController.refreshIconGroup(this);
}
} }
public void setShouldLog(boolean should) { public void setShouldLog(boolean should) {

View File

@@ -100,6 +100,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
} }
} }
group.setController(this);
mIconGroups.add(group); mIconGroups.add(group);
List<Slot> allSlots = getSlots(); List<Slot> allSlots = getSlots();
for (int i = 0; i < allSlots.size(); i++) { for (int i = 0; i < allSlots.size(); i++) {
@@ -115,6 +116,12 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
} }
} }
@Override
public void refreshIconGroup(IconManager iconManager) {
removeIconGroup(iconManager);
addIconGroup(iconManager);
}
private void refreshIconGroups() { private void refreshIconGroups() {
for (int i = mIconGroups.size() - 1; i >= 0; --i) { for (int i = mIconGroups.size() - 1; i >= 0; --i) {
IconManager group = mIconGroups.get(i); IconManager group = mIconGroups.get(i);

View File

@@ -61,6 +61,9 @@ import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.settings.SecureSettings;
import java.util.concurrent.Executor;
import javax.inject.Named; import javax.inject.Named;
@@ -260,7 +263,9 @@ public abstract class StatusBarViewModule {
StatusBarStateController statusBarStateController, StatusBarStateController statusBarStateController,
CommandQueue commandQueue, CommandQueue commandQueue,
CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
OperatorNameViewController.Factory operatorNameViewControllerFactory OperatorNameViewController.Factory operatorNameViewControllerFactory,
SecureSettings secureSettings,
@Main Executor mainExecutor
) { ) {
return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory, return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory,
ongoingCallController, ongoingCallController,
@@ -277,6 +282,8 @@ public abstract class StatusBarViewModule {
statusBarStateController, statusBarStateController,
commandQueue, commandQueue,
collapsedStatusBarFragmentLogger, collapsedStatusBarFragmentLogger,
operatorNameViewControllerFactory); operatorNameViewControllerFactory,
secureSettings,
mainExecutor);
} }
} }

View File

@@ -30,8 +30,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Fragment; import android.app.Fragment;
import android.database.ContentObserver;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
import android.provider.Settings;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -39,8 +41,11 @@ import android.view.ViewGroup;
import android.view.ViewStub; import android.view.ViewStub;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue;
@@ -66,9 +71,11 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.EncryptionHelper; import com.android.systemui.statusbar.policy.EncryptionHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor;
/** /**
* Contains the collapsed status bar and handles hiding/showing based on disable flags * Contains the collapsed status bar and handles hiding/showing based on disable flags
@@ -110,6 +117,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private final PanelExpansionStateManager mPanelExpansionStateManager; private final PanelExpansionStateManager mPanelExpansionStateManager;
private final StatusBarIconController mStatusBarIconController; private final StatusBarIconController mStatusBarIconController;
private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
private final SecureSettings mSecureSettings;
private final Executor mMainExecutor;
private List<String> mBlockedIcons = new ArrayList<>(); private List<String> mBlockedIcons = new ArrayList<>();
@@ -145,7 +154,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
StatusBarStateController statusBarStateController, StatusBarStateController statusBarStateController,
CommandQueue commandQueue, CommandQueue commandQueue,
CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
OperatorNameViewController.Factory operatorNameViewControllerFactory OperatorNameViewController.Factory operatorNameViewControllerFactory,
SecureSettings secureSettings,
@Main Executor mainExecutor
) { ) {
mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory; mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
mOngoingCallController = ongoingCallController; mOngoingCallController = ongoingCallController;
@@ -163,6 +174,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue = commandQueue; mCommandQueue = commandQueue;
mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger; mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger;
mOperatorNameViewControllerFactory = operatorNameViewControllerFactory; mOperatorNameViewControllerFactory = operatorNameViewControllerFactory;
mSecureSettings = secureSettings;
mMainExecutor = mainExecutor;
} }
@Override @Override
@@ -187,10 +200,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
} }
mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags); mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags);
mDarkIconManager.setShouldLog(true); mDarkIconManager.setShouldLog(true);
mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume)); updateBlockedIcons();
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);
mStatusBarIconController.addIconGroup(mDarkIconManager); mStatusBarIconController.addIconGroup(mDarkIconManager);
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area); mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock); mClockView = mStatusBar.findViewById(R.id.clock);
@@ -203,6 +213,24 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mAnimationScheduler.addCallback(this); 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<String> getBlockedIcons() {
return mBlockedIcons;
}
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
@@ -217,6 +245,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.addCallback(this); mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this); mStatusBarStateController.addCallback(this);
initOngoingCallChip(); initOngoingCallChip();
mSecureSettings.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
false,
mVolumeSettingObserver);
} }
@Override @Override
@@ -225,6 +258,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.removeCallback(this); mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this); mStatusBarStateController.removeCallback(this);
mOngoingCallController.removeCallback(mOngoingCallListener); mOngoingCallController.removeCallback(mOngoingCallListener);
mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
} }
@Override @Override
@@ -584,6 +618,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin); 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 // Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot
private View.OnLayoutChangeListener mStatusBarLayoutListener = private View.OnLayoutChangeListener mStatusBarLayoutListener =
(view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {

View File

@@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone.fragment;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static org.junit.Assert.assertEquals; 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.ArgumentMatchers.any;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeast;
@@ -27,6 +29,7 @@ import android.app.Fragment;
import android.app.StatusBarManager; import android.app.StatusBarManager;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableLooper.RunWithLooper;
import android.view.View; import android.view.View;
@@ -56,6 +59,9 @@ import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentCom
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController; 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; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -82,6 +88,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private final CommandQueue mCommandQueue = mock(CommandQueue.class); private final CommandQueue mCommandQueue = mock(CommandQueue.class);
private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
private OperatorNameViewController mOperatorNameViewController; private OperatorNameViewController mOperatorNameViewController;
private SecureSettings mSecureSettings;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@Mock @Mock
private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory; private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory;
@@ -298,6 +306,40 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(mStatusBarFragmentComponent, fragment.getStatusBarFragmentComponent()); 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 @Override
protected Fragment instantiate(Context context, String className, Bundle arguments) { protected Fragment instantiate(Context context, String className, Bundle arguments) {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
@@ -313,6 +355,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class); mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class);
when(mOperatorNameViewControllerFactory.create(any())) when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController); .thenReturn(mOperatorNameViewController);
mSecureSettings = mock(SecureSettings.class);
setUpNotificationIconAreaController(); setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment( return new CollapsedStatusBarFragment(
@@ -334,7 +377,9 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
new LogBuffer("TEST", 1, 1, mock(LogcatEchoTracker.class)), new LogBuffer("TEST", 1, 1, mock(LogcatEchoTracker.class)),
new DisableFlagsLogger() new DisableFlagsLogger()
), ),
mOperatorNameViewControllerFactory); mOperatorNameViewControllerFactory,
mSecureSettings,
mExecutor);
} }
private void setUpDaggerComponent() { private void setUpDaggerComponent() {

View File

@@ -42,6 +42,10 @@ public class FakeStatusBarIconController extends BaseLeakChecker<IconManager>
removeCallback(iconManager); removeCallback(iconManager);
} }
@Override
public void refreshIconGroup(IconManager iconManager) {
}
@Override @Override
public void setExternalIcon(String slot) { public void setExternalIcon(String slot) {