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.content.Context;
     20 import android.content.pm.ActivityInfo;
     21 import android.content.res.Resources;
     22 import android.graphics.PixelFormat;
     23 import android.os.SystemProperties;
     24 import android.view.Gravity;
     25 import android.view.View;
     26 import android.view.ViewGroup;
     27 import android.view.WindowManager;
     28 
     29 import com.android.keyguard.R;
     30 import com.android.systemui.keyguard.KeyguardViewMediator;
     31 import com.android.systemui.statusbar.BaseStatusBar;
     32 import com.android.systemui.statusbar.StatusBarState;
     33 
     34 import java.io.FileDescriptor;
     35 import java.io.PrintWriter;
     36 import java.lang.reflect.Field;
     37 
     38 /**
     39  * Encapsulates all logic for the status bar window state management.
     40  */
     41 public class StatusBarWindowManager {
     42 
     43     private final Context mContext;
     44     private final WindowManager mWindowManager;
     45     private View mStatusBarView;
     46     private WindowManager.LayoutParams mLp;
     47     private WindowManager.LayoutParams mLpChanged;
     48     private int mBarHeight;
     49     private final boolean mKeyguardScreenRotation;
     50 
     51     private final State mCurrentState = new State();
     52 
     53     public StatusBarWindowManager(Context context) {
     54         mContext = context;
     55         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     56         mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
     57     }
     58 
     59     private boolean shouldEnableKeyguardScreenRotation() {
     60         Resources res = mContext.getResources();
     61         return SystemProperties.getBoolean("lockscreen.rot_override", false)
     62                 || res.getBoolean(R.bool.config_enableLockScreenRotation);
     63     }
     64 
     65     /**
     66      * Adds the status bar view to the window manager.
     67      *
     68      * @param statusBarView The view to add.
     69      * @param barHeight The height of the status bar in collapsed state.
     70      */
     71     public void add(View statusBarView, int barHeight) {
     72 
     73         // Now that the status bar window encompasses the sliding panel and its
     74         // translucent backdrop, the entire thing is made TRANSLUCENT and is
     75         // hardware-accelerated.
     76         mLp = new WindowManager.LayoutParams(
     77                 ViewGroup.LayoutParams.MATCH_PARENT,
     78                 barHeight,
     79                 WindowManager.LayoutParams.TYPE_STATUS_BAR,
     80                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
     81                         | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
     82                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
     83                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
     84                         | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
     85                 PixelFormat.TRANSLUCENT);
     86         mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
     87         mLp.gravity = Gravity.TOP;
     88         mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
     89         mLp.setTitle("StatusBar");
     90         mLp.packageName = mContext.getPackageName();
     91         mStatusBarView = statusBarView;
     92         mBarHeight = barHeight;
     93         mWindowManager.addView(mStatusBarView, mLp);
     94         mLpChanged = new WindowManager.LayoutParams();
     95         mLpChanged.copyFrom(mLp);
     96     }
     97 
     98     private void applyKeyguardFlags(State state) {
     99         if (state.keyguardShowing) {
    100             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
    101             mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    102         } else {
    103             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
    104             mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    105         }
    106     }
    107 
    108     private void adjustScreenOrientation(State state) {
    109         if (state.isKeyguardShowingAndNotOccluded()) {
    110             if (mKeyguardScreenRotation) {
    111                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
    112             } else {
    113                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
    114             }
    115         } else {
    116             mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    117         }
    118     }
    119 
    120     private void applyFocusableFlag(State state) {
    121         boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
    122         if (state.keyguardShowing && state.keyguardNeedsInput && state.bouncerShowing) {
    123             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    124             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
    125         } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
    126             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    127             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
    128         } else {
    129             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    130             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
    131         }
    132     }
    133 
    134     private void applyHeight(State state) {
    135         boolean expanded = isExpanded(state);
    136         if (expanded) {
    137             mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
    138         } else {
    139             mLpChanged.height = mBarHeight;
    140         }
    141     }
    142 
    143     private boolean isExpanded(State state) {
    144         return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
    145                 || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
    146                 || state.headsUpShowing);
    147     }
    148 
    149     private void applyFitsSystemWindows(State state) {
    150         mStatusBarView.setFitsSystemWindows(!state.isKeyguardShowingAndNotOccluded());
    151     }
    152 
    153     private void applyUserActivityTimeout(State state) {
    154         if (state.isKeyguardShowingAndNotOccluded()
    155                 && state.statusBarState == StatusBarState.KEYGUARD
    156                 && !state.qsExpanded) {
    157             mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
    158         } else {
    159             mLpChanged.userActivityTimeout = -1;
    160         }
    161     }
    162 
    163     private void applyInputFeatures(State state) {
    164         if (state.isKeyguardShowingAndNotOccluded()
    165                 && state.statusBarState == StatusBarState.KEYGUARD
    166                 && !state.qsExpanded) {
    167             mLpChanged.inputFeatures |=
    168                     WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
    169         } else {
    170             mLpChanged.inputFeatures &=
    171                     ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
    172         }
    173     }
    174 
    175     private void apply(State state) {
    176         applyKeyguardFlags(state);
    177         applyForceStatusBarVisibleFlag(state);
    178         applyFocusableFlag(state);
    179         adjustScreenOrientation(state);
    180         applyHeight(state);
    181         applyUserActivityTimeout(state);
    182         applyInputFeatures(state);
    183         applyFitsSystemWindows(state);
    184         applyModalFlag(state);
    185         if (mLp.copyFrom(mLpChanged) != 0) {
    186             mWindowManager.updateViewLayout(mStatusBarView, mLp);
    187         }
    188     }
    189 
    190     private void applyForceStatusBarVisibleFlag(State state) {
    191         if (state.forceStatusBarVisible) {
    192             mLpChanged.privateFlags |= WindowManager
    193                     .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
    194         } else {
    195             mLpChanged.privateFlags &= ~WindowManager
    196                     .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
    197         }
    198     }
    199 
    200     private void applyModalFlag(State state) {
    201         if (state.headsUpShowing) {
    202             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    203         } else {
    204             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    205         }
    206     }
    207 
    208     public void setKeyguardShowing(boolean showing) {
    209         mCurrentState.keyguardShowing = showing;
    210         apply(mCurrentState);
    211     }
    212 
    213     public void setKeyguardOccluded(boolean occluded) {
    214         mCurrentState.keyguardOccluded = occluded;
    215         apply(mCurrentState);
    216     }
    217 
    218     public void setKeyguardNeedsInput(boolean needsInput) {
    219         mCurrentState.keyguardNeedsInput = needsInput;
    220         apply(mCurrentState);
    221     }
    222 
    223     public void setPanelVisible(boolean visible) {
    224         mCurrentState.panelVisible = visible;
    225         mCurrentState.statusBarFocusable = visible;
    226         apply(mCurrentState);
    227     }
    228 
    229     public void setStatusBarFocusable(boolean focusable) {
    230         mCurrentState.statusBarFocusable = focusable;
    231         apply(mCurrentState);
    232     }
    233 
    234     public void setBouncerShowing(boolean showing) {
    235         mCurrentState.bouncerShowing = showing;
    236         apply(mCurrentState);
    237     }
    238 
    239     public void setKeyguardFadingAway(boolean keyguardFadingAway) {
    240         mCurrentState.keyguardFadingAway = keyguardFadingAway;
    241         apply(mCurrentState);
    242     }
    243 
    244     public void setQsExpanded(boolean expanded) {
    245         mCurrentState.qsExpanded = expanded;
    246         apply(mCurrentState);
    247     }
    248 
    249     public void setHeadsUpShowing(boolean showing) {
    250         mCurrentState.headsUpShowing = showing;
    251         apply(mCurrentState);
    252     }
    253 
    254     /**
    255      * @param state The {@link StatusBarState} of the status bar.
    256      */
    257     public void setStatusBarState(int state) {
    258         mCurrentState.statusBarState = state;
    259         apply(mCurrentState);
    260     }
    261 
    262     public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
    263         mCurrentState.forceStatusBarVisible = forceStatusBarVisible;
    264         apply(mCurrentState);
    265     }
    266 
    267     /**
    268      * Force the window to be collapsed, even if it should theoretically be expanded.
    269      * Used for when a heads-up comes in but we still need to wait for the touchable regions to
    270      * be computed.
    271      */
    272     public void setForceWindowCollapsed(boolean force) {
    273         mCurrentState.forceCollapsed = force;
    274         apply(mCurrentState);
    275     }
    276 
    277     public void setPanelExpanded(boolean isExpanded) {
    278         mCurrentState.panelExpanded = isExpanded;
    279         apply(mCurrentState);
    280     }
    281 
    282     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    283         pw.println("StatusBarWindowManager state:");
    284         pw.println(mCurrentState);
    285     }
    286 
    287     private static class State {
    288         boolean keyguardShowing;
    289         boolean keyguardOccluded;
    290         boolean keyguardNeedsInput;
    291         boolean panelVisible;
    292         boolean panelExpanded;
    293         boolean statusBarFocusable;
    294         boolean bouncerShowing;
    295         boolean keyguardFadingAway;
    296         boolean qsExpanded;
    297         boolean headsUpShowing;
    298         boolean forceStatusBarVisible;
    299         boolean forceCollapsed;
    300 
    301         /**
    302          * The {@link BaseStatusBar} state from the status bar.
    303          */
    304         int statusBarState;
    305 
    306         private boolean isKeyguardShowingAndNotOccluded() {
    307             return keyguardShowing && !keyguardOccluded;
    308         }
    309 
    310         @Override
    311         public String toString() {
    312             StringBuilder result = new StringBuilder();
    313             String newLine = "\n";
    314             result.append("Window State {");
    315             result.append(newLine);
    316 
    317             Field[] fields = this.getClass().getDeclaredFields();
    318 
    319             // Print field names paired with their values
    320             for (Field field : fields) {
    321                 result.append("  ");
    322                 try {
    323                     result.append(field.getName());
    324                     result.append(": ");
    325                     //requires access to private field:
    326                     result.append(field.get(this));
    327                 } catch (IllegalAccessException ex) {
    328                 }
    329                 result.append(newLine);
    330             }
    331             result.append("}");
    332 
    333             return result.toString();
    334         }
    335     }
    336 }
    337