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 17 package com.android.internal.policy.impl; 18 19 import android.app.StatusBarManager; 20 import android.os.Handler; 21 import android.os.RemoteException; 22 import android.os.ServiceManager; 23 import android.os.SystemClock; 24 import android.util.Slog; 25 import android.view.View; 26 import android.view.WindowManager; 27 import android.view.WindowManagerPolicy.WindowState; 28 29 import com.android.internal.statusbar.IStatusBarService; 30 31 import java.io.PrintWriter; 32 33 /** 34 * Controls state/behavior specific to a system bar window. 35 */ 36 public class BarController { 37 private static final boolean DEBUG = false; 38 39 private static final int TRANSIENT_BAR_NONE = 0; 40 private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1; 41 private static final int TRANSIENT_BAR_SHOWING = 2; 42 private static final int TRANSIENT_BAR_HIDING = 3; 43 44 private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000; 45 46 private final String mTag; 47 private final int mTransientFlag; 48 private final int mUnhideFlag; 49 private final int mTranslucentFlag; 50 private final int mStatusBarManagerId; 51 private final int mTranslucentWmFlag; 52 private final Handler mHandler; 53 private final Object mServiceAquireLock = new Object(); 54 private IStatusBarService mStatusBarService; 55 56 private WindowState mWin; 57 private int mState = StatusBarManager.WINDOW_STATE_SHOWING; 58 private int mTransientBarState; 59 private boolean mPendingShow; 60 private long mLastTranslucent; 61 62 public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag, 63 int statusBarManagerId, int translucentWmFlag) { 64 mTag = "BarController." + tag; 65 mTransientFlag = transientFlag; 66 mUnhideFlag = unhideFlag; 67 mTranslucentFlag = translucentFlag; 68 mStatusBarManagerId = statusBarManagerId; 69 mTranslucentWmFlag = translucentWmFlag; 70 mHandler = new Handler(); 71 } 72 73 public void setWindow(WindowState win) { 74 mWin = win; 75 } 76 77 public void showTransient() { 78 if (mWin != null) { 79 setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED); 80 } 81 } 82 83 public boolean isTransientShowing() { 84 return mTransientBarState == TRANSIENT_BAR_SHOWING; 85 } 86 87 public boolean isTransientShowRequested() { 88 return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED; 89 } 90 91 public boolean wasRecentlyTranslucent() { 92 return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS; 93 } 94 95 public void adjustSystemUiVisibilityLw(int oldVis, int vis) { 96 if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING && 97 (vis & mTransientFlag) == 0) { 98 // sysui requests hide 99 setTransientBarState(TRANSIENT_BAR_HIDING); 100 setBarShowingLw(false); 101 } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) { 102 // sysui ready to unhide 103 setBarShowingLw(true); 104 } 105 } 106 107 public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) { 108 if (mWin != null) { 109 if (win != null && (win.getAttrs().privateFlags 110 & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) { 111 if ((win.getAttrs().flags & mTranslucentWmFlag) != 0) { 112 vis |= mTranslucentFlag; 113 } else { 114 vis &= ~mTranslucentFlag; 115 } 116 } else { 117 vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag); 118 } 119 } 120 return vis; 121 } 122 123 public boolean setBarShowingLw(final boolean show) { 124 if (mWin == null) return false; 125 if (show && mTransientBarState == TRANSIENT_BAR_HIDING) { 126 mPendingShow = true; 127 return false; 128 } 129 final boolean wasVis = mWin.isVisibleLw(); 130 final boolean wasAnim = mWin.isAnimatingLw(); 131 final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true); 132 final int state = computeStateLw(wasVis, wasAnim, mWin, change); 133 final boolean stateChanged = updateStateLw(state); 134 return change || stateChanged; 135 } 136 137 private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) { 138 if (win.hasDrawnLw()) { 139 final boolean vis = win.isVisibleLw(); 140 final boolean anim = win.isAnimatingLw(); 141 if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) { 142 return StatusBarManager.WINDOW_STATE_HIDDEN; 143 } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) { 144 return StatusBarManager.WINDOW_STATE_SHOWING; 145 } else if (change) { 146 if (wasVis && vis && !wasAnim && anim) { 147 return StatusBarManager.WINDOW_STATE_HIDING; 148 } else { 149 return StatusBarManager.WINDOW_STATE_SHOWING; 150 } 151 } 152 } 153 return mState; 154 } 155 156 private boolean updateStateLw(final int state) { 157 if (state != mState) { 158 mState = state; 159 if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state)); 160 mHandler.post(new Runnable() { 161 @Override 162 public void run() { 163 try { 164 IStatusBarService statusbar = getStatusBarService(); 165 if (statusbar != null) { 166 statusbar.setWindowState(mStatusBarManagerId, state); 167 } 168 } catch (RemoteException e) { 169 if (DEBUG) Slog.w(mTag, "Error posting window state", e); 170 // re-acquire status bar service next time it is needed. 171 mStatusBarService = null; 172 } 173 } 174 }); 175 return true; 176 } 177 return false; 178 } 179 180 public boolean checkHiddenLw() { 181 if (mWin != null && mWin.hasDrawnLw()) { 182 if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) { 183 updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN); 184 } 185 if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) { 186 // Finished animating out, clean up and reset style 187 setTransientBarState(TRANSIENT_BAR_NONE); 188 if (mPendingShow) { 189 setBarShowingLw(true); 190 mPendingShow = false; 191 } 192 return true; 193 } 194 } 195 return false; 196 } 197 198 public boolean checkShowTransientBarLw() { 199 if (mTransientBarState == TRANSIENT_BAR_SHOWING) { 200 if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown"); 201 return false; 202 } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) { 203 if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested"); 204 return false; 205 } else if (mWin == null) { 206 if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist"); 207 return false; 208 } else if (mWin.isDisplayedLw()) { 209 if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible"); 210 return false; 211 } else { 212 return true; 213 } 214 } 215 216 public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) { 217 if (mWin == null) return vis; 218 if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested 219 if (transientAllowed) { 220 vis |= mTransientFlag; 221 if ((oldVis & mTransientFlag) == 0) { 222 vis |= mUnhideFlag; // tell sysui we're ready to unhide 223 } 224 setTransientBarState(TRANSIENT_BAR_SHOWING); // request accepted 225 } else { 226 setTransientBarState(TRANSIENT_BAR_NONE); // request denied 227 } 228 } 229 if (mTransientBarState != TRANSIENT_BAR_NONE) { 230 vis |= mTransientFlag; // ignore clear requests until transition completes 231 vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // never show transient bars in low profile 232 } 233 if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0) { 234 mLastTranslucent = SystemClock.uptimeMillis(); 235 } 236 return vis; 237 } 238 239 private void setTransientBarState(int state) { 240 if (mWin != null && state != mTransientBarState) { 241 if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) { 242 mLastTranslucent = SystemClock.uptimeMillis(); 243 } 244 mTransientBarState = state; 245 if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state)); 246 } 247 } 248 249 private IStatusBarService getStatusBarService() { 250 synchronized (mServiceAquireLock) { 251 if (mStatusBarService == null) { 252 mStatusBarService = IStatusBarService.Stub.asInterface( 253 ServiceManager.getService("statusbar")); 254 } 255 return mStatusBarService; 256 } 257 } 258 259 private static String transientBarStateToString(int state) { 260 if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING"; 261 if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING"; 262 if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED"; 263 if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE"; 264 throw new IllegalArgumentException("Unknown state " + state); 265 } 266 267 public void dump(PrintWriter pw, String prefix) { 268 if (mWin != null) { 269 pw.print(prefix); pw.println(mTag); 270 pw.print(prefix); pw.print(" "); pw.print("mState"); pw.print('='); 271 pw.println(StatusBarManager.windowStateToString(mState)); 272 pw.print(prefix); pw.print(" "); pw.print("mTransientBar"); pw.print('='); 273 pw.println(transientBarStateToString(mTransientBarState)); 274 } 275 } 276 } 277