blob: 79527b7854661f7b12d2d1b5ca4ff679c4d2e384 [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;
Craig Mautner42bf39e2014-02-21 16:46:22 -080022
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070023import android.content.res.Configuration;
24import android.graphics.Rect;
25import android.util.DisplayMetrics;
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
Craig Mautner83162a92015-01-26 14:43:30 -080079 Task(int taskId, TaskStack stack, int userId, WindowManagerService service) {
80 mTaskId = taskId;
Craig Mautnerc00204b2013-03-05 15:02:14 -080081 mStack = stack;
Craig Mautnerac6f8432013-07-17 13:24:59 -070082 mUserId = userId;
Craig Mautnere3119b72015-01-20 15:02:36 -080083 mService = service;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070084 mOverrideConfig = Configuration.EMPTY;
Craig Mautnerc00204b2013-03-05 15:02:14 -080085 }
86
87 DisplayContent getDisplayContent() {
88 return mStack.getDisplayContent();
89 }
90
91 void addAppToken(int addPos, AppWindowToken wtoken) {
Craig Mautner42bf39e2014-02-21 16:46:22 -080092 final int lastPos = mAppTokens.size();
Craig Mautner83162a92015-01-26 14:43:30 -080093 if (addPos >= lastPos) {
94 addPos = lastPos;
95 } else {
96 for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
97 if (mAppTokens.get(pos).removed) {
98 // addPos assumes removed tokens are actually gone.
99 ++addPos;
100 }
Craig Mautner01f79cf2014-08-27 09:56:02 -0700101 }
Craig Mautner42bf39e2014-02-21 16:46:22 -0800102 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800103 mAppTokens.add(addPos, wtoken);
Craig Mautner83162a92015-01-26 14:43:30 -0800104 wtoken.mTask = this;
Craig Mautner42bf39e2014-02-21 16:46:22 -0800105 mDeferRemoval = false;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800106 }
107
Craig Mautnere3119b72015-01-20 15:02:36 -0800108 void removeLocked() {
109 if (!mAppTokens.isEmpty() && mStack.isAnimating()) {
Craig Mautner83162a92015-01-26 14:43:30 -0800110 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
Craig Mautnere3119b72015-01-20 15:02:36 -0800111 mDeferRemoval = true;
112 return;
113 }
Craig Mautner83162a92015-01-26 14:43:30 -0800114 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
115 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
Craig Mautnere3119b72015-01-20 15:02:36 -0800116 mDeferRemoval = false;
117 mStack.removeTask(this);
Craig Mautner83162a92015-01-26 14:43:30 -0800118 mService.mTaskIdToTask.delete(mTaskId);
Craig Mautnere3119b72015-01-20 15:02:36 -0800119 }
120
Wale Ogunwale53a29a92015-02-23 15:42:52 -0800121 void moveTaskToStack(TaskStack stack, boolean toTop) {
122 if (stack == mStack) {
123 return;
124 }
125 if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
126 + " from stack=" + mStack);
Wale Ogunwale000957c2015-04-03 08:19:12 -0700127 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
Wale Ogunwale53a29a92015-02-23 15:42:52 -0800128 if (mStack != null) {
129 mStack.removeTask(this);
130 }
131 stack.addTask(this, toTop);
132 }
133
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700134 void positionTaskInStack(TaskStack stack, int position) {
135 if (mStack != null && stack != mStack) {
136 if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
137 + " from stack=" + mStack);
138 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
139 mStack.removeTask(this);
140 }
141 stack.positionTask(this, position, showForAllUsers());
142 }
143
Craig Mautnerc00204b2013-03-05 15:02:14 -0800144 boolean removeAppToken(AppWindowToken wtoken) {
Craig Mautner42bf39e2014-02-21 16:46:22 -0800145 boolean removed = mAppTokens.remove(wtoken);
Craig Mautnerc00204b2013-03-05 15:02:14 -0800146 if (mAppTokens.size() == 0) {
Wale Ogunwale000957c2015-04-03 08:19:12 -0700147 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
Craig Mautner2c2549c2013-11-12 08:31:15 -0800148 "removeAppToken: last token");
Craig Mautnere3119b72015-01-20 15:02:36 -0800149 if (mDeferRemoval) {
150 removeLocked();
151 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800152 }
Craig Mautner83162a92015-01-26 14:43:30 -0800153 wtoken.mTask = null;
154 /* Leave mTaskId for now, it might be useful for debug
155 wtoken.mTaskId = -1;
156 */
Craig Mautner42bf39e2014-02-21 16:46:22 -0800157 return removed;
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800158 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800159
Craig Mautnercbd84af2014-10-22 13:21:22 -0700160 void setSendingToBottom(boolean toBottom) {
161 for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
162 mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
163 }
164 }
165
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700166 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
167 boolean setBounds(Rect bounds) {
168 boolean oldFullscreen = mFullscreen;
169 int rotation = Surface.ROTATION_0;
170 final DisplayContent displayContent = mStack.getDisplayContent();
171 if (displayContent != null) {
172 displayContent.getLogicalDisplayRect(mTmpRect);
173 rotation = displayContent.getDisplayInfo().rotation;
174 if (bounds == null) {
175 bounds = mTmpRect;
176 mFullscreen = true;
177 } else {
178 // ensure bounds are entirely within the display rect
179 if (!bounds.intersect(mTmpRect)) {
180 // Can't set bounds outside the containing display...Sorry!
181 return false;
182 }
183 mFullscreen = mTmpRect.equals(bounds);
184 }
185 }
186
187 if (bounds == null) {
188 // Can't set to fullscreen if we don't have a display to get bounds from...
189 return false;
190 }
191 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
192 return false;
193 }
194
195 mBounds.set(bounds);
196 mRotation = rotation;
197 updateDimLayer();
198 updateOverrideConfiguration();
199 return true;
200 }
201
202 void getBounds(Rect out) {
203 out.set(mBounds);
204 }
205
206 private void updateOverrideConfiguration() {
207 final Configuration serviceConfig = mService.mCurConfiguration;
208 if (mFullscreen) {
209 mOverrideConfig = Configuration.EMPTY;
210 return;
211 }
212
213 if (mOverrideConfig == Configuration.EMPTY) {
214 mOverrideConfig = new Configuration();
215 }
216
217 // TODO(multidisplay): Update Dp to that of display stack is on.
218 final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
219 mOverrideConfig.screenWidthDp =
220 Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
221 mOverrideConfig.screenHeightDp =
222 Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
223 mOverrideConfig.smallestScreenWidthDp =
224 Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
225 mOverrideConfig.orientation =
226 (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
227 ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
228 }
229
230 void updateDisplayInfo(final DisplayContent displayContent) {
231 if (displayContent == null) {
232 return;
233 }
234 if (mFullscreen) {
235 setBounds(null);
236 return;
237 }
238 final int newRotation = displayContent.getDisplayInfo().rotation;
239 if (mRotation == newRotation) {
240 return;
241 }
242
243 // Device rotation changed. We don't want the task to move around on the screen when
244 // this happens, so update the task bounds so it stays in the same place.
245 final int rotationDelta = DisplayContent.deltaRotation(mRotation, newRotation);
246 displayContent.getLogicalDisplayRect(mTmpRect);
247 switch (rotationDelta) {
248 case Surface.ROTATION_0:
249 mTmpRect2.set(mBounds);
250 break;
251 case Surface.ROTATION_90:
252 mTmpRect2.top = mTmpRect.bottom - mBounds.right;
253 mTmpRect2.left = mBounds.top;
254 mTmpRect2.right = mTmpRect2.left + mBounds.height();
255 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
256 break;
257 case Surface.ROTATION_180:
258 mTmpRect2.top = mTmpRect.bottom - mBounds.bottom;
259 mTmpRect2.left = mTmpRect.right - mBounds.right;
260 mTmpRect2.right = mTmpRect2.left + mBounds.width();
261 mTmpRect2.bottom = mTmpRect2.top + mBounds.height();
262 break;
263 case Surface.ROTATION_270:
264 mTmpRect2.top = mBounds.left;
265 mTmpRect2.left = mTmpRect.right - mBounds.bottom;
266 mTmpRect2.right = mTmpRect2.left + mBounds.height();
267 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
268 break;
269 }
270 setBounds(mTmpRect2);
271 }
272
273 /** Updates the dim layer bounds, recreating it if needed. */
274 private void updateDimLayer() {
275 DimLayer newDimLayer;
276 final boolean previousFullscreen =
277 mDimLayer != null && sSharedFullscreenDimLayers.indexOfValue(mDimLayer) > -1;
278 final int displayId = mStack.getDisplayContent().getDisplayId();
279 if (mFullscreen) {
280 if (previousFullscreen) {
281 // Nothing to do here...
282 return;
283 }
284 // Use shared fullscreen dim layer
285 newDimLayer = sSharedFullscreenDimLayers.get(displayId);
286 if (newDimLayer == null) {
287 if (mDimLayer != null) {
288 // Re-purpose the previous dim layer.
289 newDimLayer = mDimLayer;
290 } else {
291 // Create new full screen dim layer.
292 newDimLayer = new DimLayer(mService, this, displayId);
293 }
294 newDimLayer.setBounds(mBounds);
295 sSharedFullscreenDimLayers.put(displayId, newDimLayer);
296 } else if (mDimLayer != null) {
297 mDimLayer.destroySurface();
298 }
299 } else {
300 newDimLayer = (mDimLayer == null || previousFullscreen)
301 ? new DimLayer(mService, this, displayId) : mDimLayer;
302 newDimLayer.setBounds(mBounds);
303 }
304 mDimLayer = newDimLayer;
305 }
306
307 boolean animateDimLayers() {
308 final int dimLayer;
309 final float dimAmount;
310 if (mDimWinAnimator == null) {
311 dimLayer = mDimLayer.getLayer();
312 dimAmount = 0;
313 } else {
314 dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
315 dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount;
316 }
317 final float targetAlpha = mDimLayer.getTargetAlpha();
318 if (targetAlpha != dimAmount) {
319 if (mDimWinAnimator == null) {
320 mDimLayer.hide(DEFAULT_DIM_DURATION);
321 } else {
322 long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null)
323 ? mDimWinAnimator.mAnimation.computeDurationHint()
324 : DEFAULT_DIM_DURATION;
325 if (targetAlpha > dimAmount) {
326 duration = getDimBehindFadeDuration(duration);
327 }
328 mDimLayer.show(dimLayer, dimAmount, duration);
329 }
330 } else if (mDimLayer.getLayer() != dimLayer) {
331 mDimLayer.setLayer(dimLayer);
332 }
333 if (mDimLayer.isAnimating()) {
334 if (!mService.okToDisplay()) {
335 // Jump to the end of the animation.
336 mDimLayer.show();
337 } else {
338 return mDimLayer.stepAnimation();
339 }
340 }
341 return false;
342 }
343
344 private long getDimBehindFadeDuration(long duration) {
345 TypedValue tv = new TypedValue();
346 mService.mContext.getResources().getValue(
347 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
348 if (tv.type == TypedValue.TYPE_FRACTION) {
349 duration = (long)tv.getFraction(duration, duration);
350 } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
351 duration = tv.data;
352 }
353 return duration;
354 }
355
356 void clearContinueDimming() {
357 mContinueDimming = false;
358 }
359
360 void setContinueDimming() {
361 mContinueDimming = true;
362 }
363
364 boolean getContinueDimming() {
365 return mContinueDimming;
366 }
367
368 boolean isDimming() {
369 return mDimLayer.isDimming();
370 }
371
372 boolean isDimming(WindowStateAnimator winAnimator) {
373 return mDimWinAnimator == winAnimator && isDimming();
374 }
375
376 void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
377 // Only set dim params on the highest dimmed layer.
378 // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
379 if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null
380 || !mDimWinAnimator.mSurfaceShown
381 || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
382 mDimWinAnimator = newWinAnimator;
383 if (mDimWinAnimator.mWin.mAppToken == null
384 && !mFullscreen && mStack.getDisplayContent() != null) {
385 // Dim should cover the entire screen for system windows.
386 mStack.getDisplayContent().getLogicalDisplayRect(mTmpRect);
387 mDimLayer.setBounds(mTmpRect);
388 }
389 }
390 }
391
392 void stopDimmingIfNeeded() {
393 if (!mContinueDimming && isDimming()) {
394 mDimWinAnimator = null;
395 mDimLayer.setBounds(mBounds);
396 }
397 }
398
399 void close() {
400 if (mDimLayer != null) {
401 mDimLayer.destroySurface();
402 mDimLayer = null;
403 }
404 }
405
406 void resizeWindows() {
407 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
408 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
409 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
410 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
411 final WindowState win = windows.get(winNdx);
412 if (!resizingWindows.contains(win)) {
413 if (DEBUG_RESIZE) Slog.d(TAG, "setBounds: Resizing " + win);
414 resizingWindows.add(win);
415 }
416 }
417 }
418 }
419
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700420 boolean showForAllUsers() {
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700421 final int tokensCount = mAppTokens.size();
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700422 return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700423 }
424
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800425 @Override
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700426 public boolean isFullscreen() {
427 return mFullscreen;
428 }
429
430 @Override
431 public DisplayInfo getDisplayInfo() {
432 return mStack.getDisplayContent().getDisplayInfo();
433 }
434
435 @Override
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800436 public String toString() {
Craig Mautner83162a92015-01-26 14:43:30 -0800437 return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800438 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700439
440 public void printTo(String prefix, PrintWriter pw) {
441 pw.print(prefix); pw.print("taskId="); pw.print(mTaskId);
442 pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens);
443 pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval);
444 if (mDimLayer.isDimming()) {
445 pw.print(prefix); pw.println("mDimLayer:");
446 mDimLayer.printTo(prefix + " ", pw);
447 pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
448 } else {
449 pw.println();
450 }
451 }
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800452}