blob: 03a0d930a3d9aba93b26d51eb5c7e6bc7b6e6870 [file] [log] [blame]
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001/*
2 * Copyright (C) 2015 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
17package com.android.systemui.stackdivider;
18
Evan Rosky90d5b6d2020-05-13 19:39:05 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010020import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000021import static android.view.Display.DEFAULT_DISPLAY;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010022
Evan Rosky8d1c24e2020-04-23 09:21:16 -070023import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
24
Evan Rosky8d1c24e2020-04-23 09:21:16 -070025import android.app.ActivityManager;
Evan Roskyb8540a02020-03-25 16:30:24 -070026import android.app.ActivityTaskManager;
Dave Mankoffa5d8a392019-10-10 12:21:09 -040027import android.content.Context;
Winson Chung67f5c8b2018-09-24 12:09:19 -070028import android.content.res.Configuration;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000029import android.graphics.Rect;
30import android.os.Handler;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000031import android.provider.Settings;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000032import android.util.Slog;
Winson Chung67f5c8b2018-09-24 12:09:19 -070033import android.view.LayoutInflater;
34import android.view.View;
Evan Rosky8d1c24e2020-04-23 09:21:16 -070035import android.window.WindowContainerToken;
Wale Ogunwale57946582020-03-21 14:29:07 -070036import android.window.WindowContainerTransaction;
Wale Ogunwale568f9f412020-03-21 22:27:35 -070037import android.window.WindowOrganizer;
Gus Prevasab336792018-11-14 13:52:20 -050038
Evan Roskyaf9f27c2020-02-18 18:58:35 +000039import com.android.internal.policy.DividerSnapAlgorithm;
Winson Chung67f5c8b2018-09-24 12:09:19 -070040import com.android.systemui.R;
41import com.android.systemui.SystemUI;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000042import com.android.systemui.TransactionPool;
Winson Chung67f5c8b2018-09-24 12:09:19 -070043import com.android.systemui.recents.Recents;
Evan Rosky8d1c24e2020-04-23 09:21:16 -070044import com.android.systemui.shared.system.ActivityManagerWrapper;
45import com.android.systemui.shared.system.TaskStackChangeListener;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000046import com.android.systemui.statusbar.policy.KeyguardStateController;
47import com.android.systemui.wm.DisplayChangeController;
48import com.android.systemui.wm.DisplayController;
49import com.android.systemui.wm.DisplayImeController;
50import com.android.systemui.wm.DisplayLayout;
51import com.android.systemui.wm.SystemWindows;
Gus Prevasab336792018-11-14 13:52:20 -050052
Jorim Jaggi31f71702016-05-04 16:43:04 -070053import java.io.FileDescriptor;
54import java.io.PrintWriter;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000055import java.lang.ref.WeakReference;
56import java.util.ArrayList;
Dave Mankoff6c64d1f2019-11-07 17:27:50 -050057import java.util.Optional;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000058import java.util.function.Consumer;
59
60import javax.inject.Singleton;
Dave Mankoff6c64d1f2019-11-07 17:27:50 -050061
62import dagger.Lazy;
Jorim Jaggi31f71702016-05-04 16:43:04 -070063
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010064/**
65 * Controls the docked stack divider.
66 */
Evan Roskyaf9f27c2020-02-18 18:58:35 +000067@Singleton
68public class Divider extends SystemUI implements DividerView.DividerCallbacks,
69 DisplayController.OnDisplaysChangedListener {
Winson Chung67f5c8b2018-09-24 12:09:19 -070070 private static final String TAG = "Divider";
Evan Roskyaf9f27c2020-02-18 18:58:35 +000071
Evan Roskyfdc71c42020-03-13 18:23:08 -070072 static final boolean DEBUG = false;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000073
74 static final int DEFAULT_APP_TRANSITION_DURATION = 336;
75
Dave Mankoff6c64d1f2019-11-07 17:27:50 -050076 private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
Winson Chung67f5c8b2018-09-24 12:09:19 -070077
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010078 private DividerWindowManager mWindowManager;
Jorim Jaggidd98d412015-11-18 15:57:38 -080079 private DividerView mView;
Jorim Jaggia6c05d52016-05-27 00:31:21 -070080 private final DividerState mDividerState = new DividerState();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080081 private boolean mVisible = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080082 private boolean mMinimized = false;
Jorim Jaggi698e7632016-04-13 21:02:22 -070083 private boolean mAdjustedForIme = false;
Matthew Nge15352e2016-12-20 15:36:29 -080084 private boolean mHomeStackResizable = false;
Jorim Jaggi2adba072016-03-03 13:43:39 +010085 private ForcedResizableInfoActivityController mForcedResizableController;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000086 private SystemWindows mSystemWindows;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000087 private DisplayController mDisplayController;
88 private DisplayImeController mImeController;
89 final TransactionPool mTransactionPool;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010090
Evan Roskyaf9f27c2020-02-18 18:58:35 +000091 // Keeps track of real-time split geometry including snap positions and ime adjustments
92 private SplitDisplayLayout mSplitLayout;
93
94 // Transient: this contains the layout calculated for a new rotation requested by WM. This is
95 // kept around so that we can wait for a matching configuration change and then use the exact
96 // layout that we sent back to WM.
97 private SplitDisplayLayout mRotateSplitLayout;
98
99 private Handler mHandler;
100 private KeyguardStateController mKeyguardStateController;
101
Evan Rosky36138542020-05-01 18:02:11 -0700102 private WindowManagerProxy mWindowManagerProxy;
103
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000104 private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
105 new ArrayList<>();
106
107 private SplitScreenTaskOrganizer mSplits = new SplitScreenTaskOrganizer(this);
108
109 private DisplayChangeController.OnDisplayChangingListener mRotationController =
Evan Rosky36138542020-05-01 18:02:11 -0700110 (display, fromRotation, toRotation, wct) -> {
111 if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
Evan Roskyb8540a02020-03-25 16:30:24 -0700112 return;
113 }
Evan Rosky36138542020-05-01 18:02:11 -0700114 WindowContainerTransaction t = new WindowContainerTransaction();
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000115 DisplayLayout displayLayout =
116 new DisplayLayout(mDisplayController.getDisplayLayout(display));
117 SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
118 sdl.rotateTo(toRotation);
119 mRotateSplitLayout = sdl;
Evan Rosky90d5b6d2020-05-13 19:39:05 -0700120 final int position = isDividerVisible()
121 ? (mMinimized ? mView.mSnapTargetBeforeMinimized.position
122 : mView.getCurrentPosition())
123 // snap resets to middle target when not in split-mode
124 : sdl.getSnapAlgorithm().getMiddleTarget().position;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000125 DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
126 final DividerSnapAlgorithm.SnapTarget target =
127 snap.calculateNonDismissingSnapTarget(position);
128 sdl.resizeSplits(target.position, t);
129
Evan Rosky89c285e2020-06-17 21:21:53 -0700130 if (isSplitActive() && mHomeStackResizable) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000131 WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
132 }
Evan Rosky36138542020-05-01 18:02:11 -0700133 if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
134 // Because sync transactions are serialized, its possible for an "older"
135 // bounds-change to get applied after a screen rotation. In that case, we
136 // want to actually defer on that rather than apply immediately. Of course,
137 // this means that the bounds may not change until after the rotation so
138 // the user might see some artifacts. This should be rare.
139 Slog.w(TAG, "Screen rotated while other operations were pending, this may"
140 + " result in some graphical artifacts.");
141 } else {
142 wct.merge(t, true /* transfer */);
143 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000144 };
145
Evan Roskyc48c9392020-05-19 11:54:21 -0700146 private final DividerImeController mImePositionProcessor;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000147
Evan Rosky8d1c24e2020-04-23 09:21:16 -0700148 private TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
149 @Override
150 public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
151 boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
152 if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
153 != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || !mSplits.isSplitScreenSupported()) {
154 return;
155 }
156
157 if (isMinimized()) {
158 onUndockingTask();
159 }
160 }
161 };
162
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000163 public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
164 DisplayController displayController, SystemWindows systemWindows,
165 DisplayImeController imeController, Handler handler,
166 KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400167 super(context);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000168 mDisplayController = displayController;
169 mSystemWindows = systemWindows;
170 mImeController = imeController;
171 mHandler = handler;
172 mKeyguardStateController = keyguardStateController;
Dave Mankoff6c64d1f2019-11-07 17:27:50 -0500173 mRecentsOptionalLazy = recentsOptionalLazy;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000174 mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
175 mTransactionPool = transactionPool;
Evan Rosky36138542020-05-01 18:02:11 -0700176 mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
Evan Roskyc48c9392020-05-19 11:54:21 -0700177 mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
Dave Mankoffa5d8a392019-10-10 12:21:09 -0400178 }
179
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100180 @Override
181 public void start() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000182 mWindowManager = new DividerWindowManager(mSystemWindows);
183 mDisplayController.addDisplayWindowListener(this);
184 // Hide the divider when keyguard is showing. Even though keyguard/statusbar is above
185 // everything, it is actually transparent except for notifications, so we still need to
186 // hide any surfaces that are below it.
187 // TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
188 mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
189 @Override
190 public void onUnlockedChanged() {
191
192 }
193
194 @Override
195 public void onKeyguardShowingChanged() {
Evan Rosky90d5b6d2020-05-13 19:39:05 -0700196 if (!isDividerVisible() || mView == null) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000197 return;
198 }
199 mView.setHidden(mKeyguardStateController.isShowing());
200 }
201
202 @Override
203 public void onKeyguardFadingAwayChanged() {
204
205 }
206 });
207 // Don't initialize the divider or anything until we get the default display.
Evan Roskybed2d1b2019-11-05 10:26:24 -0800208 }
209
210 @Override
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000211 public void onDisplayAdded(int displayId) {
212 if (displayId != DEFAULT_DISPLAY) {
213 return;
214 }
215 mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
216 mDisplayController.getDisplayLayout(displayId), mSplits);
217 mImeController.addPositionProcessor(mImePositionProcessor);
218 mDisplayController.addDisplayChangingController(mRotationController);
Evan Roskyb8540a02020-03-25 16:30:24 -0700219 if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
220 removeDivider();
221 return;
222 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000223 try {
chaviwda7b3c22020-04-24 11:25:08 -0700224 mSplits.init();
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000225 // Set starting tile bounds based on middle target
226 final WindowContainerTransaction tct = new WindowContainerTransaction();
227 int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
228 mSplitLayout.resizeSplits(midPos, tct);
Wale Ogunwale568f9f412020-03-21 22:27:35 -0700229 WindowOrganizer.applyTransaction(tct);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000230 } catch (Exception e) {
231 Slog.e(TAG, "Failed to register docked stack listener", e);
Evan Roskyb8540a02020-03-25 16:30:24 -0700232 removeDivider();
233 return;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000234 }
Evan Rosky8d1c24e2020-04-23 09:21:16 -0700235 ActivityManagerWrapper.getInstance().registerTaskStackListener(mActivityRestartListener);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000236 }
237
238 @Override
239 public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
Evan Roskyb8540a02020-03-25 16:30:24 -0700240 if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000241 return;
242 }
243 mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
244 mDisplayController.getDisplayLayout(displayId), mSplits);
245 if (mRotateSplitLayout == null) {
246 int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
247 final WindowContainerTransaction tct = new WindowContainerTransaction();
248 mSplitLayout.resizeSplits(midPos, tct);
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700249 WindowOrganizer.applyTransaction(tct);
250 } else if (mSplitLayout.mDisplayLayout.rotation()
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000251 == mRotateSplitLayout.mDisplayLayout.rotation()) {
252 mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
253 mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
254 mRotateSplitLayout = null;
255 }
Tony Huang3dd2b932020-06-15 05:40:40 +0000256 update(newConfig);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100257 }
258
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000259 Handler getHandler() {
260 return mHandler;
261 }
262
Jorim Jaggidd98d412015-11-18 15:57:38 -0800263 public DividerView getView() {
264 return mView;
265 }
266
Matthew Ng8d372882016-12-20 11:06:49 -0800267 public boolean isMinimized() {
268 return mMinimized;
269 }
270
Matthew Ngfb692ac2017-02-02 14:02:56 -0800271 public boolean isHomeStackResizable() {
272 return mHomeStackResizable;
273 }
274
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000275 /** {@code true} if this is visible */
Evan Rosky90d5b6d2020-05-13 19:39:05 -0700276 public boolean isDividerVisible() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000277 return mView != null && mView.getVisibility() == View.VISIBLE;
278 }
279
Evan Rosky90d5b6d2020-05-13 19:39:05 -0700280 /**
281 * This indicates that at-least one of the splits has content. This differs from
282 * isDividerVisible because the divider is only visible once *everything* is in split mode
283 * while this only cares if some things are (eg. while entering/exiting as well).
284 */
285 private boolean isSplitActive() {
286 return mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
287 || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED;
288 }
289
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100290 private void addDivider(Configuration configuration) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000291 Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
Jorim Jaggidd98d412015-11-18 15:57:38 -0800292 mView = (DividerView)
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000293 LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
294 DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
Evan Roskyc3a50902020-05-19 13:36:28 -0700295 mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
Evan Rosky36138542020-05-01 18:02:11 -0700296 mImePositionProcessor, mWindowManagerProxy);
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800297 mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
Evan Rosky36138542020-05-01 18:02:11 -0700298 mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000299 final int size = dctx.getResources().getDimensionPixelSize(
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700300 com.android.internal.R.dimen.docked_stack_divider_thickness);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100301 final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000302 final int width = landscape ? size : displayLayout.width();
303 final int height = landscape ? displayLayout.height() : size;
304 mWindowManager.add(mView, width, height, mContext.getDisplayId());
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100305 }
306
307 private void removeDivider() {
Wale Ogunwale15ba1512017-06-06 08:31:17 -0700308 if (mView != null) {
309 mView.onDividerRemoved();
310 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100311 mWindowManager.remove();
312 }
313
314 private void update(Configuration configuration) {
Tony Huangdf3cfc12020-04-29 15:47:53 +0800315 final boolean isDividerHidden = mView != null && mView.isHidden();
316
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100317 removeDivider();
318 addDivider(configuration);
Tony Huangdf3cfc12020-04-29 15:47:53 +0800319
Vishnu Nair4880a302020-05-08 11:05:58 -0700320 if (mMinimized) {
Evan Rosky36138542020-05-01 18:02:11 -0700321 mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
Vishnu Nair4880a302020-05-08 11:05:58 -0700322 updateTouchable();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800323 }
Vishnu Nair4880a302020-05-08 11:05:58 -0700324 mView.setHidden(isDividerHidden);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100325 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800326
chaviwda7b3c22020-04-24 11:25:08 -0700327 void onTaskVanished() {
328 mHandler.post(this::removeDivider);
329 }
330
Tony Huang3dd2b932020-06-15 05:40:40 +0000331 void onTasksReady() {
332 mHandler.post(() -> update(mDisplayController.getDisplayContext(
333 mContext.getDisplayId()).getResources().getConfiguration()));
334 }
335
Vishnu Nair4880a302020-05-08 11:05:58 -0700336 private void updateVisibility(final boolean visible) {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700337 if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000338 if (mVisible != visible) {
339 mVisible = visible;
340 mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700341
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000342 if (visible) {
343 mView.enterSplitMode(mHomeStackResizable);
344 // Update state because animations won't finish.
Evan Rosky36138542020-05-01 18:02:11 -0700345 mWindowManagerProxy.runInSync(
346 t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
347
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000348 } else {
349 mView.exitSplitMode();
Evan Rosky36138542020-05-01 18:02:11 -0700350 mWindowManagerProxy.runInSync(
351 t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800352 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000353 // Notify existence listeners
354 synchronized (mDockedStackExistsListeners) {
355 mDockedStackExistsListeners.removeIf(wf -> {
356 Consumer<Boolean> l = wf.get();
357 if (l != null) l.accept(visible);
358 return l == null;
359 });
360 }
361 }
362 }
363
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000364 /** Switch to minimized state if appropriate */
365 public void setMinimized(final boolean minimized) {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700366 if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000367 mHandler.post(() -> {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700368 if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
369 if (!mVisible) {
370 return;
371 }
Evan Roskyfe31c042020-03-06 19:35:48 -0800372 setHomeMinimized(minimized, mHomeStackResizable);
Wale Ogunwale91ac7d72020-03-10 13:46:27 +0000373 });
Evan Rosky877739b2020-03-06 19:35:48 -0800374 }
375
Evan Roskyfe31c042020-03-06 19:35:48 -0800376 private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700377 if (DEBUG) {
378 Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
Evan Rosky90d5b6d2020-05-13 19:39:05 -0700379 + mHomeStackResizable + "->" + homeStackResizable
380 + " split:" + isDividerVisible());
Evan Roskyfdc71c42020-03-13 18:23:08 -0700381 }
Evan Roskyfe31c042020-03-06 19:35:48 -0800382 WindowContainerTransaction wct = new WindowContainerTransaction();
Evan Roskyf64f5da2020-03-16 13:47:48 -0700383 final boolean minimizedChanged = mMinimized != minimized;
Evan Roskyfe31c042020-03-06 19:35:48 -0800384 // Update minimized state
Evan Roskyf64f5da2020-03-16 13:47:48 -0700385 if (minimizedChanged) {
Evan Roskyfe31c042020-03-06 19:35:48 -0800386 mMinimized = minimized;
387 }
388 // Always set this because we could be entering split when mMinimized is already true
389 wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
390
391 // Update home-stack resizability
Evan Roskyf64f5da2020-03-16 13:47:48 -0700392 final boolean homeResizableChanged = mHomeStackResizable != homeStackResizable;
393 if (homeResizableChanged) {
Evan Roskyfe31c042020-03-06 19:35:48 -0800394 mHomeStackResizable = homeStackResizable;
Evan Rosky90d5b6d2020-05-13 19:39:05 -0700395 if (isDividerVisible()) {
Evan Roskyfe31c042020-03-06 19:35:48 -0800396 WindowManagerProxy.applyHomeTasksMinimized(
397 mSplitLayout, mSplits.mSecondary.token, wct);
398 }
399 }
400
401 // Sync state to DividerView if it exists.
402 if (mView != null) {
Evan Roskyc0eec052020-03-06 18:54:55 -0800403 final int displayId = mView.getDisplay() != null
404 ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
405 // pause ime here (before updateMinimizedDockedStack)
406 if (mMinimized) {
407 mImePositionProcessor.pause(displayId);
408 }
Evan Roskyf64f5da2020-03-16 13:47:48 -0700409 if (minimizedChanged || homeResizableChanged) {
410 // This conflicts with IME adjustment, so only call it when things change.
411 mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
412 }
Evan Roskyc0eec052020-03-06 18:54:55 -0800413 if (!mMinimized) {
414 // afterwards so it can end any animations started in view
415 mImePositionProcessor.resume(displayId);
416 }
Evan Roskyfe31c042020-03-06 19:35:48 -0800417 }
418 updateTouchable();
Evan Rosky36138542020-05-01 18:02:11 -0700419 mWindowManagerProxy.applySyncTransaction(wct);
Evan Roskyfe31c042020-03-06 19:35:48 -0800420 }
421
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000422 void setAdjustedForIme(boolean adjustedForIme) {
423 if (mAdjustedForIme == adjustedForIme) {
424 return;
425 }
426 mAdjustedForIme = adjustedForIme;
427 updateTouchable();
Jorim Jaggi2adba072016-03-03 13:43:39 +0100428 }
429
Jorim Jaggi698e7632016-04-13 21:02:22 -0700430 private void updateTouchable() {
Evan Rosky89c285e2020-06-17 21:21:53 -0700431 mWindowManager.setTouchable(!mAdjustedForIme);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700432 }
433
Winson Chung60fa6472017-06-12 15:30:14 -0700434 /**
Winson Chung67f5c8b2018-09-24 12:09:19 -0700435 * Workaround for b/62528361, at the time recents has drawn, it may happen before a
Winson Chung60fa6472017-06-12 15:30:14 -0700436 * configuration change to the Divider, and internally, the event will be posted to the
437 * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
438 * register the event handler here and proxy the event to the current DividerView.
439 */
Winson Chung67f5c8b2018-09-24 12:09:19 -0700440 public void onRecentsDrawn() {
Winson Chung60fa6472017-06-12 15:30:14 -0700441 if (mView != null) {
442 mView.onRecentsDrawn();
443 }
444 }
445
Winson Chung67f5c8b2018-09-24 12:09:19 -0700446 public void onUndockingTask() {
447 if (mView != null) {
448 mView.onUndockingTask();
449 }
450 }
451
452 public void onDockedFirstAnimationFrame() {
453 if (mView != null) {
454 mView.onDockedFirstAnimationFrame();
455 }
456 }
457
458 public void onDockedTopTask() {
459 if (mView != null) {
460 mView.onDockedTopTask();
461 }
462 }
463
464 public void onAppTransitionFinished() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000465 if (mView == null) {
466 return;
467 }
Winson Chung67f5c8b2018-09-24 12:09:19 -0700468 mForcedResizableController.onAppTransitionFinished();
469 }
470
471 @Override
472 public void onDraggingStart() {
473 mForcedResizableController.onDraggingStart();
474 }
475
476 @Override
477 public void onDraggingEnd() {
478 mForcedResizableController.onDraggingEnd();
479 }
480
481 @Override
482 public void growRecents() {
Dave Mankoff6c64d1f2019-11-07 17:27:50 -0500483 mRecentsOptionalLazy.ifPresent(recentsLazy -> recentsLazy.get().growRecents());
Winson Chung67f5c8b2018-09-24 12:09:19 -0700484 }
485
Jorim Jaggi31f71702016-05-04 16:43:04 -0700486 @Override
487 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
488 pw.print(" mVisible="); pw.println(mVisible);
489 pw.print(" mMinimized="); pw.println(mMinimized);
490 pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
491 }
492
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000493 long getAnimDuration() {
494 float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
495 Settings.Global.TRANSITION_ANIMATION_SCALE,
496 mContext.getResources().getFloat(
497 com.android.internal.R.dimen
498 .config_appTransitionAnimationDurationScaleDefault));
499 final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
500 return (long) (transitionDuration * transitionScale);
501 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100502
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000503 /** Register a listener that gets called whenever the existence of the divider changes */
504 public void registerInSplitScreenListener(Consumer<Boolean> listener) {
Evan Rosky90d5b6d2020-05-13 19:39:05 -0700505 listener.accept(isDividerVisible());
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000506 synchronized (mDockedStackExistsListeners) {
507 mDockedStackExistsListeners.add(new WeakReference<>(listener));
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800508 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000509 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100510
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000511 void startEnterSplit() {
Vishnu Nair4880a302020-05-08 11:05:58 -0700512 update(mDisplayController.getDisplayContext(
513 mContext.getDisplayId()).getResources().getConfiguration());
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000514 // Set resizable directly here because applyEnterSplit already resizes home stack.
Evan Rosky36138542020-05-01 18:02:11 -0700515 mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
516 }
517
518 void startDismissSplit() {
519 mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
520 updateVisibility(false /* visible */);
521 mMinimized = false;
522 removeDivider();
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000523 }
524
525 void ensureMinimizedSplit() {
Evan Rosky89c285e2020-06-17 21:21:53 -0700526 setHomeMinimized(true /* minimized */, mHomeStackResizable);
Tony Huang3dd2b932020-06-15 05:40:40 +0000527 if (!isDividerVisible()) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000528 // Wasn't in split-mode yet, so enter now.
529 if (DEBUG) {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700530 Slog.d(TAG, " entering split mode with minimized=true");
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000531 }
532 updateVisibility(true /* visible */);
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100533 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000534 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800535
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000536 void ensureNormalSplit() {
Evan Roskyfe31c042020-03-06 19:35:48 -0800537 setHomeMinimized(false /* minimized */, mHomeStackResizable);
Tony Huang3dd2b932020-06-15 05:40:40 +0000538 if (!isDividerVisible()) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000539 // Wasn't in split-mode, so enter now.
540 if (DEBUG) {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700541 Slog.d(TAG, " enter split mode unminimized ");
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000542 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000543 updateVisibility(true /* visible */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800544 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800545 }
Evan Rosky2af969c2020-05-08 16:26:31 +0000546
Evan Roskyc48c9392020-05-19 11:54:21 -0700547 SplitDisplayLayout getSplitLayout() {
548 return mSplitLayout;
549 }
550
Evan Rosky36138542020-05-01 18:02:11 -0700551 WindowManagerProxy getWmProxy() {
552 return mWindowManagerProxy;
553 }
554
Evan Rosky2af969c2020-05-08 16:26:31 +0000555 /** @return the container token for the secondary split root task. */
556 public WindowContainerToken getSecondaryRoot() {
557 if (mSplits == null || mSplits.mSecondary == null) {
558 return null;
559 }
560 return mSplits.mSecondary.token;
561 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100562}