diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java index 94d90a8eb0286..91d7388bc46d1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java @@ -176,6 +176,10 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback { return this; } + public boolean isEmpty() { + return getUserIcon() == null && getUserDrawable() == null; + } + public UserIconDrawable setBadge(Drawable badge) { mBadge = badge; if (mBadge != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java index c404cf69f1a8f..1b93c16dd45c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java @@ -137,4 +137,8 @@ public class UserAvatarView extends View { mDrawable.setIconDrawable(d); mDrawable.setBadgeIfManagedUser(getContext(), userId); } + + public boolean isEmpty() { + return mDrawable.isEmpty(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java index e8bf89a6a90a4..2a9048a6eb739 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -29,6 +29,7 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardVisibilityHelper; @@ -36,7 +37,6 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherScope; import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.user.UserSwitchDialogController; @@ -68,7 +68,6 @@ public class KeyguardQsUserSwitchController extends ViewController private final Context mContext; private Resources mResources; private final UserSwitcherController mUserSwitcherController; - private final ScreenLifecycle mScreenLifecycle; private UserSwitcherController.BaseUserAdapter mAdapter; private final KeyguardStateController mKeyguardStateController; private final FalsingManager mFalsingManager; @@ -77,8 +76,10 @@ public class KeyguardQsUserSwitchController extends ViewController private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; private final UserSwitchDialogController mUserSwitchDialogController; private final UiEventLogger mUiEventLogger; - private UserAvatarView mUserAvatarView; + @VisibleForTesting + UserAvatarView mUserAvatarView; UserSwitcherController.UserRecord mCurrentUser; + private boolean mIsKeyguardShowing; // State info for the user switch and keyguard private int mBarState; @@ -87,8 +88,6 @@ public class KeyguardQsUserSwitchController extends ViewController new StatusBarStateController.StateListener() { @Override public void onStateChanged(int newState) { - if (DEBUG) Log.d(TAG, String.format("onStateChanged: newState=%d", newState)); - boolean goingToFullShade = mStatusBarStateController.goingToFullShade(); boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway(); int oldState = mBarState; @@ -102,12 +101,34 @@ public class KeyguardQsUserSwitchController extends ViewController } }; - private ConfigurationController.ConfigurationListener - mConfigurationListener = new ConfigurationController.ConfigurationListener() { + private ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { @Override public void onUiModeChanged() { - updateView(true); + // Force update when dark theme toggled. Otherwise, icon will not update + // until it is clicked + if (mIsKeyguardShowing) { + updateView(); + } + } + }; + + private final KeyguardStateController.Callback mKeyguardStateCallback = + new KeyguardStateController.Callback() { + @Override + public void onUnlockedChanged() { + updateKeyguardShowing(false /* forceViewUpdate */); + } + + @Override + public void onKeyguardShowingChanged() { + updateKeyguardShowing(false /* forceViewUpdate */); + } + + @Override + public void onKeyguardFadingAwayChanged() { + updateKeyguardShowing(false /* forceViewUpdate */); } }; @@ -116,7 +137,6 @@ public class KeyguardQsUserSwitchController extends ViewController FrameLayout view, Context context, @Main Resources resources, - ScreenLifecycle screenLifecycle, UserSwitcherController userSwitcherController, KeyguardStateController keyguardStateController, FalsingManager falsingManager, @@ -130,7 +150,6 @@ public class KeyguardQsUserSwitchController extends ViewController if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController"); mContext = context; mResources = resources; - mScreenLifecycle = screenLifecycle; mUserSwitcherController = userSwitcherController; mKeyguardStateController = keyguardStateController; mFalsingManager = falsingManager; @@ -188,7 +207,10 @@ public class KeyguardQsUserSwitchController extends ViewController mDataSetObserver.onChanged(); mStatusBarStateController.addCallback(mStatusBarStateListener); mConfigurationController.addCallback(mConfigurationListener); - updateView(true /* forceUpdate */); + mKeyguardStateController.addCallback(mKeyguardStateCallback); + // Force update when view attached in case configuration changed while the view was detached + updateCurrentUser(); + updateKeyguardShowing(true /* forceViewUpdate */); } @Override @@ -198,15 +220,48 @@ public class KeyguardQsUserSwitchController extends ViewController mAdapter.unregisterDataSetObserver(mDataSetObserver); mStatusBarStateController.removeCallback(mStatusBarStateListener); mConfigurationController.removeCallback(mConfigurationListener); + mKeyguardStateController.removeCallback(mKeyguardStateCallback); } public final DataSetObserver mDataSetObserver = new DataSetObserver() { @Override public void onChanged() { - updateView(false /* forceUpdate */); + boolean userChanged = updateCurrentUser(); + if (userChanged || (mIsKeyguardShowing && mUserAvatarView.isEmpty())) { + updateView(); + } } }; + private void clearAvatar() { + if (DEBUG) Log.d(TAG, "clearAvatar"); + mUserAvatarView.setAvatar(null); + } + + /** + * @param forceViewUpdate whether view should be updated regardless of whether + * keyguard-showing state changed + */ + @VisibleForTesting + void updateKeyguardShowing(boolean forceViewUpdate) { + boolean wasKeyguardShowing = mIsKeyguardShowing; + mIsKeyguardShowing = mKeyguardStateController.isShowing() + || mKeyguardStateController.isKeyguardGoingAway(); + if (wasKeyguardShowing == mIsKeyguardShowing && !forceViewUpdate) { + return; + } + if (DEBUG) { + Log.d(TAG, "updateKeyguardShowing:" + + " mIsKeyguardShowing=" + mIsKeyguardShowing + + " forceViewUpdate=" + forceViewUpdate); + } + if (mIsKeyguardShowing) { + updateView(); + } else { + clearAvatar(); + } + } + /** * @return true if the current user has changed */ @@ -223,31 +278,22 @@ public class KeyguardQsUserSwitchController extends ViewController return mCurrentUser == null && previousUser != null; } - /** - * @param forceUpdate whether to update view even if current user did not change - */ - private void updateView(boolean forceUpdate) { - if (!updateCurrentUser() && !forceUpdate) { - return; - } - - String contentDescription = null; - if (mCurrentUser != null && mCurrentUser.info != null && !TextUtils.isEmpty( - mCurrentUser.info.name)) { + private String getContentDescription() { + if (mCurrentUser != null && mCurrentUser.info != null + && !TextUtils.isEmpty(mCurrentUser.info.name)) { // If we know the current user's name, have TalkBack to announce "Signed in as [user // name]" when the icon is selected - contentDescription = mContext.getString(R.string.accessibility_quick_settings_user, - mCurrentUser.info.name); + return mContext.getString( + R.string.accessibility_quick_settings_user, mCurrentUser.info.name); } else { // As a fallback, have TalkBack announce "Switch user" - contentDescription = mContext.getString( - R.string.accessibility_multi_user_switch_switcher); - } - - if (!TextUtils.equals(mUserAvatarView.getContentDescription(), contentDescription)) { - mUserAvatarView.setContentDescription(contentDescription); + return mContext.getString(R.string.accessibility_multi_user_switch_switcher); } + } + private void updateView() { + if (DEBUG) Log.d(TAG, "updateView"); + mUserAvatarView.setContentDescription(getContentDescription()); int userId = mCurrentUser != null ? mCurrentUser.resolveId() : UserHandle.USER_NULL; mUserAvatarView.setDrawableWithBadge(getCurrentUserIcon().mutate(), userId); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt index f58403d3651a1..b4f3987b2f957 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt @@ -26,13 +26,13 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.UiEventLogger import com.android.systemui.R import com.android.systemui.SysuiTestCase -import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.user.UserSwitchDialogController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.LockscreenGestureLogger import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before import org.junit.Test @@ -47,9 +47,6 @@ import org.mockito.MockitoAnnotations @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner::class) class KeyguardQsUserSwitchControllerTest : SysuiTestCase() { - @Mock - private lateinit var screenLifecycle: ScreenLifecycle - @Mock private lateinit var userSwitcherController: UserSwitcherController @@ -93,7 +90,6 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() { view, context, context.resources, - screenLifecycle, userSwitcherController, keyguardStateController, falsingManager, @@ -108,6 +104,8 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() { testableLooper.processAllMessages() `when`(userSwitcherController.keyguardStateController).thenReturn(keyguardStateController) `when`(userSwitcherController.keyguardStateController.isShowing).thenReturn(true) + `when`(keyguardStateController.isShowing).thenReturn(true) + `when`(keyguardStateController.isKeyguardGoingAway).thenReturn(false) keyguardQsUserSwitchController.init() } @@ -122,4 +120,28 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() { verify(uiEventLogger, times(1)) .log(LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_SWITCH_USER_TAP) } + + @Test + fun testAvatarExistsWhenKeyguardGoingAway() { + `when`(keyguardStateController.isShowing).thenReturn(false) + `when`(keyguardStateController.isKeyguardGoingAway).thenReturn(true) + keyguardQsUserSwitchController.updateKeyguardShowing(true /* forceViewUpdate */) + assertThat(keyguardQsUserSwitchController.mUserAvatarView.isEmpty).isFalse() + } + + @Test + fun testAvatarExistsWhenKeyguardShown() { + `when`(keyguardStateController.isShowing).thenReturn(true) + `when`(keyguardStateController.isKeyguardGoingAway).thenReturn(false) + keyguardQsUserSwitchController.updateKeyguardShowing(true /* forceViewUpdate */) + assertThat(keyguardQsUserSwitchController.mUserAvatarView.isEmpty).isFalse() + } + + @Test + fun testAvatarGoneWhenKeyguardGone() { + `when`(keyguardStateController.isShowing).thenReturn(false) + `when`(keyguardStateController.isKeyguardGoingAway).thenReturn(false) + keyguardQsUserSwitchController.updateKeyguardShowing(true /* forceViewUpdate */) + assertThat(keyguardQsUserSwitchController.mUserAvatarView.isEmpty).isTrue() + } }