Merge "New user switcher dialog" into sc-v2-dev am: 39615056a3
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16003855 Change-Id: I1603af3e6e7e135907d5bde9ab7a5bc7ac7f11a3
This commit is contained in:
20
packages/SystemUI/res/color/prv_color_surface.xml
Normal file
20
packages/SystemUI/res/color/prv_color_surface.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:color="?androidprv:attr/colorSurface" />
|
||||||
|
</selector>
|
||||||
20
packages/SystemUI/res/color/prv_text_color_on_accent.xml
Normal file
20
packages/SystemUI/res/color/prv_text_color_on_accent.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:color="?androidprv:attr/textColorOnAccent" />
|
||||||
|
</selector>
|
||||||
39
packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
Normal file
39
packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||||
|
android:insetTop="@dimen/qs_dialog_button_vertical_inset"
|
||||||
|
android:insetBottom="@dimen/qs_dialog_button_vertical_inset">
|
||||||
|
<ripple android:color="?android:attr/colorControlHighlight">
|
||||||
|
<item android:id="@android:id/mask">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@android:color/white"/>
|
||||||
|
<corners android:radius="?android:attr/buttonCornerRadius"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="?android:attr/buttonCornerRadius"/>
|
||||||
|
<solid android:color="?androidprv:attr/colorAccentPrimary"/>
|
||||||
|
<padding android:left="@dimen/qs_dialog_button_horizontal_padding"
|
||||||
|
android:top="@dimen/qs_dialog_button_vertical_padding"
|
||||||
|
android:right="@dimen/qs_dialog_button_horizontal_padding"
|
||||||
|
android:bottom="@dimen/qs_dialog_button_vertical_padding"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
</inset>
|
||||||
42
packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
Normal file
42
packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||||
|
android:insetTop="@dimen/qs_dialog_button_vertical_inset"
|
||||||
|
android:insetBottom="@dimen/qs_dialog_button_vertical_inset">
|
||||||
|
<ripple android:color="?android:attr/colorControlHighlight">
|
||||||
|
<item android:id="@android:id/mask">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@android:color/white"/>
|
||||||
|
<corners android:radius="?android:attr/buttonCornerRadius"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="?android:attr/buttonCornerRadius"/>
|
||||||
|
<solid android:color="@android:color/transparent"/>
|
||||||
|
<stroke android:color="?androidprv:attr/colorAccentPrimary"
|
||||||
|
android:width="1dp"
|
||||||
|
/>
|
||||||
|
<padding android:left="@dimen/qs_dialog_button_horizontal_padding"
|
||||||
|
android:top="@dimen/qs_dialog_button_vertical_padding"
|
||||||
|
android:right="@dimen/qs_dialog_button_horizontal_padding"
|
||||||
|
android:bottom="@dimen/qs_dialog_button_vertical_padding"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
</inset>
|
||||||
89
packages/SystemUI/res/layout/qs_user_dialog_content.xml
Normal file
89
packages/SystemUI/res/layout/qs_user_dialog_content.xml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:sysui="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="24dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="@drawable/qs_dialog_bg"
|
||||||
|
>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:text="@string/qs_user_switch_dialog_title"
|
||||||
|
android:textAppearance="@style/TextAppearance.QSDialog.Title"
|
||||||
|
android:layout_marginBottom="32dp"
|
||||||
|
sysui:layout_constraintTop_toTopOf="parent"
|
||||||
|
sysui:layout_constraintStart_toStartOf="parent"
|
||||||
|
sysui:layout_constraintEnd_toEndOf="parent"
|
||||||
|
sysui:layout_constraintBottom_toTopOf="@id/grid"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<com.android.systemui.qs.PseudoGridView
|
||||||
|
android:id="@+id/grid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="28dp"
|
||||||
|
sysui:verticalSpacing="4dp"
|
||||||
|
sysui:horizontalSpacing="4dp"
|
||||||
|
sysui:fixedChildWidth="80dp"
|
||||||
|
sysui:layout_constraintTop_toBottomOf="@id/title"
|
||||||
|
sysui:layout_constraintStart_toStartOf="parent"
|
||||||
|
sysui:layout_constraintEnd_toEndOf="parent"
|
||||||
|
sysui:layout_constraintBottom_toTopOf="@id/barrier"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Barrier
|
||||||
|
android:id="@+id/barrier"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
sysui:barrierDirection="top"
|
||||||
|
sysui:constraint_referenced_ids="settings,done"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/settings"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:text="@string/quick_settings_more_user_settings"
|
||||||
|
sysui:layout_constraintTop_toBottomOf="@id/barrier"
|
||||||
|
sysui:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
sysui:layout_constraintStart_toStartOf="parent"
|
||||||
|
sysui:layout_constraintEnd_toStartOf="@id/done"
|
||||||
|
sysui:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||||
|
style="@style/Widget.QSDialog.Button.BorderButton"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/done"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:text="@string/quick_settings_done"
|
||||||
|
sysui:layout_constraintTop_toBottomOf="@id/barrier"
|
||||||
|
sysui:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
sysui:layout_constraintStart_toEndOf="@id/settings"
|
||||||
|
sysui:layout_constraintEnd_toEndOf="parent"
|
||||||
|
style="@style/Widget.QSDialog.Button"
|
||||||
|
/>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
<attr name="numColumns" format="integer" />
|
<attr name="numColumns" format="integer" />
|
||||||
<attr name="verticalSpacing" format="dimension" />
|
<attr name="verticalSpacing" format="dimension" />
|
||||||
<attr name="horizontalSpacing" format="dimension" />
|
<attr name="horizontalSpacing" format="dimension" />
|
||||||
|
<attr name="fixedChildWidth" format="dimension" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<!-- Theme for icons in the status/nav bar (light/dark). background/fillColor is used for dual
|
<!-- Theme for icons in the status/nav bar (light/dark). background/fillColor is used for dual
|
||||||
|
|||||||
@@ -1639,4 +1639,9 @@
|
|||||||
<item name="communal_source_height_percentage" format="float" type="dimen">0.80</item>
|
<item name="communal_source_height_percentage" format="float" type="dimen">0.80</item>
|
||||||
|
|
||||||
<dimen name="drag_and_drop_icon_size">70dp</dimen>
|
<dimen name="drag_and_drop_icon_size">70dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="qs_dialog_button_horizontal_padding">16dp</dimen>
|
||||||
|
<dimen name="qs_dialog_button_vertical_padding">8dp</dimen>
|
||||||
|
<!-- The button will be 48dp tall, but the background needs to be 36dp tall -->
|
||||||
|
<dimen name="qs_dialog_button_vertical_inset">6dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -53,4 +53,6 @@
|
|||||||
<bool name="flag_smartspace_deduping">true</bool>
|
<bool name="flag_smartspace_deduping">true</bool>
|
||||||
|
|
||||||
<bool name="flag_combined_status_bar_signal_icons">false</bool>
|
<bool name="flag_combined_status_bar_signal_icons">false</bool>
|
||||||
|
|
||||||
|
<bool name="flag_new_user_switcher">true</bool>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -3026,4 +3026,7 @@
|
|||||||
<string name="see_all_networks">See all</string>
|
<string name="see_all_networks">See all</string>
|
||||||
<!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] -->
|
<!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] -->
|
||||||
<string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string>
|
<string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string>
|
||||||
|
|
||||||
|
<!-- Title for User Switch dialog. [CHAR LIMIT=20] -->
|
||||||
|
<string name="qs_user_switch_dialog_title">Select user</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -929,6 +929,39 @@
|
|||||||
<item name="actionDividerHeight">32dp</item>
|
<item name="actionDividerHeight">32dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.SystemUI.Dialog.QSDialog">
|
||||||
|
<item name="android:windowIsTranslucent">true</item>
|
||||||
|
<item name="android:windowBackground">@android:color/transparent</item>
|
||||||
|
<item name="android:windowIsFloating">true</item>
|
||||||
|
<item name="android:backgroundDimEnabled">true</item>
|
||||||
|
<item name="android:windowCloseOnTouchOutside">true</item>
|
||||||
|
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
|
||||||
|
<item name="android:dialogCornerRadius">28dp</item>
|
||||||
|
<item name="android:buttonCornerRadius">28dp</item>
|
||||||
|
<item name="android:colorBackground">@color/prv_color_surface</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.QSDialog.Title" parent="Theme.SystemUI.Dialog.QSDialog">
|
||||||
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
|
<item name="android:textSize">24sp</item>
|
||||||
|
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
|
||||||
|
<item name="android:lineHeight">32sp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.QSDialog.Button" parent = "Theme.SystemUI.Dialog.QSDialog">
|
||||||
|
<item name="android:background">@drawable/qs_dialog_btn_filled</item>
|
||||||
|
<item name="android:textColor">@color/prv_text_color_on_accent</item>
|
||||||
|
<item name="android:textSize">14sp</item>
|
||||||
|
<item name="android:lineHeight">20sp</item>
|
||||||
|
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
|
||||||
|
<item name="android:stateListAnimator">@null</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.QSDialog.Button.BorderButton">
|
||||||
|
<item name="android:background">@drawable/qs_dialog_btn_outline</item>
|
||||||
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="Theme.SystemUI.Dialog.Internet">
|
<style name="Theme.SystemUI.Dialog.Internet">
|
||||||
<item name="android:windowBackground">@drawable/internet_dialog_background</item>
|
<item name="android:windowBackground">@drawable/internet_dialog_background</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -192,6 +192,13 @@ public class FeatureFlags {
|
|||||||
return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
|
return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the new version of the user switcher
|
||||||
|
*/
|
||||||
|
public boolean useNewUserSwitcher() {
|
||||||
|
return mFlagReader.isEnabled(R.bool.flag_new_user_switcher);
|
||||||
|
}
|
||||||
|
|
||||||
/** static method for the system setting */
|
/** static method for the system setting */
|
||||||
public static boolean isProviderModelSettingEnabled(Context context) {
|
public static boolean isProviderModelSettingEnabled(Context context) {
|
||||||
return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
|
return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class PseudoGridView extends ViewGroup {
|
|||||||
private int mNumColumns = 3;
|
private int mNumColumns = 3;
|
||||||
private int mVerticalSpacing;
|
private int mVerticalSpacing;
|
||||||
private int mHorizontalSpacing;
|
private int mHorizontalSpacing;
|
||||||
|
private int mFixedChildWidth = -1;
|
||||||
|
|
||||||
public PseudoGridView(Context context, AttributeSet attrs) {
|
public PseudoGridView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@@ -53,6 +54,8 @@ public class PseudoGridView extends ViewGroup {
|
|||||||
mVerticalSpacing = a.getDimensionPixelSize(attr, 0);
|
mVerticalSpacing = a.getDimensionPixelSize(attr, 0);
|
||||||
} else if (attr == R.styleable.PseudoGridView_horizontalSpacing) {
|
} else if (attr == R.styleable.PseudoGridView_horizontalSpacing) {
|
||||||
mHorizontalSpacing = a.getDimensionPixelSize(attr, 0);
|
mHorizontalSpacing = a.getDimensionPixelSize(attr, 0);
|
||||||
|
} else if (attr == R.styleable.PseudoGridView_fixedChildWidth) {
|
||||||
|
mFixedChildWidth = a.getDimensionPixelSize(attr, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,8 +68,15 @@ public class PseudoGridView extends ViewGroup {
|
|||||||
throw new UnsupportedOperationException("Needs a maximum width");
|
throw new UnsupportedOperationException("Needs a maximum width");
|
||||||
}
|
}
|
||||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int childWidth;
|
||||||
int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
|
int necessarySpaceForChildWidth =
|
||||||
|
mFixedChildWidth * mNumColumns + mHorizontalSpacing * (mNumColumns - 1);
|
||||||
|
if (mFixedChildWidth != -1 && necessarySpaceForChildWidth <= width) {
|
||||||
|
childWidth = mFixedChildWidth;
|
||||||
|
width = mFixedChildWidth * mNumColumns + mHorizontalSpacing * (mNumColumns - 1);
|
||||||
|
} else {
|
||||||
|
childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
|
||||||
|
}
|
||||||
int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
|
int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
|
||||||
int childHeightSpec = MeasureSpec.UNSPECIFIED;
|
int childHeightSpec = MeasureSpec.UNSPECIFIED;
|
||||||
int totalHeight = 0;
|
int totalHeight = 0;
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import com.android.systemui.qs.PseudoGridView;
|
|||||||
import com.android.systemui.qs.QSUserSwitcherEvent;
|
import com.android.systemui.qs.QSUserSwitcherEvent;
|
||||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,6 +77,7 @@ public class UserDetailView extends PseudoGridView {
|
|||||||
private View mCurrentUserView;
|
private View mCurrentUserView;
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
private final FalsingManager mFalsingManager;
|
private final FalsingManager mFalsingManager;
|
||||||
|
private Consumer<UserSwitcherController.UserRecord> mClickCallback;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Adapter(Context context, UserSwitcherController controller,
|
public Adapter(Context context, UserSwitcherController controller,
|
||||||
@@ -92,6 +95,10 @@ public class UserDetailView extends PseudoGridView {
|
|||||||
return createUserDetailItemView(convertView, parent, item);
|
return createUserDetailItemView(convertView, parent, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void injectCallback(Consumer<UserSwitcherController.UserRecord> clickCallback) {
|
||||||
|
mClickCallback = clickCallback;
|
||||||
|
}
|
||||||
|
|
||||||
public UserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent,
|
public UserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent,
|
||||||
UserSwitcherController.UserRecord item) {
|
UserSwitcherController.UserRecord item) {
|
||||||
UserDetailItemView v = UserDetailItemView.convertOrInflate(
|
UserDetailItemView v = UserDetailItemView.convertOrInflate(
|
||||||
@@ -167,6 +174,13 @@ public class UserDetailView extends PseudoGridView {
|
|||||||
}
|
}
|
||||||
onUserListItemClicked(tag);
|
onUserListItemClicked(tag);
|
||||||
}
|
}
|
||||||
|
if (mClickCallback != null) {
|
||||||
|
mClickCallback.accept(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void linkToViewGroup(ViewGroup viewGroup) {
|
||||||
|
PseudoGridView.ViewGroupAdapterBridge.link(viewGroup, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.qs.user
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import android.view.WindowManager
|
||||||
|
import com.android.systemui.qs.PseudoGridView
|
||||||
|
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||||
|
import com.android.systemui.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog for switching users or creating new ones.
|
||||||
|
*/
|
||||||
|
class UserDialog(
|
||||||
|
context: Context
|
||||||
|
) : SystemUIDialog(context, R.style.Theme_SystemUI_Dialog_QSDialog) {
|
||||||
|
|
||||||
|
// create() is no-op after creation
|
||||||
|
private lateinit var _doneButton: View
|
||||||
|
/**
|
||||||
|
* Button with text "Done" in dialog.
|
||||||
|
*/
|
||||||
|
val doneButton: View
|
||||||
|
get() {
|
||||||
|
create()
|
||||||
|
return _doneButton
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var _settingsButton: View
|
||||||
|
/**
|
||||||
|
* Button with text "User Settings" in dialog.
|
||||||
|
*/
|
||||||
|
val settingsButton: View
|
||||||
|
get() {
|
||||||
|
create()
|
||||||
|
return _settingsButton
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var _grid: PseudoGridView
|
||||||
|
/**
|
||||||
|
* Grid to populate with user avatar from adapter
|
||||||
|
*/
|
||||||
|
val grid: ViewGroup
|
||||||
|
get() {
|
||||||
|
create()
|
||||||
|
return _grid
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
window?.apply {
|
||||||
|
setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
|
||||||
|
attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
|
||||||
|
attributes.receiveInsetsIgnoringZOrder = true
|
||||||
|
setLayout(
|
||||||
|
context.resources.getDimensionPixelSize(R.dimen.qs_panel_width),
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
setGravity(Gravity.CENTER)
|
||||||
|
}
|
||||||
|
setContentView(R.layout.qs_user_dialog_content)
|
||||||
|
|
||||||
|
_doneButton = requireViewById(R.id.done)
|
||||||
|
_settingsButton = requireViewById(R.id.settings)
|
||||||
|
_grid = requireViewById(R.id.grid)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.qs.user
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
|
import com.android.systemui.plugins.FalsingManager
|
||||||
|
import com.android.systemui.qs.tiles.UserDetailView
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Provider
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for [UserDialog].
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class UserSwitchDialogController @VisibleForTesting constructor(
|
||||||
|
private val userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>,
|
||||||
|
private val activityStarter: ActivityStarter,
|
||||||
|
private val falsingManager: FalsingManager,
|
||||||
|
private val dialogFactory: (Context) -> UserDialog
|
||||||
|
) {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>,
|
||||||
|
activityStarter: ActivityStarter,
|
||||||
|
falsingManager: FalsingManager
|
||||||
|
) : this(
|
||||||
|
userDetailViewAdapterProvider,
|
||||||
|
activityStarter,
|
||||||
|
falsingManager,
|
||||||
|
{ UserDialog(it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val USER_SETTINGS_INTENT = Intent(Settings.ACTION_USER_SETTINGS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a [UserDialog].
|
||||||
|
*
|
||||||
|
* Populate the dialog with information from and adapter obtained from
|
||||||
|
* [userDetailViewAdapterProvider] and show it as launched from [view].
|
||||||
|
*/
|
||||||
|
fun showDialog(view: View) {
|
||||||
|
with(dialogFactory(view.context)) {
|
||||||
|
setShowForAllUsers(true)
|
||||||
|
setCanceledOnTouchOutside(true)
|
||||||
|
create() // Needs to be called before we can retrieve views
|
||||||
|
|
||||||
|
settingsButton.setOnClickListener {
|
||||||
|
if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
|
||||||
|
activityStarter.postStartActivityDismissingKeyguard(USER_SETTINGS_INTENT, 0)
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
doneButton.setOnClickListener { dismiss() }
|
||||||
|
|
||||||
|
val adapter = userDetailViewAdapterProvider.get()
|
||||||
|
adapter.injectCallback {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
adapter.linkToViewGroup(grid)
|
||||||
|
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,11 +23,13 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.plugins.qs.DetailAdapter;
|
import com.android.systemui.plugins.qs.DetailAdapter;
|
||||||
import com.android.systemui.qs.FooterActionsView;
|
import com.android.systemui.qs.FooterActionsView;
|
||||||
import com.android.systemui.qs.QSDetailDisplayer;
|
import com.android.systemui.qs.QSDetailDisplayer;
|
||||||
import com.android.systemui.qs.dagger.QSScope;
|
import com.android.systemui.qs.dagger.QSScope;
|
||||||
|
import com.android.systemui.qs.user.UserSwitchDialogController;
|
||||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
import com.android.systemui.util.ViewController;
|
import com.android.systemui.util.ViewController;
|
||||||
|
|
||||||
@@ -39,6 +41,8 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
|
|||||||
private final UserSwitcherController mUserSwitcherController;
|
private final UserSwitcherController mUserSwitcherController;
|
||||||
private final QSDetailDisplayer mQsDetailDisplayer;
|
private final QSDetailDisplayer mQsDetailDisplayer;
|
||||||
private final FalsingManager mFalsingManager;
|
private final FalsingManager mFalsingManager;
|
||||||
|
private final UserSwitchDialogController mUserSwitchDialogController;
|
||||||
|
private final FeatureFlags mFeatureFlags;
|
||||||
|
|
||||||
private UserSwitcherController.BaseUserAdapter mUserListener;
|
private UserSwitcherController.BaseUserAdapter mUserListener;
|
||||||
|
|
||||||
@@ -49,6 +53,9 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mFeatureFlags.useNewUserSwitcher()) {
|
||||||
|
mUserSwitchDialogController.showDialog(v);
|
||||||
|
} else {
|
||||||
View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView;
|
View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView;
|
||||||
|
|
||||||
int[] tmpInt = new int[2];
|
int[] tmpInt = new int[2];
|
||||||
@@ -58,6 +65,7 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
|
|||||||
|
|
||||||
mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
|
mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@QSScope
|
@QSScope
|
||||||
@@ -66,31 +74,40 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
|
|||||||
private final UserSwitcherController mUserSwitcherController;
|
private final UserSwitcherController mUserSwitcherController;
|
||||||
private final QSDetailDisplayer mQsDetailDisplayer;
|
private final QSDetailDisplayer mQsDetailDisplayer;
|
||||||
private final FalsingManager mFalsingManager;
|
private final FalsingManager mFalsingManager;
|
||||||
|
private final UserSwitchDialogController mUserSwitchDialogController;
|
||||||
|
private final FeatureFlags mFeatureFlags;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Factory(UserManager userManager, UserSwitcherController userSwitcherController,
|
public Factory(UserManager userManager, UserSwitcherController userSwitcherController,
|
||||||
QSDetailDisplayer qsDetailDisplayer, FalsingManager falsingManager) {
|
QSDetailDisplayer qsDetailDisplayer, FalsingManager falsingManager,
|
||||||
|
UserSwitchDialogController userSwitchDialogController,
|
||||||
|
FeatureFlags featureFlags) {
|
||||||
mUserManager = userManager;
|
mUserManager = userManager;
|
||||||
mUserSwitcherController = userSwitcherController;
|
mUserSwitcherController = userSwitcherController;
|
||||||
mQsDetailDisplayer = qsDetailDisplayer;
|
mQsDetailDisplayer = qsDetailDisplayer;
|
||||||
mFalsingManager = falsingManager;
|
mFalsingManager = falsingManager;
|
||||||
|
mUserSwitchDialogController = userSwitchDialogController;
|
||||||
|
mFeatureFlags = featureFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultiUserSwitchController create(FooterActionsView view) {
|
public MultiUserSwitchController create(FooterActionsView view) {
|
||||||
return new MultiUserSwitchController(view.findViewById(R.id.multi_user_switch),
|
return new MultiUserSwitchController(view.findViewById(R.id.multi_user_switch),
|
||||||
mUserManager, mUserSwitcherController, mQsDetailDisplayer,
|
mUserManager, mUserSwitcherController, mQsDetailDisplayer,
|
||||||
mFalsingManager);
|
mFalsingManager, mUserSwitchDialogController, mFeatureFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiUserSwitchController(MultiUserSwitch view, UserManager userManager,
|
private MultiUserSwitchController(MultiUserSwitch view, UserManager userManager,
|
||||||
UserSwitcherController userSwitcherController, QSDetailDisplayer qsDetailDisplayer,
|
UserSwitcherController userSwitcherController, QSDetailDisplayer qsDetailDisplayer,
|
||||||
FalsingManager falsingManager) {
|
FalsingManager falsingManager, UserSwitchDialogController userSwitchDialogController,
|
||||||
|
FeatureFlags featureFlags) {
|
||||||
super(view);
|
super(view);
|
||||||
mUserManager = userManager;
|
mUserManager = userManager;
|
||||||
mUserSwitcherController = userSwitcherController;
|
mUserSwitcherController = userSwitcherController;
|
||||||
mQsDetailDisplayer = qsDetailDisplayer;
|
mQsDetailDisplayer = qsDetailDisplayer;
|
||||||
mFalsingManager = falsingManager;
|
mFalsingManager = falsingManager;
|
||||||
|
mUserSwitchDialogController = userSwitchDialogController;
|
||||||
|
mFeatureFlags = featureFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,10 +35,12 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
|
|||||||
import com.android.settingslib.drawable.CircleFramedDrawable;
|
import com.android.settingslib.drawable.CircleFramedDrawable;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.qs.tiles.UserDetailView;
|
import com.android.systemui.qs.tiles.UserDetailView;
|
||||||
|
import com.android.systemui.qs.user.UserSwitchDialogController;
|
||||||
import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
||||||
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
||||||
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
||||||
@@ -76,6 +78,8 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
|
|||||||
private final ConfigurationController mConfigurationController;
|
private final ConfigurationController mConfigurationController;
|
||||||
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
|
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
|
||||||
private final KeyguardUserDetailAdapter mUserDetailAdapter;
|
private final KeyguardUserDetailAdapter mUserDetailAdapter;
|
||||||
|
private final FeatureFlags mFeatureFlags;
|
||||||
|
private final UserSwitchDialogController mUserSwitchDialogController;
|
||||||
private NotificationPanelViewController mNotificationPanelViewController;
|
private NotificationPanelViewController mNotificationPanelViewController;
|
||||||
private UserAvatarView mUserAvatarView;
|
private UserAvatarView mUserAvatarView;
|
||||||
UserSwitcherController.UserRecord mCurrentUser;
|
UserSwitcherController.UserRecord mCurrentUser;
|
||||||
@@ -124,7 +128,9 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
|
|||||||
SysuiStatusBarStateController statusBarStateController,
|
SysuiStatusBarStateController statusBarStateController,
|
||||||
DozeParameters dozeParameters,
|
DozeParameters dozeParameters,
|
||||||
Provider<UserDetailView.Adapter> userDetailViewAdapterProvider,
|
Provider<UserDetailView.Adapter> userDetailViewAdapterProvider,
|
||||||
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
|
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
|
||||||
|
FeatureFlags featureFlags,
|
||||||
|
UserSwitchDialogController userSwitchDialogController) {
|
||||||
super(view);
|
super(view);
|
||||||
if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController");
|
if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController");
|
||||||
mContext = context;
|
mContext = context;
|
||||||
@@ -139,6 +145,8 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
|
|||||||
keyguardStateController, dozeParameters,
|
keyguardStateController, dozeParameters,
|
||||||
unlockedScreenOffAnimationController, /* animateYPos= */ false);
|
unlockedScreenOffAnimationController, /* animateYPos= */ false);
|
||||||
mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider);
|
mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider);
|
||||||
|
mFeatureFlags = featureFlags;
|
||||||
|
mUserSwitchDialogController = userSwitchDialogController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -162,7 +170,11 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tapping anywhere in the view will open QS user panel
|
// Tapping anywhere in the view will open QS user panel
|
||||||
|
if (mFeatureFlags.useNewUserSwitcher()) {
|
||||||
|
mUserSwitchDialogController.showDialog(mView);
|
||||||
|
} else {
|
||||||
openQsUserPanel();
|
openQsUserPanel();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
|
mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.qs.user
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
class UserDialogTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private lateinit var dialog: UserDialog
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
dialog = UserDialog(mContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun doneButtonExists() {
|
||||||
|
assertThat(dialog.doneButton).isInstanceOf(View::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun settingsButtonExists() {
|
||||||
|
assertThat(dialog.settingsButton).isInstanceOf(View::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun gridExistsAndIsViewGroup() {
|
||||||
|
assertThat(dialog.grid).isInstanceOf(ViewGroup::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.qs.user
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.view.View
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
|
import com.android.systemui.plugins.FalsingManager
|
||||||
|
import com.android.systemui.qs.PseudoGridView
|
||||||
|
import com.android.systemui.qs.tiles.UserDetailView
|
||||||
|
import com.android.systemui.statusbar.policy.UserSwitcherController
|
||||||
|
import com.android.systemui.util.mockito.argumentCaptor
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.android.systemui.util.mockito.eq
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.ArgumentMatcher
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.Mockito.anyInt
|
||||||
|
import org.mockito.Mockito.argThat
|
||||||
|
import org.mockito.Mockito.inOrder
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import java.util.function.Consumer
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class UserSwitchDialogControllerTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var dialog: UserDialog
|
||||||
|
@Mock
|
||||||
|
private lateinit var falsingManager: FalsingManager
|
||||||
|
@Mock
|
||||||
|
private lateinit var settingsView: View
|
||||||
|
@Mock
|
||||||
|
private lateinit var doneView: View
|
||||||
|
@Mock
|
||||||
|
private lateinit var activityStarter: ActivityStarter
|
||||||
|
@Mock
|
||||||
|
private lateinit var userDetailViewAdapter: UserDetailView.Adapter
|
||||||
|
@Mock
|
||||||
|
private lateinit var launchView: View
|
||||||
|
@Mock
|
||||||
|
private lateinit var gridView: PseudoGridView
|
||||||
|
@Captor
|
||||||
|
private lateinit var clickCaptor: ArgumentCaptor<View.OnClickListener>
|
||||||
|
|
||||||
|
private lateinit var controller: UserSwitchDialogController
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
`when`(dialog.settingsButton).thenReturn(settingsView)
|
||||||
|
`when`(dialog.doneButton).thenReturn(doneView)
|
||||||
|
`when`(dialog.grid).thenReturn(gridView)
|
||||||
|
|
||||||
|
`when`(launchView.context).thenReturn(mContext)
|
||||||
|
|
||||||
|
controller = UserSwitchDialogController(
|
||||||
|
{ userDetailViewAdapter },
|
||||||
|
activityStarter,
|
||||||
|
falsingManager,
|
||||||
|
{ dialog }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun showDialog_callsDialogShow() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
verify(dialog).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createCalledBeforeDoneButton() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
val inOrder = inOrder(dialog)
|
||||||
|
inOrder.verify(dialog).create()
|
||||||
|
inOrder.verify(dialog).doneButton
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createCalledBeforeSettingsButton() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
val inOrder = inOrder(dialog)
|
||||||
|
inOrder.verify(dialog).create()
|
||||||
|
inOrder.verify(dialog).settingsButton
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createCalledBeforeGrid() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
val inOrder = inOrder(dialog)
|
||||||
|
inOrder.verify(dialog).create()
|
||||||
|
inOrder.verify(dialog).grid
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dialog_showForAllUsers() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
verify(dialog).setShowForAllUsers(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dialog_cancelOnTouchOutside() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
verify(dialog).setCanceledOnTouchOutside(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun adapterAndGridLinked() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
verify(userDetailViewAdapter).linkToViewGroup(gridView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun clickDoneButton_dismiss() {
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
|
||||||
|
verify(doneView).setOnClickListener(capture(clickCaptor))
|
||||||
|
|
||||||
|
clickCaptor.value.onClick(doneView)
|
||||||
|
|
||||||
|
verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
|
||||||
|
verify(dialog).dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun clickSettingsButton_noFalsing_opensSettingsAndDismisses() {
|
||||||
|
`when`(falsingManager.isFalseTap(anyInt())).thenReturn(false)
|
||||||
|
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
|
||||||
|
verify(settingsView).setOnClickListener(capture(clickCaptor))
|
||||||
|
|
||||||
|
clickCaptor.value.onClick(settingsView)
|
||||||
|
|
||||||
|
verify(activityStarter)
|
||||||
|
.postStartActivityDismissingKeyguard(
|
||||||
|
argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)),
|
||||||
|
eq(0)
|
||||||
|
)
|
||||||
|
verify(dialog).dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun clickSettingsButton_Falsing_notOpensSettingsAndDismisses() {
|
||||||
|
`when`(falsingManager.isFalseTap(anyInt())).thenReturn(true)
|
||||||
|
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
|
||||||
|
verify(settingsView).setOnClickListener(capture(clickCaptor))
|
||||||
|
|
||||||
|
clickCaptor.value.onClick(settingsView)
|
||||||
|
|
||||||
|
verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
|
||||||
|
verify(dialog).dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun callbackFromDetailView_dismissesDialog() {
|
||||||
|
val captor = argumentCaptor<Consumer<UserSwitcherController.UserRecord>>()
|
||||||
|
|
||||||
|
controller.showDialog(launchView)
|
||||||
|
verify(userDetailViewAdapter).injectCallback(capture(captor))
|
||||||
|
|
||||||
|
captor.value.accept(mock(UserSwitcherController.UserRecord::class.java))
|
||||||
|
|
||||||
|
verify(dialog).dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IntentMatcher(private val action: String) : ArgumentMatcher<Intent> {
|
||||||
|
override fun matches(argument: Intent?): Boolean {
|
||||||
|
return argument?.action == action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user