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