diff options
5 files changed, 125 insertions, 15 deletions
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index dad4c19799af..b98f41329c8f 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -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> diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml index 2d883bc1477f..6bb6c2d9877c 100644 --- a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml +++ b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml @@ -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" @@ -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"/> diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml index 3319442a1a68..a3d9a69e73c5 100644 --- a/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml +++ b/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml @@ -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" diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt index 14585fb0f58e..c0d7925cf2bb 100644 --- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt @@ -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 @@ -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" @@ -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) @@ -211,7 +222,8 @@ class UserSwitcherActivity @Inject constructor( userSwitcherController.init(parent) initBroadcastReceiver() - buildUserViews() + + parent.post { buildUserViews() } } private fun showPopupMenu() { @@ -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) @@ -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, diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt new file mode 100644 index 000000000000..d4be881020e1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt @@ -0,0 +1,77 @@ +/* + * 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) + } +} |