AppWindowToken.java revision b7b4a56a6e49e1bb9bac4294d10b4e3d341cfb2b
1/*
2 * Copyright (C) 2011 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
19import static android.app.ActivityManager.StackId;
20import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
21import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
22import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
23import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
24import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
29import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
30
31import com.android.server.input.InputApplicationHandle;
32import com.android.server.wm.WindowManagerService.H;
33
34import android.annotation.NonNull;
35import android.content.pm.ActivityInfo;
36import android.graphics.Rect;
37import android.os.Message;
38import android.os.RemoteException;
39import android.util.Slog;
40import android.view.IApplicationToken;
41import android.view.View;
42import android.view.WindowManager;
43
44import java.io.PrintWriter;
45import java.util.ArrayDeque;
46import java.util.ArrayList;
47
48class AppTokenList extends ArrayList<AppWindowToken> {
49}
50
51/**
52 * Version of WindowToken that is specifically for a particular application (or
53 * really activity) that is displaying windows.
54 */
55class AppWindowToken extends WindowToken {
56    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
57
58    // Non-null only for application tokens.
59    final IApplicationToken appToken;
60
61    // All of the windows and child windows that are included in this
62    // application token.  Note this list is NOT sorted!
63    final WindowList allAppWindows = new WindowList();
64    @NonNull final AppWindowAnimator mAppAnimator;
65
66    final boolean voiceInteraction;
67
68    // Whether we're performing an entering animation with a saved surface.
69    boolean mAnimatingWithSavedSurface;
70
71
72    Task mTask;
73    boolean appFullscreen;
74    int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
75    boolean layoutConfigChanges;
76    boolean showForAllUsers;
77
78    // The input dispatching timeout for this application token in nanoseconds.
79    long inputDispatchingTimeoutNanos;
80
81    // These are used for determining when all windows associated with
82    // an activity have been drawn, so they can be made visible together
83    // at the same time.
84    // initialize so that it doesn't match mTransactionSequence which is an int.
85    long lastTransactionSequence = Long.MIN_VALUE;
86    int numInterestingWindows;
87    int numDrawnWindows;
88    boolean inPendingTransaction;
89    boolean allDrawn;
90    // Set to true when this app creates a surface while in the middle of an animation. In that
91    // case do not clear allDrawn until the animation completes.
92    boolean deferClearAllDrawn;
93
94    // Is this window's surface needed?  This is almost like hidden, except
95    // it will sometimes be true a little earlier: when the token has
96    // been shown, but is still waiting for its app transition to execute
97    // before making its windows shown.
98    boolean hiddenRequested;
99
100    // Have we told the window clients to hide themselves?
101    boolean clientHidden;
102
103    // Last visibility state we reported to the app token.
104    boolean reportedVisible;
105
106    // Last drawn state we reported to the app token.
107    boolean reportedDrawn;
108
109    // Set to true when the token has been removed from the window mgr.
110    boolean removed;
111
112    boolean appDied;
113    // Information about an application starting window if displayed.
114    StartingData startingData;
115    WindowState startingWindow;
116    View startingView;
117    boolean startingDisplayed;
118    boolean startingMoved;
119    boolean firstWindowDrawn;
120
121    // Input application handle used by the input dispatcher.
122    final InputApplicationHandle mInputApplicationHandle;
123
124    boolean mIsExiting;
125
126    boolean mLaunchTaskBehind;
127    boolean mEnteringAnimation;
128
129    boolean mAlwaysFocusable;
130
131    boolean mAppStopped;
132    int mPendingRelaunchCount;
133
134    ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
135
136    AppWindowToken(WindowManagerService _service, IApplicationToken _token,
137            boolean _voiceInteraction) {
138        super(_service, _token.asBinder(),
139                WindowManager.LayoutParams.TYPE_APPLICATION, true);
140        appWindowToken = this;
141        appToken = _token;
142        voiceInteraction = _voiceInteraction;
143        mInputApplicationHandle = new InputApplicationHandle(this);
144        mAppAnimator = new AppWindowAnimator(this);
145    }
146
147    void sendAppVisibilityToClients() {
148        final int N = allAppWindows.size();
149        for (int i=0; i<N; i++) {
150            WindowState win = allAppWindows.get(i);
151            if (win == startingWindow && clientHidden) {
152                // Don't hide the starting window.
153                continue;
154            }
155            try {
156                if (DEBUG_VISIBILITY) Slog.v(TAG,
157                        "Setting visibility of " + win + ": " + (!clientHidden));
158                win.mClient.dispatchAppVisibility(!clientHidden);
159            } catch (RemoteException e) {
160            }
161        }
162    }
163
164    void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
165        firstWindowDrawn = true;
166
167        // We now have a good window to show, remove dead placeholders
168        removeAllDeadWindows();
169
170        if (startingData != null) {
171            if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
172                    + win.mToken + ": first real window is shown, no animation");
173            // If this initial window is animating, stop it -- we will do an animation to reveal
174            // it from behind the starting window, so there is no need for it to also be doing its
175            // own stuff.
176            winAnimator.clearAnimation();
177            winAnimator.mService.mFinishedStarting.add(this);
178            winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
179        }
180        updateReportedVisibilityLocked();
181    }
182
183    void updateReportedVisibilityLocked() {
184        if (appToken == null) {
185            return;
186        }
187
188        int numInteresting = 0;
189        int numVisible = 0;
190        int numDrawn = 0;
191        boolean nowGone = true;
192
193        if (DEBUG_VISIBILITY) Slog.v(TAG,
194                "Update reported visibility: " + this);
195        final int N = allAppWindows.size();
196        for (int i=0; i<N; i++) {
197            WindowState win = allAppWindows.get(i);
198            if (win == startingWindow || win.mAppFreezing
199                    || win.mViewVisibility != View.VISIBLE
200                    || win.mAttrs.type == TYPE_APPLICATION_STARTING
201                    || win.mDestroying) {
202                continue;
203            }
204            if (DEBUG_VISIBILITY) {
205                Slog.v(TAG, "Win " + win + ": isDrawn="
206                        + win.isDrawnLw()
207                        + ", isAnimationSet=" + win.mWinAnimator.isAnimationSet());
208                if (!win.isDrawnLw()) {
209                    Slog.v(TAG, "Not displayed: s=" +
210                            win.mWinAnimator.mSurfaceController
211                            + " pv=" + win.mPolicyVisibility
212                            + " mDrawState=" + win.mWinAnimator.mDrawState
213                            + " ah=" + win.mAttachedHidden
214                            + " th="
215                            + (win.mAppToken != null
216                                    ? win.mAppToken.hiddenRequested : false)
217                            + " a=" + win.mWinAnimator.mAnimating);
218                }
219            }
220            numInteresting++;
221            if (win.isDrawnLw()) {
222                numDrawn++;
223                if (!win.mWinAnimator.isAnimationSet()) {
224                    numVisible++;
225                }
226                nowGone = false;
227            } else if (win.mWinAnimator.isAnimationSet()) {
228                nowGone = false;
229            }
230        }
231
232        boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
233        boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
234        if (!nowGone) {
235            // If the app is not yet gone, then it can only become visible/drawn.
236            if (!nowDrawn) {
237                nowDrawn = reportedDrawn;
238            }
239            if (!nowVisible) {
240                nowVisible = reportedVisible;
241            }
242        }
243        if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
244                + numInteresting + " visible=" + numVisible);
245        if (nowDrawn != reportedDrawn) {
246            if (nowDrawn) {
247                Message m = service.mH.obtainMessage(
248                        H.REPORT_APPLICATION_TOKEN_DRAWN, this);
249                service.mH.sendMessage(m);
250            }
251            reportedDrawn = nowDrawn;
252        }
253        if (nowVisible != reportedVisible) {
254            if (DEBUG_VISIBILITY) Slog.v(
255                    TAG, "Visibility changed in " + this
256                    + ": vis=" + nowVisible);
257            reportedVisible = nowVisible;
258            Message m = service.mH.obtainMessage(
259                    H.REPORT_APPLICATION_TOKEN_WINDOWS,
260                    nowVisible ? 1 : 0,
261                    nowGone ? 1 : 0,
262                    this);
263            service.mH.sendMessage(m);
264        }
265    }
266
267    WindowState findMainWindow() {
268        WindowState candidate = null;
269        int j = windows.size();
270        while (j > 0) {
271            j--;
272            WindowState win = windows.get(j);
273            if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
274                    || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
275                // In cases where there are multiple windows, we prefer the non-exiting window. This
276                // happens for example when replacing windows during an activity relaunch. When
277                // constructing the animation, we want the new window, not the exiting one.
278                if (win.mAnimatingExit) {
279                    candidate = win;
280                } else {
281                    return win;
282                }
283            }
284        }
285        return candidate;
286    }
287
288    boolean windowsAreFocusable() {
289        return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
290    }
291
292    boolean isVisible() {
293        final int N = allAppWindows.size();
294        for (int i=0; i<N; i++) {
295            WindowState win = allAppWindows.get(i);
296            // If we're animating with a saved surface, we're already visible.
297            // Return true so that the alpha doesn't get cleared.
298            if (!win.mAppFreezing
299                    && (win.mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface
300                            || (win.mWinAnimator.isAnimationSet()
301                                    && !service.mAppTransition.isTransitionSet()))
302                    && !win.mDestroying
303                    && win.isDrawnLw()) {
304                return true;
305            }
306        }
307        return false;
308    }
309
310    void removeAppFromTaskLocked() {
311        mIsExiting = false;
312        removeAllWindows();
313
314        // Use local variable because removeAppToken will null out mTask.
315        final Task task = mTask;
316        if (task != null) {
317            if (!task.removeAppToken(this)) {
318                Slog.e(TAG, "removeAppFromTaskLocked: token=" + this
319                        + " not found.");
320            }
321            task.mStack.mExitingAppTokens.remove(this);
322        }
323    }
324
325    // Here we destroy surfaces which have been marked as eligible by the animator, taking care
326    // to ensure the client has finished with them. If the client could still be using them
327    // we will skip destruction and try again when the client has stopped.
328    void destroySurfaces() {
329        final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) allAppWindows.clone();
330        final DisplayContentList displayList = new DisplayContentList();
331        for (int i = allWindows.size() - 1; i >= 0; i--) {
332            final WindowState win = allWindows.get(i);
333            if (!win.mDestroying) {
334                continue;
335            }
336
337            if (!(mAppStopped || win.mWindowRemovalAllowed)) {
338                continue;
339            }
340
341            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
342                    + " destroySurfaces: mAppStopped=" + mAppStopped
343                    + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
344                    + " win.mRemoveOnExit=" + win.mRemoveOnExit);
345
346            win.destroyOrSaveSurface();
347            if (win.mRemoveOnExit) {
348                win.mAnimatingExit = false;
349                service.removeWindowInnerLocked(win);
350            }
351            final DisplayContent displayContent = win.getDisplayContent();
352            if (displayContent != null && !displayList.contains(displayContent)) {
353                displayList.add(displayContent);
354            }
355            win.mDestroying = false;
356        }
357        for (int i = 0; i < displayList.size(); i++) {
358            final DisplayContent displayContent = displayList.get(i);
359            service.mLayersController.assignLayersLocked(displayContent.getWindowList());
360            displayContent.layoutNeeded = true;
361        }
362    }
363
364    /**
365     * If the application has stopped it is okay to destroy any surfaces which were keeping alive
366     * in case they were still being used.
367     */
368    void notifyAppStopped(boolean stopped) {
369        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this);
370        mAppStopped = stopped;
371
372        if (stopped) {
373            destroySurfaces();
374            // Remove any starting window that was added for this app if they are still around.
375            mTask.mService.scheduleRemoveStartingWindowLocked(this);
376        }
377    }
378
379    /**
380     * Checks whether we should save surfaces for this app.
381     *
382     * @return true if the surfaces should be saved, false otherwise.
383     */
384    boolean shouldSaveSurface() {
385        // We want to save surface if the app's windows are "allDrawn".
386        // (If we started entering animation early with saved surfaces, allDrawn
387        // should have been restored to true. So we'll save again in that case
388        // even if app didn't actually finish drawing.)
389        return allDrawn;
390    }
391
392    boolean hasSavedSurface() {
393        for (int i = allAppWindows.size() -1; i >= 0; i--) {
394            final WindowState ws = allAppWindows.get(i);
395            if (ws.hasSavedSurface()) {
396                return true;
397            }
398        }
399        return false;
400    }
401
402    void restoreSavedSurfaces() {
403        if (!hasSavedSurface()) {
404            return;
405        }
406        mAnimatingWithSavedSurface = true;
407
408        // Check if we have enough drawn windows to mark allDrawn= true.
409        int numInteresting = 0;
410        int numDrawn = 0;
411        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
412            WindowState w = allAppWindows.get(i);
413            if (w.hasSavedSurface()) {
414                w.restoreSavedSurface();
415            }
416            if (w != startingWindow && !w.mAppDied
417                    && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
418                numInteresting++;
419                if (w.isDrawnLw()) {
420                    numDrawn++;
421                }
422            }
423        }
424
425        allDrawn |= (numInteresting > 0) && (numInteresting == numDrawn);
426
427        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
428                "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn);
429    }
430
431    void destroySavedSurfaces() {
432        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
433            WindowState win = allAppWindows.get(i);
434            win.destroySavedSurface();
435        }
436        mAnimatingWithSavedSurface = false;
437    }
438
439    @Override
440    void removeAllWindows() {
441        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
442                // removeWindowLocked at bottom of loop may remove multiple entries from
443                // allAppWindows if the window to be removed has child windows. It also may
444                // not remove any windows from allAppWindows at all if win is exiting and
445                // currently animating away. This ensures that winNdx is monotonically decreasing
446                // and never beyond allAppWindows bounds.
447                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
448            WindowState win = allAppWindows.get(winNdx);
449            if (DEBUG_WINDOW_MOVEMENT) {
450                Slog.w(TAG, "removeAllWindows: removing win=" + win);
451            }
452
453            service.removeWindowLocked(win);
454        }
455        allAppWindows.clear();
456        windows.clear();
457    }
458
459    void removeAllDeadWindows() {
460        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
461                // removeWindowLocked at bottom of loop may remove multiple entries from
462                // allAppWindows if the window to be removed has child windows. It also may
463                // not remove any windows from allAppWindows at all if win is exiting and
464                // currently animating away. This ensures that winNdx is monotonically decreasing
465                // and never beyond allAppWindows bounds.
466                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
467            WindowState win = allAppWindows.get(winNdx);
468            if (win.mAppDied) {
469                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
470                    Slog.w(TAG, "removeAllDeadWindows: " + win);
471                }
472                // Set mDestroying, we don't want any animation or delayed removal here.
473                win.mDestroying = true;
474                service.removeWindowLocked(win);
475            }
476        }
477    }
478
479    void setReplacingWindows(boolean animate) {
480        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
481                + " with replacing windows.");
482
483        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
484            final WindowState w = allAppWindows.get(i);
485            w.setReplacing(animate);
486        }
487        if (animate) {
488            // Set-up dummy animation so we can start treating windows associated with this
489            // token like they are in transition before the new app window is ready for us to
490            // run the real transition animation.
491            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
492                    "setReplacingWindow() Setting dummy animation on: " + this);
493            mAppAnimator.setDummyAnimation();
494        }
495    }
496
497    void setReplacingChildren() {
498        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
499                + " with replacing child windows.");
500        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
501            final WindowState w = allAppWindows.get(i);
502            if (w.shouldBeReplacedWithChildren()) {
503                w.setReplacing(false /* animate */);
504            }
505        }
506    }
507
508    void resetReplacingWindows() {
509        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
510                + " of replacing window marks.");
511
512        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
513            final WindowState w = allAppWindows.get(i);
514            w.resetReplacing();
515        }
516    }
517
518    void requestUpdateWallpaperIfNeeded() {
519        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
520            final WindowState w = allAppWindows.get(i);
521            w.requestUpdateWallpaperIfNeeded();
522        }
523    }
524
525    boolean isRelaunching() {
526        return mPendingRelaunchCount > 0;
527    }
528
529    void startRelaunching() {
530        if (canFreezeBounds()) {
531            freezeBounds();
532        }
533        mPendingRelaunchCount++;
534    }
535
536    void finishRelaunching() {
537        if (canFreezeBounds()) {
538            unfreezeBounds();
539        }
540        if (mPendingRelaunchCount > 0) {
541            mPendingRelaunchCount--;
542        }
543    }
544
545    void addWindow(WindowState w) {
546        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
547            WindowState candidate = allAppWindows.get(i);
548            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
549                    candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
550                candidate.mReplacingWindow = w;
551                w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
552
553                // if we got a replacement window, reset the timeout to give drawing more time
554                service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
555                service.mH.sendMessageDelayed(
556                        service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this),
557                            WINDOW_REPLACEMENT_TIMEOUT_DURATION);
558            }
559        }
560        allAppWindows.add(w);
561    }
562
563    boolean waitingForReplacement() {
564        for (int i = allAppWindows.size() -1; i >= 0; i--) {
565            WindowState candidate = allAppWindows.get(i);
566            if (candidate.mWillReplaceWindow) {
567                return true;
568            }
569        }
570        return false;
571    }
572
573    void clearTimedoutReplacesLocked() {
574        for (int i = allAppWindows.size() - 1; i >= 0;
575             // removeWindowLocked at bottom of loop may remove multiple entries from
576             // allAppWindows if the window to be removed has child windows. It also may
577             // not remove any windows from allAppWindows at all if win is exiting and
578             // currently animating away. This ensures that winNdx is monotonically decreasing
579             // and never beyond allAppWindows bounds.
580             i = Math.min(i - 1, allAppWindows.size() - 1)) {
581            WindowState candidate = allAppWindows.get(i);
582            if (candidate.mWillReplaceWindow == false) {
583                continue;
584            }
585            candidate.mWillReplaceWindow = false;
586            if (candidate.mReplacingWindow != null) {
587                candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
588            }
589            // Since the window already timed out, remove it immediately now.
590            // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter
591            // delays removal on certain conditions, which will leave the stale window in the
592            // stack and marked mWillReplaceWindow=false, so the window will never be removed.
593            service.removeWindowInnerLocked(candidate);
594        }
595    }
596
597    private boolean canFreezeBounds() {
598        // For freeform windows, we can't freeze the bounds at the moment because this would make
599        // the resizing unresponsive.
600        return mTask != null && !mTask.inFreeformWorkspace();
601    }
602
603    /**
604     * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
605     * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
606     * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
607     * with a queue.
608     */
609    private void freezeBounds() {
610        mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
611    }
612
613    /**
614     * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
615     */
616    private void unfreezeBounds() {
617        mFrozenBounds.remove();
618        for (int i = windows.size() - 1; i >= 0; i--) {
619            final WindowState win = windows.get(i);
620            if (!win.mHasSurface) {
621                continue;
622            }
623            win.mLayoutNeeded = true;
624            win.setDisplayLayoutNeeded();
625            if (!service.mResizingWindows.contains(win)) {
626                service.mResizingWindows.add(win);
627            }
628        }
629        service.mWindowPlacerLocked.performSurfacePlacement();
630    }
631
632    @Override
633    void dump(PrintWriter pw, String prefix) {
634        super.dump(pw, prefix);
635        if (appToken != null) {
636            pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
637        }
638        if (allAppWindows.size() > 0) {
639            pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
640        }
641        pw.print(prefix); pw.print("task="); pw.println(mTask);
642        pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen);
643                pw.print(" requestedOrientation="); pw.println(requestedOrientation);
644        pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
645                pw.print(" clientHidden="); pw.print(clientHidden);
646                pw.print(" reportedDrawn="); pw.print(reportedDrawn);
647                pw.print(" reportedVisible="); pw.println(reportedVisible);
648        if (paused) {
649            pw.print(prefix); pw.print("paused="); pw.println(paused);
650        }
651        if (mAppStopped) {
652            pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
653        }
654        if (numInterestingWindows != 0 || numDrawnWindows != 0
655                || allDrawn || mAppAnimator.allDrawn) {
656            pw.print(prefix); pw.print("numInterestingWindows=");
657                    pw.print(numInterestingWindows);
658                    pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
659                    pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
660                    pw.print(" allDrawn="); pw.print(allDrawn);
661                    pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
662                    pw.println(")");
663        }
664        if (inPendingTransaction) {
665            pw.print(prefix); pw.print("inPendingTransaction=");
666                    pw.println(inPendingTransaction);
667        }
668        if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
669            pw.print(prefix); pw.print("startingData="); pw.print(startingData);
670                    pw.print(" removed="); pw.print(removed);
671                    pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
672                    pw.print(" mIsExiting="); pw.println(mIsExiting);
673        }
674        if (startingWindow != null || startingView != null
675                || startingDisplayed || startingMoved) {
676            pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
677                    pw.print(" startingView="); pw.print(startingView);
678                    pw.print(" startingDisplayed="); pw.print(startingDisplayed);
679                    pw.print(" startingMoved="); pw.println(startingMoved);
680        }
681        if (!mFrozenBounds.isEmpty()) {
682            pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
683        }
684        if (mPendingRelaunchCount != 0) {
685            pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
686        }
687    }
688
689    @Override
690    public String toString() {
691        if (stringName == null) {
692            StringBuilder sb = new StringBuilder();
693            sb.append("AppWindowToken{");
694            sb.append(Integer.toHexString(System.identityHashCode(this)));
695            sb.append(" token="); sb.append(token); sb.append('}');
696            stringName = sb.toString();
697        }
698        return stringName;
699    }
700}
701