BarController.java revision 5b9145bf990a9bbf4fdef1739e61ff8c70ec868f
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.util.Slog;
24import android.view.View;
25import android.view.WindowManagerPolicy.WindowState;
26
27import com.android.internal.statusbar.IStatusBarService;
28
29import java.io.PrintWriter;
30
31/**
32 * Controls state/behavior specific to a system bar window.
33 */
34public class BarController {
35    private static final boolean DEBUG = false;
36
37    private static final int TRANSIENT_BAR_NONE = 0;
38    private static final int TRANSIENT_BAR_SHOWING = 1;
39    private static final int TRANSIENT_BAR_HIDING = 2;
40
41    private final String mTag;
42    private final int mTransientFlag;
43    private final int mUnhideFlag;
44    private final int mStatusBarManagerId;
45    private final Handler mHandler;
46    private final Object mServiceAquireLock = new Object();
47    private IStatusBarService mStatusBarService;
48
49    private WindowState mWin;
50    private int mState;
51    private int mTransientBarState;
52    private boolean mPendingShow;
53
54    public BarController(String tag, int transientFlag, int unhideFlag, int statusBarManagerId) {
55        mTag = "BarController." + tag;
56        mTransientFlag = transientFlag;
57        mUnhideFlag = unhideFlag;
58        mStatusBarManagerId = statusBarManagerId;
59        mHandler = new Handler();
60    }
61
62    public void setWindow(WindowState win) {
63        mWin = win;
64    }
65
66    public boolean isHidden() {
67        return mState == StatusBarManager.WINDOW_STATE_HIDDEN;
68    }
69
70    public void showTransient() {
71        if (mWin != null) {
72            setTransientBarState(TRANSIENT_BAR_SHOWING);
73        }
74    }
75
76    public boolean isTransientShowing() {
77        return mTransientBarState == TRANSIENT_BAR_SHOWING;
78    }
79
80    public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
81        if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
82                (vis & mTransientFlag) == 0) {
83            // sysui requests hide
84            setTransientBarState(TRANSIENT_BAR_HIDING);
85            setBarShowingLw(false);
86        } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
87            // sysui ready to unhide
88            setBarShowingLw(true);
89        }
90    }
91
92    public boolean setBarShowingLw(final boolean show) {
93        if (mWin == null) return false;
94        if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
95            mPendingShow = true;
96            return false;
97        }
98        final boolean oldVis = mWin.isVisibleLw();
99        final boolean oldAnim = mWin.isAnimatingLw();
100        final boolean rt = show ? mWin.showLw(true) : mWin.hideLw(true);
101        final int state = computeState(oldVis, oldAnim, mWin.isVisibleLw(), mWin.isAnimatingLw());
102        if (state > -1) {
103            updateState(state);
104        }
105        return rt;
106    }
107
108    private int computeState(boolean oldVis, boolean oldAnim, boolean newVis, boolean newAnim) {
109        return (!newVis && !newAnim) ? StatusBarManager.WINDOW_STATE_HIDDEN
110                : (!oldVis && newVis && newAnim) ? StatusBarManager.WINDOW_STATE_SHOWING
111                : (oldVis && newVis && !oldAnim && newAnim) ? StatusBarManager.WINDOW_STATE_HIDING
112                : -1;
113    }
114
115    private void updateState(final int state) {
116        if (state != mState) {
117            mState = state;
118            mHandler.post(new Runnable() {
119                @Override
120                public void run() {
121                    try {
122                        IStatusBarService statusbar = getStatusBarService();
123                        if (statusbar != null) {
124                            statusbar.setWindowState(mStatusBarManagerId, state);
125                        }
126                    } catch (RemoteException e) {
127                        // re-acquire status bar service next time it is needed.
128                        mStatusBarService = null;
129                    }
130                }
131            });
132        }
133    }
134
135    public boolean checkHiddenLw() {
136        if (mWin != null) {
137            if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
138                updateState(StatusBarManager.WINDOW_STATE_HIDDEN);
139            }
140            if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
141                // Finished animating out, clean up and reset style
142                setTransientBarState(TRANSIENT_BAR_NONE);
143                if (mPendingShow) {
144                    setBarShowingLw(true);
145                    mPendingShow = false;
146                }
147                return true;
148            }
149        }
150        return false;
151    }
152
153    public boolean checkShowTransientBarLw() {
154        if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
155            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
156            return false;
157        } else if (mWin == null) {
158            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
159            return false;
160        } else if (mWin.isDisplayedLw()) {
161            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
162            return false;
163        } else {
164            return true;
165        }
166    }
167
168    public int updateVisibilityLw(boolean allowed, int oldVis, int vis) {
169        if (mWin == null) return vis;
170        if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
171            if (allowed) {
172                vis |= mTransientFlag;
173                if ((oldVis & mTransientFlag) == 0) {
174                    vis |= mUnhideFlag;  // tell sysui we're ready to unhide
175                }
176            } else {
177                setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
178            }
179        }
180        if (mTransientBarState != TRANSIENT_BAR_NONE) {
181            vis |= mTransientFlag;  // ignore clear requests until transition completes
182            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
183        }
184        return vis;
185    }
186
187    private void setTransientBarState(int state) {
188        if (mWin != null && state != mTransientBarState) {
189            mTransientBarState = state;
190            if (DEBUG) Slog.d(mTag, "New state: " + transientBarStateToString(state));
191        }
192    }
193
194    private IStatusBarService getStatusBarService() {
195        synchronized (mServiceAquireLock) {
196            if (mStatusBarService == null) {
197                mStatusBarService = IStatusBarService.Stub.asInterface(
198                        ServiceManager.getService("statusbar"));
199            }
200            return mStatusBarService;
201        }
202    }
203
204    private static String transientBarStateToString(int state) {
205        if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
206        if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
207        if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
208        throw new IllegalArgumentException("Unknown state " + state);
209    }
210
211    public void dump(PrintWriter pw, String prefix) {
212        if (mWin != null) {
213            pw.print(prefix); pw.print(mTag); pw.print(' ');
214            pw.print("mTransientBar"); pw.print('=');
215            pw.println(transientBarStateToString(mTransientBarState));
216        }
217    }
218}
219