Merge "Update lock screen user switcher on settings update and re-create view stub after disabling multi-user" into sc-dev am: cdd6adb5c5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14974991

Change-Id: Iecdfa1216a82e1a076a38b77d0583aae99366038
This commit is contained in:
TreeHugger Robot
2021-06-23 19:00:30 +00:00
committed by Automerger Merge Worker
4 changed files with 159 additions and 7 deletions

View File

@@ -27,6 +27,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList()
private val lastConfig = Configuration()
private var density: Int = 0
private var smallestScreenWidth: Int = 0
private var fontScale: Float = 0.toFloat()
private val inCarMode: Boolean
private var uiMode: Int = 0
@@ -38,6 +39,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
this.context = context
fontScale = currentConfig.fontScale
density = currentConfig.densityDpi
smallestScreenWidth = currentConfig.smallestScreenWidthDp
inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK ==
Configuration.UI_MODE_TYPE_CAR
uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
@@ -72,6 +74,14 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
this.fontScale = fontScale
}
val smallestScreenWidth = newConfig.smallestScreenWidthDp
if (smallestScreenWidth != this.smallestScreenWidth) {
this.smallestScreenWidth = smallestScreenWidth
listeners.filterForEach({ this.listeners.contains(it) }) {
it.onSmallestScreenWidthChanged()
}
}
val localeList = newConfig.locales
if (localeList != this.localeList) {
this.localeList = localeList

View File

@@ -38,9 +38,11 @@ import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.StatusBarManager;
import android.content.ContentResolver;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -52,10 +54,12 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.os.VibrationEffect;
import android.provider.Settings;
import android.util.Log;
import android.util.MathUtils;
import android.view.LayoutInflater;
@@ -212,6 +216,8 @@ public class NotificationPanelViewController extends PanelViewController {
new MyOnHeadsUpChangedListener();
private final HeightListener mHeightListener = new HeightListener();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
private final SettingsChangeObserver mSettingsChangeObserver;
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
private final BiometricUnlockController mBiometricUnlockController;
@@ -596,6 +602,8 @@ public class NotificationPanelViewController extends PanelViewController {
private int mScreenCornerRadius;
private boolean mQSAnimatingHiddenFromCollapsed;
private final ContentResolver mContentResolver;
private final Executor mUiExecutor;
private final SecureSettings mSecureSettings;
@@ -637,6 +645,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Resources resources,
@Main Handler handler,
LayoutInflater layoutInflater,
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
@@ -680,6 +689,7 @@ public class NotificationPanelViewController extends PanelViewController {
TapAgainViewController tapAgainViewController,
NavigationModeController navigationModeController,
FragmentService fragmentService,
ContentResolver contentResolver,
QuickAccessWalletController quickAccessWalletController,
@Main Executor uiExecutor,
SecureSettings secureSettings,
@@ -706,15 +716,12 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
mDepthController = notificationShadeDepthController;
mFeatureFlags = featureFlags;
mContentResolver = contentResolver;
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
mQSDetailDisplayer = qsDetailDisplayer;
mFragmentService = fragmentService;
mKeyguardUserSwitcherEnabled = mResources.getBoolean(
com.android.internal.R.bool.config_keyguardUserSwitcher);
mKeyguardQsUserSwitchEnabled =
mKeyguardUserSwitcherEnabled && mResources.getBoolean(
R.bool.config_keyguard_user_switch_opens_qs_details);
mSettingsChangeObserver = new SettingsChangeObserver(handler);
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
mView.setWillNotDraw(!DEBUG);
@@ -797,6 +804,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
updateUserSwitcherFlags();
onFinishInflate();
}
@@ -1036,6 +1044,10 @@ public class NotificationPanelViewController extends PanelViewController {
view = mLayoutInflater.inflate(layoutId, mView, false);
mView.addView(view, index);
} else {
// Add the stub back so we can re-inflate it again if necessary
ViewStub stub = new ViewStub(mView.getContext(), layoutId);
stub.setId(stubId);
mView.addView(stub, index);
view = null;
}
} else if (enabled) {
@@ -1063,6 +1075,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateResources();
// Re-inflate the keyguard user switcher group.
updateUserSwitcherFlags();
boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled();
boolean showQsUserSwitch = mKeyguardQsUserSwitchEnabled && isUserSwitcherEnabled;
boolean showKeyguardUserSwitcher =
@@ -3887,6 +3900,26 @@ public class NotificationPanelViewController extends PanelViewController {
return false;
}
private void updateUserSwitcherFlags() {
mKeyguardUserSwitcherEnabled = mResources.getBoolean(
com.android.internal.R.bool.config_keyguardUserSwitcher);
mKeyguardQsUserSwitchEnabled =
mKeyguardUserSwitcherEnabled && mResources.getBoolean(
R.bool.config_keyguard_user_switch_opens_qs_details);
}
private void registerSettingsChangeListener() {
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.USER_SWITCHER_ENABLED),
/* notifyForDescendants */ false,
mSettingsChangeObserver
);
}
private void unregisterSettingsChangeListener() {
mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
}
private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
@Override
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
@@ -4207,6 +4240,15 @@ public class NotificationPanelViewController extends PanelViewController {
reInflateViews();
}
@Override
public void onSmallestScreenWidthChanged() {
if (DEBUG) Log.d(TAG, "onSmallestScreenWidthChanged");
// Can affect multi-user switcher visibility as it depends on screen size by default:
// it is enabled only for devices with large screens (see config_keyguardUserSwitcher)
reInflateViews();
}
@Override
public void onOverlayChanged() {
if (DEBUG) Log.d(TAG, "onOverlayChanged");
@@ -4220,6 +4262,21 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
private class SettingsChangeObserver extends ContentObserver {
SettingsChangeObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
if (DEBUG) Log.d(TAG, "onSettingsChanged");
// Can affect multi-user switcher visibility
reInflateViews();
}
}
private class StatusBarStateListener implements StateListener {
@Override
public void onStateChanged(int statusBarState) {
@@ -4335,10 +4392,12 @@ public class NotificationPanelViewController extends PanelViewController {
mConfigurationListener.onThemeChanged();
mFalsingManager.addTapListener(mFalsingTapListener);
mKeyguardIndicationController.init();
registerSettingsChangeListener();
}
@Override
public void onViewDetachedFromWindow(View v) {
unregisterSettingsChangeListener();
mFragmentService.getFragmentHostManager(mView)
.removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);

View File

@@ -33,6 +33,7 @@ public interface ConfigurationController extends CallbackController<Configuratio
interface ConfigurationListener {
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
default void onSmallestScreenWidthChanged() {}
default void onOverlayChanged() {}
default void onUiModeChanged() {}
default void onThemeChanged() {}

View File

@@ -28,9 +28,12 @@ import static com.android.systemui.statusbar.notification.ViewGroupFadeHelper.re
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -40,9 +43,13 @@ import static org.mockito.Mockito.when;
import android.annotation.IdRes;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserManager;
import android.testing.AndroidTestingRunner;
@@ -53,6 +60,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -63,6 +71,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
@@ -143,6 +152,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private KeyguardBottomAreaView mKeyguardBottomArea;
@Mock
private KeyguardBottomAreaView mQsFrame;
private KeyguardStatusView mKeyguardStatusView;
@Mock
private ViewGroup mBigClockContainer;
@Mock
@@ -156,6 +166,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private KeyguardStatusBarView mKeyguardStatusBar;
@Mock
private View mUserSwitcherView;
@Mock
private ViewStub mUserSwitcherStubView;
@Mock
private HeadsUpTouchHelper.Callback mHeadsUpCallback;
@Mock
private PanelBar mPanelBar;
@@ -207,7 +221,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private KeyguardClockSwitch mKeyguardClockSwitch;
private PanelViewController.TouchHandler mTouchHandler;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private MediaHierarchyManager mMediaHiearchyManager;
@@ -268,6 +281,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private SecureSettings mSecureSettings;
@Mock
private ContentResolver mContentResolver;
@Mock
private TapAgainViewController mTapAgainViewController;
@Mock
private KeyguardIndicationController mKeyguardIndicationController;
@@ -290,6 +305,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger);
mKeyguardStatusView = new KeyguardStatusView(mContext);
mKeyguardStatusView.setId(R.id.keyguard_status_view);
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources);
@@ -304,6 +322,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mResources.getDimensionPixelSize(R.dimen.notification_panel_width)).thenReturn(400);
when(mView.getContext()).thenReturn(getContext());
when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn(
mUserSwitcherStubView);
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
when(mView.findViewById(R.id.notification_stack_scroller))
.thenReturn(mNotificationStackScrollLayout);
@@ -323,7 +344,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
mNotificationContainerParent.addView(mKeyguardStatusView);
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
@@ -351,6 +372,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mFalsingManager,
mLockscreenShadeTransitionController,
new FalsingCollectorFake());
mConfigurationController = new ConfigurationControllerImpl(mContext);
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -361,10 +383,16 @@ public class NotificationPanelViewTest extends SysuiTestCase {
.thenReturn(mKeyguardStatusBarViewComponent);
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
.thenReturn(mKeyguardStatusView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
.thenReturn(mKeyguardBottomArea);
reset(mView);
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
new Handler(Looper.getMainLooper()),
mLayoutInflater,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
@@ -398,6 +426,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mTapAgainViewController,
mNavigationModeController,
mFragmentService,
mContentResolver,
mQuickAccessWalletController,
new FakeExecutor(new FakeSystemClock()),
mSecureSettings,
@@ -551,6 +580,38 @@ public class NotificationPanelViewTest extends SysuiTestCase {
.isEqualTo(R.id.qs_edge_guideline);
}
@Test
public void testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() {
givenViewAttached();
when(mResources.getBoolean(
com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
updateMultiUserSetting(true);
clearInvocations(mView);
updateMultiUserSetting(false);
ArgumentCaptor<View> captor = ArgumentCaptor.forClass(View.class);
verify(mView, atLeastOnce()).addView(captor.capture(), anyInt());
final View userSwitcherStub = CollectionUtils.find(captor.getAllValues(),
view -> view.getId() == R.id.keyguard_user_switcher_stub);
assertThat(userSwitcherStub).isNotNull();
assertThat(userSwitcherStub).isInstanceOf(ViewStub.class);
}
@Test
public void testChangeSmallestScreenWidthAndUserSwitchEnabled_inflatesUserSwitchView() {
givenViewAttached();
when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(null);
updateSmallestScreenWidth(300);
when(mResources.getBoolean(
com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
when(mUserManager.isUserSwitcherEnabled()).thenReturn(true);
updateSmallestScreenWidth(800);
verify(mUserSwitcherStubView).inflate();
}
@Test
public void testSplitShadeLayout_isAlignedToGuideline() {
enableSplitShade();
@@ -717,6 +778,12 @@ public class NotificationPanelViewTest extends SysuiTestCase {
return mFalsingManager.getTapListeners().get(0);
}
private void givenViewAttached() {
for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
listener.onViewAttachedToWindow(mView);
}
}
private View newViewWithId(int id) {
View view = new View(mContext);
view.setId(id);
@@ -739,6 +806,21 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mNotificationPanelViewController.updateResources();
}
private void updateMultiUserSetting(boolean enabled) {
when(mUserManager.isUserSwitcherEnabled()).thenReturn(enabled);
final ArgumentCaptor<ContentObserver> observerCaptor =
ArgumentCaptor.forClass(ContentObserver.class);
verify(mContentResolver)
.registerContentObserver(any(), anyBoolean(), observerCaptor.capture());
observerCaptor.getValue().onChange(/* selfChange */ false);
}
private void updateSmallestScreenWidth(int smallestScreenWidthDp) {
Configuration configuration = new Configuration();
configuration.smallestScreenWidthDp = smallestScreenWidthDp;
mConfigurationController.onConfigurationChanged(configuration);
}
private void onTouchEvent(MotionEvent ev) {
mTouchHandler.onTouch(mView, ev);
}