blob: 09d70d88cdefdd53ef2908d64981f7d1ade07977 [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
Craig Mautnerc00204b2013-03-05 15:02:14 -0800134 boolean removeAppToken(AppWindowToken wtoken) {
Craig Mautner42bf39e2014-02-21 16:46:22 -0800135 boolean removed = mAppTokens.remove(wtoken);
Craig Mautnerc00204b2013-03-05 15:02:14 -0800136 if (mAppTokens.size() == 0) {
Wale Ogunwale000957c2015-04-03 08:19:12 -0700137 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
Craig Mautner2c2549c2013-11-12 08:31:15 -0800138 "removeAppToken: last token");
Craig Mautnere3119b72015-01-20 15:02:36 -0800139 if (mDeferRemoval) {
140 removeLocked();
141 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800142 }
Craig Mautner83162a92015-01-26 14:43:30 -0800143 wtoken.mTask = null;
144 /* Leave mTaskId for now, it might be useful for debug
145 wtoken.mTaskId = -1;
146 */
Craig Mautner42bf39e2014-02-21 16:46:22 -0800147 return removed;
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800148 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800149
Craig Mautnercbd84af2014-10-22 13:21:22 -0700150 void setSendingToBottom(boolean toBottom) {
151 for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
152 mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
153 }
154 }
155
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700156 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
157 boolean setBounds(Rect bounds) {
158 boolean oldFullscreen = mFullscreen;
159 int rotation = Surface.ROTATION_0;
160 final DisplayContent displayContent = mStack.getDisplayContent();
161 if (displayContent != null) {
162 displayContent.getLogicalDisplayRect(mTmpRect);
163 rotation = displayContent.getDisplayInfo().rotation;
164 if (bounds == null) {
165 bounds = mTmpRect;
166 mFullscreen = true;
167 } else {
168 // ensure bounds are entirely within the display rect
169 if (!bounds.intersect(mTmpRect)) {
170 // Can't set bounds outside the containing display...Sorry!
171 return false;
172 }
173 mFullscreen = mTmpRect.equals(bounds);
174 }
175 }
176
177 if (bounds == null) {
178 // Can't set to fullscreen if we don't have a display to get bounds from...
179 return false;
180 }
181 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
182 return false;
183 }
184
185 mBounds.set(bounds);
186 mRotation = rotation;
187 updateDimLayer();
188 updateOverrideConfiguration();
189 return true;
190 }
191
192 void getBounds(Rect out) {
193 out.set(mBounds);
194 }
195
196 private void updateOverrideConfiguration() {
197 final Configuration serviceConfig = mService.mCurConfiguration;
198 if (mFullscreen) {
199 mOverrideConfig = Configuration.EMPTY;
200 return;
201 }
202
203 if (mOverrideConfig == Configuration.EMPTY) {
204 mOverrideConfig = new Configuration();
205 }
206
207 // TODO(multidisplay): Update Dp to that of display stack is on.
208 final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
209 mOverrideConfig.screenWidthDp =
210 Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
211 mOverrideConfig.screenHeightDp =
212 Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
213 mOverrideConfig.smallestScreenWidthDp =
214 Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
215 mOverrideConfig.orientation =
216 (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
217 ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
218 }
219
220 void updateDisplayInfo(final DisplayContent displayContent) {
221 if (displayContent == null) {
222 return;
223 }
224 if (mFullscreen) {
225 setBounds(null);
226 return;
227 }
228 final int newRotation = displayContent.getDisplayInfo().rotation;
229 if (mRotation == newRotation) {
230 return;
231 }
232
233 // Device rotation changed. We don't want the task to move around on the screen when
234 // this happens, so update the task bounds so it stays in the same place.
235 final int rotationDelta = DisplayContent.deltaRotation(mRotation, newRotation);
236 displayContent.getLogicalDisplayRect(mTmpRect);
237 switch (rotationDelta) {
238 case Surface.ROTATION_0:
239 mTmpRect2.set(mBounds);
240 break;
241 case Surface.ROTATION_90:
242 mTmpRect2.top = mTmpRect.bottom - mBounds.right;
243 mTmpRect2.left = mBounds.top;
244 mTmpRect2.right = mTmpRect2.left + mBounds.height();
245 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
246 break;
247 case Surface.ROTATION_180:
248 mTmpRect2.top = mTmpRect.bottom - mBounds.bottom;
249 mTmpRect2.left = mTmpRect.right - mBounds.right;
250 mTmpRect2.right = mTmpRect2.left + mBounds.width();
251 mTmpRect2.bottom = mTmpRect2.top + mBounds.height();
252 break;
253 case Surface.ROTATION_270:
254 mTmpRect2.top = mBounds.left;
255 mTmpRect2.left = mTmpRect.right - mBounds.bottom;
256 mTmpRect2.right = mTmpRect2.left + mBounds.height();
257 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
258 break;
259 }
260 setBounds(mTmpRect2);
261 }
262
263 /** Updates the dim layer bounds, recreating it if needed. */
264 private void updateDimLayer() {
265 DimLayer newDimLayer;
266 final boolean previousFullscreen =
267 mDimLayer != null && sSharedFullscreenDimLayers.indexOfValue(mDimLayer) > -1;
268 final int displayId = mStack.getDisplayContent().getDisplayId();
269 if (mFullscreen) {
270 if (previousFullscreen) {
271 // Nothing to do here...
272 return;
273 }
274 // Use shared fullscreen dim layer
275 newDimLayer = sSharedFullscreenDimLayers.get(displayId);
276 if (newDimLayer == null) {
277 if (mDimLayer != null) {
278 // Re-purpose the previous dim layer.
279 newDimLayer = mDimLayer;
280 } else {
281 // Create new full screen dim layer.
282 newDimLayer = new DimLayer(mService, this, displayId);
283 }
284 newDimLayer.setBounds(mBounds);
285 sSharedFullscreenDimLayers.put(displayId, newDimLayer);
286 } else if (mDimLayer != null) {
287 mDimLayer.destroySurface();
288 }
289 } else {
290 newDimLayer = (mDimLayer == null || previousFullscreen)
291 ? new DimLayer(mService, this, displayId) : mDimLayer;
292 newDimLayer.setBounds(mBounds);
293 }
294 mDimLayer = newDimLayer;
295 }
296
297 boolean animateDimLayers() {
298 final int dimLayer;
299 final float dimAmount;
300 if (mDimWinAnimator == null) {
301 dimLayer = mDimLayer.getLayer();
302 dimAmount = 0;
303 } else {
304 dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
305 dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount;
306 }
307 final float targetAlpha = mDimLayer.getTargetAlpha();
308 if (targetAlpha != dimAmount) {
309 if (mDimWinAnimator == null) {
310 mDimLayer.hide(DEFAULT_DIM_DURATION);
311 } else {
312 long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null)
313 ? mDimWinAnimator.mAnimation.computeDurationHint()
314 : DEFAULT_DIM_DURATION;
315 if (targetAlpha > dimAmount) {
316 duration = getDimBehindFadeDuration(duration);
317 }
318 mDimLayer.show(dimLayer, dimAmount, duration);
319 }
320 } else if (mDimLayer.getLayer() != dimLayer) {
321 mDimLayer.setLayer(dimLayer);
322 }
323 if (mDimLayer.isAnimating()) {
324 if (!mService.okToDisplay()) {
325 // Jump to the end of the animation.
326 mDimLayer.show();
327 } else {
328 return mDimLayer.stepAnimation();
329 }
330 }
331 return false;
332 }
333
334 private long getDimBehindFadeDuration(long duration) {
335 TypedValue tv = new TypedValue();
336 mService.mContext.getResources().getValue(
337 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
338 if (tv.type == TypedValue.TYPE_FRACTION) {
339 duration = (long)tv.getFraction(duration, duration);
340 } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
341 duration = tv.data;
342 }
343 return duration;
344 }
345
346 void clearContinueDimming() {
347 mContinueDimming = false;
348 }
349
350 void setContinueDimming() {
351 mContinueDimming = true;
352 }
353
354 boolean getContinueDimming() {
355 return mContinueDimming;
356 }
357
358 boolean isDimming() {
359 return mDimLayer.isDimming();
360 }
361
362 boolean isDimming(WindowStateAnimator winAnimator) {
363 return mDimWinAnimator == winAnimator && isDimming();
364 }
365
366 void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
367 // Only set dim params on the highest dimmed layer.
368 // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
369 if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null
370 || !mDimWinAnimator.mSurfaceShown
371 || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
372 mDimWinAnimator = newWinAnimator;
373 if (mDimWinAnimator.mWin.mAppToken == null
374 && !mFullscreen && mStack.getDisplayContent() != null) {
375 // Dim should cover the entire screen for system windows.
376 mStack.getDisplayContent().getLogicalDisplayRect(mTmpRect);
377 mDimLayer.setBounds(mTmpRect);
378 }
379 }
380 }
381
382 void stopDimmingIfNeeded() {
383 if (!mContinueDimming && isDimming()) {
384 mDimWinAnimator = null;
385 mDimLayer.setBounds(mBounds);
386 }
387 }
388
389 void close() {
390 if (mDimLayer != null) {
391 mDimLayer.destroySurface();
392 mDimLayer = null;
393 }
394 }
395
396 void resizeWindows() {
397 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
398 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
399 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
400 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
401 final WindowState win = windows.get(winNdx);
402 if (!resizingWindows.contains(win)) {
403 if (DEBUG_RESIZE) Slog.d(TAG, "setBounds: Resizing " + win);
404 resizingWindows.add(win);
405 }
406 }
407 }
408 }
409
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700410 boolean showForAllUsers() {
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700411 final int tokensCount = mAppTokens.size();
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700412 return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700413 }
414
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800415 @Override
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700416 public boolean isFullscreen() {
417 return mFullscreen;
418 }
419
420 @Override
421 public DisplayInfo getDisplayInfo() {
422 return mStack.getDisplayContent().getDisplayInfo();
423 }
424
425 @Override
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800426 public String toString() {
Craig Mautner83162a92015-01-26 14:43:30 -0800427 return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800428 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700429
430 public void printTo(String prefix, PrintWriter pw) {
431 pw.print(prefix); pw.print("taskId="); pw.print(mTaskId);
432 pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens);
433 pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval);
434 if (mDimLayer.isDimming()) {
435 pw.print(prefix); pw.println("mDimLayer:");
436 mDimLayer.printTo(prefix + " ", pw);
437 pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
438 } else {
439 pw.println();
440 }
441 }
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800442}