Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2014 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.systemui.statusbar.phone;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.app.IActivityManager;
     21 import android.content.Context;
     22 import android.content.pm.ActivityInfo;
     23 import android.content.res.Resources;
     24 import android.graphics.PixelFormat;
     25 import android.os.RemoteException;
     26 import android.os.SystemProperties;
     27 import android.os.Trace;
     28 import android.util.Log;
     29 import android.view.Gravity;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 import android.view.WindowManager;
     33 
     34 import com.android.keyguard.R;
     35 import com.android.systemui.keyguard.KeyguardViewMediator;
     36 import com.android.systemui.statusbar.BaseStatusBar;
     37 import com.android.systemui.statusbar.RemoteInputController;
     38 import com.android.systemui.statusbar.StatusBarState;
     39 
     40 import java.io.FileDescriptor;
     41 import java.io.PrintWriter;
     42 import java.lang.reflect.Field;
     43 
     44 /**
     45  * Encapsulates all logic for the status bar window state management.
     46  */
     47 public class StatusBarWindowManager implements RemoteInputController.Callback {
     48 
     49     private static final String TAG = "StatusBarWindowManager";
     50 
     51     private final Context mContext;
     52     private final WindowManager mWindowManager;
     53     private final IActivityManager mActivityManager;
     54     private View mStatusBarView;
     55     private WindowManager.LayoutParams mLp;
     56     private WindowManager.LayoutParams mLpChanged;
     57     private boolean mHasTopUi;
     58     private boolean mHasTopUiChanged;
     59     private int mBarHeight;
     60     private final boolean mKeyguardScreenRotation;
     61     private final float mScreenBrightnessDoze;
     62     private final State mCurrentState = new State();
     63 
     64     public StatusBarWindowManager(Context context) {
     65         mContext = context;
     66         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     67         mActivityManager = ActivityManagerNative.getDefault();
     68         mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
     69         mScreenBrightnessDoze = mContext.getResources().getInteger(
     70                 com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
     71     }
     72 
     73     private boolean shouldEnableKeyguardScreenRotation() {
     74         Resources res = mContext.getResources();
     75         return SystemProperties.getBoolean("lockscreen.rot_override", false)
     76                 || res.getBoolean(R.bool.config_enableLockScreenRotation);
     77     }
     78 
     79     /**
     80      * Adds the status bar view to the window manager.
     81      *
     82      * @param statusBarView The view to add.
     83      * @param barHeight The height of the status bar in collapsed state.
     84      */
     85     public void add(View statusBarView, int barHeight) {
     86 
     87         // Now that the status bar window encompasses the sliding panel and its
     88         // translucent backdrop, the entire thing is made TRANSLUCENT and is
     89         // hardware-accelerated.
     90         mLp = new WindowManager.LayoutParams(
     91                 ViewGroup.LayoutParams.MATCH_PARENT,
     92                 barHeight,
     93                 WindowManager.LayoutParams.TYPE_STATUS_BAR,
     94                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
     95                         | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
     96                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
     97                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
     98                         | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
     99                 PixelFormat.TRANSLUCENT);
    100         mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
    101         mLp.gravity = Gravity.TOP;
    102         mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
    103         mLp.setTitle("StatusBar");
    104         mLp.packageName = mContext.getPackageName();
    105         mStatusBarView = statusBarView;
    106         mBarHeight = barHeight;
    107         mWindowManager.addView(mStatusBarView, mLp);
    108         mLpChanged = new WindowManager.LayoutParams();
    109         mLpChanged.copyFrom(mLp);
    110     }
    111 
    112     private void applyKeyguardFlags(State state) {
    113         if (state.keyguardShowing) {
    114             mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    115         } else {
    116             mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    117         }
    118 
    119         if (state.keyguardShowing && !state.backdropShowing) {
    120             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
    121         } else {
    122             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
    123         }
    124     }
    125 
    126     private void adjustScreenOrientation(State state) {
    127         if (state.isKeyguardShowingAndNotOccluded()) {
    128             if (mKeyguardScreenRotation) {
    129                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
    130             } else {
    131                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
    132             }
    133         } else {
    134             mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    135         }
    136     }
    137 
    138     private void applyFocusableFlag(State state) {
    139         boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
    140         if (state.keyguardShowing && state.keyguardNeedsInput && state.bouncerShowing
    141                 || BaseStatusBar.ENABLE_REMOTE_INPUT && state.remoteInputActive) {
    142             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    143             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
    144         } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
    145             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    146             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
    147         } else {
    148             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    149             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
    150         }
    151 
    152         mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
    153     }
    154 
    155     private void applyHeight(State state) {
    156         boolean expanded = isExpanded(state);
    157         if (expanded) {
    158             mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
    159         } else {
    160             mLpChanged.height = mBarHeight;
    161         }
    162     }
    163 
    164     private boolean isExpanded(State state) {
    165         return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
    166                 || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
    167                 || state.headsUpShowing);
    168     }
    169 
    170     private void applyFitsSystemWindows(State state) {
    171         boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
    172         if (mStatusBarView.getFitsSystemWindows() != fitsSystemWindows) {
    173             mStatusBarView.setFitsSystemWindows(fitsSystemWindows);
    174             mStatusBarView.requestApplyInsets();
    175         }
    176     }
    177 
    178     private void applyUserActivityTimeout(State state) {
    179         if (state.isKeyguardShowingAndNotOccluded()
    180                 && state.statusBarState == StatusBarState.KEYGUARD
    181                 && !state.qsExpanded) {
    182             mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
    183         } else {
    184             mLpChanged.userActivityTimeout = -1;
    185         }
    186     }
    187 
    188     private void applyInputFeatures(State state) {
    189         if (state.isKeyguardShowingAndNotOccluded()
    190                 && state.statusBarState == StatusBarState.KEYGUARD
    191                 && !state.qsExpanded && !state.forceUserActivity) {
    192             mLpChanged.inputFeatures |=
    193                     WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
    194         } else {
    195             mLpChanged.inputFeatures &=
    196                     ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
    197         }
    198     }
    199 
    200     private void apply(State state) {
    201         applyKeyguardFlags(state);
    202         applyForceStatusBarVisibleFlag(state);
    203         applyFocusableFlag(state);
    204         adjustScreenOrientation(state);
    205         applyHeight(state);
    206         applyUserActivityTimeout(state);
    207         applyInputFeatures(state);
    208         applyFitsSystemWindows(state);
    209         applyModalFlag(state);
    210         applyBrightness(state);
    211         applyHasTopUi(state);
    212         if (mLp.copyFrom(mLpChanged) != 0) {
    213             mWindowManager.updateViewLayout(mStatusBarView, mLp);
    214         }
    215         if (mHasTopUi != mHasTopUiChanged) {
    216             try {
    217                 mActivityManager.setHasTopUi(mHasTopUiChanged);
    218             } catch (RemoteException e) {
    219                 Log.e(TAG, "Failed to call setHasTopUi", e);
    220             }
    221             mHasTopUi = mHasTopUiChanged;
    222         }
    223     }
    224 
    225     private void applyForceStatusBarVisibleFlag(State state) {
    226         if (state.forceStatusBarVisible) {
    227             mLpChanged.privateFlags |= WindowManager
    228                     .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
    229         } else {
    230             mLpChanged.privateFlags &= ~WindowManager
    231                     .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
    232         }
    233     }
    234 
    235     private void applyModalFlag(State state) {
    236         if (state.headsUpShowing) {
    237             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    238         } else {
    239             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    240         }
    241     }
    242 
    243     private void applyBrightness(State state) {
    244         if (state.forceDozeBrightness) {
    245             mLpChanged.screenBrightness = mScreenBrightnessDoze;
    246         } else {
    247             mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
    248         }
    249     }
    250 
    251     private void applyHasTopUi(State state) {
    252         mHasTopUiChanged = isExpanded(state);
    253     }
    254 
    255     public void setKeyguardShowing(boolean showing) {
    256         mCurrentState.keyguardShowing = showing;
    257         apply(mCurrentState);
    258     }
    259 
    260     public void setKeyguardOccluded(boolean occluded) {
    261         mCurrentState.keyguardOccluded = occluded;
    262         apply(mCurrentState);
    263     }
    264 
    265     public void setKeyguardNeedsInput(boolean needsInput) {
    266         mCurrentState.keyguardNeedsInput = needsInput;
    267         apply(mCurrentState);
    268     }
    269 
    270     public void setPanelVisible(boolean visible) {
    271         mCurrentState.panelVisible = visible;
    272         mCurrentState.statusBarFocusable = visible;
    273         apply(mCurrentState);
    274     }
    275 
    276     public void setStatusBarFocusable(boolean focusable) {
    277         mCurrentState.statusBarFocusable = focusable;
    278         apply(mCurrentState);
    279     }
    280 
    281     public void setBouncerShowing(boolean showing) {
    282         mCurrentState.bouncerShowing = showing;
    283         apply(mCurrentState);
    284     }
    285 
    286     public void setBackdropShowing(boolean showing) {
    287         mCurrentState.backdropShowing = showing;
    288         apply(mCurrentState);
    289     }
    290 
    291     public void setKeyguardFadingAway(boolean keyguardFadingAway) {
    292         mCurrentState.keyguardFadingAway = keyguardFadingAway;
    293         apply(mCurrentState);
    294     }
    295 
    296     public void setQsExpanded(boolean expanded) {
    297         mCurrentState.qsExpanded = expanded;
    298         apply(mCurrentState);
    299     }
    300 
    301     public void setForceUserActivity(boolean forceUserActivity) {
    302         mCurrentState.forceUserActivity = forceUserActivity;
    303         apply(mCurrentState);
    304     }
    305 
    306     public void setHeadsUpShowing(boolean showing) {
    307         mCurrentState.headsUpShowing = showing;
    308         apply(mCurrentState);
    309     }
    310 
    311     /**
    312      * @param state The {@link StatusBarState} of the status bar.
    313      */
    314     public void setStatusBarState(int state) {
    315         mCurrentState.statusBarState = state;
    316         apply(mCurrentState);
    317     }
    318 
    319     public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
    320         mCurrentState.forceStatusBarVisible = forceStatusBarVisible;
    321         apply(mCurrentState);
    322     }
    323 
    324     /**
    325      * Force the window to be collapsed, even if it should theoretically be expanded.
    326      * Used for when a heads-up comes in but we still need to wait for the touchable regions to
    327      * be computed.
    328      */
    329     public void setForceWindowCollapsed(boolean force) {
    330         mCurrentState.forceCollapsed = force;
    331         apply(mCurrentState);
    332     }
    333 
    334     public void setPanelExpanded(boolean isExpanded) {
    335         mCurrentState.panelExpanded = isExpanded;
    336         apply(mCurrentState);
    337     }
    338 
    339     @Override
    340     public void onRemoteInputActive(boolean remoteInputActive) {
    341         mCurrentState.remoteInputActive = remoteInputActive;
    342         apply(mCurrentState);
    343     }
    344 
    345     /**
    346      * Set whether the screen brightness is forced to the value we use for doze mode by the status
    347      * bar window.
    348      */
    349     public void setForceDozeBrightness(boolean forceDozeBrightness) {
    350         mCurrentState.forceDozeBrightness = forceDozeBrightness;
    351         apply(mCurrentState);
    352     }
    353 
    354     public void setBarHeight(int barHeight) {
    355         mBarHeight = barHeight;
    356         apply(mCurrentState);
    357     }
    358 
    359     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    360         pw.println("StatusBarWindowManager state:");
    361         pw.println(mCurrentState);
    362     }
    363 
    364     public boolean isShowingWallpaper() {
    365         return !mCurrentState.backdropShowing;
    366     }
    367 
    368     private static class State {
    369         boolean keyguardShowing;
    370         boolean keyguardOccluded;
    371         boolean keyguardNeedsInput;
    372         boolean panelVisible;
    373         boolean panelExpanded;
    374         boolean statusBarFocusable;
    375         boolean bouncerShowing;
    376         boolean keyguardFadingAway;
    377         boolean qsExpanded;
    378         boolean headsUpShowing;
    379         boolean forceStatusBarVisible;
    380         boolean forceCollapsed;
    381         boolean forceDozeBrightness;
    382         boolean forceUserActivity;
    383         boolean backdropShowing;
    384 
    385         /**
    386          * The {@link BaseStatusBar} state from the status bar.
    387          */
    388         int statusBarState;
    389 
    390         boolean remoteInputActive;
    391 
    392         private boolean isKeyguardShowingAndNotOccluded() {
    393             return keyguardShowing && !keyguardOccluded;
    394         }
    395 
    396         @Override
    397         public String toString() {
    398             StringBuilder result = new StringBuilder();
    399             String newLine = "\n";
    400             result.append("Window State {");
    401             result.append(newLine);
    402 
    403             Field[] fields = this.getClass().getDeclaredFields();
    404 
    405             // Print field names paired with their values
    406             for (Field field : fields) {
    407                 result.append("  ");
    408                 try {
    409                     result.append(field.getName());
    410                     result.append(": ");
    411                     //requires access to private field:
    412                     result.append(field.get(this));
    413                 } catch (IllegalAccessException ex) {
    414                 }
    415                 result.append(newLine);
    416             }
    417             result.append("}");
    418 
    419             return result.toString();
    420         }
    421     }
    422 }
    423