blob: 29c07053e169df60db79061be3ee2d0c3334d6b5 [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.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.Trace;
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.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.reflect.Field;
/**
* Encapsulates all logic for the status bar window state management.
*/
public class StatusBarWindowManager implements RemoteInputController.Callback {
private static final String TAG = "StatusBarWindowManager";
private final Context mContext;
private final WindowManager mWindowManager;
private final IActivityManager mActivityManager;
private View mStatusBarView;
private WindowManager.LayoutParams mLp;
private WindowManager.LayoutParams mLpChanged;
private boolean mHasTopUi;
private boolean mHasTopUiChanged;
private int mBarHeight;
private final boolean mKeyguardScreenRotation;
private final float mScreenBrightnessDoze;
private final State mCurrentState = new State();
public StatusBarWindowManager(Context context) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mActivityManager = ActivityManager.getService();
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
mScreenBrightnessDoze = mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
}
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.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
} else {
mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
if (state.keyguardShowing && !state.backdropShowing) {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
}
}
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.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
|| BaseStatusBar.ENABLE_REMOTE_INPUT && state.remoteInputActive) {
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;
}
mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
}
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) {
boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
if (mStatusBarView.getFitsSystemWindows() != fitsSystemWindows) {
mStatusBarView.setFitsSystemWindows(fitsSystemWindows);
mStatusBarView.requestApplyInsets();
}
}
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 && !state.forceUserActivity) {
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);
applyBrightness(state);
applyHasTopUi(state);
if (mLp.copyFrom(mLpChanged) != 0) {
mWindowManager.updateViewLayout(mStatusBarView, mLp);
}
if (mHasTopUi != mHasTopUiChanged) {
try {
mActivityManager.setHasTopUi(mHasTopUiChanged);
} catch (RemoteException e) {
Log.e(TAG, "Failed to call setHasTopUi", e);
}
mHasTopUi = mHasTopUiChanged;
}
}
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;
}
}
private void applyBrightness(State state) {
if (state.forceDozeBrightness) {
mLpChanged.screenBrightness = mScreenBrightnessDoze;
} else {
mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
}
}
private void applyHasTopUi(State state) {
mHasTopUiChanged = isExpanded(state);
}
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 setBackdropShowing(boolean showing) {
mCurrentState.backdropShowing = 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 setForceUserActivity(boolean forceUserActivity) {
mCurrentState.forceUserActivity = forceUserActivity;
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);
}
@Override
public void onRemoteInputActive(boolean remoteInputActive) {
mCurrentState.remoteInputActive = remoteInputActive;
apply(mCurrentState);
}
/**
* Set whether the screen brightness is forced to the value we use for doze mode by the status
* bar window.
*/
public void setForceDozeBrightness(boolean forceDozeBrightness) {
mCurrentState.forceDozeBrightness = forceDozeBrightness;
apply(mCurrentState);
}
public void setBarHeight(int barHeight) {
mBarHeight = barHeight;
apply(mCurrentState);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("StatusBarWindowManager state:");
pw.println(mCurrentState);
}
public boolean isShowingWallpaper() {
return !mCurrentState.backdropShowing;
}
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;
boolean forceDozeBrightness;
boolean forceUserActivity;
boolean backdropShowing;
/**
* The {@link BaseStatusBar} state from the status bar.
*/
int statusBarState;
boolean remoteInputActive;
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();
}
}
}