blob: 666d902682a7b9c1c4e7415a058b70092f260397 [file] [log] [blame]
Craig Mautnerb1fd65c02013-02-05 13:34:57 -08001/*
2 * Copyright (C) 2013 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.server.wm;
18
Craig Mautner42bf39e2014-02-21 16:46:22 -080019import static com.android.server.wm.WindowManagerService.TAG;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070020import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
Craig Mautnere3119b72015-01-20 15:02:36 -080021import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
Stefan Kuhne234dbf82015-08-13 09:44:28 -070022import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
Craig Mautner42bf39e2014-02-21 16:46:22 -080023
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070024import android.content.res.Configuration;
25import android.graphics.Rect;
Craig Mautner2c2549c2013-11-12 08:31:15 -080026import android.util.EventLog;
Craig Mautner42bf39e2014-02-21 16:46:22 -080027import android.util.Slog;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070028import android.util.SparseArray;
29import android.util.TypedValue;
30import android.view.DisplayInfo;
31import android.view.Surface;
32
Craig Mautnere3119b72015-01-20 15:02:36 -080033import com.android.server.EventLogTags;
Craig Mautner2c2549c2013-11-12 08:31:15 -080034
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070035import java.io.PrintWriter;
36import java.util.ArrayList;
37
38class Task implements DimLayer.DimLayerUser {
39 /** Amount of time in milliseconds to animate the dim surface from one value to another,
40 * when no window animation is driving it. */
41 private static final int DEFAULT_DIM_DURATION = 200;
42
Craig Mautnerc00204b2013-03-05 15:02:14 -080043 TaskStack mStack;
Craig Mautner05d6272ba2013-02-11 09:39:27 -080044 final AppTokenList mAppTokens = new AppTokenList();
Craig Mautner83162a92015-01-26 14:43:30 -080045 final int mTaskId;
Craig Mautnerac6f8432013-07-17 13:24:59 -070046 final int mUserId;
Craig Mautner9ef471f2014-02-07 13:11:47 -080047 boolean mDeferRemoval = false;
Craig Mautnere3119b72015-01-20 15:02:36 -080048 final WindowManagerService mService;
Craig Mautnerb1fd65c02013-02-05 13:34:57 -080049
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070050 // Content limits relative to the DisplayContent this sits in.
51 private Rect mBounds = new Rect();
52
53 // Device rotation as of the last time {@link #mBounds} was set.
54 int mRotation;
55
56 // Whether mBounds is fullscreen
57 private boolean mFullscreen = true;
58
59 // Contains configurations settings that are different from the global configuration due to
60 // stack specific operations. E.g. {@link #setBounds}.
61 Configuration mOverrideConfig;
62
63 // For comparison with DisplayContent bounds.
64 private Rect mTmpRect = new Rect();
65 // For handling display rotations.
66 private Rect mTmpRect2 = new Rect();
67
68 // The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer.
69 WindowStateAnimator mDimWinAnimator;
70 // Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}
71 private DimLayer mDimLayer;
72 // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end
73 // then stop any dimming.
74 private boolean mContinueDimming;
75 // Shared dim layer for fullscreen tasks. {@link #mDimLayer} will point to this instead
76 // of creating a new object per fullscreen task on a display.
77 private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
78
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -070079 Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
80 Configuration config) {
Craig Mautner83162a92015-01-26 14:43:30 -080081 mTaskId = taskId;
Craig Mautnerc00204b2013-03-05 15:02:14 -080082 mStack = stack;
Craig Mautnerac6f8432013-07-17 13:24:59 -070083 mUserId = userId;
Craig Mautnere3119b72015-01-20 15:02:36 -080084 mService = service;
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -070085 setBounds(bounds, config);
Craig Mautnerc00204b2013-03-05 15:02:14 -080086 }
87
88 DisplayContent getDisplayContent() {
89 return mStack.getDisplayContent();
90 }
91
92 void addAppToken(int addPos, AppWindowToken wtoken) {
Craig Mautner42bf39e2014-02-21 16:46:22 -080093 final int lastPos = mAppTokens.size();
Craig Mautner83162a92015-01-26 14:43:30 -080094 if (addPos >= lastPos) {
95 addPos = lastPos;
96 } else {
97 for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
98 if (mAppTokens.get(pos).removed) {
99 // addPos assumes removed tokens are actually gone.
100 ++addPos;
101 }
Craig Mautner01f79cf2014-08-27 09:56:02 -0700102 }
Craig Mautner42bf39e2014-02-21 16:46:22 -0800103 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800104 mAppTokens.add(addPos, wtoken);
Craig Mautner83162a92015-01-26 14:43:30 -0800105 wtoken.mTask = this;
Craig Mautner42bf39e2014-02-21 16:46:22 -0800106 mDeferRemoval = false;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800107 }
108
Craig Mautnere3119b72015-01-20 15:02:36 -0800109 void removeLocked() {
110 if (!mAppTokens.isEmpty() && mStack.isAnimating()) {
Craig Mautner83162a92015-01-26 14:43:30 -0800111 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
Craig Mautnere3119b72015-01-20 15:02:36 -0800112 mDeferRemoval = true;
113 return;
114 }
Craig Mautner83162a92015-01-26 14:43:30 -0800115 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
116 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
Craig Mautnere3119b72015-01-20 15:02:36 -0800117 mDeferRemoval = false;
118 mStack.removeTask(this);
Craig Mautner83162a92015-01-26 14:43:30 -0800119 mService.mTaskIdToTask.delete(mTaskId);
Craig Mautnere3119b72015-01-20 15:02:36 -0800120 }
121
Wale Ogunwale53a29a92015-02-23 15:42:52 -0800122 void moveTaskToStack(TaskStack stack, boolean toTop) {
123 if (stack == mStack) {
124 return;
125 }
126 if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
127 + " from stack=" + mStack);
Wale Ogunwale000957c2015-04-03 08:19:12 -0700128 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
Wale Ogunwale53a29a92015-02-23 15:42:52 -0800129 if (mStack != null) {
130 mStack.removeTask(this);
131 }
132 stack.addTask(this, toTop);
133 }
134
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700135 void positionTaskInStack(TaskStack stack, int position) {
136 if (mStack != null && stack != mStack) {
137 if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
138 + " from stack=" + mStack);
139 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
140 mStack.removeTask(this);
141 }
142 stack.positionTask(this, position, showForAllUsers());
143 }
144
Craig Mautnerc00204b2013-03-05 15:02:14 -0800145 boolean removeAppToken(AppWindowToken wtoken) {
Craig Mautner42bf39e2014-02-21 16:46:22 -0800146 boolean removed = mAppTokens.remove(wtoken);
Craig Mautnerc00204b2013-03-05 15:02:14 -0800147 if (mAppTokens.size() == 0) {
Wale Ogunwale000957c2015-04-03 08:19:12 -0700148 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
Craig Mautner2c2549c2013-11-12 08:31:15 -0800149 "removeAppToken: last token");
Craig Mautnere3119b72015-01-20 15:02:36 -0800150 if (mDeferRemoval) {
151 removeLocked();
152 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800153 }
Craig Mautner83162a92015-01-26 14:43:30 -0800154 wtoken.mTask = null;
155 /* Leave mTaskId for now, it might be useful for debug
156 wtoken.mTaskId = -1;
157 */
Craig Mautner42bf39e2014-02-21 16:46:22 -0800158 return removed;
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800159 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800160
Craig Mautnercbd84af2014-10-22 13:21:22 -0700161 void setSendingToBottom(boolean toBottom) {
162 for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
163 mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
164 }
165 }
166
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700167 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700168 boolean setBounds(Rect bounds, Configuration config) {
169 if (config == null) {
170 config = Configuration.EMPTY;
171 }
172 if (bounds == null && !Configuration.EMPTY.equals(config)) {
173 throw new IllegalArgumentException("null bounds but non empty configuration: "
174 + config);
175 }
176 if (bounds != null && Configuration.EMPTY.equals(config)) {
177 throw new IllegalArgumentException("non null bounds, but empty configuration");
178 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700179 boolean oldFullscreen = mFullscreen;
180 int rotation = Surface.ROTATION_0;
181 final DisplayContent displayContent = mStack.getDisplayContent();
182 if (displayContent != null) {
183 displayContent.getLogicalDisplayRect(mTmpRect);
184 rotation = displayContent.getDisplayInfo().rotation;
185 if (bounds == null) {
186 bounds = mTmpRect;
187 mFullscreen = true;
188 } else {
Stefan Kuhne234dbf82015-08-13 09:44:28 -0700189 if (mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID || bounds.isEmpty()) {
190 // ensure bounds are entirely within the display rect
191 if (!bounds.intersect(mTmpRect)) {
192 // Can't set bounds outside the containing display...Sorry!
193 return false;
194 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700195 }
196 mFullscreen = mTmpRect.equals(bounds);
197 }
198 }
199
200 if (bounds == null) {
201 // Can't set to fullscreen if we don't have a display to get bounds from...
202 return false;
203 }
204 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
205 return false;
206 }
207
208 mBounds.set(bounds);
209 mRotation = rotation;
210 updateDimLayer();
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700211 mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700212 return true;
213 }
214
215 void getBounds(Rect out) {
216 out.set(mBounds);
217 }
218
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700219 void updateDisplayInfo(final DisplayContent displayContent) {
220 if (displayContent == null) {
221 return;
222 }
223 if (mFullscreen) {
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700224 setBounds(null, Configuration.EMPTY);
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700225 return;
226 }
227 final int newRotation = displayContent.getDisplayInfo().rotation;
228 if (mRotation == newRotation) {
229 return;
230 }
231
232 // Device rotation changed. We don't want the task to move around on the screen when
233 // this happens, so update the task bounds so it stays in the same place.
234 final int rotationDelta = DisplayContent.deltaRotation(mRotation, newRotation);
235 displayContent.getLogicalDisplayRect(mTmpRect);
236 switch (rotationDelta) {
237 case Surface.ROTATION_0:
238 mTmpRect2.set(mBounds);
239 break;
240 case Surface.ROTATION_90:
241 mTmpRect2.top = mTmpRect.bottom - mBounds.right;
242 mTmpRect2.left = mBounds.top;
243 mTmpRect2.right = mTmpRect2.left + mBounds.height();
244 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
245 break;
246 case Surface.ROTATION_180:
247 mTmpRect2.top = mTmpRect.bottom - mBounds.bottom;
248 mTmpRect2.left = mTmpRect.right - mBounds.right;
249 mTmpRect2.right = mTmpRect2.left + mBounds.width();
250 mTmpRect2.bottom = mTmpRect2.top + mBounds.height();
251 break;
252 case Surface.ROTATION_270:
253 mTmpRect2.top = mBounds.left;
254 mTmpRect2.left = mTmpRect.right - mBounds.bottom;
255 mTmpRect2.right = mTmpRect2.left + mBounds.height();
256 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
257 break;
258 }
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700259 setBounds(mTmpRect2, mOverrideConfig);
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700260 }
261
262 /** Updates the dim layer bounds, recreating it if needed. */
263 private void updateDimLayer() {
264 DimLayer newDimLayer;
265 final boolean previousFullscreen =
266 mDimLayer != null && sSharedFullscreenDimLayers.indexOfValue(mDimLayer) > -1;
267 final int displayId = mStack.getDisplayContent().getDisplayId();
268 if (mFullscreen) {
269 if (previousFullscreen) {
270 // Nothing to do here...
271 return;
272 }
273 // Use shared fullscreen dim layer
274 newDimLayer = sSharedFullscreenDimLayers.get(displayId);
275 if (newDimLayer == null) {
276 if (mDimLayer != null) {
277 // Re-purpose the previous dim layer.
278 newDimLayer = mDimLayer;
279 } else {
280 // Create new full screen dim layer.
281 newDimLayer = new DimLayer(mService, this, displayId);
282 }
283 newDimLayer.setBounds(mBounds);
284 sSharedFullscreenDimLayers.put(displayId, newDimLayer);
285 } else if (mDimLayer != null) {
286 mDimLayer.destroySurface();
287 }
288 } else {
289 newDimLayer = (mDimLayer == null || previousFullscreen)
290 ? new DimLayer(mService, this, displayId) : mDimLayer;
291 newDimLayer.setBounds(mBounds);
292 }
293 mDimLayer = newDimLayer;
294 }
295
296 boolean animateDimLayers() {
297 final int dimLayer;
298 final float dimAmount;
299 if (mDimWinAnimator == null) {
300 dimLayer = mDimLayer.getLayer();
301 dimAmount = 0;
302 } else {
303 dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
304 dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount;
305 }
306 final float targetAlpha = mDimLayer.getTargetAlpha();
307 if (targetAlpha != dimAmount) {
308 if (mDimWinAnimator == null) {
309 mDimLayer.hide(DEFAULT_DIM_DURATION);
310 } else {
311 long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null)
312 ? mDimWinAnimator.mAnimation.computeDurationHint()
313 : DEFAULT_DIM_DURATION;
314 if (targetAlpha > dimAmount) {
315 duration = getDimBehindFadeDuration(duration);
316 }
317 mDimLayer.show(dimLayer, dimAmount, duration);
318 }
319 } else if (mDimLayer.getLayer() != dimLayer) {
320 mDimLayer.setLayer(dimLayer);
321 }
322 if (mDimLayer.isAnimating()) {
323 if (!mService.okToDisplay()) {
324 // Jump to the end of the animation.
325 mDimLayer.show();
326 } else {
327 return mDimLayer.stepAnimation();
328 }
329 }
330 return false;
331 }
332
333 private long getDimBehindFadeDuration(long duration) {
334 TypedValue tv = new TypedValue();
335 mService.mContext.getResources().getValue(
336 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
337 if (tv.type == TypedValue.TYPE_FRACTION) {
338 duration = (long)tv.getFraction(duration, duration);
339 } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
340 duration = tv.data;
341 }
342 return duration;
343 }
344
345 void clearContinueDimming() {
346 mContinueDimming = false;
347 }
348
349 void setContinueDimming() {
350 mContinueDimming = true;
351 }
352
353 boolean getContinueDimming() {
354 return mContinueDimming;
355 }
356
357 boolean isDimming() {
358 return mDimLayer.isDimming();
359 }
360
361 boolean isDimming(WindowStateAnimator winAnimator) {
362 return mDimWinAnimator == winAnimator && isDimming();
363 }
364
365 void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
366 // Only set dim params on the highest dimmed layer.
367 // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
368 if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null
369 || !mDimWinAnimator.mSurfaceShown
370 || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
371 mDimWinAnimator = newWinAnimator;
372 if (mDimWinAnimator.mWin.mAppToken == null
373 && !mFullscreen && mStack.getDisplayContent() != null) {
374 // Dim should cover the entire screen for system windows.
375 mStack.getDisplayContent().getLogicalDisplayRect(mTmpRect);
376 mDimLayer.setBounds(mTmpRect);
377 }
378 }
379 }
380
381 void stopDimmingIfNeeded() {
382 if (!mContinueDimming && isDimming()) {
383 mDimWinAnimator = null;
384 mDimLayer.setBounds(mBounds);
385 }
386 }
387
388 void close() {
389 if (mDimLayer != null) {
390 mDimLayer.destroySurface();
391 mDimLayer = null;
392 }
393 }
394
395 void resizeWindows() {
396 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
397 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
398 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
399 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
400 final WindowState win = windows.get(winNdx);
401 if (!resizingWindows.contains(win)) {
402 if (DEBUG_RESIZE) Slog.d(TAG, "setBounds: Resizing " + win);
403 resizingWindows.add(win);
404 }
405 }
406 }
407 }
408
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700409 boolean showForAllUsers() {
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700410 final int tokensCount = mAppTokens.size();
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700411 return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700412 }
413
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800414 @Override
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700415 public boolean isFullscreen() {
416 return mFullscreen;
417 }
418
419 @Override
420 public DisplayInfo getDisplayInfo() {
421 return mStack.getDisplayContent().getDisplayInfo();
422 }
423
424 @Override
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800425 public String toString() {
Craig Mautner83162a92015-01-26 14:43:30 -0800426 return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800427 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700428
429 public void printTo(String prefix, PrintWriter pw) {
430 pw.print(prefix); pw.print("taskId="); pw.print(mTaskId);
431 pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens);
432 pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval);
433 if (mDimLayer.isDimming()) {
434 pw.print(prefix); pw.println("mDimLayer:");
435 mDimLayer.printTo(prefix + " ", pw);
436 pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
437 } else {
438 pw.println();
439 }
440 }
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800441}