From 9d62e7e332bf239a034a56ddce94587d66cfa48e Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Tue, 20 Dec 2022 11:34:19 +0100 Subject: [PATCH 1/8] Add the option to disable lazy notifications (2/2) Bug: 247473910 Test: Manual Change-Id: I514a4ceeeef78556774b9d699f13b716d086dd01 --- .../compose/runtime/MovableContent.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/SystemUI/compose/core/src/com/android/systemui/compose/runtime/MovableContent.kt diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/runtime/MovableContent.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/runtime/MovableContent.kt new file mode 100644 index 0000000000000..3f2f96b293e0a --- /dev/null +++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/runtime/MovableContent.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.compose.runtime + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.InternalComposeApi +import androidx.compose.runtime.MovableContent +import androidx.compose.runtime.currentComposer + +/** + * An overload of [androidx.compose.runtime.movableContentOf] with 5 parameters. + * + * @see androidx.compose.runtime.movableContentOf + */ +@OptIn(InternalComposeApi::class) +fun movableContentOf( + content: @Composable (P1, P2, P3, P4, P5) -> Unit +): @Composable (P1, P2, P3, P4, P5) -> Unit { + val movableContent = + MovableContent, Pair>> { + content( + it.first.first, + it.first.second, + it.first.third, + it.second.first, + it.second.second, + ) + } + return { p1, p2, p3, p4, p5 -> + currentComposer.insertMovableContent(movableContent, Triple(p1, p2, p3) to (p4 to p5)) + } +} From 68e91829f8c26dfc91ef22f109694827e5d065b6 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Fri, 16 Dec 2022 10:55:47 +0100 Subject: [PATCH 2/8] Add SystemUI build flag for Compose code (1/3) This CL adds a Soong build flag that enables Compose code when building SystemUI, or anything depending on SystemUI-core. The flag is disabled by default, and will be first used to measure the impact of Compose on our apk and system health. It will be turned on for one/many/all targets once agreed with the Android System Health & Performance team. To turn this flag on, one simply have to `export SYSTEMUI_USE_COMPOSE=true` before compiling. This flag is implemented such that: - When it is enabled, SystemUI-core depends on the SystemUIComposeCore library and compiles the source files of SystemUIComposeFeatures. In an ideal world, SystemUI-core would also just depend on SystemUIComposeFeatures instead of recompiling its sources, but given that the code in SystemUIComposeFeatures depends on code in SystemUI-core, this would lead to a cyclic dependency. Therefore, when this flag is enabled, we compile those files together. SystemUIComposeFeatures also contains a ComposeFacade object that is the bridge between SystemUI-core code and SystemUIComposeFeatures code. - When it is disabled, we only add another ComposeFacade object with the same API as the ComposeFacade object in SystemUIComposeFeatures, which throws when its functions are called (except for ComposeFacade#isComposeAvailable(), which returns false). This way, any code in SystemUI-core can check ComposeFacade#isComposeAvailable() first then call other functions to indirectly access Compose code. See http://ag/20759151 for an example. Bug: 242304109 Test: Builds Change-Id: Ibd895a73041c163816e779273ec0b6588aabef76 --- packages/SystemUI/Android.bp | 51 +++++++++++++++++++ .../android/systemui/compose/ComposeFacade.kt | 30 +++++++++++ .../android/systemui/compose/ComposeFacade.kt | 22 ++++++++ .../systemui/compose/BaseComposeFacade.kt | 34 +++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt create mode 100644 packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt create mode 100644 packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 25fb24a3417fc..9515aa5d3f53c 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -31,6 +31,51 @@ license { ], } +// Opt-in configuration for code depending on Jetpack Compose. +soong_config_module_type { + name: "systemui_compose_java_defaults", + module_type: "java_defaults", + config_namespace: "ANDROID", + bool_variables: ["SYSTEMUI_USE_COMPOSE"], + properties: [ + "srcs", + "static_libs", + ], +} + +systemui_compose_java_defaults { + name: "SystemUI_compose_defaults", + soong_config_variables: { + SYSTEMUI_USE_COMPOSE: { + // Because files in compose/features/ depend on SystemUI + // code, we compile those files when compiling SystemUI-core. + // We also compile the ComposeFacade in + // compose/facade/enabled/. + srcs: [ + "compose/features/src/**/*.kt", + "compose/facade/enabled/src/**/*.kt", + ], + + // The dependencies needed by SystemUIComposeFeatures, + // except for SystemUI-core. + // Copied from compose/features/Android.bp. + static_libs: [ + "SystemUIComposeCore", + + "androidx.compose.runtime_runtime", + "androidx.compose.material3_material3", + ], + + // By default, Compose is disabled and we compile the ComposeFacade + // in compose/facade/disabled/. + conditions_default: { + srcs: ["compose/facade/disabled/src/**/*.kt"], + static_libs: [], + }, + }, + }, +} + java_library { name: "SystemUI-proto", @@ -68,6 +113,9 @@ filegroup { android_library { name: "SystemUI-core", + defaults: [ + "SystemUI_compose_defaults", + ], srcs: [ "src/**/*.kt", "src/**/*.java", @@ -227,6 +275,9 @@ android_library { android_library { name: "SystemUI-tests", + defaults: [ + "SystemUI_compose_defaults", + ], manifest: "tests/AndroidManifest-base.xml", additional_manifests: ["tests/AndroidManifest.xml"], srcs: [ diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt new file mode 100644 index 0000000000000..b3359070df8ca --- /dev/null +++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.compose + +/** The Compose facade, when Compose is *not* available. */ +object ComposeFacade : BaseComposeFacade { + override fun isComposeAvailable(): Boolean = false + + private fun throwComposeUnavailableError() { + error( + "Compose is not available. Make sure to check isComposeAvailable() before calling any" + + " other function on ComposeFacade." + ) + } +} diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt new file mode 100644 index 0000000000000..d950057404ca1 --- /dev/null +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.compose + +/** The Compose facade, when Compose is available. */ +object ComposeFacade : BaseComposeFacade { + override fun isComposeAvailable(): Boolean = true +} diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt new file mode 100644 index 0000000000000..859867a309ad4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.compose + +/** + * A facade to interact with Compose, when it is available. + * + * You should access this facade by calling the static methods on + * [com.android.systemui.compose.ComposeFacade] directly. + */ +interface BaseComposeFacade { + /** + * Whether Compose is currently available. This function should be checked before calling any + * other functions on this facade. + * + * This value will never change at runtime. + */ + fun isComposeAvailable(): Boolean +} From bf43b1d32d9e366371326a38df5f8a74daa7aa1b Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Fri, 16 Dec 2022 13:00:23 +0100 Subject: [PATCH 3/8] Show the Compose implementation of PeopleSpace when Compose is available Bug: 238993727 Test: Manual Change-Id: I41a6bae879e5a1f4e12f9ff998fb7f5d1320e135 --- packages/SystemUI/Android.bp | 1 + .../android/systemui/compose/ComposeFacade.kt | 11 +++++++++ .../android/systemui/compose/ComposeFacade.kt | 14 +++++++++++ packages/SystemUI/compose/features/Android.bp | 1 + .../systemui/compose/BaseComposeFacade.kt | 10 ++++++++ .../systemui/people/PeopleSpaceActivity.java | 23 +++++++++++++------ 6 files changed, 53 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 9515aa5d3f53c..6b4d5ae86d1e9 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -64,6 +64,7 @@ systemui_compose_java_defaults { "androidx.compose.runtime_runtime", "androidx.compose.material3_material3", + "androidx.activity_activity-compose", ], // By default, Compose is disabled and we compile the ComposeFacade diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt index b3359070df8ca..6e728ce7248f1 100644 --- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt +++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -17,10 +17,21 @@ package com.android.systemui.compose +import androidx.activity.ComponentActivity +import com.android.systemui.people.ui.viewmodel.PeopleViewModel + /** The Compose facade, when Compose is *not* available. */ object ComposeFacade : BaseComposeFacade { override fun isComposeAvailable(): Boolean = false + override fun setPeopleSpaceActivityContent( + activity: ComponentActivity, + viewModel: PeopleViewModel, + onResult: (PeopleViewModel.Result) -> Unit, + ) { + throwComposeUnavailableError() + } + private fun throwComposeUnavailableError() { error( "Compose is not available. Make sure to check isComposeAvailable() before calling any" + diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt index d950057404ca1..16294d9c19772 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -16,7 +16,21 @@ package com.android.systemui.compose +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import com.android.systemui.compose.theme.SystemUITheme +import com.android.systemui.people.ui.compose.PeopleScreen +import com.android.systemui.people.ui.viewmodel.PeopleViewModel + /** The Compose facade, when Compose is available. */ object ComposeFacade : BaseComposeFacade { override fun isComposeAvailable(): Boolean = true + + override fun setPeopleSpaceActivityContent( + activity: ComponentActivity, + viewModel: PeopleViewModel, + onResult: (PeopleViewModel.Result) -> Unit, + ) { + activity.setContent { SystemUITheme { PeopleScreen(viewModel, onResult) } } + } } diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp index 325ede613de8e..4533330531180 100644 --- a/packages/SystemUI/compose/features/Android.bp +++ b/packages/SystemUI/compose/features/Android.bp @@ -35,6 +35,7 @@ android_library { "androidx.compose.runtime_runtime", "androidx.compose.material3_material3", + "androidx.activity_activity-compose", ], kotlincflags: ["-Xjvm-default=all"], diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt index 859867a309ad4..e5ec727f04379 100644 --- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt +++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt @@ -17,6 +17,9 @@ package com.android.systemui.compose +import androidx.activity.ComponentActivity +import com.android.systemui.people.ui.viewmodel.PeopleViewModel + /** * A facade to interact with Compose, when it is available. * @@ -31,4 +34,11 @@ interface BaseComposeFacade { * This value will never change at runtime. */ fun isComposeAvailable(): Boolean + + /** Bind the content of [activity] to [viewModel]. */ + fun setPeopleSpaceActivityContent( + activity: ComponentActivity, + viewModel: PeopleViewModel, + onResult: (PeopleViewModel.Result) -> Unit, + ) } diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java index 7cc95a158a140..fba5f63ea9c78 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java @@ -27,11 +27,15 @@ import android.view.ViewGroup; import androidx.activity.ComponentActivity; import androidx.lifecycle.ViewModelProvider; +import com.android.systemui.compose.ComposeFacade; import com.android.systemui.people.ui.view.PeopleViewBinder; import com.android.systemui.people.ui.viewmodel.PeopleViewModel; import javax.inject.Inject; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; + /** People Tile Widget configuration activity that shows the user their conversation tiles. */ public class PeopleSpaceActivity extends ComponentActivity { @@ -58,13 +62,18 @@ public class PeopleSpaceActivity extends ComponentActivity { int widgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID); viewModel.onWidgetIdChanged(widgetId); - ViewGroup view = PeopleViewBinder.create(this); - PeopleViewBinder.bind(view, viewModel, /* lifecycleOwner= */ this, - (result) -> { - finishActivity(result); - return null; - }); - setContentView(view); + Function1 onResult = (result) -> { + finishActivity(result); + return null; + }; + + if (ComposeFacade.INSTANCE.isComposeAvailable()) { + ComposeFacade.INSTANCE.setPeopleSpaceActivityContent(this, viewModel, onResult); + } else { + ViewGroup view = PeopleViewBinder.create(this); + PeopleViewBinder.bind(view, viewModel, /* lifecycleOwner= */ this, onResult); + setContentView(view); + } } private void finishActivity(PeopleViewModel.Result result) { From 028d793955fd35846f33bd81853d779e623d4a77 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Wed, 21 Dec 2022 11:41:28 +0100 Subject: [PATCH 4/8] Fix PeopleSpace when showing only priority or recent conversations (1/2) Bug: 238993727 Test: atest PeopleSpaceScreenshotTest Change-Id: I273859b1b8173d7feb329114e59d242e0a0dfb45 --- .../systemui/people/ui/compose/PeopleScreen.kt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt index 2aac46e903426..4a56b027e07c3 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt @@ -139,11 +139,20 @@ private fun PeopleScreenWithConversations( bottom = PeopleSpacePadding, start = 8.dp, end = 8.dp, - ) + ), ) { - ConversationList(R.string.priority_conversations, priorityTiles, onTileClicked) - item { Spacer(Modifier.height(35.dp)) } - ConversationList(R.string.recent_conversations, recentTiles, onTileClicked) + val hasPriorityConversations = priorityTiles.isNotEmpty() + if (hasPriorityConversations) { + ConversationList(R.string.priority_conversations, priorityTiles, onTileClicked) + } + + if (recentTiles.isNotEmpty()) { + if (hasPriorityConversations) { + item { Spacer(Modifier.height(35.dp)) } + } + + ConversationList(R.string.recent_conversations, recentTiles, onTileClicked) + } } } } From b576702e30f7e5eb25467119fba6c5bd0ebd0837 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Wed, 14 Dec 2022 12:35:18 -0800 Subject: [PATCH 5/8] Do not reset surface when entering PiP When UnfoldAnimationController is present and entering PiP from a Task with multiple activities, the resetTask within UnfoldAnimationController could conflict with the PiP animation and cause flicker. Fixed this by ignoring restTask in UnfoldAnimationController if there is no state change going on. Bug: 261996076 Test: Enter PiP from Task with multi-Activity on foldables Change-Id: I7f13e86d030d427383e65a37efde13ec94dea2a8 --- .../unfold/UnfoldAnimationController.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java index 6b59e313b01ba..d7cb490ed0cb8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java @@ -16,8 +16,6 @@ package com.android.wm.shell.unfold; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; - import android.annotation.NonNull; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; @@ -56,6 +54,12 @@ public class UnfoldAnimationController implements UnfoldListener { private final SparseArray mTaskSurfaces = new SparseArray<>(); private final SparseArray mAnimatorsByTaskId = new SparseArray<>(); + /** + * Indicates whether we're in stage change process. This should be set to {@code true} in + * {@link #onStateChangeStarted()} and {@code false} in {@link #onStateChangeFinished()}. + */ + private boolean mIsInStageChange; + public UnfoldAnimationController( @NonNull ShellInit shellInit, @NonNull TransactionPool transactionPool, @@ -123,7 +127,7 @@ public class UnfoldAnimationController implements UnfoldListener { animator.onTaskChanged(taskInfo); } else { // Became inapplicable - resetTask(animator, taskInfo); + maybeResetTask(animator, taskInfo); animator.onTaskVanished(taskInfo); mAnimatorsByTaskId.remove(taskInfo.taskId); } @@ -154,7 +158,7 @@ public class UnfoldAnimationController implements UnfoldListener { final boolean isCurrentlyApplicable = animator != null; if (isCurrentlyApplicable) { - resetTask(animator, taskInfo); + maybeResetTask(animator, taskInfo); animator.onTaskVanished(taskInfo); mAnimatorsByTaskId.remove(taskInfo.taskId); } @@ -166,6 +170,7 @@ public class UnfoldAnimationController implements UnfoldListener { return; } + mIsInStageChange = true; SurfaceControl.Transaction transaction = null; for (int i = 0; i < mAnimators.size(); i++) { final UnfoldTaskAnimator animator = mAnimators.get(i); @@ -219,11 +224,12 @@ public class UnfoldAnimationController implements UnfoldListener { transaction.apply(); mTransactionPool.release(transaction); + mIsInStageChange = false; } - private void resetTask(UnfoldTaskAnimator animator, TaskInfo taskInfo) { - if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) { - // PiP task has its own cleanup path, ignore surface reset to avoid conflict. + private void maybeResetTask(UnfoldTaskAnimator animator, TaskInfo taskInfo) { + if (!mIsInStageChange) { + // No need to resetTask if there is no ongoing state change. return; } final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); From 75845880e92f64e463a5a744c6c3c0fa28389d07 Mon Sep 17 00:00:00 2001 From: Massimo Carli Date: Wed, 30 Nov 2022 23:32:36 +0000 Subject: [PATCH 6/8] [1/n] Create Configuration for CompatUX Enhancements This flags allow to enable/disable some of the new compat ui enhancements related to a confirmation dialog for restart button and an education for letterbox reachability. Fixes: 260909953 Test: Manual using `adb shell dumpsys activity service SystemUIService WMShell compatui ` where commands are `restartDialogEnabled` and `reachabilityEducationEnabled` and the values `0, false, 1 or true` Change-Id: I10a99cc73d97026e12d4c60b751d349281b1d1cf --- .../WindowManager/Shell/res/values/config.xml | 6 + .../shell/compatui/CompatUIConfiguration.java | 119 ++++++++++++++++++ .../compatui/CompatUIShellCommandHandler.java | 103 +++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIShellCommandHandler.java diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index 23db2335ecc07..774f6c6379b2c 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -115,4 +115,10 @@ + + + false + + + false diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java new file mode 100644 index 0000000000000..4f33a71b80d50 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui; + +import android.content.Context; +import android.provider.DeviceConfig; + +import androidx.annotation.NonNull; + +import com.android.wm.shell.R; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.dagger.WMSingleton; + +import javax.inject.Inject; + +/** + * Configuration flags for the CompatUX implementation + */ +@WMSingleton +public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedListener { + + static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG = "enable_letterbox_restart_dialog"; + + static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = + "enable_letterbox_reachability_education"; + + // Whether the extended restart dialog is enabled + private boolean mIsRestartDialogEnabled; + + // Whether the additional education about reachability is enabled + private boolean mIsReachabilityEducationEnabled; + + // Whether the extended restart dialog is enabled + private boolean mIsRestartDialogOverrideEnabled; + + // Whether the additional education about reachability is enabled + private boolean mIsReachabilityEducationOverrideEnabled; + + // Whether the extended restart dialog is allowed from backend + private boolean mIsLetterboxRestartDialogAllowed; + + // Whether the additional education about reachability is allowed from backend + private boolean mIsLetterboxReachabilityEducationAllowed; + + @Inject + public CompatUIConfiguration(Context context, @ShellMainThread ShellExecutor mainExecutor) { + mIsRestartDialogEnabled = context.getResources().getBoolean( + R.bool.config_letterboxIsRestartDialogEnabled); + mIsReachabilityEducationEnabled = context.getResources().getBoolean( + R.bool.config_letterboxIsReachabilityEducationEnabled); + mIsLetterboxRestartDialogAllowed = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG, false); + mIsLetterboxReachabilityEducationAllowed = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION, + false); + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT, mainExecutor, + this); + } + + /** + * @return {@value true} if the restart dialog is enabled. + */ + boolean isRestartDialogEnabled() { + return mIsRestartDialogOverrideEnabled || (mIsRestartDialogEnabled + && mIsLetterboxRestartDialogAllowed); + } + + /** + * Enables/Disables the restart education dialog + */ + void setIsRestartDialogOverrideEnabled(boolean enabled) { + mIsRestartDialogOverrideEnabled = enabled; + } + + /** + * @return {@value true} if the reachability education is enabled. + */ + boolean isReachabilityEducationEnabled() { + return mIsReachabilityEducationOverrideEnabled || (mIsReachabilityEducationEnabled + && mIsLetterboxReachabilityEducationAllowed); + } + + /** + * Enables/Disables the reachability education + */ + void setIsReachabilityEducationOverrideEnabled(boolean enabled) { + mIsReachabilityEducationOverrideEnabled = enabled; + } + + @Override + public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { + // TODO(b/263349751): Update flag and default value to true + if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_RESTART_DIALOG)) { + mIsLetterboxRestartDialogAllowed = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG, + false); + } + if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION)) { + mIsLetterboxReachabilityEducationAllowed = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION, false); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIShellCommandHandler.java new file mode 100644 index 0000000000000..4fb18e27b1456 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIShellCommandHandler.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui; + +import com.android.wm.shell.dagger.WMSingleton; +import com.android.wm.shell.sysui.ShellCommandHandler; + +import java.io.PrintWriter; +import java.util.function.Consumer; + +import javax.inject.Inject; + +/** + * Handles the shell commands for the CompatUX. + * + *

Use with {@code adb shell dumpsys activity service SystemUIService WMShell compatui + * <command>}. + */ +@WMSingleton +public final class CompatUIShellCommandHandler implements + ShellCommandHandler.ShellCommandActionHandler { + + private final CompatUIConfiguration mCompatUIConfiguration; + private final ShellCommandHandler mShellCommandHandler; + + @Inject + public CompatUIShellCommandHandler(ShellCommandHandler shellCommandHandler, + CompatUIConfiguration compatUIConfiguration) { + mShellCommandHandler = shellCommandHandler; + mCompatUIConfiguration = compatUIConfiguration; + } + + void onInit() { + mShellCommandHandler.addCommandCallback("compatui", this, this); + } + + @Override + public boolean onShellCommand(String[] args, PrintWriter pw) { + if (args.length != 2) { + pw.println("Invalid command: " + args[0]); + return false; + } + switch (args[0]) { + case "restartDialogEnabled": + return invokeOrError(args[1], pw, + mCompatUIConfiguration::setIsRestartDialogOverrideEnabled); + case "reachabilityEducationEnabled": + return invokeOrError(args[1], pw, + mCompatUIConfiguration::setIsReachabilityEducationOverrideEnabled); + default: + pw.println("Invalid command: " + args[0]); + return false; + } + } + + @Override + public void printShellCommandHelp(PrintWriter pw, String prefix) { + pw.println(prefix + "restartDialogEnabled [0|false|1|true]"); + pw.println(prefix + " Enable/Disable the restart education dialog for Size Compat Mode"); + pw.println(prefix + "reachabilityEducationEnabled [0|false|1|true]"); + pw.println(prefix + + " Enable/Disable the restart education dialog for letterbox reachability"); + pw.println(prefix + " Disable the restart education dialog for letterbox reachability"); + } + + private static boolean invokeOrError(String input, PrintWriter pw, + Consumer setter) { + Boolean asBoolean = strToBoolean(input); + if (asBoolean == null) { + pw.println("Error: expected true, 1, false, 0."); + return false; + } + setter.accept(asBoolean); + return true; + } + + // Converts a String to boolean if possible or it returns null otherwise + private static Boolean strToBoolean(String str) { + switch(str) { + case "1": + case "true": + return true; + case "0": + case "false": + return false; + } + return null; + } +} From 33cf8ca0bb712a73dbf3c42a1291c52d12aa6bee Mon Sep 17 00:00:00 2001 From: Massimo Carli Date: Mon, 19 Dec 2022 14:46:35 +0000 Subject: [PATCH 7/8] [2/n] Makes EduAnimationController generic Use generics to reuse EduAnimationController Fixes: 263113045 Test: Manual Change-Id: Ifdcf879f3c3f6050622bc893ad639ccbc05d7f23 --- ...er.java => DialogAnimationController.java} | 39 +++++++++++-------- .../compatui/DialogContainerSupplier.java | 36 +++++++++++++++++ .../LetterboxEduDialogLayout.java | 19 +++++---- .../LetterboxEduWindowManager.java | 12 ++++-- .../LetterboxEduDialogLayoutTest.java | 4 +- .../LetterboxEduWindowManagerTest.java | 5 ++- 6 files changed, 81 insertions(+), 34 deletions(-) rename libs/WindowManager/Shell/src/com/android/wm/shell/compatui/{letterboxedu/LetterboxEduAnimationController.java => DialogAnimationController.java} (85%) create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/DialogContainerSupplier.java diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/DialogAnimationController.java similarity index 85% rename from libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java rename to libs/WindowManager/Shell/src/com/android/wm/shell/compatui/DialogAnimationController.java index 3061eab17d249..7475feac5b12d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/DialogAnimationController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.compatui.letterboxedu; +package com.android.wm.shell.compatui; import static com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation; import static com.android.internal.R.styleable.WindowAnimation_windowExitAnimation; @@ -38,10 +38,15 @@ import android.view.animation.Animation; import com.android.internal.policy.TransitionAnimation; /** - * Controls the enter/exit animations of the letterbox education. + * Controls the enter/exit a dialog. + * + * @param The {@link DialogContainerSupplier} to use */ -class LetterboxEduAnimationController { - private static final String TAG = "LetterboxEduAnimation"; +public class DialogAnimationController { + + // The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque). + // 204 is simply 255 * 0.8. + static final int BACKGROUND_DIM_ALPHA = 204; // If shell transitions are enabled, startEnterAnimation will be called after all transitions // have finished, and therefore the start delay should be shorter. @@ -49,6 +54,7 @@ class LetterboxEduAnimationController { private final TransitionAnimation mTransitionAnimation; private final String mPackageName; + private final String mTag; @AnyRes private final int mAnimStyleResId; @@ -57,23 +63,24 @@ class LetterboxEduAnimationController { @Nullable private Animator mBackgroundDimAnimator; - LetterboxEduAnimationController(Context context) { - mTransitionAnimation = new TransitionAnimation(context, /* debug= */ false, TAG); + public DialogAnimationController(Context context, String tag) { + mTransitionAnimation = new TransitionAnimation(context, /* debug= */ false, tag); mAnimStyleResId = (new ContextThemeWrapper(context, android.R.style.ThemeOverlay_Material_Dialog).getTheme()).obtainStyledAttributes( com.android.internal.R.styleable.Window).getResourceId( com.android.internal.R.styleable.Window_windowAnimationStyle, 0); mPackageName = context.getPackageName(); + mTag = tag; } /** * Starts both background dim fade-in animation and the dialog enter animation. */ - void startEnterAnimation(@NonNull LetterboxEduDialogLayout layout, Runnable endCallback) { + public void startEnterAnimation(@NonNull T layout, Runnable endCallback) { // Cancel any previous animation if it's still running. cancelAnimation(); - final View dialogContainer = layout.getDialogContainer(); + final View dialogContainer = layout.getDialogContainerView(); mDialogAnimation = loadAnimation(WindowAnimation_windowEnterAnimation); if (mDialogAnimation == null) { endCallback.run(); @@ -86,8 +93,8 @@ class LetterboxEduAnimationController { endCallback.run(); })); - mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(), - /* endAlpha= */ LetterboxEduDialogLayout.BACKGROUND_DIM_ALPHA, + mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDimDrawable(), + /* endAlpha= */ BACKGROUND_DIM_ALPHA, mDialogAnimation.getDuration()); mBackgroundDimAnimator.addListener(getDimAnimatorListener()); @@ -101,11 +108,11 @@ class LetterboxEduAnimationController { /** * Starts both the background dim fade-out animation and the dialog exit animation. */ - void startExitAnimation(@NonNull LetterboxEduDialogLayout layout, Runnable endCallback) { + public void startExitAnimation(@NonNull T layout, Runnable endCallback) { // Cancel any previous animation if it's still running. cancelAnimation(); - final View dialogContainer = layout.getDialogContainer(); + final View dialogContainer = layout.getDialogContainerView(); mDialogAnimation = loadAnimation(WindowAnimation_windowExitAnimation); if (mDialogAnimation == null) { endCallback.run(); @@ -119,8 +126,8 @@ class LetterboxEduAnimationController { endCallback.run(); })); - mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(), /* endAlpha= */ 0, - mDialogAnimation.getDuration()); + mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDimDrawable(), + /* endAlpha= */ 0, mDialogAnimation.getDuration()); mBackgroundDimAnimator.addListener(getDimAnimatorListener()); dialogContainer.startAnimation(mDialogAnimation); @@ -130,7 +137,7 @@ class LetterboxEduAnimationController { /** * Cancels all animations and resets the state of the controller. */ - void cancelAnimation() { + public void cancelAnimation() { if (mDialogAnimation != null) { mDialogAnimation.cancel(); mDialogAnimation = null; @@ -145,7 +152,7 @@ class LetterboxEduAnimationController { Animation animation = mTransitionAnimation.loadAnimationAttr(mPackageName, mAnimStyleResId, animAttr, /* translucent= */ false); if (animation == null) { - Log.e(TAG, "Failed to load animation " + animAttr); + Log.e(mTag, "Failed to load animation " + animAttr); } return animation; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/DialogContainerSupplier.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/DialogContainerSupplier.java new file mode 100644 index 0000000000000..7eea446fce265 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/DialogContainerSupplier.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui; + +import android.graphics.drawable.Drawable; +import android.view.View; + +/** + * A component which can provide a {@link View} to use as a container for a Dialog + */ +public interface DialogContainerSupplier { + + /** + * @return The {@link View} to use as a container for a Dialog + */ + View getDialogContainerView(); + + /** + * @return The {@link Drawable} to use as background of the dialog. + */ + Drawable getBackgroundDimDrawable(); +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java index 2e0b09e9d230a..9232f36cf9397 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java @@ -26,6 +26,7 @@ import android.widget.TextView; import androidx.constraintlayout.widget.ConstraintLayout; import com.android.wm.shell.R; +import com.android.wm.shell.compatui.DialogContainerSupplier; /** * Container for Letterbox Education Dialog and background dim. @@ -33,11 +34,7 @@ import com.android.wm.shell.R; *

This layout should fill the entire task and the background around the dialog acts as the * background dim which dismisses the dialog when clicked. */ -class LetterboxEduDialogLayout extends ConstraintLayout { - - // The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque). - // 204 is simply 255 * 0.8. - static final int BACKGROUND_DIM_ALPHA = 204; +class LetterboxEduDialogLayout extends ConstraintLayout implements DialogContainerSupplier { private View mDialogContainer; private TextView mDialogTitle; @@ -60,18 +57,20 @@ class LetterboxEduDialogLayout extends ConstraintLayout { super(context, attrs, defStyleAttr, defStyleRes); } - View getDialogContainer() { + @Override + public View getDialogContainerView() { return mDialogContainer; } + @Override + public Drawable getBackgroundDimDrawable() { + return mBackgroundDim; + } + TextView getDialogTitle() { return mDialogTitle; } - Drawable getBackgroundDim() { - return mBackgroundDim; - } - /** * Register a callback for the dismiss button and background dim. * diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java index 867d0ef732ac9..c14c009721a1f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java @@ -37,6 +37,7 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.DockStateReader; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract; +import com.android.wm.shell.compatui.DialogAnimationController; import com.android.wm.shell.transition.Transitions; /** @@ -63,7 +64,7 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { */ private final SharedPreferences mSharedPreferences; - private final LetterboxEduAnimationController mAnimationController; + private final DialogAnimationController mAnimationController; private final Transitions mTransitions; @@ -96,14 +97,17 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback, DockStateReader dockStateReader) { this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions, - onDismissCallback, new LetterboxEduAnimationController(context), dockStateReader); + onDismissCallback, + new DialogAnimationController<>(context, /* tag */ "LetterboxEduWindowManager"), + dockStateReader); } @VisibleForTesting LetterboxEduWindowManager(Context context, TaskInfo taskInfo, SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback, - LetterboxEduAnimationController animationController, DockStateReader dockStateReader) { + DialogAnimationController animationController, + DockStateReader dockStateReader) { super(context, taskInfo, syncQueue, taskListener, displayLayout); mTransitions = transitions; mOnDismissCallback = onDismissCallback; @@ -160,7 +164,7 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { if (mLayout == null) { return; } - final View dialogContainer = mLayout.getDialogContainer(); + final View dialogContainer = mLayout.getDialogContainerView(); MarginLayoutParams marginParams = (MarginLayoutParams) dialogContainer.getLayoutParams(); final Rect taskBounds = getTaskBounds(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java index 1dee88c438064..a58620dfc6dcf 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java @@ -68,11 +68,11 @@ public class LetterboxEduDialogLayoutTest extends ShellTestCase { @Test public void testOnFinishInflate() { - assertEquals(mLayout.getDialogContainer(), + assertEquals(mLayout.getDialogContainerView(), mLayout.findViewById(R.id.letterbox_education_dialog_container)); assertEquals(mLayout.getDialogTitle(), mLayout.findViewById(R.id.letterbox_education_dialog_title)); - assertEquals(mLayout.getBackgroundDim(), mLayout.getBackground()); + assertEquals(mLayout.getBackgroundDimDrawable(), mLayout.getBackground()); assertEquals(mLayout.getBackground().getAlpha(), 0); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java index 16517c0a00103..14190f18929c2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java @@ -56,6 +56,7 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.DockStateReader; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.compatui.DialogAnimationController; import com.android.wm.shell.transition.Transitions; import org.junit.After; @@ -98,7 +99,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Captor private ArgumentCaptor mRunOnIdleCaptor; - @Mock private LetterboxEduAnimationController mAnimationController; + @Mock private DialogAnimationController mAnimationController; @Mock private SyncTransactionQueue mSyncTransactionQueue; @Mock private ShellTaskOrganizer.TaskListener mTaskListener; @Mock private SurfaceControlViewHost mViewHost; @@ -366,7 +367,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { assertThat(params.width).isEqualTo(expectedWidth); assertThat(params.height).isEqualTo(expectedHeight); MarginLayoutParams dialogParams = - (MarginLayoutParams) layout.getDialogContainer().getLayoutParams(); + (MarginLayoutParams) layout.getDialogContainerView().getLayoutParams(); int verticalMargin = (int) mContext.getResources().getDimension( R.dimen.letterbox_education_dialog_margin); assertThat(dialogParams.topMargin).isEqualTo(verticalMargin + expectedExtraTopMargin); From a8047ca3dfdd765bfe879ccdb3afb28b5e462a32 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 15 Dec 2022 20:38:06 +0000 Subject: [PATCH 8/8] Revert "Implement a global maximum on number of shortcuts an app can publish" This reverts commit 7622d6da0e0e7ddc2893249bd489da7b140b437f. Reason for revert: bugs related to conversation shortcuts can lead to system retaining shortcuts exceeding this number, causing crashes in chat apps such as whatsapp, messages ... e.t.c Bug: 250576066 Merged-In: I1d7c265160389e45cf57a4bf8ce756376068d5b7 Change-Id: I1d7c265160389e45cf57a4bf8ce756376068d5b7 --- .../android/server/pm/ShortcutPackage.java | 8 +-- .../android/server/pm/ShortcutService.java | 49 +++---------------- 2 files changed, 8 insertions(+), 49 deletions(-) diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 7fd1b24c9b6c2..3506fd9be15dc 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -1479,15 +1479,9 @@ class ShortcutPackage extends ShortcutPackageItem { } // Then make sure none of the activities have more than the max number of shortcuts. - int total = 0; for (int i = counts.size() - 1; i >= 0; i--) { - int count = counts.valueAt(i); - service.enforceMaxActivityShortcuts(count); - total += count; + service.enforceMaxActivityShortcuts(counts.valueAt(i)); } - - // Finally make sure that the app doesn't have more than the max number of shortcuts. - service.enforceMaxAppShortcuts(total); } /** diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 7e5613fd892fc..62d6717e847a1 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -179,9 +179,6 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting static final int DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY = 15; - @VisibleForTesting - static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 60; - @VisibleForTesting static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96; @@ -256,11 +253,6 @@ public class ShortcutService extends IShortcutService.Stub { */ String KEY_MAX_SHORTCUTS = "max_shortcuts"; - /** - * Key name for the max dynamic shortcuts per app. (int) - */ - String KEY_MAX_SHORTCUTS_PER_APP = "max_shortcuts_per_app"; - /** * Key name for icon compression quality, 0-100. */ @@ -332,15 +324,10 @@ public class ShortcutService extends IShortcutService.Stub { private final SparseArray mShortcutNonPersistentUsers = new SparseArray<>(); - /** - * Max number of dynamic + manifest shortcuts that each activity can have at a time. - */ - private int mMaxShortcutsPerActivity; - /** * Max number of dynamic + manifest shortcuts that each application can have at a time. */ - private int mMaxShortcutsPerApp; + private int mMaxShortcuts; /** * Max number of updating API calls that each application can make during the interval. @@ -800,12 +787,9 @@ public class ShortcutService extends IShortcutService.Stub { mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong( ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL)); - mMaxShortcutsPerActivity = Math.max(0, (int) parser.getLong( + mMaxShortcuts = Math.max(0, (int) parser.getLong( ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY)); - mMaxShortcutsPerApp = Math.max(0, (int) parser.getLong( - ConfigConstants.KEY_MAX_SHORTCUTS_PER_APP, DEFAULT_MAX_SHORTCUTS_PER_APP)); - final int iconDimensionDp = Math.max(1, injectIsLowRamDevice() ? (int) parser.getLong( ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM, @@ -1761,33 +1745,16 @@ public class ShortcutService extends IShortcutService.Stub { * {@link #getMaxActivityShortcuts()}. */ void enforceMaxActivityShortcuts(int numShortcuts) { - if (numShortcuts > mMaxShortcutsPerActivity) { + if (numShortcuts > mMaxShortcuts) { throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded"); } } - /** - * @throws IllegalArgumentException if {@code numShortcuts} is bigger than - * {@link #getMaxAppShortcuts()}. - */ - void enforceMaxAppShortcuts(int numShortcuts) { - if (numShortcuts > mMaxShortcutsPerApp) { - throw new IllegalArgumentException("Max number of dynamic shortcuts per app exceeded"); - } - } - /** * Return the max number of dynamic + manifest shortcuts for each launcher icon. */ int getMaxActivityShortcuts() { - return mMaxShortcutsPerActivity; - } - - /** - * Return the max number of dynamic + manifest shortcuts for each launcher icon. - */ - int getMaxAppShortcuts() { - return mMaxShortcutsPerApp; + return mMaxShortcuts; } /** @@ -2246,8 +2213,6 @@ public class ShortcutService extends IShortcutService.Stub { ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true); fillInDefaultActivity(Arrays.asList(shortcut)); - enforceMaxAppShortcuts(ps.getShortcutCount()); - if (!shortcut.hasRank()) { shortcut.setRank(0); } @@ -2806,7 +2771,7 @@ public class ShortcutService extends IShortcutService.Stub { throws RemoteException { verifyCaller(packageName, userId); - return mMaxShortcutsPerActivity; + return mMaxShortcuts; } @Override @@ -4858,7 +4823,7 @@ public class ShortcutService extends IShortcutService.Stub { pw.print(" maxUpdatesPerInterval: "); pw.println(mMaxUpdatesPerInterval); pw.print(" maxShortcutsPerActivity: "); - pw.println(mMaxShortcutsPerActivity); + pw.println(mMaxShortcuts); pw.println(); mStatLogger.dump(pw, " "); @@ -5346,7 +5311,7 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting int getMaxShortcutsForTest() { - return mMaxShortcutsPerActivity; + return mMaxShortcuts; } @VisibleForTesting