Loading libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java +38 −5 Original line number Diff line number Diff line Loading @@ -16,11 +16,12 @@ package com.android.wm.shell.compatui; import android.annotation.NonNull; import android.app.TaskInfo; import android.content.Context; import android.content.SharedPreferences; 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; Loading @@ -34,11 +35,23 @@ import javax.inject.Inject; @WMSingleton public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedListener { static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG = "enable_letterbox_restart_dialog"; private static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG = "enable_letterbox_restart_dialog"; static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = private static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = "enable_letterbox_reachability_education"; /** * The name of the {@link SharedPreferences} that holds which user has seen the Restart * confirmation dialog. */ private static final String DONT_SHOW_RESTART_DIALOG_PREF_NAME = "dont_show_restart_dialog"; /** * The {@link SharedPreferences} instance for {@link #DONT_SHOW_RESTART_DIALOG_PREF_NAME}. */ private final SharedPreferences mSharedPreferences; // Whether the extended restart dialog is enabled private boolean mIsRestartDialogEnabled; Loading Loading @@ -70,6 +83,8 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi false); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT, mainExecutor, this); mSharedPreferences = context.getSharedPreferences(DONT_SHOW_RESTART_DIALOG_PREF_NAME, Context.MODE_PRIVATE); } /** Loading Loading @@ -102,6 +117,20 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi mIsReachabilityEducationOverrideEnabled = enabled; } boolean getDontShowRestartDialogAgain(TaskInfo taskInfo) { final int userId = taskInfo.userId; final String packageName = taskInfo.topActivity.getPackageName(); return mSharedPreferences.getBoolean( getDontShowAgainRestartKey(userId, packageName), /* default= */ false); } void setDontShowRestartDialogAgain(TaskInfo taskInfo) { final int userId = taskInfo.userId; final String packageName = taskInfo.topActivity.getPackageName(); mSharedPreferences.edit().putBoolean(getDontShowAgainRestartKey(userId, packageName), true).apply(); } @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { // TODO(b/263349751): Update flag and default value to true Loading @@ -116,4 +145,8 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION, false); } } private String getDontShowAgainRestartKey(int userId, String packageName) { return packageName + "@" + userId; } } No newline at end of file libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +113 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.Display; import android.view.InsetsSourceControl; Loading @@ -49,6 +50,7 @@ import com.android.wm.shell.transition.Transitions; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; Loading Loading @@ -90,6 +92,18 @@ public class CompatUIController implements OnDisplaysChangedListener, */ private final SparseArray<CompatUIWindowManager> mActiveCompatLayouts = new SparseArray<>(0); /** * {@link SparseArray} that maps task ids to {@link RestartDialogWindowManager} that are * currently visible */ private final SparseArray<RestartDialogWindowManager> mTaskIdToRestartDialogWindowManagerMap = new SparseArray<>(0); /** * {@link Set} of task ids for which we need to display a restart confirmation dialog */ private Set<Integer> mSetOfTaskIdsShowingRestartDialog = new HashSet<>(); /** * The active Letterbox Education layout if there is one (there can be at most one active). * Loading @@ -111,12 +125,15 @@ public class CompatUIController implements OnDisplaysChangedListener, private final ShellExecutor mMainExecutor; private final Lazy<Transitions> mTransitionsLazy; private final DockStateReader mDockStateReader; private final CompatUIConfiguration mCompatUIConfiguration; private CompatUICallback mCallback; // Only show each hint once automatically in the process life. private final CompatUIHintsState mCompatUIHintsState; private final CompatUIShellCommandHandler mCompatUIShellCommandHandler; // Indicates if the keyguard is currently showing, in which case compat UIs shouldn't // be shown. private boolean mKeyguardShowing; Loading @@ -130,7 +147,9 @@ public class CompatUIController implements OnDisplaysChangedListener, SyncTransactionQueue syncQueue, ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy, DockStateReader dockStateReader) { DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration, CompatUIShellCommandHandler compatUIShellCommandHandler) { mContext = context; mShellController = shellController; mDisplayController = displayController; Loading @@ -140,14 +159,17 @@ public class CompatUIController implements OnDisplaysChangedListener, mMainExecutor = mainExecutor; mTransitionsLazy = transitionsLazy; mCompatUIHintsState = new CompatUIHintsState(); shellInit.addInitCallback(this::onInit, this); mDockStateReader = dockStateReader; mCompatUIConfiguration = compatUIConfiguration; mCompatUIShellCommandHandler = compatUIShellCommandHandler; shellInit.addInitCallback(this::onInit, this); } private void onInit() { mShellController.addKeyguardChangeListener(this); mDisplayController.addDisplayWindowListener(this); mImeController.addPositionProcessor(this); mCompatUIShellCommandHandler.onInit(); } /** Sets the callback for UI interactions. */ Loading @@ -164,6 +186,9 @@ public class CompatUIController implements OnDisplaysChangedListener, */ public void onCompatInfoChanged(TaskInfo taskInfo, @Nullable ShellTaskOrganizer.TaskListener taskListener) { if (taskInfo != null && !taskInfo.topActivityInSizeCompat) { mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId); } if (taskInfo.configuration == null || taskListener == null) { // Null token means the current foreground activity is not in compatibility mode. removeLayouts(taskInfo.taskId); Loading @@ -172,6 +197,7 @@ public class CompatUIController implements OnDisplaysChangedListener, createOrUpdateCompatLayout(taskInfo, taskListener); createOrUpdateLetterboxEduLayout(taskInfo, taskListener); createOrUpdateRestartDialogLayout(taskInfo, taskListener); } @Override Loading Loading @@ -278,7 +304,21 @@ public class CompatUIController implements OnDisplaysChangedListener, ShellTaskOrganizer.TaskListener taskListener) { return new CompatUIWindowManager(context, taskInfo, mSyncQueue, mCallback, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), mCompatUIHintsState); mDisplayController.getDisplayLayout(taskInfo.displayId), mCompatUIHintsState, mCompatUIConfiguration, this::onRestartButtonClicked); } private void onRestartButtonClicked( Pair<TaskInfo, ShellTaskOrganizer.TaskListener> taskInfoState) { if (mCompatUIConfiguration.isRestartDialogEnabled() && !mCompatUIConfiguration.getDontShowRestartDialogAgain( taskInfoState.first)) { // We need to show the dialog mSetOfTaskIdsShowingRestartDialog.add(taskInfoState.first.taskId); onCompatInfoChanged(taskInfoState.first, taskInfoState.second); } else { mCallback.onSizeCompatRestartButtonClicked(taskInfoState.first.taskId); } } private void createOrUpdateLetterboxEduLayout(TaskInfo taskInfo, Loading Loading @@ -327,6 +367,60 @@ public class CompatUIController implements OnDisplaysChangedListener, mActiveLetterboxEduLayout = null; } private void createOrUpdateRestartDialogLayout(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { RestartDialogWindowManager layout = mTaskIdToRestartDialogWindowManagerMap.get(taskInfo.taskId); if (layout != null) { // TODO(b/266262111) Handle theme change when taskListener changes if (layout.getTaskListener() != taskListener) { mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId); } layout.setRequestRestartDialog( mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId)); // UI already exists, update the UI layout. if (!layout.updateCompatInfo(taskInfo, taskListener, showOnDisplay(layout.getDisplayId()))) { // The layout is no longer eligible to be shown, remove from active layouts. mTaskIdToRestartDialogWindowManagerMap.remove(taskInfo.taskId); } return; } // Create a new UI layout. final Context context = getOrCreateDisplayContext(taskInfo.displayId); if (context == null) { return; } layout = createRestartDialogWindowManager(context, taskInfo, taskListener); layout.setRequestRestartDialog( mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId)); if (layout.createLayout(showOnDisplay(taskInfo.displayId))) { // The new layout is eligible to be shown, add it the active layouts. mTaskIdToRestartDialogWindowManagerMap.put(taskInfo.taskId, layout); } } @VisibleForTesting RestartDialogWindowManager createRestartDialogWindowManager(Context context, TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { return new RestartDialogWindowManager(context, taskInfo, mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), mTransitionsLazy.get(), this::onRestartDialogCallback, this::onRestartDialogDismissCallback, mCompatUIConfiguration); } private void onRestartDialogCallback( Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) { mTaskIdToRestartDialogWindowManagerMap.remove(stateInfo.first.taskId); mCallback.onSizeCompatRestartButtonClicked(stateInfo.first.taskId); } private void onRestartDialogDismissCallback( Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) { mSetOfTaskIdsShowingRestartDialog.remove(stateInfo.first.taskId); onCompatInfoChanged(stateInfo.first, stateInfo.second); } private void removeLayouts(int taskId) { final CompatUIWindowManager layout = mActiveCompatLayouts.get(taskId); if (layout != null) { Loading @@ -338,6 +432,14 @@ public class CompatUIController implements OnDisplaysChangedListener, mActiveLetterboxEduLayout.release(); mActiveLetterboxEduLayout = null; } final RestartDialogWindowManager restartLayout = mTaskIdToRestartDialogWindowManagerMap.get(taskId); if (restartLayout != null) { restartLayout.release(); mTaskIdToRestartDialogWindowManagerMap.remove(taskId); mSetOfTaskIdsShowingRestartDialog.remove(taskId); } } private Context getOrCreateDisplayContext(int displayId) { Loading Loading @@ -382,6 +484,14 @@ public class CompatUIController implements OnDisplaysChangedListener, if (mActiveLetterboxEduLayout != null && condition.test(mActiveLetterboxEduLayout)) { callback.accept(mActiveLetterboxEduLayout); } for (int i = 0; i < mTaskIdToRestartDialogWindowManagerMap.size(); i++) { final int taskId = mTaskIdToRestartDialogWindowManagerMap.keyAt(i); final RestartDialogWindowManager layout = mTaskIdToRestartDialogWindowManagerMap.get(taskId); if (layout != null && condition.test(layout)) { callback.accept(layout); } } } /** An implementation of {@link OnInsetsChangedListener} for a given display id. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java +18 −2 Original line number Diff line number Diff line Loading @@ -21,12 +21,14 @@ import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.TaskInfo; import android.app.TaskInfo.CameraCompatControlState; import android.content.Context; import android.graphics.Rect; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; Loading @@ -38,6 +40,8 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.CompatUIController.CompatUICallback; import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager; import java.util.function.Consumer; /** * Window manager for the Size Compat restart button and Camera Compat control. */ Loading @@ -50,6 +54,13 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { private final CompatUICallback mCallback; private final CompatUIConfiguration mCompatUIConfiguration; private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartButtonClicked; @NonNull private TaskInfo mTaskInfo; // Remember the last reported states in case visibility changes due to keyguard or IME updates. @VisibleForTesting boolean mHasSizeCompat; Loading @@ -68,12 +79,16 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { CompatUIWindowManager(Context context, TaskInfo taskInfo, SyncTransactionQueue syncQueue, CompatUICallback callback, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, CompatUIHintsState compatUIHintsState) { CompatUIHintsState compatUIHintsState, CompatUIConfiguration compatUIConfiguration, Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartButtonClicked) { super(context, taskInfo, syncQueue, taskListener, displayLayout); mTaskInfo = taskInfo; mCallback = callback; mHasSizeCompat = taskInfo.topActivityInSizeCompat; mCameraCompatControlState = taskInfo.cameraCompatControlState; mCompatUIHintsState = compatUIHintsState; mCompatUIConfiguration = compatUIConfiguration; mOnRestartButtonClicked = onRestartButtonClicked; } @Override Loading Loading @@ -119,6 +134,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { @Override public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener, boolean canShow) { mTaskInfo = taskInfo; final boolean prevHasSizeCompat = mHasSizeCompat; final int prevCameraCompatControlState = mCameraCompatControlState; mHasSizeCompat = taskInfo.topActivityInSizeCompat; Loading @@ -138,7 +154,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { /** Called when the restart button is clicked. */ void onRestartButtonClicked() { mCallback.onSizeCompatRestartButtonClicked(mTaskId); mOnRestartButtonClicked.accept(Pair.create(mTaskInfo, getTaskListener())); } /** Called when the camera treatment button is clicked. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java +5 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana @Override public void setConfiguration(Configuration configuration) { super.setConfiguration(configuration); // TODO(b/266262111): Investigate loss of theme configuration when switching TaskListener mContext = mContext.createConfigurationContext(configuration); } Loading @@ -169,6 +170,10 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana initSurface(mLeash); } protected ShellTaskOrganizer.TaskListener getTaskListener() { return mTaskListener; } /** Inits the z-order of the surface. */ private void initSurface(SurfaceControl leash) { final int z = getZOrder(); Loading libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * 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.annotation.Nullable; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; import androidx.constraintlayout.widget.ConstraintLayout; import com.android.wm.shell.R; import java.util.function.Consumer; /** * Container for a SCM restart confirmation dialog and background dim. */ public class RestartDialogLayout extends ConstraintLayout implements DialogContainerSupplier { private View mDialogContainer; private TextView mDialogTitle; private Drawable mBackgroundDim; public RestartDialogLayout(Context context) { this(context, null); } public RestartDialogLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RestartDialogLayout(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public RestartDialogLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public View getDialogContainerView() { return mDialogContainer; } TextView getDialogTitle() { return mDialogTitle; } @Override public Drawable getBackgroundDimDrawable() { return mBackgroundDim; } /** * Register a callback for the dismiss button and background dim. * * @param callback The callback to register or null if all on click listeners should be removed. */ void setDismissOnClickListener(@Nullable Runnable callback) { final OnClickListener listener = callback == null ? null : view -> callback.run(); findViewById(R.id.letterbox_restart_dialog_dismiss_button).setOnClickListener(listener); } /** * Register a callback for the restart button * * @param callback The callback to register or null if all on click listeners should be removed. */ void setRestartOnClickListener(@Nullable Consumer<Boolean> callback) { final CheckBox dontShowAgainCheckbox = findViewById(R.id.letterbox_restart_dialog_checkbox); final OnClickListener listener = callback == null ? null : view -> callback.accept( dontShowAgainCheckbox.isChecked()); findViewById(R.id.letterbox_restart_dialog_restart_button).setOnClickListener(listener); } @Override protected void onFinishInflate() { super.onFinishInflate(); mDialogContainer = findViewById(R.id.letterbox_restart_dialog_container); mDialogTitle = findViewById(R.id.letterbox_restart_dialog_title); mBackgroundDim = getBackground().mutate(); // Set the alpha of the background dim to 0 for enter animation. mBackgroundDim.setAlpha(0); // We add a no-op on-click listener to the dialog container so that clicks on it won't // propagate to the listener of the layout (which represents the background dim). mDialogContainer.setOnClickListener(view -> {}); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java +38 −5 Original line number Diff line number Diff line Loading @@ -16,11 +16,12 @@ package com.android.wm.shell.compatui; import android.annotation.NonNull; import android.app.TaskInfo; import android.content.Context; import android.content.SharedPreferences; 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; Loading @@ -34,11 +35,23 @@ import javax.inject.Inject; @WMSingleton public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedListener { static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG = "enable_letterbox_restart_dialog"; private static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG = "enable_letterbox_restart_dialog"; static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = private static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = "enable_letterbox_reachability_education"; /** * The name of the {@link SharedPreferences} that holds which user has seen the Restart * confirmation dialog. */ private static final String DONT_SHOW_RESTART_DIALOG_PREF_NAME = "dont_show_restart_dialog"; /** * The {@link SharedPreferences} instance for {@link #DONT_SHOW_RESTART_DIALOG_PREF_NAME}. */ private final SharedPreferences mSharedPreferences; // Whether the extended restart dialog is enabled private boolean mIsRestartDialogEnabled; Loading Loading @@ -70,6 +83,8 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi false); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT, mainExecutor, this); mSharedPreferences = context.getSharedPreferences(DONT_SHOW_RESTART_DIALOG_PREF_NAME, Context.MODE_PRIVATE); } /** Loading Loading @@ -102,6 +117,20 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi mIsReachabilityEducationOverrideEnabled = enabled; } boolean getDontShowRestartDialogAgain(TaskInfo taskInfo) { final int userId = taskInfo.userId; final String packageName = taskInfo.topActivity.getPackageName(); return mSharedPreferences.getBoolean( getDontShowAgainRestartKey(userId, packageName), /* default= */ false); } void setDontShowRestartDialogAgain(TaskInfo taskInfo) { final int userId = taskInfo.userId; final String packageName = taskInfo.topActivity.getPackageName(); mSharedPreferences.edit().putBoolean(getDontShowAgainRestartKey(userId, packageName), true).apply(); } @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { // TODO(b/263349751): Update flag and default value to true Loading @@ -116,4 +145,8 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION, false); } } private String getDontShowAgainRestartKey(int userId, String packageName) { return packageName + "@" + userId; } } No newline at end of file
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +113 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.Display; import android.view.InsetsSourceControl; Loading @@ -49,6 +50,7 @@ import com.android.wm.shell.transition.Transitions; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; Loading Loading @@ -90,6 +92,18 @@ public class CompatUIController implements OnDisplaysChangedListener, */ private final SparseArray<CompatUIWindowManager> mActiveCompatLayouts = new SparseArray<>(0); /** * {@link SparseArray} that maps task ids to {@link RestartDialogWindowManager} that are * currently visible */ private final SparseArray<RestartDialogWindowManager> mTaskIdToRestartDialogWindowManagerMap = new SparseArray<>(0); /** * {@link Set} of task ids for which we need to display a restart confirmation dialog */ private Set<Integer> mSetOfTaskIdsShowingRestartDialog = new HashSet<>(); /** * The active Letterbox Education layout if there is one (there can be at most one active). * Loading @@ -111,12 +125,15 @@ public class CompatUIController implements OnDisplaysChangedListener, private final ShellExecutor mMainExecutor; private final Lazy<Transitions> mTransitionsLazy; private final DockStateReader mDockStateReader; private final CompatUIConfiguration mCompatUIConfiguration; private CompatUICallback mCallback; // Only show each hint once automatically in the process life. private final CompatUIHintsState mCompatUIHintsState; private final CompatUIShellCommandHandler mCompatUIShellCommandHandler; // Indicates if the keyguard is currently showing, in which case compat UIs shouldn't // be shown. private boolean mKeyguardShowing; Loading @@ -130,7 +147,9 @@ public class CompatUIController implements OnDisplaysChangedListener, SyncTransactionQueue syncQueue, ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy, DockStateReader dockStateReader) { DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration, CompatUIShellCommandHandler compatUIShellCommandHandler) { mContext = context; mShellController = shellController; mDisplayController = displayController; Loading @@ -140,14 +159,17 @@ public class CompatUIController implements OnDisplaysChangedListener, mMainExecutor = mainExecutor; mTransitionsLazy = transitionsLazy; mCompatUIHintsState = new CompatUIHintsState(); shellInit.addInitCallback(this::onInit, this); mDockStateReader = dockStateReader; mCompatUIConfiguration = compatUIConfiguration; mCompatUIShellCommandHandler = compatUIShellCommandHandler; shellInit.addInitCallback(this::onInit, this); } private void onInit() { mShellController.addKeyguardChangeListener(this); mDisplayController.addDisplayWindowListener(this); mImeController.addPositionProcessor(this); mCompatUIShellCommandHandler.onInit(); } /** Sets the callback for UI interactions. */ Loading @@ -164,6 +186,9 @@ public class CompatUIController implements OnDisplaysChangedListener, */ public void onCompatInfoChanged(TaskInfo taskInfo, @Nullable ShellTaskOrganizer.TaskListener taskListener) { if (taskInfo != null && !taskInfo.topActivityInSizeCompat) { mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId); } if (taskInfo.configuration == null || taskListener == null) { // Null token means the current foreground activity is not in compatibility mode. removeLayouts(taskInfo.taskId); Loading @@ -172,6 +197,7 @@ public class CompatUIController implements OnDisplaysChangedListener, createOrUpdateCompatLayout(taskInfo, taskListener); createOrUpdateLetterboxEduLayout(taskInfo, taskListener); createOrUpdateRestartDialogLayout(taskInfo, taskListener); } @Override Loading Loading @@ -278,7 +304,21 @@ public class CompatUIController implements OnDisplaysChangedListener, ShellTaskOrganizer.TaskListener taskListener) { return new CompatUIWindowManager(context, taskInfo, mSyncQueue, mCallback, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), mCompatUIHintsState); mDisplayController.getDisplayLayout(taskInfo.displayId), mCompatUIHintsState, mCompatUIConfiguration, this::onRestartButtonClicked); } private void onRestartButtonClicked( Pair<TaskInfo, ShellTaskOrganizer.TaskListener> taskInfoState) { if (mCompatUIConfiguration.isRestartDialogEnabled() && !mCompatUIConfiguration.getDontShowRestartDialogAgain( taskInfoState.first)) { // We need to show the dialog mSetOfTaskIdsShowingRestartDialog.add(taskInfoState.first.taskId); onCompatInfoChanged(taskInfoState.first, taskInfoState.second); } else { mCallback.onSizeCompatRestartButtonClicked(taskInfoState.first.taskId); } } private void createOrUpdateLetterboxEduLayout(TaskInfo taskInfo, Loading Loading @@ -327,6 +367,60 @@ public class CompatUIController implements OnDisplaysChangedListener, mActiveLetterboxEduLayout = null; } private void createOrUpdateRestartDialogLayout(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { RestartDialogWindowManager layout = mTaskIdToRestartDialogWindowManagerMap.get(taskInfo.taskId); if (layout != null) { // TODO(b/266262111) Handle theme change when taskListener changes if (layout.getTaskListener() != taskListener) { mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId); } layout.setRequestRestartDialog( mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId)); // UI already exists, update the UI layout. if (!layout.updateCompatInfo(taskInfo, taskListener, showOnDisplay(layout.getDisplayId()))) { // The layout is no longer eligible to be shown, remove from active layouts. mTaskIdToRestartDialogWindowManagerMap.remove(taskInfo.taskId); } return; } // Create a new UI layout. final Context context = getOrCreateDisplayContext(taskInfo.displayId); if (context == null) { return; } layout = createRestartDialogWindowManager(context, taskInfo, taskListener); layout.setRequestRestartDialog( mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId)); if (layout.createLayout(showOnDisplay(taskInfo.displayId))) { // The new layout is eligible to be shown, add it the active layouts. mTaskIdToRestartDialogWindowManagerMap.put(taskInfo.taskId, layout); } } @VisibleForTesting RestartDialogWindowManager createRestartDialogWindowManager(Context context, TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { return new RestartDialogWindowManager(context, taskInfo, mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), mTransitionsLazy.get(), this::onRestartDialogCallback, this::onRestartDialogDismissCallback, mCompatUIConfiguration); } private void onRestartDialogCallback( Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) { mTaskIdToRestartDialogWindowManagerMap.remove(stateInfo.first.taskId); mCallback.onSizeCompatRestartButtonClicked(stateInfo.first.taskId); } private void onRestartDialogDismissCallback( Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) { mSetOfTaskIdsShowingRestartDialog.remove(stateInfo.first.taskId); onCompatInfoChanged(stateInfo.first, stateInfo.second); } private void removeLayouts(int taskId) { final CompatUIWindowManager layout = mActiveCompatLayouts.get(taskId); if (layout != null) { Loading @@ -338,6 +432,14 @@ public class CompatUIController implements OnDisplaysChangedListener, mActiveLetterboxEduLayout.release(); mActiveLetterboxEduLayout = null; } final RestartDialogWindowManager restartLayout = mTaskIdToRestartDialogWindowManagerMap.get(taskId); if (restartLayout != null) { restartLayout.release(); mTaskIdToRestartDialogWindowManagerMap.remove(taskId); mSetOfTaskIdsShowingRestartDialog.remove(taskId); } } private Context getOrCreateDisplayContext(int displayId) { Loading Loading @@ -382,6 +484,14 @@ public class CompatUIController implements OnDisplaysChangedListener, if (mActiveLetterboxEduLayout != null && condition.test(mActiveLetterboxEduLayout)) { callback.accept(mActiveLetterboxEduLayout); } for (int i = 0; i < mTaskIdToRestartDialogWindowManagerMap.size(); i++) { final int taskId = mTaskIdToRestartDialogWindowManagerMap.keyAt(i); final RestartDialogWindowManager layout = mTaskIdToRestartDialogWindowManagerMap.get(taskId); if (layout != null && condition.test(layout)) { callback.accept(layout); } } } /** An implementation of {@link OnInsetsChangedListener} for a given display id. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java +18 −2 Original line number Diff line number Diff line Loading @@ -21,12 +21,14 @@ import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.TaskInfo; import android.app.TaskInfo.CameraCompatControlState; import android.content.Context; import android.graphics.Rect; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; Loading @@ -38,6 +40,8 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.CompatUIController.CompatUICallback; import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager; import java.util.function.Consumer; /** * Window manager for the Size Compat restart button and Camera Compat control. */ Loading @@ -50,6 +54,13 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { private final CompatUICallback mCallback; private final CompatUIConfiguration mCompatUIConfiguration; private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartButtonClicked; @NonNull private TaskInfo mTaskInfo; // Remember the last reported states in case visibility changes due to keyguard or IME updates. @VisibleForTesting boolean mHasSizeCompat; Loading @@ -68,12 +79,16 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { CompatUIWindowManager(Context context, TaskInfo taskInfo, SyncTransactionQueue syncQueue, CompatUICallback callback, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, CompatUIHintsState compatUIHintsState) { CompatUIHintsState compatUIHintsState, CompatUIConfiguration compatUIConfiguration, Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartButtonClicked) { super(context, taskInfo, syncQueue, taskListener, displayLayout); mTaskInfo = taskInfo; mCallback = callback; mHasSizeCompat = taskInfo.topActivityInSizeCompat; mCameraCompatControlState = taskInfo.cameraCompatControlState; mCompatUIHintsState = compatUIHintsState; mCompatUIConfiguration = compatUIConfiguration; mOnRestartButtonClicked = onRestartButtonClicked; } @Override Loading Loading @@ -119,6 +134,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { @Override public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener, boolean canShow) { mTaskInfo = taskInfo; final boolean prevHasSizeCompat = mHasSizeCompat; final int prevCameraCompatControlState = mCameraCompatControlState; mHasSizeCompat = taskInfo.topActivityInSizeCompat; Loading @@ -138,7 +154,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { /** Called when the restart button is clicked. */ void onRestartButtonClicked() { mCallback.onSizeCompatRestartButtonClicked(mTaskId); mOnRestartButtonClicked.accept(Pair.create(mTaskInfo, getTaskListener())); } /** Called when the camera treatment button is clicked. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java +5 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana @Override public void setConfiguration(Configuration configuration) { super.setConfiguration(configuration); // TODO(b/266262111): Investigate loss of theme configuration when switching TaskListener mContext = mContext.createConfigurationContext(configuration); } Loading @@ -169,6 +170,10 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana initSurface(mLeash); } protected ShellTaskOrganizer.TaskListener getTaskListener() { return mTaskListener; } /** Inits the z-order of the surface. */ private void initSurface(SurfaceControl leash) { final int z = getZOrder(); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogLayout.java 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * 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.annotation.Nullable; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; import androidx.constraintlayout.widget.ConstraintLayout; import com.android.wm.shell.R; import java.util.function.Consumer; /** * Container for a SCM restart confirmation dialog and background dim. */ public class RestartDialogLayout extends ConstraintLayout implements DialogContainerSupplier { private View mDialogContainer; private TextView mDialogTitle; private Drawable mBackgroundDim; public RestartDialogLayout(Context context) { this(context, null); } public RestartDialogLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RestartDialogLayout(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public RestartDialogLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public View getDialogContainerView() { return mDialogContainer; } TextView getDialogTitle() { return mDialogTitle; } @Override public Drawable getBackgroundDimDrawable() { return mBackgroundDim; } /** * Register a callback for the dismiss button and background dim. * * @param callback The callback to register or null if all on click listeners should be removed. */ void setDismissOnClickListener(@Nullable Runnable callback) { final OnClickListener listener = callback == null ? null : view -> callback.run(); findViewById(R.id.letterbox_restart_dialog_dismiss_button).setOnClickListener(listener); } /** * Register a callback for the restart button * * @param callback The callback to register or null if all on click listeners should be removed. */ void setRestartOnClickListener(@Nullable Consumer<Boolean> callback) { final CheckBox dontShowAgainCheckbox = findViewById(R.id.letterbox_restart_dialog_checkbox); final OnClickListener listener = callback == null ? null : view -> callback.accept( dontShowAgainCheckbox.isChecked()); findViewById(R.id.letterbox_restart_dialog_restart_button).setOnClickListener(listener); } @Override protected void onFinishInflate() { super.onFinishInflate(); mDialogContainer = findViewById(R.id.letterbox_restart_dialog_container); mDialogTitle = findViewById(R.id.letterbox_restart_dialog_title); mBackgroundDim = getBackground().mutate(); // Set the alpha of the background dim to 0 for enter animation. mBackgroundDim.setAlpha(0); // We add a no-op on-click listener to the dialog container so that clicks on it won't // propagate to the listener of the layout (which represents the background dim). mDialogContainer.setOnClickListener(view -> {}); } }