blob: 0d816dd1b6a16ff41cd13b11e17348c96af874a0 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.SystemProperties;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import com.android.keyguard.R;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.StatusBarState;
import java.lang.reflect.Field;
/**
* Encapsulates all logic for the status bar window state management.
*/
public class StatusBarWindowManager {
private final Context mContext;
private final WindowManager mWindowManager;
private View mStatusBarView;
private WindowManager.LayoutParams mLp;
private WindowManager.LayoutParams mLpChanged;
private int mBarHeight;
private final boolean mKeyguardScreenRotation;
private final State mCurrentState = new State();
private boolean mLogState;
public StatusBarWindowManager(Context context) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
}
private boolean shouldEnableKeyguardScreenRotation() {
Resources res = mContext.getResources();
return SystemProperties.getBoolean("lockscreen.rot_override", false)
|| res.getBoolean(R.bool.config_enableLockScreenRotation);
}
/**
* Adds the status bar view to the window manager.
*
* @param statusBarView The view to add.
* @param barHeight The height of the status bar in collapsed state.
*/
public void add(View statusBarView, int barHeight) {
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
barHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar");
mLp.packageName = mContext.getPackageName();
mStatusBarView = statusBarView;
mBarHeight = barHeight;
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
}
private void applyKeyguardFlags(State state) {
if (state.keyguardShowing) {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
}
private void adjustScreenOrientation(State state) {
if (state.isKeyguardShowingAndNotOccluded()) {
if (mKeyguardScreenRotation) {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
} else {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
}
} else {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
}
private void applyFocusableFlag(State state) {
boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
if (state.keyguardShowing && state.keyguardNeedsInput && state.bouncerShowing) {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
}
}
private void applyHeight(State state) {
boolean expanded = isExpanded(state);
if (expanded) {
mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
mLpChanged.height = mBarHeight;
}
}
private boolean isExpanded(State state) {
return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
|| state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
|| state.headsUpShowing);
}
private void applyFitsSystemWindows(State state) {
mStatusBarView.setFitsSystemWindows(!state.isKeyguardShowingAndNotOccluded());
}
private void applyUserActivityTimeout(State state) {
if (state.isKeyguardShowingAndNotOccluded()
&& state.statusBarState == StatusBarState.KEYGUARD
&& !state.qsExpanded) {
mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
} else {
mLpChanged.userActivityTimeout = -1;
}
}
private void applyInputFeatures(State state) {
if (state.isKeyguardShowingAndNotOccluded()
&& state.statusBarState == StatusBarState.KEYGUARD
&& !state.qsExpanded) {
mLpChanged.inputFeatures |=
WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
} else {
mLpChanged.inputFeatures &=
~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
}
}
private void apply(State state) {
applyKeyguardFlags(state);
applyForceStatusBarVisibleFlag(state);
applyFocusableFlag(state);
adjustScreenOrientation(state);
applyHeight(state);
applyUserActivityTimeout(state);
applyInputFeatures(state);
applyFitsSystemWindows(state);
applyModalFlag(state);
if (mLp.copyFrom(mLpChanged) != 0) {
if (PhoneStatusBar.DEBUG_EMPTY_KEYGUARD && mLogState) {
logCurrentState();
}
mWindowManager.updateViewLayout(mStatusBarView, mLp);
}
}
private void applyForceStatusBarVisibleFlag(State state) {
if (state.forceStatusBarVisible) {
mLpChanged.privateFlags |= WindowManager
.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
} else {
mLpChanged.privateFlags &= ~WindowManager
.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
}
}
private void applyModalFlag(State state) {
if (state.headsUpShowing) {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
}
}
public void setKeyguardShowing(boolean showing) {
mCurrentState.keyguardShowing = showing;
apply(mCurrentState);
}
public void setKeyguardOccluded(boolean occluded) {
mCurrentState.keyguardOccluded = occluded;
apply(mCurrentState);
}
public void setKeyguardNeedsInput(boolean needsInput) {
mCurrentState.keyguardNeedsInput = needsInput;
apply(mCurrentState);
}
public void setPanelVisible(boolean visible) {
mCurrentState.panelVisible = visible;
mCurrentState.statusBarFocusable = visible;
apply(mCurrentState);
}
public void setStatusBarFocusable(boolean focusable) {
mCurrentState.statusBarFocusable = focusable;
apply(mCurrentState);
}
public void setBouncerShowing(boolean showing) {
mCurrentState.bouncerShowing = showing;
apply(mCurrentState);
}
public void setKeyguardFadingAway(boolean keyguardFadingAway) {
mCurrentState.keyguardFadingAway = keyguardFadingAway;
apply(mCurrentState);
}
public void setQsExpanded(boolean expanded) {
mCurrentState.qsExpanded = expanded;
apply(mCurrentState);
}
public void setHeadsUpShowing(boolean showing) {
mCurrentState.headsUpShowing = showing;
apply(mCurrentState);
}
/**
* @param state The {@link StatusBarState} of the status bar.
*/
public void setStatusBarState(int state) {
mCurrentState.statusBarState = state;
apply(mCurrentState);
}
public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
mCurrentState.forceStatusBarVisible = forceStatusBarVisible;
apply(mCurrentState);
}
/**
* Force the window to be collapsed, even if it should theoretically be expanded.
* Used for when a heads-up comes in but we still need to wait for the touchable regions to
* be computed.
*/
public void setForceWindowCollapsed(boolean force) {
mCurrentState.forceCollapsed = force;
apply(mCurrentState);
}
public void setPanelExpanded(boolean isExpanded) {
mCurrentState.panelExpanded = isExpanded;
apply(mCurrentState);
}
public void setLogState(boolean logState) {
mLogState = logState;
if (logState) {
Log.w(PhoneStatusBar.TAG, "===== Started logging WM state changes =====");
logCurrentState();
} else {
Log.w(PhoneStatusBar.TAG, "===== Finished logging WM state changes =====");
}
}
private void logCurrentState() {
Log.i(PhoneStatusBar.TAG, mCurrentState.toString()
+ "\n Expanded: " + isExpanded(mCurrentState));
}
private static class State {
boolean keyguardShowing;
boolean keyguardOccluded;
boolean keyguardNeedsInput;
boolean panelVisible;
boolean panelExpanded;
boolean statusBarFocusable;
boolean bouncerShowing;
boolean keyguardFadingAway;
boolean qsExpanded;
boolean headsUpShowing;
boolean forceStatusBarVisible;
boolean forceCollapsed;
/**
* The {@link BaseStatusBar} state from the status bar.
*/
int statusBarState;
private boolean isKeyguardShowingAndNotOccluded() {
return keyguardShowing && !keyguardOccluded;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
String newLine = "\n";
result.append("Window State {");
result.append(newLine);
Field[] fields = this.getClass().getDeclaredFields();
// Print field names paired with their values
for (Field field : fields) {
result.append(" ");
try {
result.append(field.getName());
result.append(": ");
//requires access to private field:
result.append(field.get(this));
} catch (IllegalAccessException ex) {
}
result.append(newLine);
}
result.append("}");
return result.toString();
}
}
}