From c529723fa8e11f8293447c080b7c06cc6ee63017 Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Fri, 11 Feb 2022 17:42:13 +0000 Subject: [PATCH] User Switcher: Dynamically set max col We want to even out number of user tiles on each row. Fixes: 218310680 Test: Manual Change-Id: I5876867b0c6d9a6ab2a0dd363d8aa5881dfc5cb5 --- .../SystemUI/res-keyguard/values/dimens.xml | 1 + .../res/layout/user_switcher_fullscreen.xml | 7 +- .../layout/user_switcher_fullscreen_item.xml | 4 +- .../systemui/user/UserSwitcherActivity.kt | 51 +++++++++--- .../systemui/user/UserSwitcherActivityTest.kt | 77 +++++++++++++++++++ 5 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index dad4c19799afb..b98f41329c8fd 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -123,6 +123,7 @@ 190dp 222dp + 64dp 8dp 14sp 12dp diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml index 2d883bc1477fd..6bb6c2d9877c7 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"> diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml index 3319442a1a685..a3d9a69e73c5f 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 @@ + android:layout_width="@dimen/bouncer_user_switcher_icon_size_plus_margin" + android:layout_height="@dimen/bouncer_user_switcher_icon_size_plus_margin" /> + !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(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(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 0000000000000..d4be881020e15 --- /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) + } +}