• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.wm.shell.appzoomout;
18 
19 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
20 import static android.view.Display.DEFAULT_DISPLAY;
21 import static com.android.systemui.Flags.spatialModelAppPushback;
22 
23 import android.app.ActivityManager;
24 import android.app.WindowConfiguration;
25 import android.content.Context;
26 import android.content.res.Configuration;
27 import android.util.Slog;
28 import android.window.DisplayAreaInfo;
29 import android.window.WindowContainerTransaction;
30 
31 import androidx.annotation.Nullable;
32 import androidx.annotation.VisibleForTesting;
33 
34 import com.android.wm.shell.ShellTaskOrganizer;
35 import com.android.wm.shell.common.DisplayChangeController;
36 import com.android.wm.shell.common.DisplayController;
37 import com.android.wm.shell.common.DisplayLayout;
38 import com.android.wm.shell.common.RemoteCallable;
39 import com.android.wm.shell.common.ShellExecutor;
40 import com.android.wm.shell.shared.annotations.ExternalThread;
41 import com.android.wm.shell.shared.annotations.ShellMainThread;
42 import com.android.wm.shell.sysui.ShellInit;
43 
44 /** Class that manages the app zoom out UI and states. */
45 public class AppZoomOutController implements RemoteCallable<AppZoomOutController>,
46         ShellTaskOrganizer.FocusListener, DisplayChangeController.OnDisplayChangingListener {
47 
48     private static final String TAG = "AppZoomOutController";
49 
50     private final Context mContext;
51     private final ShellTaskOrganizer mTaskOrganizer;
52     private final DisplayController mDisplayController;
53     private final AppZoomOutDisplayAreaOrganizer mDisplayAreaOrganizer;
54     private final ShellExecutor mMainExecutor;
55     private final AppZoomOutImpl mImpl = new AppZoomOutImpl();
56 
57     private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
58             new DisplayController.OnDisplaysChangedListener() {
59                 @Override
60                 public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
61                     if (displayId != DEFAULT_DISPLAY) {
62                         return;
63                     }
64                     updateDisplayLayout(displayId);
65                 }
66 
67                 @Override
68                 public void onDisplayAdded(int displayId) {
69                     if (displayId != DEFAULT_DISPLAY) {
70                         return;
71                     }
72                     updateDisplayLayout(displayId);
73                 }
74             };
75 
76 
create(Context context, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, DisplayController displayController, DisplayLayout displayLayout, @ShellMainThread ShellExecutor mainExecutor)77     public static AppZoomOutController create(Context context, ShellInit shellInit,
78             ShellTaskOrganizer shellTaskOrganizer, DisplayController displayController,
79             DisplayLayout displayLayout, @ShellMainThread ShellExecutor mainExecutor) {
80         AppZoomOutDisplayAreaOrganizer displayAreaOrganizer = new AppZoomOutDisplayAreaOrganizer(
81                 context, displayLayout, mainExecutor);
82         return new AppZoomOutController(context, shellInit, shellTaskOrganizer, displayController,
83                 displayAreaOrganizer, mainExecutor);
84     }
85 
86     @VisibleForTesting
AppZoomOutController(Context context, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, DisplayController displayController, AppZoomOutDisplayAreaOrganizer displayAreaOrganizer, @ShellMainThread ShellExecutor mainExecutor)87     AppZoomOutController(Context context, ShellInit shellInit,
88             ShellTaskOrganizer shellTaskOrganizer, DisplayController displayController,
89             AppZoomOutDisplayAreaOrganizer displayAreaOrganizer,
90             @ShellMainThread ShellExecutor mainExecutor) {
91         mContext = context;
92         mTaskOrganizer = shellTaskOrganizer;
93         mDisplayController = displayController;
94         mDisplayAreaOrganizer = displayAreaOrganizer;
95         mMainExecutor = mainExecutor;
96 
97         if (spatialModelAppPushback()) {
98             shellInit.addInitCallback(this::onInit, this);
99         }
100     }
101 
onInit()102     private void onInit() {
103         mTaskOrganizer.addFocusListener(this);
104 
105         mDisplayController.addDisplayWindowListener(mDisplaysChangedListener);
106         mDisplayController.addDisplayChangingController(this);
107         updateDisplayLayout(mContext.getDisplayId());
108 
109         mDisplayAreaOrganizer.registerOrganizer();
110     }
111 
asAppZoomOut()112     public AppZoomOut asAppZoomOut() {
113         return mImpl;
114     }
115 
setProgress(float progress)116     public void setProgress(float progress) {
117         mDisplayAreaOrganizer.setProgress(progress);
118     }
119 
updateDisplayLayout(int displayId)120     void updateDisplayLayout(int displayId) {
121         final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId);
122         if (newDisplayLayout == null) {
123             Slog.w(TAG, "Failed to get new DisplayLayout.");
124             return;
125         }
126         mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout);
127     }
128 
129     @Override
onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo)130     public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
131         if (taskInfo == null) {
132             return;
133         }
134         if (taskInfo.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_HOME) {
135             mDisplayAreaOrganizer.setIsHomeTaskFocused(taskInfo.isFocused);
136         }
137     }
138 
139     @Override
onDisplayChange(int displayId, int fromRotation, int toRotation, @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct)140     public void onDisplayChange(int displayId, int fromRotation, int toRotation,
141             @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
142         // TODO: verify if there is synchronization issues.
143         if (toRotation != ROTATION_UNDEFINED) {
144             mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation);
145         }
146     }
147 
148     @Override
getContext()149     public Context getContext() {
150         return mContext;
151     }
152 
153     @Override
getRemoteCallExecutor()154     public ShellExecutor getRemoteCallExecutor() {
155         return mMainExecutor;
156     }
157 
158     @ExternalThread
159     private class AppZoomOutImpl implements AppZoomOut {
160         @Override
setProgress(float progress)161         public void setProgress(float progress) {
162             mMainExecutor.execute(() -> AppZoomOutController.this.setProgress(progress));
163         }
164     }
165 }
166