AppWindowToken.java revision e42d0e102dbdf5287703389183a69019b64fc35e
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            if (!win.mDestroying) {
333                continue;
334            }
335
336            if (!(mAppStopped || win.mWindowRemovalAllowed)) {
337                continue;
338            }
339
340            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
341                    + " destroySurfaces: mAppStopped=" + mAppStopped
342                    + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
343                    + " win.mRemoveOnExit=" + win.mRemoveOnExit);
344
345            win.destroyOrSaveSurface();
346            if (win.mRemoveOnExit) {
347                win.mAnimatingExit = false;
348                service.removeWindowInnerLocked(win);
349            }
350            final DisplayContent displayContent = win.getDisplayContent();
351            if (displayContent != null && !displayList.contains(displayContent)) {
352                displayList.add(displayContent);
353            }
354            win.mDestroying = false;
355        }
356        for (int i = 0; i < displayList.size(); i++) {
357            final DisplayContent displayContent = displayList.get(i);
358            service.mLayersController.assignLayersLocked(displayContent.getWindowList());
359            displayContent.layoutNeeded = true;
360        }
361    }
362
363    /**
364     * If the application has stopped it is okay to destroy any surfaces which were keeping alive
365     * in case they were still being used.
366     */
367    void notifyAppStopped(boolean stopped) {
368        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this);
369        mAppStopped = stopped;
370
371        if (stopped) {
372            destroySurfaces();
373            // Remove any starting window that was added for this app if they are still around.
374            mTask.mService.scheduleRemoveStartingWindowLocked(this);
375        }
376    }
377
378    /**
379     * Checks whether we should save surfaces for this app.
380     *
381     * @return true if the surfaces should be saved, false otherwise.
382     */
383    boolean shouldSaveSurface() {
384        // We want to save surface if the app's windows are "allDrawn".
385        // (If we started entering animation early with saved surfaces, allDrawn
386        // should have been restored to true. So we'll save again in that case
387        // even if app didn't actually finish drawing.)
388        return allDrawn;
389    }
390
391    boolean hasSavedSurface() {
392        for (int i = allAppWindows.size() -1; i >= 0; i--) {
393            final WindowState ws = allAppWindows.get(i);
394            if (ws.hasSavedSurface()) {
395                return true;
396            }
397        }
398        return false;
399    }
400
401    void restoreSavedSurfaces() {
402        if (!hasSavedSurface()) {
403            return;
404        }
405        mAnimatingWithSavedSurface = true;
406
407        // Check if we have enough drawn windows to mark allDrawn= true.
408        int numInteresting = 0;
409        int numDrawn = 0;
410        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
411            WindowState w = allAppWindows.get(i);
412            if (w.hasSavedSurface()) {
413                w.restoreSavedSurface();
414            }
415            if (w != startingWindow && !w.mAppDied
416                    && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
417                numInteresting++;
418                if (w.isDrawnLw()) {
419                    numDrawn++;
420                }
421            }
422        }
423
424        allDrawn |= (numInteresting > 0) && (numInteresting == numDrawn);
425
426        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
427                "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn);
428    }
429
430    void destroySavedSurfaces() {
431        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
432            WindowState win = allAppWindows.get(i);
433            win.destroySavedSurface();
434        }
435        mAnimatingWithSavedSurface = false;
436    }
437
438    @Override
439    void removeAllWindows() {
440        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
441                // removeWindowLocked at bottom of loop may remove multiple entries from
442                // allAppWindows if the window to be removed has child windows. It also may
443                // not remove any windows from allAppWindows at all if win is exiting and
444                // currently animating away. This ensures that winNdx is monotonically decreasing
445                // and never beyond allAppWindows bounds.
446                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
447            WindowState win = allAppWindows.get(winNdx);
448            if (DEBUG_WINDOW_MOVEMENT) {
449                Slog.w(TAG, "removeAllWindows: removing win=" + win);
450            }
451
452            service.removeWindowLocked(win);
453        }
454        allAppWindows.clear();
455        windows.clear();
456    }
457
458    void removeAllDeadWindows() {
459        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
460            // removeWindowLocked at bottom of loop may remove multiple entries from
461            // allAppWindows if the window to be removed has child windows. It also may
462            // not remove any windows from allAppWindows at all if win is exiting and
463            // currently animating away. This ensures that winNdx is monotonically decreasing
464            // and never beyond allAppWindows bounds.
465            winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
466            WindowState win = allAppWindows.get(winNdx);
467            if (win.mAppDied) {
468                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
469                    Slog.w(TAG, "removeAllDeadWindows: " + win);
470                }
471                // Set mDestroying, we don't want any animation or delayed removal here.
472                win.mDestroying = true;
473                service.removeWindowLocked(win);
474            }
475        }
476    }
477
478    boolean hasWindowsAlive() {
479        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
480            if (!allAppWindows.get(i).mAppDied) {
481                return true;
482            }
483        }
484        return false;
485    }
486
487    void setReplacingWindows(boolean animate) {
488        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
489                + " with replacing windows.");
490
491        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
492            final WindowState w = allAppWindows.get(i);
493            w.setReplacing(animate);
494        }
495        if (animate) {
496            // Set-up dummy animation so we can start treating windows associated with this
497            // token like they are in transition before the new app window is ready for us to
498            // run the real transition animation.
499            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
500                    "setReplacingWindow() Setting dummy animation on: " + this);
501            mAppAnimator.setDummyAnimation();
502        }
503    }
504
505    void setReplacingChildren() {
506        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
507                + " with replacing child windows.");
508        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
509            final WindowState w = allAppWindows.get(i);
510            if (w.shouldBeReplacedWithChildren()) {
511                w.setReplacing(false /* animate */);
512            }
513        }
514    }
515
516    void resetReplacingWindows() {
517        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
518                + " of replacing window marks.");
519
520        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
521            final WindowState w = allAppWindows.get(i);
522            w.resetReplacing();
523        }
524    }
525
526    void requestUpdateWallpaperIfNeeded() {
527        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
528            final WindowState w = allAppWindows.get(i);
529            w.requestUpdateWallpaperIfNeeded();
530        }
531    }
532
533    boolean isRelaunching() {
534        return mPendingRelaunchCount > 0;
535    }
536
537    void startRelaunching() {
538        if (canFreezeBounds()) {
539            freezeBounds();
540        }
541        mPendingRelaunchCount++;
542    }
543
544    void finishRelaunching() {
545        if (canFreezeBounds()) {
546            unfreezeBounds();
547        }
548        if (mPendingRelaunchCount > 0) {
549            mPendingRelaunchCount--;
550        }
551    }
552
553    void addWindow(WindowState w) {
554        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
555            WindowState candidate = allAppWindows.get(i);
556            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
557                    candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
558                candidate.mReplacingWindow = w;
559                w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
560
561                // if we got a replacement window, reset the timeout to give drawing more time
562                service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
563                service.mH.sendMessageDelayed(
564                        service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this),
565                            WINDOW_REPLACEMENT_TIMEOUT_DURATION);
566            }
567        }
568        allAppWindows.add(w);
569    }
570
571    boolean waitingForReplacement() {
572        for (int i = allAppWindows.size() -1; i >= 0; i--) {
573            WindowState candidate = allAppWindows.get(i);
574            if (candidate.mWillReplaceWindow) {
575                return true;
576            }
577        }
578        return false;
579    }
580
581    void clearTimedoutReplacesLocked() {
582        for (int i = allAppWindows.size() - 1; i >= 0;
583             // removeWindowLocked at bottom of loop may remove multiple entries from
584             // allAppWindows if the window to be removed has child windows. It also may
585             // not remove any windows from allAppWindows at all if win is exiting and
586             // currently animating away. This ensures that winNdx is monotonically decreasing
587             // and never beyond allAppWindows bounds.
588             i = Math.min(i - 1, allAppWindows.size() - 1)) {
589            WindowState candidate = allAppWindows.get(i);
590            if (candidate.mWillReplaceWindow == false) {
591                continue;
592            }
593            candidate.mWillReplaceWindow = false;
594            if (candidate.mReplacingWindow != null) {
595                candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
596            }
597            // Since the window already timed out, remove it immediately now.
598            // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter
599            // delays removal on certain conditions, which will leave the stale window in the
600            // stack and marked mWillReplaceWindow=false, so the window will never be removed.
601            service.removeWindowInnerLocked(candidate);
602        }
603    }
604
605    private boolean canFreezeBounds() {
606        // For freeform windows, we can't freeze the bounds at the moment because this would make
607        // the resizing unresponsive.
608        return mTask != null && !mTask.inFreeformWorkspace();
609    }
610
611    /**
612     * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
613     * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
614     * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
615     * with a queue.
616     */
617    private void freezeBounds() {
618        mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
619    }
620
621    /**
622     * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
623     */
624    private void unfreezeBounds() {
625        mFrozenBounds.remove();
626        for (int i = windows.size() - 1; i >= 0; i--) {
627            final WindowState win = windows.get(i);
628            if (!win.mHasSurface) {
629                continue;
630            }
631            win.mLayoutNeeded = true;
632            win.setDisplayLayoutNeeded();
633            if (!service.mResizingWindows.contains(win)) {
634                service.mResizingWindows.add(win);
635            }
636        }
637        service.mWindowPlacerLocked.performSurfacePlacement();
638    }
639
640    @Override
641    void dump(PrintWriter pw, String prefix) {
642        super.dump(pw, prefix);
643        if (appToken != null) {
644            pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
645        }
646        if (allAppWindows.size() > 0) {
647            pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
648        }
649        pw.print(prefix); pw.print("task="); pw.println(mTask);
650        pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen);
651                pw.print(" requestedOrientation="); pw.println(requestedOrientation);
652        pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
653                pw.print(" clientHidden="); pw.print(clientHidden);
654                pw.print(" reportedDrawn="); pw.print(reportedDrawn);
655                pw.print(" reportedVisible="); pw.println(reportedVisible);
656        if (paused) {
657            pw.print(prefix); pw.print("paused="); pw.println(paused);
658        }
659        if (mAppStopped) {
660            pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
661        }
662        if (numInterestingWindows != 0 || numDrawnWindows != 0
663                || allDrawn || mAppAnimator.allDrawn) {
664            pw.print(prefix); pw.print("numInterestingWindows=");
665                    pw.print(numInterestingWindows);
666                    pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
667                    pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
668                    pw.print(" allDrawn="); pw.print(allDrawn);
669                    pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
670                    pw.println(")");
671        }
672        if (inPendingTransaction) {
673            pw.print(prefix); pw.print("inPendingTransaction=");
674                    pw.println(inPendingTransaction);
675        }
676        if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
677            pw.print(prefix); pw.print("startingData="); pw.print(startingData);
678                    pw.print(" removed="); pw.print(removed);
679                    pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
680                    pw.print(" mIsExiting="); pw.println(mIsExiting);
681        }
682        if (startingWindow != null || startingView != null
683                || startingDisplayed || startingMoved) {
684            pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
685                    pw.print(" startingView="); pw.print(startingView);
686                    pw.print(" startingDisplayed="); pw.print(startingDisplayed);
687                    pw.print(" startingMoved="); pw.println(startingMoved);
688        }
689        if (!mFrozenBounds.isEmpty()) {
690            pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
691        }
692        if (mPendingRelaunchCount != 0) {
693            pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
694        }
695    }
696
697    @Override
698    public String toString() {
699        if (stringName == null) {
700            StringBuilder sb = new StringBuilder();
701            sb.append("AppWindowToken{");
702            sb.append(Integer.toHexString(System.identityHashCode(this)));
703            sb.append(" token="); sb.append(token); sb.append('}');
704            stringName = sb.toString();
705        }
706        return stringName;
707    }
708}
709