diff options
71 files changed, 1094 insertions, 617 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index a4fb2c1f12ff..a8e06fc4c8a0 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3204,12 +3204,6 @@ package android.window { field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskAppearedInfo> CREATOR; } - public final class TaskFragmentAppearedInfo implements android.os.Parcelable { - method @NonNull public android.view.SurfaceControl getLeash(); - method @NonNull public android.window.TaskFragmentInfo getTaskFragmentInfo(); - field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentAppearedInfo> CREATOR; - } - public final class TaskFragmentCreationParams implements android.os.Parcelable { method @NonNull public android.os.IBinder getFragmentToken(); method @NonNull public android.graphics.Rect getInitialBounds(); @@ -3246,7 +3240,7 @@ package android.window { ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor); method @NonNull public java.util.concurrent.Executor getExecutor(); method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken(); - method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentAppearedInfo); + method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo); method public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable); method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo); method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 992f02ca538b..db45466d98d2 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4076,6 +4076,34 @@ public class ActivityManager { } /** + * Gets the message that is shown when a user is switched from. + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_USERS) + public @Nullable String getSwitchingFromUserMessage() { + try { + return getService().getSwitchingFromUserMessage(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Gets the message that is shown when a user is switched to. + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_USERS) + public @Nullable String getSwitchingToUserMessage() { + try { + return getService().getSwitchingToUserMessage(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Uses the value defined by the platform. * * @hide diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 9e9e28b8bd4c..4912703bc2ce 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -338,6 +338,8 @@ interface IActivityManager { void setPackageScreenCompatMode(in String packageName, int mode); @UnsupportedAppUsage boolean switchUser(int userid); + String getSwitchingFromUserMessage(); + String getSwitchingToUserMessage(); @UnsupportedAppUsage void setStopUserOnSwitch(int value); boolean removeTask(int taskId); diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl index 5eb432e785ee..cdfa206423c2 100644 --- a/core/java/android/window/ITaskFragmentOrganizer.aidl +++ b/core/java/android/window/ITaskFragmentOrganizer.aidl @@ -19,12 +19,11 @@ package android.window; import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; -import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentInfo; /** @hide */ oneway interface ITaskFragmentOrganizer { - void onTaskFragmentAppeared(in TaskFragmentAppearedInfo taskFragmentAppearedInfo); + void onTaskFragmentAppeared(in TaskFragmentInfo taskFragmentInfo); void onTaskFragmentInfoChanged(in TaskFragmentInfo taskFragmentInfo); void onTaskFragmentVanished(in TaskFragmentInfo taskFragmentInfo); diff --git a/core/java/android/window/TaskFragmentAppearedInfo.aidl b/core/java/android/window/TaskFragmentAppearedInfo.aidl deleted file mode 100644 index 3729c09168a6..000000000000 --- a/core/java/android/window/TaskFragmentAppearedInfo.aidl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 android.window; - -/** - * Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer. - * @hide - */ -parcelable TaskFragmentAppearedInfo; diff --git a/core/java/android/window/TaskFragmentAppearedInfo.java b/core/java/android/window/TaskFragmentAppearedInfo.java deleted file mode 100644 index 89d9a9508a71..000000000000 --- a/core/java/android/window/TaskFragmentAppearedInfo.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 android.window; - -import android.annotation.NonNull; -import android.annotation.TestApi; -import android.os.Parcel; -import android.os.Parcelable; -import android.view.SurfaceControl; - -/** - * Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer. - * @hide - */ -@TestApi -public final class TaskFragmentAppearedInfo implements Parcelable { - - @NonNull - private final TaskFragmentInfo mTaskFragmentInfo; - - @NonNull - private final SurfaceControl mLeash; - - /** @hide */ - public TaskFragmentAppearedInfo( - @NonNull TaskFragmentInfo taskFragmentInfo, @NonNull SurfaceControl leash) { - mTaskFragmentInfo = taskFragmentInfo; - mLeash = leash; - } - - @NonNull - public TaskFragmentInfo getTaskFragmentInfo() { - return mTaskFragmentInfo; - } - - @NonNull - public SurfaceControl getLeash() { - return mLeash; - } - - private TaskFragmentAppearedInfo(Parcel in) { - mTaskFragmentInfo = in.readTypedObject(TaskFragmentInfo.CREATOR); - mLeash = in.readTypedObject(SurfaceControl.CREATOR); - } - - /** @hide */ - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeTypedObject(mTaskFragmentInfo, flags); - dest.writeTypedObject(mLeash, flags); - } - - @NonNull - public static final Creator<TaskFragmentAppearedInfo> CREATOR = - new Creator<TaskFragmentAppearedInfo>() { - @Override - public TaskFragmentAppearedInfo createFromParcel(Parcel in) { - return new TaskFragmentAppearedInfo(in); - } - - @Override - public TaskFragmentAppearedInfo[] newArray(int size) { - return new TaskFragmentAppearedInfo[size]; - } - }; - - @Override - public String toString() { - return "TaskFragmentAppearedInfo{" - + " taskFragmentInfo=" + mTaskFragmentInfo - + "}"; - } - - /** @hide */ - @Override - public int describeContents() { - return 0; - } -} diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 337c5a14e9d3..7e7d37083b5b 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -120,8 +120,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer { } /** Called when a TaskFragment is created and organized by this organizer. */ - public void onTaskFragmentAppeared( - @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {} + public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {} /** Called when the status of an organized TaskFragment is changed. */ public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {} @@ -169,7 +168,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer { private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() { @Override - public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) { + public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { mExecutor.execute( () -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo)); } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 5aff0e0cf38a..4d851644903e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4879,9 +4879,10 @@ the app in the letterbox mode. --> <item name="config_fixedOrientationLetterboxAspectRatio" format="float" type="dimen">0.0</item> - <!-- Corners radius for activity presented the letterbox mode. Values < 0 will be ignored and - min between device bottom corner radii will be used instead. --> - <integer name="config_letterboxActivityCornersRadius">-1</integer> + <!-- Corners radius for activity presented the letterbox mode. Values < 0 enable rounded + corners with radius equal to min between device bottom corner radii. Default 0 value turns + off rounded corners logic in LetterboxUiController. --> + <integer name="config_letterboxActivityCornersRadius">0</integer> <!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are ignored and 0 is used. --> diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index 85ef270ac49d..df751fc9fa48 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -27,8 +27,6 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.util.ArrayMap; -import android.view.SurfaceControl; -import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; @@ -51,9 +49,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { /** Mapping from the client assigned unique token to the {@link TaskFragmentInfo}. */ private final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>(); - /** Mapping from the client assigned unique token to the TaskFragment {@link SurfaceControl}. */ - private final Map<IBinder, SurfaceControl> mFragmentLeashes = new ArrayMap<>(); - /** * Mapping from the client assigned unique token to the TaskFragment parent * {@link Configuration}. @@ -67,7 +62,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { * Callback that notifies the controller about changes to task fragments. */ interface TaskFragmentCallback { - void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo); + void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo); void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo); void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo); void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken, @@ -259,15 +254,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } @Override - public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) { - final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo(); - final IBinder fragmentToken = info.getFragmentToken(); - final SurfaceControl leash = taskFragmentAppearedInfo.getLeash(); - mFragmentInfos.put(fragmentToken, info); - mFragmentLeashes.put(fragmentToken, leash); + public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { + final IBinder fragmentToken = taskFragmentInfo.getFragmentToken(); + mFragmentInfos.put(fragmentToken, taskFragmentInfo); if (mCallback != null) { - mCallback.onTaskFragmentAppeared(taskFragmentAppearedInfo); + mCallback.onTaskFragmentAppeared(taskFragmentInfo); } } @@ -284,7 +276,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { @Override public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { mFragmentInfos.remove(taskFragmentInfo.getFragmentToken()); - mFragmentLeashes.remove(taskFragmentInfo.getFragmentToken()); mFragmentParentConfigs.remove(taskFragmentInfo.getFragmentToken()); if (mCallback != null) { diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 68c19041940c..fe6c7ba3b24c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -37,7 +37,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; -import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; @@ -110,14 +109,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } @Override - public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) { - TaskFragmentContainer container = getContainer( - taskFragmentAppearedInfo.getTaskFragmentInfo().getFragmentToken()); + public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { + TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken()); if (container == null) { return; } - container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo()); + container.setInfo(taskFragmentInfo); if (container.isFinished()) { mPresenter.cleanupContainer(container, false /* shouldFinishDependent */); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index d239e56bfd69..6b622044d25d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -337,7 +337,7 @@ public abstract class WMShellBaseModule { @Provides static Optional<OneHandedController> providesOneHandedController( @DynamicOverride Optional<OneHandedController> oneHandedController) { - if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { + if (SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { return oneHandedController; } return Optional.empty(); diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java index a210e90a3cfc..8b17be1e8ec9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java @@ -19,7 +19,6 @@ package com.android.settingslib.notification; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AlertDialog; -import android.app.Dialog; import android.app.NotificationManager; import android.content.Context; import android.content.DialogInterface; @@ -85,6 +84,7 @@ public class EnableZenModeDialog { @VisibleForTesting protected Context mContext; + private final int mThemeResId; @VisibleForTesting protected TextView mZenAlarmWarning; @VisibleForTesting @@ -97,10 +97,15 @@ public class EnableZenModeDialog { protected LayoutInflater mLayoutInflater; public EnableZenModeDialog(Context context) { + this(context, 0); + } + + public EnableZenModeDialog(Context context, int themeResId) { mContext = context; + mThemeResId = themeResId; } - public Dialog createDialog() { + public AlertDialog createDialog() { mNotificationManager = (NotificationManager) mContext. getSystemService(Context.NOTIFICATION_SERVICE); mForeverId = Condition.newId(mContext).appendPath("forever").build(); @@ -108,7 +113,7 @@ public class EnableZenModeDialog { mUserId = mContext.getUserId(); mAttached = false; - final AlertDialog.Builder builder = new AlertDialog.Builder(mContext) + final AlertDialog.Builder builder = new AlertDialog.Builder(mContext, mThemeResId) .setTitle(R.string.zen_mode_settings_turn_on_dialog_title) .setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.zen_mode_enable_dialog_turn_on, diff --git a/packages/SystemUI/res/color/prv_text_color_on_accent.xml b/packages/SystemUI/res/color/prv_text_color_on_accent.xml deleted file mode 100644 index 9f44acadb420..000000000000 --- a/packages/SystemUI/res/color/prv_text_color_on_accent.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?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>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml index 1a128dfe8b10..14cb1de9fa2d 100644 --- a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml +++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml @@ -16,8 +16,8 @@ --> <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"> + android:insetTop="@dimen/dialog_button_vertical_inset" + android:insetBottom="@dimen/dialog_button_vertical_inset"> <ripple android:color="?android:attr/colorControlHighlight"> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> @@ -29,10 +29,10 @@ <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"/> + <padding android:left="@dimen/dialog_button_horizontal_padding" + android:top="@dimen/dialog_button_vertical_padding" + android:right="@dimen/dialog_button_horizontal_padding" + android:bottom="@dimen/dialog_button_vertical_padding"/> </shape> </item> </ripple> diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml index 467c20f3ffcd..665b4564ebf1 100644 --- a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml +++ b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml @@ -16,8 +16,8 @@ --> <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"> + android:insetTop="@dimen/dialog_button_vertical_inset" + android:insetBottom="@dimen/dialog_button_vertical_inset"> <ripple android:color="?android:attr/colorControlHighlight"> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> @@ -32,10 +32,10 @@ <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"/> + <padding android:left="@dimen/dialog_button_horizontal_padding" + android:top="@dimen/dialog_button_vertical_padding" + android:right="@dimen/dialog_button_horizontal_padding" + android:bottom="@dimen/dialog_button_vertical_padding"/> </shape> </item> </ripple> diff --git a/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml new file mode 100644 index 000000000000..a3e289a42d05 --- /dev/null +++ b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml @@ -0,0 +1,63 @@ +<?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. + --> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@*android:id/buttonPanel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:scrollbarAlwaysDrawVerticalTrack="true" + android:scrollIndicators="top|bottom" + android:fillViewport="true" + android:paddingTop="@dimen/dialog_button_bar_top_padding" + android:paddingStart="@dimen/dialog_side_padding" + android:paddingEnd="@dimen/dialog_side_padding" + android:paddingBottom="@dimen/dialog_bottom_padding" + style="?android:attr/buttonBarStyle"> + <com.android.internal.widget.ButtonBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layoutDirection="locale" + android:orientation="horizontal" + android:gravity="bottom"> + + <Button + android:id="@android:id/button3" + style="?android:attr/buttonBarNeutralButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <Space + android:id="@*android:id/spacer" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1" + android:visibility="invisible" /> + + <Button + android:id="@android:id/button2" + style="?android:attr/buttonBarNegativeButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <Button + android:id="@android:id/button1" + style="?android:attr/buttonBarPositiveButtonStyle" + android:layout_marginStart="8dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </com.android.internal.widget.ButtonBarLayout> +</ScrollView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/alert_dialog_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_systemui.xml new file mode 100644 index 000000000000..f280cbd16a0f --- /dev/null +++ b/packages/SystemUI/res/layout/alert_dialog_systemui.xml @@ -0,0 +1,91 @@ +<?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. + --> +<com.android.internal.widget.AlertDialogLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@*android:id/parentPanel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal|top" + android:orientation="vertical" + android:paddingTop="@dimen/dialog_top_padding" + > + + <include layout="@layout/alert_dialog_title_systemui" /> + + <FrameLayout + android:id="@*android:id/contentPanel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp" + android:paddingStart="@dimen/dialog_side_padding" + android:paddingEnd="@dimen/dialog_side_padding" + > + + <ScrollView + android:id="@*android:id/scrollView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipToPadding="false"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <Space + android:id="@*android:id/textSpacerNoTitle" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="0dp" /> + + <TextView + android:id="@*android:id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/TextAppearance.Dialog.Body.Message" /> + + <Space + android:id="@*android:id/textSpacerNoButtons" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="6dp" /> + </LinearLayout> + </ScrollView> + </FrameLayout> + + <FrameLayout + android:id="@*android:id/customPanel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp" + android:paddingStart="@dimen/dialog_side_padding" + android:paddingEnd="@dimen/dialog_side_padding" + > + + <FrameLayout + android:id="@*android:id/custom" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + </FrameLayout> + + <include + android:layout_width="match_parent" + android:layout_height="wrap_content" + layout="@layout/alert_dialog_button_bar_systemui" /> + +</com.android.internal.widget.AlertDialogLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml new file mode 100644 index 000000000000..480ba001fae1 --- /dev/null +++ b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml @@ -0,0 +1,63 @@ +<?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. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:id="@*android:id/topPanel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingStart="@dimen/dialog_side_padding" + android:paddingEnd="@dimen/dialog_side_padding" +> + + <!-- If the client uses a customTitle, it will be added here. --> + + <LinearLayout + android:id="@*android:id/title_template" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="center_horizontal|top"> + + <ImageView + android:id="@*android:id/icon" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_marginBottom="16dp" + android:scaleType="fitCenter" + android:src="@null" + android:tint="?androidprv:attr/colorAccentPrimaryVariant" + /> + + <com.android.internal.widget.DialogTitle + android:id="@*android:id/alertTitle" + android:singleLine="true" + android:ellipsize="end" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="16dp" + style="@style/TextAppearance.Dialog.Title" /> + </LinearLayout> + + <Space + android:id="@*android:id/titleDividerNoCustom" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="0dp" /> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 86e2661f9534..98518c2bbf97 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -156,6 +156,14 @@ style="@style/InternetDialog.NetworkSummary"/> </LinearLayout> + <View + android:id="@+id/mobile_toggle_divider" + android:layout_width="1dp" + android:layout_height="28dp" + android:layout_marginEnd="16dp" + android:layout_gravity="center_vertical" + android:background="?android:attr/textColorSecondary"/> + <FrameLayout android:layout_width="@dimen/settingslib_switch_track_width" android:layout_height="48dp" @@ -367,8 +375,9 @@ android:id="@+id/done_layout" android:layout_width="67dp" android:layout_height="48dp" + android:layout_marginTop="8dp" android:layout_marginEnd="24dp" - android:layout_marginBottom="40dp" + android:layout_marginBottom="34dp" android:layout_gravity="end|center_vertical" android:clickable="true" android:focusable="true"> diff --git a/packages/SystemUI/res/layout/privacy_dialog.xml b/packages/SystemUI/res/layout/privacy_dialog.xml index ee4530cb4377..9368a6a0b7da 100644 --- a/packages/SystemUI/res/layout/privacy_dialog.xml +++ b/packages/SystemUI/res/layout/privacy_dialog.xml @@ -22,10 +22,9 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/ongoing_appops_dialog_side_margins" android:layout_marginEnd="@dimen/ongoing_appops_dialog_side_margins" - android:layout_marginTop="8dp" android:orientation="vertical" android:paddingBottom="8dp" - android:paddingTop="12dp" + android:paddingTop="8dp" android:paddingHorizontal="@dimen/ongoing_appops_dialog_side_padding" android:background="@drawable/qs_dialog_bg" /> diff --git a/packages/SystemUI/res/layout/qs_user_detail.xml b/packages/SystemUI/res/layout/qs_user_detail.xml index 91d3a53556a7..1aec296f4f5c 100644 --- a/packages/SystemUI/res/layout/qs_user_detail.xml +++ b/packages/SystemUI/res/layout/qs_user_detail.xml @@ -22,6 +22,6 @@ xmlns:sysui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - sysui:verticalSpacing="4dp" + sysui:verticalSpacing="20dp" sysui:horizontalSpacing="4dp" style="@style/UserDetailView" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml index cc6c5d343502..91b11fcc3c26 100644 --- a/packages/SystemUI/res/layout/qs_user_detail_item.xml +++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml @@ -24,8 +24,6 @@ android:layout_height="wrap_content" android:orientation="vertical" android:gravity="top|center_horizontal" - android:paddingTop="16dp" - android:minHeight="112dp" android:clipChildren="false" android:clipToPadding="false" android:focusable="true" diff --git a/packages/SystemUI/res/layout/qs_user_dialog_content.xml b/packages/SystemUI/res/layout/qs_user_dialog_content.xml index 9495ee6f3139..355df2c4448a 100644 --- a/packages/SystemUI/res/layout/qs_user_dialog_content.xml +++ b/packages/SystemUI/res/layout/qs_user_dialog_content.xml @@ -15,75 +15,19 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - -<androidx.constraintlayout.widget.ConstraintLayout +<FrameLayout 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" -> - <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" + android:id="@+id/grid" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + sysui:verticalSpacing="20dp" + sysui:horizontalSpacing="4dp" + sysui:fixedChildWidth="80dp" /> - - <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>
\ No newline at end of file +</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml index 07e28b6d7f20..cb963e6ffc89 100644 --- a/packages/SystemUI/res/values-night/styles.xml +++ b/packages/SystemUI/res/values-night/styles.xml @@ -16,9 +16,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Dialog"> - <item name="android:buttonCornerRadius">28dp</item> - </style> + <style name="Theme.SystemUI.DayNightDialog" parent="@android:style/Theme.DeviceDefault.Dialog"/> <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Dialog.Alert" /> @@ -53,13 +51,17 @@ <style name="TextAppearance.InternetDialog.Active"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:textSize">16sp</item> - <item name="android:textColor">@color/connected_network_primary_color</item> + <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> <item name="android:textDirection">locale</item> </style> <style name="TextAppearance.InternetDialog.Secondary.Active"> <item name="android:textSize">14sp</item> - <item name="android:textColor">@color/connected_network_secondary_color</item> + <item name="android:textColor">?android:attr/textColorSecondaryInverse</item> + </style> + + <style name="InternetDialog.Divider.Active"> + <item name="android:background">?android:attr/textColorSecondaryInverse</item> </style> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 2afbe8c648be..a2fd669c69fd 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1275,10 +1275,19 @@ <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> + <!-- Dimensions for unified SystemUI dialogs styling. Used by Theme.SystemUI.Dialog and + alert_dialog_systemui.xml + --> + <dimen name="dialog_button_horizontal_padding">16dp</dimen> + <dimen name="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> + <dimen name="dialog_button_vertical_inset">6dp</dimen> + <dimen name="dialog_top_padding">24dp</dimen> + <dimen name="dialog_bottom_padding">18dp</dimen> + <dimen name="dialog_side_padding">24dp</dimen> + <dimen name="dialog_button_bar_top_padding">32dp</dimen> + + <!-- ************************************************************************* --> <dimen name="keyguard_unfold_translation_x">16dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 94d10decd269..3c7b53a8e6db 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -14,8 +14,8 @@ limitations under the License. --> -<resources xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- NOTE: Adding the androidprv: namespace to this file will break the studio build. --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <!-- HybridNotification themes and styles --> @@ -351,11 +351,19 @@ <item name="android:windowIsFloating">true</item> </style> - <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"> + <style name="Theme.SystemUI.DayNightDialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"/> + + <style name="Theme.SystemUI.Dialog" parent="@style/Theme.SystemUI.DayNightDialog"> <item name="android:buttonCornerRadius">28dp</item> - <item name="android:buttonBarPositiveButtonStyle">@style/Widget.QSDialog.Button</item> - <item name="android:buttonBarNegativeButtonStyle">@style/Widget.QSDialog.Button.BorderButton</item> - <item name="android:buttonBarNeutralButtonStyle">@style/Widget.QSDialog.Button.BorderButton</item> + <item name="android:buttonBarPositiveButtonStyle">@style/Widget.Dialog.Button</item> + <item name="android:buttonBarNegativeButtonStyle">@style/Widget.Dialog.Button.BorderButton</item> + <item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.BorderButton</item> + <item name="android:colorBackground">?androidprv:attr/colorSurface</item> + <item name="android:alertDialogStyle">@style/AlertDialogStyle</item> + </style> + + <style name="AlertDialogStyle" parent="@androidprv:style/AlertDialog.DeviceDefault"> + <item name="android:layout">@layout/alert_dialog_systemui</item> </style> <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" /> @@ -853,24 +861,37 @@ <item name="actionDividerHeight">32dp</item> </style> - <style name="TextAppearance.QSDialog.Title" parent="Theme.SystemUI.Dialog"> + <style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large"> <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> + <item name="android:gravity">center</item> + <item name="android:textAlignment">center</item> + </style> + + <style name="TextAppearance.Dialog.Body" parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:lineHeight">20sp</item> </style> - <style name="Widget.QSDialog.Button" parent = "Theme.SystemUI.Dialog"> + <style name="TextAppearance.Dialog.Body.Message"> + <item name="android:gravity">center</item> + <item name="android:textAlignment">center</item> + </style> + + <style name="Widget.Dialog.Button" parent = "Theme.SystemUI.Dialog"> <item name="android:background">@drawable/qs_dialog_btn_filled</item> - <item name="android:textColor">@color/prv_text_color_on_accent</item> + <item name="android:textColor">?androidprv:attr/textColorOnAccent</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:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> <item name="android:stateListAnimator">@null</item> - <item name="android:layout_marginHorizontal">4dp</item> </style> - <style name="Widget.QSDialog.Button.BorderButton"> + <style name="Widget.Dialog.Button.BorderButton"> <item name="android:background">@drawable/qs_dialog_btn_outline</item> <item name="android:textColor">?android:attr/textColorPrimary</item> </style> @@ -947,4 +968,10 @@ <style name="TextAppearance.InternetDialog.Secondary.Active"/> + <style name="InternetDialog.Divider"> + <item name="android:background">?android:attr/textColorSecondary</item> + </style> + + <style name="InternetDialog.Divider.Active"/> + </resources> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index 8bd0f910dac3..01497516e0b1 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -95,4 +95,9 @@ oneway interface IOverviewProxy { * Sent when screen turned on and ready to use (blocker scrim is hidden) */ void onScreenTurnedOn() = 21; + + /** + * Sent when the desired dark intensity of the nav buttons has changed + */ + void onNavButtonsDarkIntensityChanged(float darkIntensity) = 22; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index 3128ffdbc67b..675dc9b533fb 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -28,6 +28,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.view.ViewDebug; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.io.PrintWriter; @@ -50,6 +51,7 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public int windowingMode; @ViewDebug.ExportedProperty(category="recents") + @NonNull public final Intent baseIntent; @ViewDebug.ExportedProperty(category="recents") public final int userId; @@ -83,7 +85,7 @@ public class Task { updateHashCode(); } - public TaskKey(int id, int windowingMode, Intent intent, + public TaskKey(int id, int windowingMode, @NonNull Intent intent, ComponentName sourceComponent, int userId, long lastActiveTime) { this.id = id; this.windowingMode = windowingMode; @@ -95,7 +97,7 @@ public class Task { updateHashCode(); } - public TaskKey(int id, int windowingMode, Intent intent, + public TaskKey(int id, int windowingMode, @NonNull Intent intent, ComponentName sourceComponent, int userId, long lastActiveTime, int displayId) { this.id = id; this.windowingMode = windowingMode; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index e24f07c21076..b56d189d3ab3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -801,13 +801,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT); } + boolean lockedOutStateChanged = false; if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) { + lockedOutStateChanged |= !mFingerprintLockedOutPermanent; mFingerprintLockedOutPermanent = true; requireStrongAuthIfAllLockedOut(); } if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) { + lockedOutStateChanged |= !mFingerprintLockedOut; mFingerprintLockedOut = true; if (isUdfpsEnrolled()) { updateFingerprintListeningState(); @@ -820,9 +823,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onBiometricError(msgId, errString, BiometricSourceType.FINGERPRINT); } } + + if (lockedOutStateChanged) { + notifyLockedOutStateChanged(BiometricSourceType.FINGERPRINT); + } } private void handleFingerprintLockoutReset() { + boolean changed = mFingerprintLockedOut || mFingerprintLockedOutPermanent; mFingerprintLockedOut = false; mFingerprintLockedOutPermanent = false; @@ -837,6 +845,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } else { updateFingerprintListeningState(); } + + if (changed) { + notifyLockedOutStateChanged(BiometricSourceType.FINGERPRINT); + } } private void setFingerprintRunningState(int fingerprintRunningState) { @@ -999,7 +1011,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } + boolean lockedOutStateChanged = false; if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) { + lockedOutStateChanged = !mFaceLockedOutPermanent; mFaceLockedOutPermanent = true; requireStrongAuthIfAllLockedOut(); } @@ -1011,11 +1025,21 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab BiometricSourceType.FACE); } } + + if (lockedOutStateChanged) { + notifyLockedOutStateChanged(BiometricSourceType.FACE); + } } private void handleFaceLockoutReset() { + boolean changed = mFaceLockedOutPermanent; mFaceLockedOutPermanent = false; + updateFaceListeningState(); + + if (changed) { + notifyLockedOutStateChanged(BiometricSourceType.FACE); + } } private void setFaceRunningState(int faceRunningState) { @@ -1237,6 +1261,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } + private void notifyLockedOutStateChanged(BiometricSourceType type) { + Assert.isMainThread(); + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onLockedOutStateChanged(type); + } + } + } + public boolean isScreenOn() { return mScreenOn; } @@ -2454,6 +2488,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } + public boolean isFingerprintLockedOut() { + return mFingerprintLockedOut || mFingerprintLockedOutPermanent; + } + /** * If biometrics hardware is available, not disabled, and user has enrolled templates. * This does NOT check if the device is encrypted or in lockdown. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 12431984c9b9..8170a81a09e6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -292,6 +292,11 @@ public class KeyguardUpdateMonitorCallback { public void onStrongAuthStateChanged(int userId) { } /** + * When the current user's locked out state changed. + */ + public void onLockedOutStateChanged(BiometricSourceType biometricSourceType) { } + + /** * Called when the dream's window state is changed. * @param dreaming true if the dream's window has been created and is visible */ diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 223eb78044c4..8f4d6f6aa973 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -255,7 +255,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud private void maybeShowInputBouncer() { if (mShowingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) { mKeyguardViewManager.showBouncer(true); - mKeyguardViewManager.resetAlternateAuth(false); } } diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index b45dc52585ad..10878dcc2474 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -42,7 +42,6 @@ import com.android.systemui.util.leak.LeakDetector; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; @@ -308,22 +307,22 @@ public class FragmentHostManager { return instantiateWithInjections(context, className, arguments); } - private Fragment instantiateWithInjections(Context context, String className, - Bundle args) { - Method method = mManager.getInjectionMap().get(className); - if (method != null) { + private Fragment instantiateWithInjections( + Context context, String className, Bundle args) { + FragmentService.FragmentInstantiationInfo fragmentInstantiationInfo = + mManager.getInjectionMap().get(className); + if (fragmentInstantiationInfo != null) { try { - Fragment f = (Fragment) method.invoke(mManager.getFragmentCreator()); + Fragment f = (Fragment) fragmentInstantiationInfo + .mMethod + .invoke(fragmentInstantiationInfo.mDaggerComponent); // Setup the args, taken from Fragment#instantiate. if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); f.setArguments(args); } return f; - } catch (IllegalAccessException e) { - throw new Fragment.InstantiationException("Unable to instantiate " + className, - e); - } catch (InvocationTargetException e) { + } catch (IllegalAccessException | InvocationTargetException e) { throw new Fragment.InstantiationException("Unable to instantiate " + className, e); } diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java index 7f57fcc56117..2a5e653dd051 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java @@ -18,13 +18,13 @@ import android.app.Fragment; import android.content.res.Configuration; import android.os.Handler; import android.util.ArrayMap; +import android.util.Log; import android.view.View; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.qs.QSFragment; -import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; import com.android.systemui.statusbar.policy.ConfigurationController; import java.io.FileDescriptor; @@ -46,9 +46,14 @@ public class FragmentService implements Dumpable { private static final String TAG = "FragmentService"; private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>(); - private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>(); + /** + * A map with the means to create fragments via Dagger injection. + * + * key: the fragment class name. + * value: see {@link FragmentInstantiationInfo}. + */ + private final ArrayMap<String, FragmentInstantiationInfo> mInjectionMap = new ArrayMap<>(); private final Handler mHandler = new Handler(); - private final FragmentCreator mFragmentCreator; private ConfigurationController.ConfigurationListener mConfigurationListener = new ConfigurationController.ConfigurationListener() { @@ -65,26 +70,31 @@ public class FragmentService implements Dumpable { FragmentCreator.Factory fragmentCreatorFactory, ConfigurationController configurationController, DumpManager dumpManager) { - mFragmentCreator = fragmentCreatorFactory.build(); - initInjectionMap(); + addFragmentInstantiationProvider(fragmentCreatorFactory.build()); configurationController.addCallback(mConfigurationListener); dumpManager.registerDumpable(getClass().getSimpleName(), this); } - ArrayMap<String, Method> getInjectionMap() { + ArrayMap<String, FragmentInstantiationInfo> getInjectionMap() { return mInjectionMap; } - FragmentCreator getFragmentCreator() { - return mFragmentCreator; - } - - private void initInjectionMap() { - for (Method method : FragmentCreator.class.getDeclaredMethods()) { + /** + * Adds a new Dagger component object that provides method(s) to create fragments via injection. + */ + public void addFragmentInstantiationProvider(Object daggerComponent) { + for (Method method : daggerComponent.getClass().getDeclaredMethods()) { if (Fragment.class.isAssignableFrom(method.getReturnType()) && (method.getModifiers() & Modifier.PUBLIC) != 0) { - mInjectionMap.put(method.getReturnType().getName(), method); + String fragmentName = method.getReturnType().getName(); + if (mInjectionMap.containsKey(fragmentName)) { + Log.w(TAG, "Fragment " + fragmentName + " is already provided by different" + + " Dagger component; Not adding method"); + continue; + } + mInjectionMap.put( + fragmentName, new FragmentInstantiationInfo(method, daggerComponent)); } } } @@ -134,9 +144,6 @@ public class FragmentService implements Dumpable { * Inject a QSFragment. */ QSFragment createQSFragment(); - - /** Inject a CollapsedStatusBarFragment. */ - CollapsedStatusBarFragment createCollapsedStatusBarFragment(); } private class FragmentHostState { @@ -161,4 +168,16 @@ public class FragmentService implements Dumpable { mFragmentHostManager.onConfigurationChanged(newConfig); } } + + /** An object containing the information needed to instantiate a fragment. */ + static class FragmentInstantiationInfo { + /** The method that returns a newly-created fragment of the given class. */ + final Method mMethod; + /** The Dagger component that the method should be invoked on. */ + final Object mDaggerComponent; + FragmentInstantiationInfo(Method method, Object daggerComponent) { + this.mMethod = method; + this.mDaggerComponent = daggerComponent; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 7f9eae8bd55f..8d0733645117 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -793,7 +793,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN; } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) { return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; - } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) { + } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0 + || mUpdateMonitor.isFingerprintLockedOut())) { return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT; } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) != 0) { return KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE; diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 47ef5e4c62fd..d54b1514abf7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -400,7 +400,7 @@ class MediaCarouselController @Inject constructor( } updatePageIndicator() mediaCarouselScrollHandler.onPlayersChanged() - mediaCarousel.requiresRemeasuring = true + mediaFrame.requiresRemeasuring = true // Check postcondition: mediaContent should have the same number of children as there are // elements in mediaPlayers. if (MediaPlayerData.players().size != mediaContent.childCount) { @@ -439,7 +439,7 @@ class MediaCarouselController @Inject constructor( updatePlayerToState(newRecs, noAnimation = true) reorderAllPlayers(curVisibleMediaKey) updatePageIndicator() - mediaCarousel.requiresRemeasuring = true + mediaFrame.requiresRemeasuring = true // Check postcondition: mediaContent should have the same number of children as there are // elements in mediaPlayers. if (MediaPlayerData.players().size != mediaContent.childCount) { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 339877824b16..0429c022234d 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -57,6 +57,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; +import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.policy.ConfigurationController; import java.io.FileDescriptor; @@ -104,7 +105,8 @@ public class NavigationBarController implements TaskbarDelegate taskbarDelegate, NavigationBar.Factory navigationBarFactory, DumpManager dumpManager, - AutoHideController autoHideController) { + AutoHideController autoHideController, + LightBarController lightBarController) { mContext = context; mHandler = mainHandler; mNavigationBarFactory = navigationBarFactory; @@ -116,7 +118,7 @@ public class NavigationBarController implements mTaskbarDelegate = taskbarDelegate; mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService, navBarHelper, navigationModeController, sysUiFlagsContainer, - dumpManager, autoHideController); + dumpManager, autoHideController, lightBarController); mIsTablet = isTablet(mContext); dumpManager.registerDumpable(this); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index 428d9d6993b7..3d58a5a81251 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -64,6 +64,9 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.BarTransitions; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.LightBarTransitionsController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -85,6 +88,8 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, private NavigationModeController mNavigationModeController; private SysUiState mSysUiState; private AutoHideController mAutoHideController; + private LightBarController mLightBarController; + private LightBarTransitionsController mLightBarTransitionsController; private int mDisplayId; private int mNavigationIconHints; private final NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater = @@ -141,7 +146,8 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, NavBarHelper navBarHelper, NavigationModeController navigationModeController, SysUiState sysUiState, DumpManager dumpManager, - AutoHideController autoHideController) { + AutoHideController autoHideController, + LightBarController lightBarController) { // TODO: adding this in the ctor results in a dagger dependency cycle :( mCommandQueue = commandQueue; mOverviewProxyService = overviewProxyService; @@ -150,6 +156,30 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, mSysUiState = sysUiState; dumpManager.registerDumpable(this); mAutoHideController = autoHideController; + mLightBarController = lightBarController; + mLightBarTransitionsController = createLightBarTransitionsController(); + } + + // Separated into a method to keep setDependencies() clean/readable. + private LightBarTransitionsController createLightBarTransitionsController() { + return new LightBarTransitionsController(mContext, + new LightBarTransitionsController.DarkIntensityApplier() { + @Override + public void applyDarkIntensity(float darkIntensity) { + mOverviewProxyService.onNavButtonsDarkIntensityChanged(darkIntensity); + } + + @Override + public int getTintAnimationDuration() { + return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION; + } + }, mCommandQueue) { + @Override + public boolean supportsIconTintForNavMode(int navigationMode) { + // Always tint taskbar nav buttons (region sampling handles gesture bar separately). + return true; + } + }; } public void init(int displayId) { @@ -171,6 +201,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, // Set initial state for any listeners updateSysuiFlags(); mAutoHideController.setNavigationBar(mAutoHideUiElement); + mLightBarController.setNavigationBar(mLightBarTransitionsController); mInitialized = true; } @@ -189,6 +220,8 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, mWindowContext = null; } mAutoHideController.setNavigationBar(null); + mLightBarTransitionsController.destroy(mContext); + mLightBarController.setNavigationBar(null); mInitialized = false; } @@ -268,6 +301,10 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior, InsetsVisibilities requestedVisibilities, String packageName) { mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior); + if (mLightBarController != null && displayId == mDisplayId) { + mLightBarController.onNavigationBarAppearanceChanged(appearance, false/*nbModeChanged*/, + BarTransitions.MODE_TRANSPARENT /*navigationBarMode*/, navbarColorManagedByIme); + } if (mBehavior != behavior) { mBehavior = behavior; updateSysuiFlags(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java index 2f189beb7780..768598af6885 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java @@ -133,10 +133,7 @@ public class PseudoGridView extends ViewGroup { x += width + mHorizontalSpacing; } } - y += maxHeight; - if (row > 0) { - y += mVerticalSpacing; - } + y += maxHeight + mVerticalSpacing; } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index b1cd68e5185c..3163c5f5a3c9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles; import static android.provider.Settings.Global.ZEN_MODE_ALARMS; import static android.provider.Settings.Global.ZEN_MODE_OFF; +import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.Intent; @@ -41,7 +42,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnAttachStateChangeListener; import android.view.ViewGroup; -import android.view.WindowManager; import android.widget.Switch; import android.widget.Toast; @@ -53,6 +53,7 @@ import com.android.settingslib.notification.EnableZenModeDialog; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysUIToast; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; @@ -84,6 +85,7 @@ public class DndTile extends QSTileImpl<BooleanState> { private final DndDetailAdapter mDetailAdapter; private final SharedPreferences mSharedPreferences; private final SecureSetting mSettingZenDuration; + private final DialogLaunchAnimator mDialogLaunchAnimator; private boolean mListening; private boolean mShowingDetail; @@ -100,7 +102,8 @@ public class DndTile extends QSTileImpl<BooleanState> { QSLogger qsLogger, ZenModeController zenModeController, @Main SharedPreferences sharedPreferences, - SecureSettings secureSettings + SecureSettings secureSettings, + DialogLaunchAnimator dialogLaunchAnimator ) { super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); @@ -108,6 +111,7 @@ public class DndTile extends QSTileImpl<BooleanState> { mSharedPreferences = sharedPreferences; mDetailAdapter = new DndDetailAdapter(); mController.observe(getLifecycle(), mZenCallback); + mDialogLaunchAnimator = dialogLaunchAnimator; mSettingZenDuration = new SecureSetting(secureSettings, mUiHandler, Settings.Secure.ZEN_DURATION, getHost().getUserId()) { @Override @@ -117,8 +121,6 @@ public class DndTile extends QSTileImpl<BooleanState> { }; } - - public static void setVisible(Context context, boolean visible) { Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible); } @@ -187,14 +189,17 @@ public class DndTile extends QSTileImpl<BooleanState> { switch (zenDuration) { case Settings.Secure.ZEN_DURATION_PROMPT: mUiHandler.post(() -> { - Dialog mDialog = new EnableZenModeDialog(mContext).createDialog(); - mDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - SystemUIDialog.setShowForAllUsers(mDialog, true); - SystemUIDialog.registerDismissListener(mDialog); - SystemUIDialog.setWindowOnTop(mDialog); - mUiHandler.post(() -> mDialog.show()); - mHost.collapsePanels(); + Dialog dialog = makeZenModeDialog(); + if (view != null) { + final Dialog hostDialog = + mDialogLaunchAnimator.showFromView(dialog, view, false); + setDialogListeners(dialog, hostDialog); + } else { + // If we are not launching with animator, register default + // dismiss listener + SystemUIDialog.registerDismissListener(dialog); + dialog.show(); + } }); break; case Settings.Secure.ZEN_DURATION_FOREVER: @@ -209,6 +214,20 @@ public class DndTile extends QSTileImpl<BooleanState> { } } + private Dialog makeZenModeDialog() { + AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog) + .createDialog(); + SystemUIDialog.applyFlags(dialog); + SystemUIDialog.setShowForAllUsers(dialog, true); + return dialog; + } + + private void setDialogListeners(Dialog zenModeDialog, Dialog hostDialog) { + // Zen mode dialog is never hidden. + SystemUIDialog.registerDismissListener(zenModeDialog, hostDialog::dismiss); + zenModeDialog.setOnCancelListener(dialog -> hostDialog.cancel()); + } + @Override protected void handleSecondaryClick(@Nullable View view) { if (mController.isVolumeRestricted()) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index 77b9cc14fa6d..883552a1f7c3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -56,6 +56,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; +import com.android.settingslib.Utils; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan; @@ -120,6 +121,7 @@ public class InternetDialog extends SystemUIDialog implements private TextView mMobileTitleText; private TextView mMobileSummaryText; private Switch mMobileDataToggle; + private View mMobileToggleDivider; private Switch mWiFiToggle; private FrameLayout mDoneLayout; private Drawable mBackgroundOn; @@ -207,6 +209,7 @@ public class InternetDialog extends SystemUIDialog implements mSignalIcon = mDialogView.requireViewById(R.id.signal_icon); mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title); mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary); + mMobileToggleDivider = mDialogView.requireViewById(R.id.mobile_toggle_divider); mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle); mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle); mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on); @@ -378,6 +381,14 @@ public class InternetDialog extends SystemUIDialog implements mMobileNetworkLayout.setBackground( isCarrierNetworkConnected ? mBackgroundOn : mBackgroundOff); + TypedArray array = mContext.obtainStyledAttributes( + R.style.InternetDialog_Divider_Active, new int[]{android.R.attr.background}); + int dividerColor = Utils.getColorAttrDefaultColor(mContext, + android.R.attr.textColorSecondary); + mMobileToggleDivider.setBackgroundColor(isCarrierNetworkConnected + ? array.getColor(0, dividerColor) : dividerColor); + array.recycle(); + mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt deleted file mode 100644 index 26d1bbde2a54..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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) { - - // 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 - 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) - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt index d74a50e24ed3..00e04540fd94 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt @@ -21,13 +21,16 @@ import android.content.Context import android.content.DialogInterface import android.content.Intent import android.provider.Settings +import android.view.LayoutInflater import android.view.View import androidx.annotation.VisibleForTesting +import com.android.systemui.R import com.android.systemui.animation.DialogLaunchAnimator 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 com.android.systemui.statusbar.phone.SystemUIDialog import javax.inject.Inject import javax.inject.Provider @@ -40,7 +43,7 @@ class UserSwitchDialogController @VisibleForTesting constructor( private val activityStarter: ActivityStarter, private val falsingManager: FalsingManager, private val dialogLaunchAnimator: DialogLaunchAnimator, - private val dialogFactory: (Context) -> UserDialog + private val dialogFactory: (Context) -> SystemUIDialog ) { @Inject @@ -54,7 +57,7 @@ class UserSwitchDialogController @VisibleForTesting constructor( activityStarter, falsingManager, dialogLaunchAnimator, - { UserDialog(it) } + { SystemUIDialog(it) } ) companion object { @@ -71,9 +74,10 @@ class UserSwitchDialogController @VisibleForTesting constructor( with(dialogFactory(view.context)) { setShowForAllUsers(true) setCanceledOnTouchOutside(true) - create() // Needs to be called before we can retrieve views - settingsButton.setOnClickListener { + setTitle(R.string.qs_user_switch_dialog_title) + setPositiveButton(R.string.quick_settings_done, null) + setNeutralButton(R.string.quick_settings_more_user_settings) { _, _ -> if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations() activityStarter.postStartActivityDismissingKeyguard( @@ -81,12 +85,14 @@ class UserSwitchDialogController @VisibleForTesting constructor( 0 ) } - dismiss() } - doneButton.setOnClickListener { dismiss() } + val gridFrame = LayoutInflater.from(this.context) + .inflate(R.layout.qs_user_dialog_content, null) + setView(gridFrame) val adapter = userDetailViewAdapterProvider.get() - adapter.linkToViewGroup(grid) + + adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid)) val hostDialog = dialogLaunchAnimator.showFromView(this, view) adapter.injectDialogShower(DialogShowerImpl(hostDialog, dialogLaunchAnimator)) diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index fa874b19c2cc..3ed7e84af020 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -986,6 +986,18 @@ public class OverviewProxyService extends CurrentUserTracker implements } } + public void onNavButtonsDarkIntensityChanged(float darkIntensity) { + try { + if (mOverviewProxy != null) { + mOverviewProxy.onNavButtonsDarkIntensityChanged(darkIntensity); + } else { + Log.e(TAG_OPS, "Failed to get overview proxy to update nav buttons dark intensity"); + } + } catch (RemoteException e) { + Log.e(TAG_OPS, "Failed to call onNavButtonsDarkIntensityChanged()", e); + } + } + private void updateEnabledState() { final int currentUser = ActivityManagerWrapper.getInstance().getCurrentUserId(); mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 6676901997bf..5876703a800e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -513,9 +513,13 @@ public class CommandQueue extends IStatusBar.Stub implements * @param animate {@code true} to show animations. */ public void recomputeDisableFlags(int displayId, boolean animate) { - int disabled1 = getDisabled1(displayId); - int disabled2 = getDisabled2(displayId); - disable(displayId, disabled1, disabled2, animate); + // This must update holding the lock otherwise it can clobber the disabled flags set on the + // binder thread from the disable() call + synchronized (mLock) { + int disabled1 = getDisabled1(displayId); + int disabled2 = getDisabled2(displayId); + disable(displayId, disabled1, disabled2, animate); + } } private void setDisabled(int displayId, int disabled1, int disabled2) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 67f51cb9ab43..aa3b3e12b8f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.content.Context; import android.content.res.Resources; import android.hardware.biometrics.BiometricSourceType; +import android.hardware.fingerprint.FingerprintManager; import android.metrics.LogMaker; import android.os.Handler; import android.os.PowerManager; @@ -46,9 +47,11 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationShadeWindowController; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.KeyguardStateController; import java.io.FileDescriptor; @@ -71,6 +74,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000; private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock"; private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl(); + private static final int FP_ATTEMPTS_BEFORE_SHOW_BOUNCER = 3; @IntDef(prefix = { "MODE_" }, value = { MODE_NONE, @@ -167,6 +171,10 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private final MetricsLogger mMetricsLogger; private final AuthController mAuthController; + private final StatusBarStateController mStatusBarStateController; + + private long mLastFpFailureUptimeMillis; + private int mNumConsecutiveFpFailures; private static final class PendingAuthenticated { public final int userId; @@ -209,7 +217,10 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp BIOMETRIC_IRIS_FAILURE(403), @UiEvent(doc = "A biometric event of type iris errored.") - BIOMETRIC_IRIS_ERROR(404); + BIOMETRIC_IRIS_ERROR(404), + + @UiEvent(doc = "Bouncer was shown as a result of consecutive failed UDFPS attempts.") + BIOMETRIC_BOUNCER_SHOWN(916); private final int mId; @@ -257,7 +268,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp NotificationMediaManager notificationMediaManager, WakefulnessLifecycle wakefulnessLifecycle, ScreenLifecycle screenLifecycle, - AuthController authController) { + AuthController authController, + StatusBarStateController statusBarStateController) { mContext = context; mPowerManager = powerManager; mShadeController = shadeController; @@ -279,6 +291,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mKeyguardBypassController.setUnlockController(this); mMetricsLogger = metricsLogger; mAuthController = authController; + mStatusBarStateController = statusBarStateController; dumpManager.registerDumpable(getClass().getName(), this); } @@ -620,6 +633,22 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp .setType(MetricsEvent.TYPE_FAILURE).setSubtype(toSubtype(biometricSourceType))); Optional.ofNullable(BiometricUiEvent.FAILURE_EVENT_BY_SOURCE_TYPE.get(biometricSourceType)) .ifPresent(UI_EVENT_LOGGER::log); + + long currUptimeMillis = SystemClock.uptimeMillis(); + if (currUptimeMillis - mLastFpFailureUptimeMillis < 2000) { // attempt within 2 seconds + mNumConsecutiveFpFailures += 1; + } else { + mNumConsecutiveFpFailures = 1; + } + mLastFpFailureUptimeMillis = currUptimeMillis; + + if (biometricSourceType.equals(BiometricSourceType.FINGERPRINT) + && mUpdateMonitor.isUdfpsSupported() + && mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) { + mKeyguardViewController.showBouncer(true); + UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN); + mNumConsecutiveFpFailures = 0; + } cleanup(); } @@ -631,6 +660,16 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp .addTaggedData(MetricsEvent.FIELD_BIOMETRIC_AUTH_ERROR, msgId)); Optional.ofNullable(BiometricUiEvent.ERROR_EVENT_BY_SOURCE_TYPE.get(biometricSourceType)) .ifPresent(UI_EVENT_LOGGER::log); + + // if we're on the shade and we're locked out, immediately show the bouncer + if (biometricSourceType == BiometricSourceType.FINGERPRINT + && (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT + || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) + && mUpdateMonitor.isUdfpsSupported() + && (mStatusBarStateController.getState() == StatusBarState.SHADE + || mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED)) { + mKeyguardViewController.showBouncer(true); + } cleanup(); } @@ -664,6 +703,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mBiometricModeListener.onResetMode(); mBiometricModeListener.notifyBiometricAuthModeChanged(); } + mNumConsecutiveFpFailures = 0; + mLastFpFailureUptimeMillis = 0; } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 353868ba969f..9647486be992 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -21,6 +21,7 @@ import static com.android.systemui.plugins.ActivityStarter.OnDismissAction; import android.content.Context; import android.content.res.ColorStateList; +import android.hardware.biometrics.BiometricSourceType; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; @@ -81,6 +82,13 @@ public class KeyguardBouncer { public void onStrongAuthStateChanged(int userId) { mBouncerPromptReason = mCallback.getBouncerPromptReason(); } + + @Override + public void onLockedOutStateChanged(BiometricSourceType type) { + if (type == BiometricSourceType.FINGERPRINT) { + mBouncerPromptReason = mCallback.getBouncerPromptReason(); + } + } }; private final Runnable mRemoveViewRunnable = this::removeView; private final KeyguardBypassController mKeyguardBypassController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index 570b0ca3564c..88ae0db5bad0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -37,7 +37,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.policy.BatteryController; import java.io.FileDescriptor; @@ -251,7 +250,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private void updateNavigation() { if (mNavigationBarController != null - && !QuickStepContract.isGesturalMode(mNavigationMode)) { + && mNavigationBarController.supportsIconTintForNavMode(mNavigationMode)) { mNavigationBarController.setIconsDark(mNavigationLight, animateChange()); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index 9021b74d1518..415fb92e37ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java @@ -28,6 +28,7 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.animation.Interpolators; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -230,6 +231,14 @@ public class LightBarTransitionsController implements Dumpable, Callbacks, } /** + * Return whether to use the tint calculated in this class for nav icons. + */ + public boolean supportsIconTintForNavMode(int navigationMode) { + // In gesture mode, we already do region sampling to update tint based on content beneath. + return !QuickStepContract.isGesturalMode(navigationMode); + } + + /** * Interface to apply a specific dark intensity. */ public interface DarkIntensityApplier { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt index c814622ff074..a4feeab48e6e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt @@ -25,6 +25,7 @@ import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.flags.FeatureFlags import com.android.systemui.qs.carrier.QSCarrierGroupController import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope +import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_BATTERY_CONTROLLER import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER import javax.inject.Inject import javax.inject.Named @@ -35,7 +36,7 @@ class SplitShadeHeaderController @Inject constructor( private val statusBarIconController: StatusBarIconController, qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder, featureFlags: FeatureFlags, - batteryMeterViewController: BatteryMeterViewController + @Named(SPLIT_SHADE_BATTERY_CONTROLLER) batteryMeterViewController: BatteryMeterViewController ) { companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index e033c4725999..0f55f289ff27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -150,6 +150,7 @@ import com.android.systemui.emergency.EmergencyGesture; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.fragments.ExtensionFragmentListener; import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -489,7 +490,6 @@ public class StatusBar extends SystemUI implements private final DozeParameters mDozeParameters; private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; private final StatusBarComponent.Factory mStatusBarComponentFactory; - private final StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory; private final PluginManager mPluginManager; private final Optional<LegacySplitScreen> mSplitScreenOptional; private final StatusBarNotificationActivityStarter.Builder @@ -538,7 +538,7 @@ public class StatusBar extends SystemUI implements protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider; private final BrightnessSliderController.Factory mBrightnessSliderFactory; private final FeatureFlags mFeatureFlags; - + private final FragmentService mFragmentService; private final WallpaperController mWallpaperController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final MessageRouter mMessageRouter; @@ -546,6 +546,8 @@ public class StatusBar extends SystemUI implements private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; private final TunerService mTunerService; + private StatusBarComponent mStatusBarComponent; + // Flags for disabling the status bar // Two variables becaseu the first one evidently ran out of room for new flags. private int mDisabled1 = 0; @@ -690,6 +692,7 @@ public class StatusBar extends SystemUI implements public StatusBar( Context context, NotificationsController notificationsController, + FragmentService fragmentService, LightBarController lightBarController, AutoHideController autoHideController, StatusBarWindowController statusBarWindowController, @@ -747,7 +750,6 @@ public class StatusBar extends SystemUI implements CommandQueue commandQueue, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, StatusBarComponent.Factory statusBarComponentFactory, - StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory, PluginManager pluginManager, Optional<LegacySplitScreen> splitScreenOptional, LightsOutNotifController lightsOutNotifController, @@ -791,6 +793,7 @@ public class StatusBar extends SystemUI implements ActivityLaunchAnimator activityLaunchAnimator) { super(context); mNotificationsController = notificationsController; + mFragmentService = fragmentService; mLightBarController = lightBarController; mAutoHideController = autoHideController; mStatusBarWindowController = statusBarWindowController; @@ -852,7 +855,6 @@ public class StatusBar extends SystemUI implements mCommandQueue = commandQueue; mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger; mStatusBarComponentFactory = statusBarComponentFactory; - mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory; mPluginManager = pluginManager; mSplitScreenOptional = splitScreenOptional; mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder; @@ -1184,24 +1186,7 @@ public class StatusBar extends SystemUI implements }).getFragmentManager() .beginTransaction() .replace(R.id.status_bar_container, - new CollapsedStatusBarFragment( - mStatusBarFragmentComponentFactory, - mOngoingCallController, - mAnimationScheduler, - mStatusBarLocationPublisher, - mNotificationIconAreaController, - mPanelExpansionStateManager, - mFeatureFlags, - () -> Optional.of(this), - mStatusBarIconController, - mStatusBarHideIconsForBouncerManager, - mKeyguardStateController, - mNetworkController, - mStatusBarStateController, - mCommandQueue, - mCollapsedStatusBarFragmentLogger, - mOperatorNameViewControllerFactory - ), + mStatusBarComponent.createCollapsedStatusBarFragment(), CollapsedStatusBarFragment.TAG) .commit(); @@ -1557,32 +1542,34 @@ public class StatusBar extends SystemUI implements } private void inflateStatusBarWindow() { - StatusBarComponent statusBarComponent = mStatusBarComponentFactory.create(); - mNotificationShadeWindowView = statusBarComponent.getNotificationShadeWindowView(); - mNotificationShadeWindowViewController = statusBarComponent + mStatusBarComponent = mStatusBarComponentFactory.create(); + mFragmentService.addFragmentInstantiationProvider(mStatusBarComponent); + + mNotificationShadeWindowView = mStatusBarComponent.getNotificationShadeWindowView(); + mNotificationShadeWindowViewController = mStatusBarComponent .getNotificationShadeWindowViewController(); mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView); mNotificationShadeWindowViewController.setupExpandedStatusBar(); - mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController(); - statusBarComponent.getLockIconViewController().init(); - mStackScrollerController = statusBarComponent.getNotificationStackScrollLayoutController(); + mNotificationPanelViewController = mStatusBarComponent.getNotificationPanelViewController(); + mStatusBarComponent.getLockIconViewController().init(); + mStackScrollerController = mStatusBarComponent.getNotificationStackScrollLayoutController(); mStackScroller = mStackScrollerController.getView(); - mNotificationShelfController = statusBarComponent.getNotificationShelfController(); - mAuthRippleController = statusBarComponent.getAuthRippleController(); + mNotificationShelfController = mStatusBarComponent.getNotificationShelfController(); + mAuthRippleController = mStatusBarComponent.getAuthRippleController(); mAuthRippleController.init(); - mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener()); + mHeadsUpManager.addListener(mStatusBarComponent.getStatusBarHeadsUpChangeListener()); - mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener()); + mHeadsUpManager.addListener(mStatusBarComponent.getStatusBarHeadsUpChangeListener()); // Listen for demo mode changes - mDemoModeController.addCallback(statusBarComponent.getStatusBarDemoMode()); + mDemoModeController.addCallback(mStatusBarComponent.getStatusBarDemoMode()); if (mCommandQueueCallbacks != null) { mCommandQueue.removeCallback(mCommandQueueCallbacks); } - mCommandQueueCallbacks = statusBarComponent.getStatusBarCommandQueueCallbacks(); + mCommandQueueCallbacks = mStatusBarComponent.getStatusBarCommandQueueCallbacks(); // Connect in to the status bar manager service mCommandQueue.addCallback(mCommandQueueCallbacks); } @@ -2000,7 +1987,7 @@ public class StatusBar extends SystemUI implements } } - public void maybeEscalateHeadsUp() { + private void maybeEscalateHeadsUp() { mHeadsUpManager.getAllEntries().forEach(entry -> { final StatusBarNotification sbn = entry.getSbn(); final Notification notification = sbn.getNotification(); @@ -2011,6 +1998,7 @@ public class StatusBar extends SystemUI implements try { EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION, sbn.getKey()); + wakeUpForFullScreenIntent(); notification.fullScreenIntent.send(); entry.notifyFullScreenIntentLaunched(); } catch (PendingIntent.CanceledException e) { @@ -2020,6 +2008,17 @@ public class StatusBar extends SystemUI implements mHeadsUpManager.releaseAllImmediately(); } + void wakeUpForFullScreenIntent() { + if (isGoingToSleep() || mDozing) { + mPowerManager.wakeUp( + SystemClock.uptimeMillis(), + PowerManager.WAKE_REASON_APPLICATION, + "com.android.systemui:full_screen_intent"); + mWakeUpComingFromTouch = false; + mWakeUpTouchLocation = null; + } + } + void makeExpandedVisible(boolean force) { if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) { @@ -3549,7 +3548,7 @@ public class StatusBar extends SystemUI implements DejankUtils.startDetectingBlockingIpcs(tag); updateRevealEffect(false /* wakingUp */); updateNotificationPanelTouchState(); - notifyHeadsUpGoingToSleep(); + maybeEscalateHeadsUp(); dismissVolumeDialog(); mWakeUpCoordinator.setFullyAwake(false); mBypassHeadsUpNotifier.setFullyAwake(false); @@ -4094,10 +4093,6 @@ public class StatusBar extends SystemUI implements } } - protected void notifyHeadsUpGoingToSleep() { - maybeEscalateHeadsUp(); - } - /** * @return Whether the security bouncer from Keyguard is showing. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 7ab4a1ec237e..0d23d663c51c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -441,6 +441,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)} */ public void showBouncer(boolean scrimmed) { + resetAlternateAuth(false); + if (mShowing && !mBouncer.isShowing()) { mBouncer.show(false /* resetSecuritySelection */, scrimmed); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index dba3b2418790..ce3811113912 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -41,6 +41,8 @@ import android.text.TextUtils; import android.util.EventLog; import android.view.View; +import androidx.annotation.VisibleForTesting; + import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.NotificationVisibility; @@ -593,7 +595,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } } - private void handleFullScreenIntent(NotificationEntry entry) { + @VisibleForTesting + void handleFullScreenIntent(NotificationEntry entry) { if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) { if (shouldSuppressFullScreenIntent(entry)) { mLogger.logFullScreenIntentSuppressedByDnD(entry.getKey()); @@ -617,6 +620,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit try { EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, entry.getKey()); + mStatusBar.wakeUpForFullScreenIntent(); fullscreenIntent.send(); entry.notifyFullScreenIntentLaunched(); mMetricsLogger.count("note_fullscreen", 1); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 1130ec24108a..ed52a81751dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -36,6 +36,8 @@ import android.view.WindowInsets.Type; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; +import androidx.annotation.Nullable; + import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.DialogListener; @@ -303,13 +305,32 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog, * the screen off / close system dialogs broadcast. * <p> * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after - * calling this because it causes a leak of BroadcastReceiver. + * calling this because it causes a leak of BroadcastReceiver. Instead, call the version that + * takes an extra Runnable as a parameter. * * @param dialog The dialog to be associated with the listener. */ public static void registerDismissListener(Dialog dialog) { + registerDismissListener(dialog, null); + } + + + /** + * Registers a listener that dismisses the given dialog when it receives + * the screen off / close system dialogs broadcast. + * <p> + * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after + * calling this because it causes a leak of BroadcastReceiver. + * + * @param dialog The dialog to be associated with the listener. + * @param dismissAction An action to run when the dialog is dismissed. + */ + public static void registerDismissListener(Dialog dialog, @Nullable Runnable dismissAction) { DismissReceiver dismissReceiver = new DismissReceiver(dialog); - dialog.setOnDismissListener(d -> dismissReceiver.unregister()); + dialog.setOnDismissListener(d -> { + dismissReceiver.unregister(); + if (dismissAction != null) dismissAction.run(); + }); dismissReceiver.register(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java index e06605eac46f..375641fdb69d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.phone.SplitShadeHeaderController; import com.android.systemui.statusbar.phone.StatusBarCommandQueueCallbacks; import com.android.systemui.statusbar.phone.StatusBarDemoMode; import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener; +import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -38,7 +39,13 @@ import javax.inject.Scope; import dagger.Subcomponent; /** - * Dagger subcomponent tied to the lifecycle of StatusBar views. + * Dagger subcomponent for classes (semi-)related to the status bar. The component is created once + * inside {@link com.android.systemui.statusbar.phone.StatusBar} and never re-created. + * + * TODO(b/197137564): This should likely be re-factored a bit. It includes classes that aren't + * directly related to status bar functionality, like multiple notification classes. And, the fact + * that it has many getter methods indicates that we need to access many of these classes from + * outside the component. Should more items be moved *into* this component to avoid so many getters? */ @Subcomponent(modules = {StatusBarViewModule.class}) @StatusBarComponent.StatusBarScope @@ -121,4 +128,10 @@ public interface StatusBarComponent { */ @StatusBarScope SplitShadeHeaderController getSplitShadeHeaderController(); + + /** + * Creates a new {@link CollapsedStatusBarFragment} each time it's called. See + * {@link StatusBarViewModule#createCollapsedStatusBarFragment}. + */ + CollapsedStatusBarFragment createCollapsedStatusBarFragment(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 27ece84859d8..50e6151bd3a3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -39,6 +39,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; @@ -100,7 +101,6 @@ import com.android.systemui.statusbar.phone.StatusBarSignalPolicy; import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger; -import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.BatteryController; @@ -143,6 +143,7 @@ public interface StatusBarPhoneModule { static StatusBar provideStatusBar( Context context, NotificationsController notificationsController, + FragmentService fragmentService, LightBarController lightBarController, AutoHideController autoHideController, StatusBarWindowController statusBarWindowController, @@ -200,7 +201,6 @@ public interface StatusBarPhoneModule { CommandQueue commandQueue, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, StatusBarComponent.Factory statusBarComponentFactory, - StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory, PluginManager pluginManager, Optional<LegacySplitScreen> splitScreenOptional, LightsOutNotifController lightsOutNotifController, @@ -245,6 +245,7 @@ public interface StatusBarPhoneModule { return new StatusBar( context, notificationsController, + fragmentService, lightBarController, autoHideController, statusBarWindowController, @@ -302,7 +303,6 @@ public interface StatusBarPhoneModule { commandQueue, collapsedStatusBarFragmentLogger, statusBarComponentFactory, - statusBarFragmentComponentFactory, pluginManager, splitScreenOptional, lightsOutNotifController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index 2765fe37f846..76176df136b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone.dagger; import android.annotation.Nullable; +import android.content.ContentResolver; +import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.view.ViewStub; @@ -24,19 +26,45 @@ import android.view.ViewStub; import com.android.keyguard.LockIconView; import com.android.systemui.R; import com.android.systemui.battery.BatteryMeterView; +import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.biometrics.AuthRippleView; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelfController; +import com.android.systemui.statusbar.OperatorNameViewController; +import com.android.systemui.statusbar.connectivity.NetworkController; +import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.NotificationPanelView; +import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusBarLocationPublisher; import com.android.systemui.statusbar.phone.TapAgainView; +import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; +import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger; +import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent; +import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; +import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.tuner.TunerService; + +import java.util.Optional; import javax.inject.Named; +import dagger.Lazy; import dagger.Module; import dagger.Provides; @@ -44,6 +72,8 @@ import dagger.Provides; public abstract class StatusBarViewModule { public static final String SPLIT_SHADE_HEADER = "split_shade_header"; + private static final String SPLIT_SHADE_BATTERY_VIEW = "split_shade_battery_view"; + public static final String SPLIT_SHADE_BATTERY_CONTROLLER = "split_shade_battery_controller"; /** */ @Provides @@ -143,10 +173,34 @@ public abstract class StatusBarViewModule { /** */ @Provides @StatusBarComponent.StatusBarScope + @Named(SPLIT_SHADE_BATTERY_VIEW) static BatteryMeterView getBatteryMeterView(@Named(SPLIT_SHADE_HEADER) View view) { return view.findViewById(R.id.batteryRemainingIcon); } + @Provides + @StatusBarComponent.StatusBarScope + @Named(SPLIT_SHADE_BATTERY_CONTROLLER) + static BatteryMeterViewController getBatteryMeterViewController( + @Named(SPLIT_SHADE_BATTERY_VIEW) BatteryMeterView batteryMeterView, + ConfigurationController configurationController, + TunerService tunerService, + BroadcastDispatcher broadcastDispatcher, + @Main Handler mainHandler, + ContentResolver contentResolver, + BatteryController batteryController + ) { + return new BatteryMeterViewController( + batteryMeterView, + configurationController, + tunerService, + broadcastDispatcher, + mainHandler, + contentResolver, + batteryController); + + } + /** */ @Provides @StatusBarComponent.StatusBarScope @@ -161,4 +215,54 @@ public abstract class StatusBarViewModule { NotificationShadeWindowView notificationShadeWindowView) { return notificationShadeWindowView.findViewById(R.id.notification_container_parent); } + + /** + * Creates a new {@link CollapsedStatusBarFragment}. + * + * **IMPORTANT**: This method intentionally does not have + * {@link StatusBarComponent.StatusBarScope}, which means a new fragment *will* be created each + * time this method is called. This is intentional because we need fragments to re-created in + * certain lifecycle scenarios. + * + * **IMPORTANT**: This method also intentionally does not have a {@link Provides} annotation. If + * you need to get access to a {@link CollapsedStatusBarFragment}, go through + * {@link StatusBarFragmentComponent} instead. + */ + public static CollapsedStatusBarFragment createCollapsedStatusBarFragment( + StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory, + OngoingCallController ongoingCallController, + SystemStatusAnimationScheduler animationScheduler, + StatusBarLocationPublisher locationPublisher, + NotificationIconAreaController notificationIconAreaController, + PanelExpansionStateManager panelExpansionStateManager, + FeatureFlags featureFlags, + Lazy<Optional<StatusBar>> statusBarOptionalLazy, + StatusBarIconController statusBarIconController, + StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, + KeyguardStateController keyguardStateController, + NotificationPanelViewController notificationPanelViewController, + NetworkController networkController, + StatusBarStateController statusBarStateController, + CommandQueue commandQueue, + CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, + OperatorNameViewController.Factory operatorNameViewControllerFactory + ) { + return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory, + ongoingCallController, + animationScheduler, + locationPublisher, + notificationIconAreaController, + panelExpansionStateManager, + featureFlags, + statusBarOptionalLazy, + statusBarIconController, + statusBarHideIconsForBouncerManager, + keyguardStateController, + notificationPanelViewController, + networkController, + statusBarStateController, + commandQueue, + collapsedStatusBarFragmentLogger, + operatorNameViewControllerFactory); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index 9bcf4a58ce0b..b32acce51e84 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -53,6 +53,7 @@ import com.android.systemui.statusbar.connectivity.SignalCallback; import com.android.systemui.statusbar.events.SystemStatusAnimationCallback; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.phone.NotificationIconAreaController; +import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager; @@ -94,6 +95,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private PhoneStatusBarView mStatusBar; private final StatusBarStateController mStatusBarStateController; private final KeyguardStateController mKeyguardStateController; + private final NotificationPanelViewController mNotificationPanelViewController; private final NetworkController mNetworkController; private LinearLayout mSystemIconArea; private View mClockView; @@ -147,6 +149,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue StatusBarIconController statusBarIconController, StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, KeyguardStateController keyguardStateController, + NotificationPanelViewController notificationPanelViewController, NetworkController networkController, StatusBarStateController statusBarStateController, CommandQueue commandQueue, @@ -164,6 +167,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mStatusBarIconController = statusBarIconController; mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager; mKeyguardStateController = keyguardStateController; + mNotificationPanelViewController = notificationPanelViewController; mNetworkController = networkController; mStatusBarStateController = statusBarStateController; mCommandQueue = commandQueue; @@ -354,8 +358,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue // The shelf will be hidden when dozing with a custom clock, we must show notification // icons in this occasion. if (mStatusBarStateController.isDozing() - && mStatusBarOptionalLazy.get().map( - sb -> sb.getPanelController().hasCustomClock()).orElse(false)) { + && mNotificationPanelViewController.hasCustomClock()) { state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 0e86964147d7..1cf21ac40e31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -351,9 +351,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { mSystemClock.advanceTime(205); mController.onTouchOutsideView(); - // THEN show the bouncer and reset alt auth + // THEN show the bouncer verify(mStatusBarKeyguardViewManager).showBouncer(eq(true)); - verify(mStatusBarKeyguardViewManager).resetAlternateAuth(anyBoolean()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt new file mode 100644 index 000000000000..77c837b803af --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt @@ -0,0 +1,82 @@ +package com.android.systemui.fragments + +import android.app.Fragment +import android.os.Looper +import android.test.suitebuilder.annotation.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager +import com.android.systemui.qs.QSFragment +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test + +@SmallTest +class FragmentServiceTest : SysuiTestCase() { + private val fragmentCreator = TestFragmentCreator() + private val fragmentCreatorFactory = FragmentService.FragmentCreator.Factory { fragmentCreator } + + private lateinit var fragmentService: FragmentService + + @Before + fun setUp() { + if (Looper.myLooper() == null) { + Looper.prepare() + } + + fragmentService = FragmentService(fragmentCreatorFactory, mock(), DumpManager()) + } + + @Test + fun constructor_addsFragmentCreatorMethodsToMap() { + val map = fragmentService.injectionMap + assertThat(map).hasSize(2) + assertThat(map.keys).contains(QSFragment::class.java.name) + assertThat(map.keys).contains(TestFragmentInCreator::class.java.name) + } + + @Test + fun addFragmentInstantiationProvider_objectHasNoFragmentMethods_nothingAdded() { + fragmentService.addFragmentInstantiationProvider(Object()) + + assertThat(fragmentService.injectionMap).hasSize(2) + } + + @Test + fun addFragmentInstantiationProvider_objectHasFragmentMethods_methodsAdded() { + fragmentService.addFragmentInstantiationProvider( + @Suppress("unused") + object : Any() { + fun createTestFragment2() = TestFragment2() + fun createTestFragment3() = TestFragment3() + } + ) + + val map = fragmentService.injectionMap + assertThat(map).hasSize(4) + assertThat(map.keys).contains(TestFragment2::class.java.name) + assertThat(map.keys).contains(TestFragment3::class.java.name) + } + + @Test + fun addFragmentInstantiationProvider_objectFragmentMethodsAlreadyProvided_nothingAdded() { + fragmentService.addFragmentInstantiationProvider( + @Suppress("unused") + object : Any() { + fun createTestFragment() = TestFragmentInCreator() + } + ) + + assertThat(fragmentService.injectionMap).hasSize(2) + } + + class TestFragmentCreator : FragmentService.FragmentCreator { + override fun createQSFragment(): QSFragment = mock() + @Suppress("unused") + fun createTestFragment(): TestFragmentInCreator = TestFragmentInCreator() + } + + class TestFragmentInCreator : Fragment() + class TestFragment2 : Fragment() + class TestFragment3 : Fragment() +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java index 31d88303485c..9d2541c0150f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java @@ -45,6 +45,7 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.policy.ConfigurationController; import org.junit.After; @@ -86,7 +87,8 @@ public class NavigationBarControllerTest extends SysuiTestCase { mock(TaskbarDelegate.class), mNavigationBarFactory, mock(DumpManager.class), - mock(AutoHideController.class))); + mock(AutoHideController.class), + mock(LightBarController.class))); initializeNavigationBars(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt index f99703e2415d..13df04ccef6f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt @@ -16,22 +16,28 @@ package com.android.systemui.qs.tiles +import android.app.Dialog import android.content.ContextWrapper import android.content.SharedPreferences import android.os.Handler import android.provider.Settings +import android.provider.Settings.Global.ZEN_MODE_OFF import android.testing.AndroidTestingRunner import android.testing.TestableLooper +import android.view.View import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.logging.QSLogger import com.android.systemui.statusbar.policy.ZenModeController +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat @@ -40,9 +46,12 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito +import org.mockito.Mockito.anyBoolean +import org.mockito.Mockito.never +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.io.File +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -70,6 +79,10 @@ class DndTileTest : SysuiTestCase() { private lateinit var zenModeController: ZenModeController @Mock private lateinit var sharedPreferences: SharedPreferences + @Mock + private lateinit var dialogLaunchAnimator: DialogLaunchAnimator + @Mock + private lateinit var hostDialog: Dialog private lateinit var secureSettings: SecureSettings private lateinit var testableLooper: TestableLooper @@ -81,15 +94,17 @@ class DndTileTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) secureSettings = FakeSettings() - Mockito.`when`(qsHost.userId).thenReturn(DEFAULT_USER) - Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) + whenever(qsHost.userId).thenReturn(DEFAULT_USER) + whenever(qsHost.uiEventLogger).thenReturn(uiEventLogger) + whenever(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean())) + .thenReturn(hostDialog) val wrappedContext = object : ContextWrapper(context) { override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { return sharedPreferences } } - Mockito.`when`(qsHost.context).thenReturn(wrappedContext) + whenever(qsHost.context).thenReturn(wrappedContext) tile = DndTile( qsHost, @@ -102,7 +117,8 @@ class DndTileTest : SysuiTestCase() { qsLogger, zenModeController, sharedPreferences, - secureSettings + secureSettings, + dialogLaunchAnimator ) } @@ -147,4 +163,32 @@ class DndTileTest : SysuiTestCase() { assertThat(tile.state.forceExpandIcon).isTrue() } + + @Test + fun testLaunchDialogFromViewWhenPrompt() { + whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) + + secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) + testableLooper.processAllMessages() + + val view = View(context) + tile.handleClick(view) + testableLooper.processAllMessages() + + verify(dialogLaunchAnimator).showFromView(any(), eq(view), anyBoolean()) + } + + @Test + fun testNoLaunchDialogWhenNotPrompt() { + whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) + + secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) + testableLooper.processAllMessages() + + val view = View(context) + tile.handleClick(view) + testableLooper.processAllMessages() + + verify(dialogLaunchAnimator, never()).showFromView(any(), any(), anyBoolean()) + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt deleted file mode 100644 index d5fe588b2115..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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) - } -}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt index ea3a42ce501c..3c4a557eac10 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.user import android.app.Dialog +import android.content.DialogInterface import android.content.Intent import android.provider.Settings import android.testing.AndroidTestingRunner @@ -28,6 +29,7 @@ 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.phone.SystemUIDialog import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture @@ -43,7 +45,6 @@ import org.mockito.Mockito.`when` import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.anyInt import org.mockito.Mockito.argThat -import org.mockito.Mockito.inOrder import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -53,27 +54,21 @@ import org.mockito.MockitoAnnotations class UserSwitchDialogControllerTest : SysuiTestCase() { @Mock - private lateinit var dialog: UserDialog + private lateinit var dialog: SystemUIDialog @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 - @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator @Mock private lateinit var hostDialog: Dialog @Captor - private lateinit var clickCaptor: ArgumentCaptor<View.OnClickListener> + private lateinit var clickCaptor: ArgumentCaptor<DialogInterface.OnClickListener> private lateinit var controller: UserSwitchDialogController @@ -81,11 +76,8 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { 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) + `when`(dialog.context).thenReturn(mContext) `when`(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean())) .thenReturn(hostDialog) @@ -105,30 +97,6 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { } @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) @@ -143,51 +111,44 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { @Test fun adapterAndGridLinked() { controller.showDialog(launchView) - verify(userDetailViewAdapter).linkToViewGroup(gridView) + verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>()) } @Test - fun clickDoneButton_dismiss() { + fun doneButtonSetWithNullHandler() { controller.showDialog(launchView) - verify(doneView).setOnClickListener(capture(clickCaptor)) - - clickCaptor.value.onClick(doneView) - - verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt()) - verify(dialog).dismiss() + verify(dialog).setPositiveButton(anyInt(), eq(null)) } @Test - fun clickSettingsButton_noFalsing_opensSettingsAndDismisses() { + fun clickSettingsButton_noFalsing_opensSettings() { `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false) controller.showDialog(launchView) - verify(settingsView).setOnClickListener(capture(clickCaptor)) + verify(dialog).setNeutralButton(anyInt(), capture(clickCaptor)) - clickCaptor.value.onClick(settingsView) + clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL) verify(activityStarter) .postStartActivityDismissingKeyguard( argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)), eq(0) ) - verify(dialog).dismiss() } @Test - fun clickSettingsButton_Falsing_notOpensSettingsAndDismisses() { + fun clickSettingsButton_Falsing_notOpensSettings() { `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true) controller.showDialog(launchView) - verify(settingsView).setOnClickListener(capture(clickCaptor)) + verify(dialog).setNeutralButton(anyInt(), capture(clickCaptor)) - clickCaptor.value.onClick(settingsView) + clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL) verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt()) - verify(dialog).dismiss() } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index 25fd80133897..07debe68e224 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -45,6 +45,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -101,6 +102,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { private WakefulnessLifecycle mWakefulnessLifecycle; @Mock private ScreenLifecycle mScreenLifecycle; + @Mock + private StatusBarStateController mStatusBarStateController; private BiometricUnlockController mBiometricUnlockController; @Before @@ -123,7 +126,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters, mMetricsLogger, mDumpManager, mPowerManager, mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle, - mAuthController); + mAuthController, mStatusBarStateController); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener); } @@ -378,6 +381,23 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test + public void onUdfpsConsecutivelyFailedThreeTimes_showBouncer() { + // GIVEN UDFPS is supported + when(mUpdateMonitor.isUdfpsSupported()).thenReturn(true); + + // WHEN udfps fails twice - then don't show the bouncer + mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT); + mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT); + verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); + + // WHEN udfps fails the third time + mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT); + + // THEN show the bouncer + verify(mStatusBarKeyguardViewManager).showBouncer(true); + } + + @Test public void onFinishedGoingToSleep_authenticatesWhenPending() { when(mUpdateMonitor.isGoingToSleep()).thenReturn(true); mBiometricUnlockController.onFinishedGoingToSleep(-1); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 6f174cbe0021..c5bdfed6082b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -374,6 +374,21 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { } @Test + public void testHideAltAuth_onShowBouncer() { + // GIVEN alt auth is showing + mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); + when(mBouncer.isShowing()).thenReturn(false); + when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); + reset(mAlternateAuthInterceptor); + + // WHEN showBouncer is called + mStatusBarKeyguardViewManager.showBouncer(true); + + // THEN alt bouncer should be hidden + verify(mAlternateAuthInterceptor).hideAlternateAuthBouncer(); + } + + @Test public void testUpdateResources_delegatesToBouncer() { mStatusBarKeyguardViewManager.updateResources(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 72a3d664a6ce..cec5877e324a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -34,6 +34,7 @@ import static org.mockito.Mockito.when; import android.app.KeyguardManager; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Intent; import android.os.Handler; @@ -62,7 +63,6 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -114,6 +114,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private KeyguardStateController mKeyguardStateController; @Mock + private NotificationInterruptStateProvider mNotificationInterruptStateProvider; + @Mock private Handler mHandler; @Mock private BubblesManager mBubblesManager; @@ -133,7 +135,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private OnUserInteractionCallback mOnUserInteractionCallback; @Mock - private NotificationActivityStarter mNotificationActivityStarter; + private StatusBarNotificationActivityStarter mNotificationActivityStarter; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -209,7 +211,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mock(NotificationLockscreenUserManager.class), mShadeController, mKeyguardStateController, - mock(NotificationInterruptStateProvider.class), + mNotificationInterruptStateProvider, mock(LockPatternUtils.class), mock(StatusBarRemoteInputCallback.class), mActivityIntentHelper, @@ -365,4 +367,27 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // Notification should not be cancelled. verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt()); } + + @Test + public void testOnFullScreenIntentWhenDozing_wakeUpDevice() { + // GIVEN entry that can has a full screen intent that can show + Notification.Builder nb = new Notification.Builder(mContext, "a") + .setContentTitle("foo") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setFullScreenIntent(mock(PendingIntent.class), true); + StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, + "tag" + System.currentTimeMillis(), 0, 0, + nb.build(), new UserHandle(0), null, 0); + NotificationEntry entry = mock(NotificationEntry.class); + when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH); + when(entry.getSbn()).thenReturn(sbn); + when(mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(eq(entry))) + .thenReturn(true); + + // WHEN + mNotificationActivityStarter.handleFullScreenIntent(entry); + + // THEN display should try wake up for the full screen intent + verify(mStatusBar).wakeUpForFullScreenIntent(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 88d36b0e3d44..d58e13cd8a64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -86,6 +86,7 @@ import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; @@ -132,7 +133,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger; -import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.BatteryController; @@ -244,8 +244,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private CollapsedStatusBarFragmentLogger mCollapsedStatusBarFragmentLogger; @Mock private StatusBarComponent.Factory mStatusBarComponentFactory; @Mock private StatusBarComponent mStatusBarComponent; - @Mock private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory; - @Mock private StatusBarFragmentComponent mStatusBarFragmentComponent; @Mock private PluginManager mPluginManager; @Mock private LegacySplitScreen mLegacySplitScreen; @Mock private LightsOutNotifController mLightsOutNotifController; @@ -350,8 +348,6 @@ public class StatusBarTest extends SysuiTestCase { when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController); when(mStatusBarComponentFactory.create()).thenReturn(mStatusBarComponent); - when(mStatusBarFragmentComponentFactory.create(any())) - .thenReturn(mStatusBarFragmentComponent); when(mStatusBarComponent.getNotificationShadeWindowViewController()).thenReturn( mNotificationShadeWindowViewController); @@ -366,6 +362,7 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar = new StatusBar( mContext, mNotificationsController, + mock(FragmentService.class), mLightBarController, mAutoHideController, mStatusBarWindowController, @@ -422,7 +419,6 @@ public class StatusBarTest extends SysuiTestCase { mCommandQueue, mCollapsedStatusBarFragmentLogger, mStatusBarComponentFactory, - mStatusBarFragmentComponentFactory, mPluginManager, Optional.of(mLegacySplitScreen), mLightsOutNotifController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index ec35edfdfab2..8b5989ff61a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -295,6 +295,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { new StatusBarHideIconsForBouncerManager( mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()), mKeyguardStateController, + mock(NotificationPanelViewController.class), mNetworkController, mStatusBarStateController, mCommandQueue, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5cd66aabbf2e..dde1ed9cdca9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15091,6 +15091,16 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public String getSwitchingFromUserMessage() { + return mUserController.getSwitchingFromSystemUserMessage(); + } + + @Override + public String getSwitchingToUserMessage() { + return mUserController.getSwitchingToSystemUserMessage(); + } + + @Override public void setStopUserOnSwitch(@StopUserOnSwitch int value) { mUserController.setStopUserOnSwitch(value); } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 429696fd88a2..b28b1a66cd97 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1792,7 +1792,8 @@ class UserController implements Handler.Callback { private void showUserSwitchDialog(Pair<UserInfo, UserInfo> fromToUserPair) { // The dialog will show and then initiate the user switch by calling startUserInForeground mInjector.showUserSwitchingDialog(fromToUserPair.first, fromToUserPair.second, - getSwitchingFromSystemUserMessage(), getSwitchingToSystemUserMessage()); + getSwitchingFromSystemUserMessageUnchecked(), + getSwitchingToSystemUserMessageUnchecked()); } private void dispatchForegroundProfileChanged(@UserIdInt int userId) { @@ -2564,18 +2565,40 @@ class UserController implements Handler.Callback { } } - private String getSwitchingFromSystemUserMessage() { + // Called by AMS, must check permission + String getSwitchingFromSystemUserMessage() { + checkHasManageUsersPermission("getSwitchingFromSystemUserMessage()"); + + return getSwitchingFromSystemUserMessageUnchecked(); + } + + // Called by AMS, must check permission + String getSwitchingToSystemUserMessage() { + checkHasManageUsersPermission("getSwitchingToSystemUserMessage()"); + + return getSwitchingToSystemUserMessageUnchecked(); + } + + private String getSwitchingFromSystemUserMessageUnchecked() { synchronized (mLock) { return mSwitchingFromSystemUserMessage; } } - private String getSwitchingToSystemUserMessage() { + private String getSwitchingToSystemUserMessageUnchecked() { synchronized (mLock) { return mSwitchingToSystemUserMessage; } } + private void checkHasManageUsersPermission(String operation) { + if (mInjector.checkCallingPermission( + android.Manifest.permission.MANAGE_USERS) == PackageManager.PERMISSION_DENIED) { + throw new SecurityException( + "You need MANAGE_USERS permission to call " + operation); + } + } + void dumpDebug(ProtoOutputStream proto, long fieldId) { synchronized (mLock) { long token = proto.start(fieldId); @@ -2648,6 +2671,12 @@ class UserController implements Handler.Callback { pw.println(" mMaxRunningUsers:" + mMaxRunningUsers); pw.println(" mUserSwitchUiEnabled:" + mUserSwitchUiEnabled); pw.println(" mInitialized:" + mInitialized); + if (mSwitchingFromSystemUserMessage != null) { + pw.println(" mSwitchingFromSystemUserMessage: " + mSwitchingFromSystemUserMessage); + } + if (mSwitchingToSystemUserMessage != null) { + pw.println(" mSwitchingToSystemUserMessage: " + mSwitchingToSystemUserMessage); + } } } diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 6d83fb6d12c9..29c27f9f3af6 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -31,10 +31,8 @@ import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; import android.view.RemoteAnimationDefinition; -import android.view.SurfaceControl; import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; -import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentInfo; import com.android.internal.protolog.common.ProtoLog; @@ -135,11 +133,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName()); final TaskFragmentInfo info = tf.getTaskFragmentInfo(); - final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(), - "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared"); try { - organizer.onTaskFragmentAppeared( - new TaskFragmentAppearedInfo(info, outSurfaceControl)); + organizer.onTaskFragmentAppeared(info); mLastSentTaskFragmentInfos.put(tf, info); tf.mTaskFragmentAppearedSent = true; } catch (RemoteException e) { |