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.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
20
21import com.android.server.input.InputApplicationHandle;
22import com.android.server.wm.WindowManagerService.H;
23
24import android.content.pm.ActivityInfo;
25import android.os.Message;
26import android.os.RemoteException;
27import android.util.Slog;
28import android.view.IApplicationToken;
29import android.view.View;
30import android.view.WindowManager;
31
32import java.io.PrintWriter;
33import java.util.ArrayList;
34
35class AppTokenList extends ArrayList<AppWindowToken> {
36}
37
38/**
39 * Version of WindowToken that is specifically for a particular application (or
40 * really activity) that is displaying windows.
41 */
42class AppWindowToken extends WindowToken {
43    // Non-null only for application tokens.
44    final IApplicationToken appToken;
45
46    // All of the windows and child windows that are included in this
47    // application token.  Note this list is NOT sorted!
48    final WindowList allAppWindows = new WindowList();
49    final AppWindowAnimator mAppAnimator;
50
51    final WindowAnimator mAnimator;
52
53    final boolean voiceInteraction;
54
55    int groupId = -1;
56    boolean appFullscreen;
57    int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
58    boolean layoutConfigChanges;
59    boolean showWhenLocked;
60
61    // The input dispatching timeout for this application token in nanoseconds.
62    long inputDispatchingTimeoutNanos;
63
64    // These are used for determining when all windows associated with
65    // an activity have been drawn, so they can be made visible together
66    // at the same time.
67    // initialize so that it doesn't match mTransactionSequence which is an int.
68    long lastTransactionSequence = Long.MIN_VALUE;
69    int numInterestingWindows;
70    int numDrawnWindows;
71    boolean inPendingTransaction;
72    boolean allDrawn;
73    // Set to true when this app creates a surface while in the middle of an animation. In that
74    // case do not clear allDrawn until the animation completes.
75    boolean deferClearAllDrawn;
76
77    // Is this token going to be hidden in a little while?  If so, it
78    // won't be taken into account for setting the screen orientation.
79    boolean willBeHidden;
80
81    // Is this window's surface needed?  This is almost like hidden, except
82    // it will sometimes be true a little earlier: when the token has
83    // been shown, but is still waiting for its app transition to execute
84    // before making its windows shown.
85    boolean hiddenRequested;
86
87    // Have we told the window clients to hide themselves?
88    boolean clientHidden;
89
90    // Last visibility state we reported to the app token.
91    boolean reportedVisible;
92
93    // Last drawn state we reported to the app token.
94    boolean reportedDrawn;
95
96    // Set to true when the token has been removed from the window mgr.
97    boolean removed;
98
99    // Information about an application starting window if displayed.
100    StartingData startingData;
101    WindowState startingWindow;
102    View startingView;
103    boolean startingDisplayed;
104    boolean startingMoved;
105    boolean firstWindowDrawn;
106
107    // Input application handle used by the input dispatcher.
108    final InputApplicationHandle mInputApplicationHandle;
109
110    boolean mDeferRemoval;
111
112    boolean mLaunchTaskBehind;
113    boolean mEnteringAnimation;
114
115    AppWindowToken(WindowManagerService _service, IApplicationToken _token,
116            boolean _voiceInteraction) {
117        super(_service, _token.asBinder(),
118                WindowManager.LayoutParams.TYPE_APPLICATION, true);
119        appWindowToken = this;
120        appToken = _token;
121        voiceInteraction = _voiceInteraction;
122        mInputApplicationHandle = new InputApplicationHandle(this);
123        mAnimator = service.mAnimator;
124        mAppAnimator = new AppWindowAnimator(this);
125    }
126
127    void sendAppVisibilityToClients() {
128        final int N = allAppWindows.size();
129        for (int i=0; i<N; i++) {
130            WindowState win = allAppWindows.get(i);
131            if (win == startingWindow && clientHidden) {
132                // Don't hide the starting window.
133                continue;
134            }
135            try {
136                if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
137                        "Setting visibility of " + win + ": " + (!clientHidden));
138                win.mClient.dispatchAppVisibility(!clientHidden);
139            } catch (RemoteException e) {
140            }
141        }
142    }
143
144    void updateReportedVisibilityLocked() {
145        if (appToken == null) {
146            return;
147        }
148
149        int numInteresting = 0;
150        int numVisible = 0;
151        int numDrawn = 0;
152        boolean nowGone = true;
153
154        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
155                "Update reported visibility: " + this);
156        final int N = allAppWindows.size();
157        for (int i=0; i<N; i++) {
158            WindowState win = allAppWindows.get(i);
159            if (win == startingWindow || win.mAppFreezing
160                    || win.mViewVisibility != View.VISIBLE
161                    || win.mAttrs.type == TYPE_APPLICATION_STARTING
162                    || win.mDestroying) {
163                continue;
164            }
165            if (WindowManagerService.DEBUG_VISIBILITY) {
166                Slog.v(WindowManagerService.TAG, "Win " + win + ": isDrawn="
167                        + win.isDrawnLw()
168                        + ", isAnimating=" + win.mWinAnimator.isAnimating());
169                if (!win.isDrawnLw()) {
170                    Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mWinAnimator.mSurfaceControl
171                            + " pv=" + win.mPolicyVisibility
172                            + " mDrawState=" + win.mWinAnimator.mDrawState
173                            + " ah=" + win.mAttachedHidden
174                            + " th="
175                            + (win.mAppToken != null
176                                    ? win.mAppToken.hiddenRequested : false)
177                            + " a=" + win.mWinAnimator.mAnimating);
178                }
179            }
180            numInteresting++;
181            if (win.isDrawnLw()) {
182                numDrawn++;
183                if (!win.mWinAnimator.isAnimating()) {
184                    numVisible++;
185                }
186                nowGone = false;
187            } else if (win.mWinAnimator.isAnimating()) {
188                nowGone = false;
189            }
190        }
191
192        boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
193        boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
194        if (!nowGone) {
195            // If the app is not yet gone, then it can only become visible/drawn.
196            if (!nowDrawn) {
197                nowDrawn = reportedDrawn;
198            }
199            if (!nowVisible) {
200                nowVisible = reportedVisible;
201            }
202        }
203        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "VIS " + this + ": interesting="
204                + numInteresting + " visible=" + numVisible);
205        if (nowDrawn != reportedDrawn) {
206            if (nowDrawn) {
207                Message m = service.mH.obtainMessage(
208                        H.REPORT_APPLICATION_TOKEN_DRAWN, this);
209                service.mH.sendMessage(m);
210            }
211            reportedDrawn = nowDrawn;
212        }
213        if (nowVisible != reportedVisible) {
214            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(
215                    WindowManagerService.TAG, "Visibility changed in " + this
216                    + ": vis=" + nowVisible);
217            reportedVisible = nowVisible;
218            Message m = service.mH.obtainMessage(
219                    H.REPORT_APPLICATION_TOKEN_WINDOWS,
220                    nowVisible ? 1 : 0,
221                    nowGone ? 1 : 0,
222                    this);
223            service.mH.sendMessage(m);
224        }
225    }
226
227    WindowState findMainWindow() {
228        int j = windows.size();
229        while (j > 0) {
230            j--;
231            WindowState win = windows.get(j);
232            if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
233                    || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
234                return win;
235            }
236        }
237        return null;
238    }
239
240    boolean isVisible() {
241        final int N = allAppWindows.size();
242        for (int i=0; i<N; i++) {
243            WindowState win = allAppWindows.get(i);
244            if (!win.mAppFreezing
245                    && (win.mViewVisibility == View.VISIBLE ||
246                        (win.mWinAnimator.isAnimating() &&
247                                !service.mAppTransition.isTransitionSet()))
248                    && !win.mDestroying && win.isDrawnLw()) {
249                return true;
250            }
251        }
252        return false;
253    }
254
255    @Override
256    void removeAllWindows() {
257        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
258                // removeWindowLocked at bottom of loop may remove multiple entries from
259                // allAppWindows if the window to be removed has child windows. It also may
260                // not remove any windows from allAppWindows at all if win is exiting and
261                // currently animating away. This ensures that winNdx is monotonically decreasing
262                // and never beyond allAppWindows bounds.
263                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
264            WindowState win = allAppWindows.get(winNdx);
265            if (WindowManagerService.DEBUG_WINDOW_MOVEMENT) {
266                Slog.w(WindowManagerService.TAG, "removeAllWindows: removing win=" + win);
267            }
268
269            win.mService.removeWindowLocked(win.mSession, win);
270        }
271    }
272
273    @Override
274    void dump(PrintWriter pw, String prefix) {
275        super.dump(pw, prefix);
276        if (appToken != null) {
277            pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
278        }
279        if (allAppWindows.size() > 0) {
280            pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
281        }
282        pw.print(prefix); pw.print("groupId="); pw.print(groupId);
283                pw.print(" appFullscreen="); pw.print(appFullscreen);
284                pw.print(" requestedOrientation="); pw.println(requestedOrientation);
285        pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
286                pw.print(" clientHidden="); pw.print(clientHidden);
287                pw.print(" willBeHidden="); pw.print(willBeHidden);
288                pw.print(" reportedDrawn="); pw.print(reportedDrawn);
289                pw.print(" reportedVisible="); pw.println(reportedVisible);
290        if (paused) {
291            pw.print(prefix); pw.print("paused="); pw.println(paused);
292        }
293        if (numInterestingWindows != 0 || numDrawnWindows != 0
294                || allDrawn || mAppAnimator.allDrawn) {
295            pw.print(prefix); pw.print("numInterestingWindows=");
296                    pw.print(numInterestingWindows);
297                    pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
298                    pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
299                    pw.print(" allDrawn="); pw.print(allDrawn);
300                    pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
301                    pw.println(")");
302        }
303        if (inPendingTransaction) {
304            pw.print(prefix); pw.print("inPendingTransaction=");
305                    pw.println(inPendingTransaction);
306        }
307        if (startingData != null || removed || firstWindowDrawn || mDeferRemoval) {
308            pw.print(prefix); pw.print("startingData="); pw.print(startingData);
309                    pw.print(" removed="); pw.print(removed);
310                    pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
311                    pw.print(" mDeferRemoval="); pw.println(mDeferRemoval);
312        }
313        if (startingWindow != null || startingView != null
314                || startingDisplayed || startingMoved) {
315            pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
316                    pw.print(" startingView="); pw.print(startingView);
317                    pw.print(" startingDisplayed="); pw.print(startingDisplayed);
318                    pw.print(" startingMoved"); pw.println(startingMoved);
319        }
320    }
321
322    @Override
323    public String toString() {
324        if (stringName == null) {
325            StringBuilder sb = new StringBuilder();
326            sb.append("AppWindowToken{");
327            sb.append(Integer.toHexString(System.identityHashCode(this)));
328            sb.append(" token="); sb.append(token); sb.append('}');
329            stringName = sb.toString();
330        }
331        return stringName;
332    }
333}
334