BarController.java revision 0ec64c65fb7fbfd89556bc33f5caab4ef0937fd4
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.policy.impl;
18
19import android.app.StatusBarManager;
20import android.os.Handler;
21import android.os.RemoteException;
22import android.os.ServiceManager;
23import android.os.SystemClock;
24import android.util.Slog;
25import android.view.View;
26import android.view.WindowManagerPolicy.WindowState;
27
28import com.android.internal.statusbar.IStatusBarService;
29
30import java.io.PrintWriter;
31
32/**
33 * Controls state/behavior specific to a system bar window.
34 */
35public class BarController {
36    private static final boolean DEBUG = true;
37
38    private static final int TRANSIENT_BAR_NONE = 0;
39    private static final int TRANSIENT_BAR_SHOWING = 1;
40    private static final int TRANSIENT_BAR_HIDING = 2;
41
42    private static final int TRANSPARENT_ANIMATION_DELAY_MS = 1000;
43
44    private final String mTag;
45    private final int mTransientFlag;
46    private final int mUnhideFlag;
47    private final int mTransparentFlag;
48    private final int mStatusBarManagerId;
49    private final Handler mHandler;
50    private final Object mServiceAquireLock = new Object();
51    private IStatusBarService mStatusBarService;
52
53    private WindowState mWin;
54    private int mState;
55    private int mTransientBarState;
56    private boolean mPendingShow;
57    private long mLastTransparent;
58
59    public BarController(String tag, int transientFlag, int unhideFlag, int transparentFlag,
60            int statusBarManagerId) {
61        mTag = "BarController." + tag;
62        mTransientFlag = transientFlag;
63        mUnhideFlag = unhideFlag;
64        mTransparentFlag = transparentFlag;
65        mStatusBarManagerId = statusBarManagerId;
66        mHandler = new Handler();
67    }
68
69    public void setWindow(WindowState win) {
70        mWin = win;
71    }
72
73    public boolean isHidden() {
74        return mState == StatusBarManager.WINDOW_STATE_HIDDEN;
75    }
76
77    public void showTransient() {
78        if (mWin != null) {
79            setTransientBarState(TRANSIENT_BAR_SHOWING);
80        }
81    }
82
83    public boolean isTransientShowing() {
84        return mTransientBarState == TRANSIENT_BAR_SHOWING;
85    }
86
87    public boolean wasRecentlyTransparent() {
88        return (SystemClock.uptimeMillis() - mLastTransparent) < TRANSPARENT_ANIMATION_DELAY_MS;
89    }
90
91    public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
92        if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
93                (vis & mTransientFlag) == 0) {
94            // sysui requests hide
95            setTransientBarState(TRANSIENT_BAR_HIDING);
96            setBarShowingLw(false);
97        } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
98            // sysui ready to unhide
99            setBarShowingLw(true);
100        }
101    }
102
103    public boolean setBarShowingLw(final boolean show) {
104        if (mWin == null) return false;
105        if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
106            mPendingShow = true;
107            return false;
108        }
109        final boolean oldVis = mWin.isVisibleLw();
110        final boolean oldAnim = mWin.isAnimatingLw();
111        final boolean rt = show ? mWin.showLw(true) : mWin.hideLw(true);
112        final int state = computeState(oldVis, oldAnim, mWin.isVisibleLw(), mWin.isAnimatingLw());
113        if (state > -1) {
114            updateState(state);
115        }
116        return rt;
117    }
118
119    private int computeState(boolean oldVis, boolean oldAnim, boolean newVis, boolean newAnim) {
120        return (!newVis && !newAnim) ? StatusBarManager.WINDOW_STATE_HIDDEN
121                : (!oldVis && newVis && newAnim) ? StatusBarManager.WINDOW_STATE_SHOWING
122                : (oldVis && newVis && !oldAnim && newAnim) ? StatusBarManager.WINDOW_STATE_HIDING
123                : -1;
124    }
125
126    private void updateState(final int state) {
127        if (state != mState) {
128            mState = state;
129            if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
130            mHandler.post(new Runnable() {
131                @Override
132                public void run() {
133                    try {
134                        IStatusBarService statusbar = getStatusBarService();
135                        if (statusbar != null) {
136                            statusbar.setWindowState(mStatusBarManagerId, state);
137                        }
138                    } catch (RemoteException e) {
139                        if (DEBUG) Slog.w(mTag, "Error posting window state", e);
140                        // re-acquire status bar service next time it is needed.
141                        mStatusBarService = null;
142                    }
143                }
144            });
145        }
146    }
147
148    public boolean checkHiddenLw() {
149        if (mWin != null) {
150            if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
151                updateState(StatusBarManager.WINDOW_STATE_HIDDEN);
152            }
153            if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
154                // Finished animating out, clean up and reset style
155                setTransientBarState(TRANSIENT_BAR_NONE);
156                if (mPendingShow) {
157                    setBarShowingLw(true);
158                    mPendingShow = false;
159                }
160                return true;
161            }
162        }
163        return false;
164    }
165
166    public boolean checkShowTransientBarLw() {
167        if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
168            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
169            return false;
170        } else if (mWin == null) {
171            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
172            return false;
173        } else if (mWin.isDisplayedLw()) {
174            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
175            return false;
176        } else {
177            return true;
178        }
179    }
180
181    public int updateVisibilityLw(boolean allowed, int oldVis, int vis) {
182        if (mWin == null) return vis;
183        if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
184            if (allowed) {
185                vis |= mTransientFlag;
186                if ((oldVis & mTransientFlag) == 0) {
187                    vis |= mUnhideFlag;  // tell sysui we're ready to unhide
188                }
189            } else {
190                setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
191            }
192        }
193        if (mTransientBarState != TRANSIENT_BAR_NONE) {
194            vis |= mTransientFlag;  // ignore clear requests until transition completes
195            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
196        }
197        if ((vis & mTransparentFlag) != 0 || (oldVis & mTransparentFlag) != 0) {
198            mLastTransparent = SystemClock.uptimeMillis();
199        }
200        return vis;
201    }
202
203    private void setTransientBarState(int state) {
204        if (mWin != null && state != mTransientBarState) {
205            if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
206                mLastTransparent = SystemClock.uptimeMillis();
207            }
208            mTransientBarState = state;
209            if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
210        }
211    }
212
213    private IStatusBarService getStatusBarService() {
214        synchronized (mServiceAquireLock) {
215            if (mStatusBarService == null) {
216                mStatusBarService = IStatusBarService.Stub.asInterface(
217                        ServiceManager.getService("statusbar"));
218            }
219            return mStatusBarService;
220        }
221    }
222
223    private static String transientBarStateToString(int state) {
224        if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
225        if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
226        if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
227        throw new IllegalArgumentException("Unknown state " + state);
228    }
229
230    public void dump(PrintWriter pw, String prefix) {
231        if (mWin != null) {
232            pw.print(prefix); pw.println(mTag);
233            pw.print("  "); pw.print("mState"); pw.print('=');
234            pw.println(StatusBarManager.windowStateToString(mState));
235            pw.print("  "); pw.print("mTransientBar"); pw.print('=');
236            pw.println(transientBarStateToString(mTransientBarState));
237        }
238    }
239}
240