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