Loading packages/SystemUI/res-keyguard/values/dimens.xml +1 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ <dimen name="bouncer_user_switcher_icon_size">190dp</dimen> <dimen name="bouncer_user_switcher_icon_size_plus_margin">222dp</dimen> <dimen name="user_switcher_fullscreen_horizontal_gap">64dp</dimen> <dimen name="user_switcher_icon_selected_width">8dp</dimen> <dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen> <dimen name="user_switcher_fullscreen_button_padding">12dp</dimen> Loading packages/SystemUI/res/layout/user_switcher_fullscreen.xml +3 −4 Original line number Diff line number Diff line Loading @@ -21,9 +21,8 @@ android:id="@+id/user_switcher_root" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="40dp" android:layout_marginEnd="60dp" android:layout_marginStart="60dp"> android:layout_marginVertical="40dp" android:layout_marginHorizontal="60dp"> <androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" Loading @@ -36,7 +35,7 @@ app:flow_horizontalBias="0.5" app:flow_verticalAlign="center" app:flow_wrapMode="chain" app:flow_horizontalGap="64dp" app:flow_horizontalGap="@dimen/user_switcher_fullscreen_horizontal_gap" app:flow_verticalGap="44dp" app:flow_horizontalStyle="packed"/> Loading packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml +2 −2 Original line number Diff line number Diff line Loading @@ -21,8 +21,8 @@ <ImageView android:id="@+id/user_switcher_icon" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_width="@dimen/bouncer_user_switcher_icon_size_plus_margin" android:layout_height="@dimen/bouncer_user_switcher_icon_size_plus_margin" /> <TextView style="@style/Bouncer.UserSwitcher.Spinner.Item" android:id="@+id/user_switcher_text" Loading packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +42 −9 Original line number Diff line number Diff line Loading @@ -35,9 +35,8 @@ import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.ImageView import android.widget.TextView import androidx.constraintlayout.helper.widget.Flow import com.android.internal.annotations.VisibleForTesting import com.android.internal.util.UserIcons import com.android.settingslib.Utils import com.android.systemui.R Loading @@ -47,12 +46,12 @@ import com.android.systemui.plugins.FalsingManager.LOW_PENALTY import com.android.systemui.statusbar.phone.ShadeController import com.android.systemui.statusbar.policy.UserSwitcherController import com.android.systemui.statusbar.policy.UserSwitcherController.BaseUserAdapter import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord import com.android.systemui.util.LifecycleActivity import javax.inject.Inject import kotlin.math.ceil private const val USER_VIEW = "user_view" Loading Loading @@ -137,6 +136,18 @@ class UserSwitcherActivity @Inject constructor( return UserIcons.getDefaultUserIcon(resources, item.info.id, false) } fun getTotalUserViews(): Int { return users.count { item -> !doNotRenderUserView(item) } } fun doNotRenderUserView(item: UserRecord): Boolean { return item.isAddUser || item.isAddSupervisedUser || item.isGuest && item.info == null } private fun getDrawable(item: UserRecord): Drawable { var drawable = if (item.isCurrent && item.isGuest) { getDrawable(R.drawable.ic_avatar_guest_user) Loading Loading @@ -211,7 +222,8 @@ class UserSwitcherActivity @Inject constructor( userSwitcherController.init(parent) initBroadcastReceiver() buildUserViews() parent.post { buildUserViews() } } private fun showPopupMenu() { Loading Loading @@ -272,16 +284,32 @@ class UserSwitcherActivity @Inject constructor( } parent.removeViews(start, count) addUserRecords.clear() val flow = requireViewById<Flow>(R.id.flow) val totalWidth = parent.width val userViewCount = adapter.getTotalUserViews() val maxColumns = getMaxColumns(userViewCount) val horizontalGap = resources .getDimensionPixelSize(R.dimen.user_switcher_fullscreen_horizontal_gap) val totalWidthOfHorizontalGap = (maxColumns - 1) * horizontalGap val maxWidgetDiameter = (totalWidth - totalWidthOfHorizontalGap) / maxColumns flow.setMaxElementsWrap(maxColumns) for (i in 0 until adapter.getCount()) { val item = adapter.getItem(i) if (item.isAddUser || item.isAddSupervisedUser || item.isGuest && item.info == null) { if (adapter.doNotRenderUserView(item)) { addUserRecords.add(item) } else { val userView = adapter.getView(i, null, parent) userView.requireViewById<ImageView>(R.id.user_switcher_icon).apply { val lp = layoutParams if (maxWidgetDiameter < lp.width) { lp.width = maxWidgetDiameter lp.height = maxWidgetDiameter layoutParams = lp } } userView.setId(View.generateViewId()) parent.addView(userView) Loading Loading @@ -333,6 +361,11 @@ class UserSwitcherActivity @Inject constructor( broadcastDispatcher.registerReceiver(broadcastReceiver, filter) } @VisibleForTesting fun getMaxColumns(userCount: Int): Int { return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt() } private class ItemAdapter( val parentContext: Context, val resource: Int, Loading packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.user import android.os.UserManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.LayoutInflater import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.phone.ShadeController import com.android.systemui.statusbar.policy.UserSwitcherController import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) @RunWithLooper(setAsMainLooper = true) class UserSwitcherActivityTest : SysuiTestCase() { @Mock private lateinit var activity: UserSwitcherActivity @Mock private lateinit var userSwitcherController: UserSwitcherController @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var layoutInflater: LayoutInflater @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var userManager: UserManager @Mock private lateinit var shadeController: ShadeController @Before fun setUp() { MockitoAnnotations.initMocks(this) activity = UserSwitcherActivity( userSwitcherController, broadcastDispatcher, layoutInflater, falsingManager, userManager, shadeController ) } @Test fun testMaxColumns() { assertThat(activity.getMaxColumns(3)).isEqualTo(4) assertThat(activity.getMaxColumns(4)).isEqualTo(4) assertThat(activity.getMaxColumns(5)).isEqualTo(3) assertThat(activity.getMaxColumns(6)).isEqualTo(3) assertThat(activity.getMaxColumns(7)).isEqualTo(4) assertThat(activity.getMaxColumns(9)).isEqualTo(5) } } Loading
packages/SystemUI/res-keyguard/values/dimens.xml +1 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ <dimen name="bouncer_user_switcher_icon_size">190dp</dimen> <dimen name="bouncer_user_switcher_icon_size_plus_margin">222dp</dimen> <dimen name="user_switcher_fullscreen_horizontal_gap">64dp</dimen> <dimen name="user_switcher_icon_selected_width">8dp</dimen> <dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen> <dimen name="user_switcher_fullscreen_button_padding">12dp</dimen> Loading
packages/SystemUI/res/layout/user_switcher_fullscreen.xml +3 −4 Original line number Diff line number Diff line Loading @@ -21,9 +21,8 @@ android:id="@+id/user_switcher_root" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="40dp" android:layout_marginEnd="60dp" android:layout_marginStart="60dp"> android:layout_marginVertical="40dp" android:layout_marginHorizontal="60dp"> <androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" Loading @@ -36,7 +35,7 @@ app:flow_horizontalBias="0.5" app:flow_verticalAlign="center" app:flow_wrapMode="chain" app:flow_horizontalGap="64dp" app:flow_horizontalGap="@dimen/user_switcher_fullscreen_horizontal_gap" app:flow_verticalGap="44dp" app:flow_horizontalStyle="packed"/> Loading
packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml +2 −2 Original line number Diff line number Diff line Loading @@ -21,8 +21,8 @@ <ImageView android:id="@+id/user_switcher_icon" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_width="@dimen/bouncer_user_switcher_icon_size_plus_margin" android:layout_height="@dimen/bouncer_user_switcher_icon_size_plus_margin" /> <TextView style="@style/Bouncer.UserSwitcher.Spinner.Item" android:id="@+id/user_switcher_text" Loading
packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +42 −9 Original line number Diff line number Diff line Loading @@ -35,9 +35,8 @@ import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.ImageView import android.widget.TextView import androidx.constraintlayout.helper.widget.Flow import com.android.internal.annotations.VisibleForTesting import com.android.internal.util.UserIcons import com.android.settingslib.Utils import com.android.systemui.R Loading @@ -47,12 +46,12 @@ import com.android.systemui.plugins.FalsingManager.LOW_PENALTY import com.android.systemui.statusbar.phone.ShadeController import com.android.systemui.statusbar.policy.UserSwitcherController import com.android.systemui.statusbar.policy.UserSwitcherController.BaseUserAdapter import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord import com.android.systemui.util.LifecycleActivity import javax.inject.Inject import kotlin.math.ceil private const val USER_VIEW = "user_view" Loading Loading @@ -137,6 +136,18 @@ class UserSwitcherActivity @Inject constructor( return UserIcons.getDefaultUserIcon(resources, item.info.id, false) } fun getTotalUserViews(): Int { return users.count { item -> !doNotRenderUserView(item) } } fun doNotRenderUserView(item: UserRecord): Boolean { return item.isAddUser || item.isAddSupervisedUser || item.isGuest && item.info == null } private fun getDrawable(item: UserRecord): Drawable { var drawable = if (item.isCurrent && item.isGuest) { getDrawable(R.drawable.ic_avatar_guest_user) Loading Loading @@ -211,7 +222,8 @@ class UserSwitcherActivity @Inject constructor( userSwitcherController.init(parent) initBroadcastReceiver() buildUserViews() parent.post { buildUserViews() } } private fun showPopupMenu() { Loading Loading @@ -272,16 +284,32 @@ class UserSwitcherActivity @Inject constructor( } parent.removeViews(start, count) addUserRecords.clear() val flow = requireViewById<Flow>(R.id.flow) val totalWidth = parent.width val userViewCount = adapter.getTotalUserViews() val maxColumns = getMaxColumns(userViewCount) val horizontalGap = resources .getDimensionPixelSize(R.dimen.user_switcher_fullscreen_horizontal_gap) val totalWidthOfHorizontalGap = (maxColumns - 1) * horizontalGap val maxWidgetDiameter = (totalWidth - totalWidthOfHorizontalGap) / maxColumns flow.setMaxElementsWrap(maxColumns) for (i in 0 until adapter.getCount()) { val item = adapter.getItem(i) if (item.isAddUser || item.isAddSupervisedUser || item.isGuest && item.info == null) { if (adapter.doNotRenderUserView(item)) { addUserRecords.add(item) } else { val userView = adapter.getView(i, null, parent) userView.requireViewById<ImageView>(R.id.user_switcher_icon).apply { val lp = layoutParams if (maxWidgetDiameter < lp.width) { lp.width = maxWidgetDiameter lp.height = maxWidgetDiameter layoutParams = lp } } userView.setId(View.generateViewId()) parent.addView(userView) Loading Loading @@ -333,6 +361,11 @@ class UserSwitcherActivity @Inject constructor( broadcastDispatcher.registerReceiver(broadcastReceiver, filter) } @VisibleForTesting fun getMaxColumns(userCount: Int): Int { return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt() } private class ItemAdapter( val parentContext: Context, val resource: Int, Loading
packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.user import android.os.UserManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.LayoutInflater import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.phone.ShadeController import com.android.systemui.statusbar.policy.UserSwitcherController import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) @RunWithLooper(setAsMainLooper = true) class UserSwitcherActivityTest : SysuiTestCase() { @Mock private lateinit var activity: UserSwitcherActivity @Mock private lateinit var userSwitcherController: UserSwitcherController @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var layoutInflater: LayoutInflater @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var userManager: UserManager @Mock private lateinit var shadeController: ShadeController @Before fun setUp() { MockitoAnnotations.initMocks(this) activity = UserSwitcherActivity( userSwitcherController, broadcastDispatcher, layoutInflater, falsingManager, userManager, shadeController ) } @Test fun testMaxColumns() { assertThat(activity.getMaxColumns(3)).isEqualTo(4) assertThat(activity.getMaxColumns(4)).isEqualTo(4) assertThat(activity.getMaxColumns(5)).isEqualTo(3) assertThat(activity.getMaxColumns(6)).isEqualTo(3) assertThat(activity.getMaxColumns(7)).isEqualTo(4) assertThat(activity.getMaxColumns(9)).isEqualTo(5) } }