diff options
Diffstat (limited to 'policy')
6 files changed, 870 insertions, 733 deletions
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 9c81f0a..30a271e 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -101,6 +101,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.PopupWindow; @@ -1332,6 +1333,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + public final void setElevation(float elevation) { + mElevation = elevation; + if (mDecor != null) { + mDecor.setElevation(elevation); + } + } + + @Override + public final void setClipToOutline(boolean clipToOutline) { + mClipToOutline = clipToOutline; + if (mDecor != null) { + mDecor.setClipToOutline(clipToOutline); + } + } + + @Override public final void setBackgroundDrawable(Drawable drawable) { if (drawable != mBackgroundDrawable || mBackgroundResource != 0) { mBackgroundResource = 0; @@ -2137,6 +2154,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private final class DecorView extends FrameLayout implements RootViewSurfaceTaker { + /* package */int mDefaultOpacity = PixelFormat.OPAQUE; /** The feature ID of the panel, or -1 if this is the application's DecorView */ @@ -2166,18 +2184,45 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // View added at runtime to draw under the navigation bar area private View mNavigationGuard; - private View mStatusColorView; - private View mNavigationColorView; + private final ColorViewState mStatusColorViewState = new ColorViewState( + SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, + Gravity.TOP, + STATUS_BAR_BACKGROUND_TRANSITION_NAME, + com.android.internal.R.id.statusBarBackground, + FLAG_FULLSCREEN); + private final ColorViewState mNavigationColorViewState = new ColorViewState( + SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, + Gravity.BOTTOM, + NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, + com.android.internal.R.id.navigationBarBackground, + 0 /* hideWindowFlag */); + + private final Interpolator mShowInterpolator; + private final Interpolator mHideInterpolator; + private final int mBarEnterExitDuration; + private final BackgroundFallback mBackgroundFallback = new BackgroundFallback(); private int mLastTopInset = 0; private int mLastBottomInset = 0; private int mLastRightInset = 0; + private boolean mLastHasTopStableInset = false; + private boolean mLastHasBottomStableInset = false; + private int mLastWindowFlags = 0; + private int mRootScrollY = 0; public DecorView(Context context, int featureId) { super(context); mFeatureId = featureId; + + mShowInterpolator = AnimationUtils.loadInterpolator(context, + android.R.interpolator.linear_out_slow_in); + mHideInterpolator = AnimationUtils.loadInterpolator(context, + android.R.interpolator.fast_out_linear_in); + + mBarEnterExitDuration = context.getResources().getInteger( + R.integer.dock_enter_exit_duration); } public void setBackgroundFallback(int resId) { @@ -2770,13 +2815,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void onWindowSystemUiVisibilityChanged(int visible) { - updateColorViews(null /* insets */); + updateColorViews(null /* insets */, true /* animate */); } @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { mFrameOffsets.set(insets.getSystemWindowInsets()); - insets = updateColorViews(insets); + insets = updateColorViews(insets, true /* animate */); insets = updateStatusGuard(insets); updateNavigationGuard(insets); if (getForeground() != null) { @@ -2790,11 +2835,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } - private WindowInsets updateColorViews(WindowInsets insets) { + private WindowInsets updateColorViews(WindowInsets insets, boolean animate) { WindowManager.LayoutParams attrs = getAttributes(); int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility(); if (!mIsFloating && ActivityManager.isHighEndGfx()) { + boolean disallowAnimate = !isLaidOut(); + disallowAnimate |= ((mLastWindowFlags ^ attrs.flags) + & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; + mLastWindowFlags = attrs.flags; + if (insets != null) { mLastTopInset = Math.min(insets.getStableInsetTop(), insets.getSystemWindowInsetTop()); @@ -2802,19 +2852,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { insets.getSystemWindowInsetBottom()); mLastRightInset = Math.min(insets.getStableInsetRight(), insets.getSystemWindowInsetRight()); + + // Don't animate if the presence of stable insets has changed, because that + // indicates that the window was either just added and received them for the + // first time, or the window size or position has changed. + boolean hasTopStableInset = insets.getStableInsetTop() != 0; + disallowAnimate |= hasTopStableInset && !mLastHasTopStableInset; + mLastHasTopStableInset = hasTopStableInset; + + boolean hasBottomStableInset = insets.getStableInsetBottom() != 0; + disallowAnimate |= hasBottomStableInset && !mLastHasBottomStableInset; + mLastHasBottomStableInset = hasBottomStableInset; } - mStatusColorView = updateColorViewInt(mStatusColorView, sysUiVisibility, - SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, - mStatusBarColor, mLastTopInset, Gravity.TOP, - STATUS_BAR_BACKGROUND_TRANSITION_NAME, - com.android.internal.R.id.statusBarBackground, - (getAttributes().flags & FLAG_FULLSCREEN) != 0); - mNavigationColorView = updateColorViewInt(mNavigationColorView, sysUiVisibility, - SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, - mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM, - NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, - com.android.internal.R.id.navigationBarBackground, - false /* hiddenByWindowFlag */); + + updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor, + mLastTopInset, animate && !disallowAnimate); + updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor, + mLastBottomInset, animate && !disallowAnimate); } // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need @@ -2858,27 +2912,35 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return insets; } - private View updateColorViewInt(View view, int sysUiVis, int systemUiHideFlag, - int translucentFlag, int color, int height, int verticalGravity, - String transitionName, int id, boolean hiddenByWindowFlag) { - boolean show = height > 0 && (sysUiVis & systemUiHideFlag) == 0 - && !hiddenByWindowFlag - && (getAttributes().flags & translucentFlag) == 0 + private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color, + int height, boolean animate) { + boolean show = height > 0 && (sysUiVis & state.systemUiHideFlag) == 0 + && (getAttributes().flags & state.hideWindowFlag) == 0 + && (getAttributes().flags & state.translucentFlag) == 0 && (color & Color.BLACK) != 0 && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; + boolean visibilityChanged = false; + View view = state.view; + if (view == null) { if (show) { - view = new View(mContext); + state.view = view = new View(mContext); view.setBackgroundColor(color); - view.setTransitionName(transitionName); - view.setId(id); + view.setTransitionName(state.transitionName); + view.setId(state.id); + visibilityChanged = true; + view.setVisibility(INVISIBLE); + state.targetVisibility = VISIBLE; + addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height, - Gravity.START | verticalGravity)); + Gravity.START | state.verticalGravity)); + updateColorViewTranslations(); } } else { int vis = show ? VISIBLE : INVISIBLE; - view.setVisibility(vis); + visibilityChanged = state.targetVisibility != vis; + state.targetVisibility = vis; if (show) { LayoutParams lp = (LayoutParams) view.getLayoutParams(); if (lp.height != height) { @@ -2888,7 +2950,44 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { view.setBackgroundColor(color); } } - return view; + if (visibilityChanged) { + view.animate().cancel(); + if (animate) { + if (show) { + if (view.getVisibility() != VISIBLE) { + view.setVisibility(VISIBLE); + view.setAlpha(0.0f); + } + view.animate().alpha(1.0f).setInterpolator(mShowInterpolator). + setDuration(mBarEnterExitDuration); + } else { + view.animate().alpha(0.0f).setInterpolator(mHideInterpolator) + .setDuration(mBarEnterExitDuration) + .withEndAction(new Runnable() { + @Override + public void run() { + state.view.setAlpha(1.0f); + state.view.setVisibility(INVISIBLE); + } + }); + } + } else { + view.setAlpha(1.0f); + view.setVisibility(show ? VISIBLE : INVISIBLE); + } + } + } + + private void updateColorViewTranslations() { + // Put the color views back in place when they get moved off the screen + // due to the the ViewRootImpl panning. + int rootScrollY = mRootScrollY; + if (mStatusColorViewState.view != null) { + mStatusColorViewState.view.setTranslationY(rootScrollY > 0 ? rootScrollY : 0); + } + if (mNavigationColorViewState.view != null) { + mNavigationColorViewState.view.setTranslationY(rootScrollY < 0 ? rootScrollY : 0); + } } private WindowInsets updateStatusGuard(WindowInsets insets) { @@ -2918,7 +3017,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mStatusGuard = new View(mContext); mStatusGuard.setBackgroundColor(mContext.getResources() .getColor(R.color.input_method_navigation_guard)); - addView(mStatusGuard, indexOfChild(mStatusColorView), + addView(mStatusGuard, indexOfChild(mStatusColorViewState.view), new LayoutParams(LayoutParams.MATCH_PARENT, mlp.topMargin, Gravity.START | Gravity.TOP)); } else { @@ -2978,9 +3077,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mNavigationGuard = new View(mContext); mNavigationGuard.setBackgroundColor(mContext.getResources() .getColor(R.color.input_method_navigation_guard)); - addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams( - LayoutParams.MATCH_PARENT, insets.getSystemWindowInsetBottom(), - Gravity.START | Gravity.BOTTOM)); + addView(mNavigationGuard, indexOfChild(mNavigationColorViewState.view), + new LayoutParams(LayoutParams.MATCH_PARENT, + insets.getSystemWindowInsetBottom(), + Gravity.START | Gravity.BOTTOM)); } else { LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams(); lp.height = insets.getSystemWindowInsetBottom(); @@ -3149,6 +3249,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } + @Override + public void onRootViewScrollYChanged(int rootScrollY) { + mRootScrollY = rootScrollY; + updateColorViewTranslations(); + } + /** * Clears out internal reference when the action mode is destroyed. */ @@ -3342,9 +3448,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE); if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) { - addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); + setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE); } else { - clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); + setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE); } // Non-floating windows on high end devices must put up decor beneath the system bars and @@ -3876,7 +3982,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) { super.dispatchWindowAttributesChanged(attrs); if (mDecor != null) { - mDecor.updateColorViews(null /* insets */); + mDecor.updateColorViews(null /* insets */, true /* animate */); } } @@ -4603,6 +4709,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + private static class ColorViewState { + View view = null; + int targetVisibility = View.INVISIBLE; + + final int id; + final int systemUiHideFlag; + final int translucentFlag; + final int verticalGravity; + final String transitionName; + final int hideWindowFlag; + + ColorViewState(int systemUiHideFlag, + int translucentFlag, int verticalGravity, + String transitionName, int id, int hideWindowFlag) { + this.id = id; + this.systemUiHideFlag = systemUiHideFlag; + this.translucentFlag = translucentFlag; + this.verticalGravity = verticalGravity; + this.transitionName = transitionName; + this.hideWindowFlag = hideWindowFlag; + } + } + void sendCloseSystemWindows() { PhoneWindowManager.sendCloseSystemWindows(getContext(), null); } @@ -4621,7 +4750,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mStatusBarColor = color; mForcedStatusBarColor = true; if (mDecor != null) { - mDecor.updateColorViews(null); + mDecor.updateColorViews(null, false /* animate */); } } @@ -4635,7 +4764,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mNavigationBarColor = color; mForcedNavigationBarColor = true; if (mDecor != null) { - mDecor.updateColorViews(null); + mDecor.updateColorViews(null, false /* animate */); } } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 99d5848..f0c6bb7 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -48,6 +48,7 @@ import android.media.Ringtone; import android.media.RingtoneManager; import android.media.session.MediaSessionLegacyHelper; import android.os.Bundle; +import android.os.Debug; import android.os.FactoryTest; import android.os.Handler; import android.os.IBinder; @@ -102,8 +103,6 @@ import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; import com.android.internal.R; -import com.android.internal.policy.IKeyguardService; -import com.android.internal.policy.IKeyguardServiceConstants; import com.android.internal.policy.PolicyManager; import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate; import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate.ShowListener; @@ -116,6 +115,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; +import java.util.List; import static android.view.WindowManager.LayoutParams.*; import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; @@ -136,8 +136,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final String TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean localLOGV = false; - static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_INPUT = false; + static final boolean DEBUG_KEYGUARD = false; + static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_WAKEUP = false; static final boolean SHOW_STARTING_ANIMATIONS = true; @@ -158,6 +159,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int LONG_PRESS_POWER_SHUT_OFF = 2; static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3; + static final int MULTI_PRESS_POWER_NOTHING = 0; + static final int MULTI_PRESS_POWER_THEATER_MODE = 1; + static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2; + // These need to match the documentation/constant in // core/res/res/values/config.xml static final int LONG_PRESS_HOME_NOTHING = 0; @@ -300,12 +305,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { }; GlobalActions mGlobalActions; - volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread - boolean mPendingPowerKeyUpCanceled; Handler mHandler; WindowState mLastInputMethodWindow = null; WindowState mLastInputMethodTargetWindow = null; + // FIXME This state is shared between the input reader and handler thread. + // Technically it's broken and buggy but it has been like this for many years + // and we have not yet seen any problems. Someday we'll rewrite this logic + // so that only one thread is involved in handling input policy. Unfortunately + // it's on a critical path for power management so we can't just post the work to the + // handler thread. We'll need to resolve this someday by teaching the input dispatcher + // to hold wakelocks during dispatch and eliminating the critical path. + volatile boolean mPowerKeyHandled; + volatile boolean mBeganFromNonInteractive; + volatile int mPowerKeyPressCounter; + volatile boolean mEndCallKeyHandled; + boolean mRecentsVisible; int mRecentAppsHeldModifiers; boolean mLanguageSwitchKeyPressed; @@ -326,6 +341,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mUndockedHdmiRotation; int mDemoHdmiRotation; boolean mDemoHdmiRotationLock; + int mDemoRotation; + boolean mDemoRotationLock; boolean mWakeGestureEnabledSetting; MyWakeGestureListener mWakeGestureListener; @@ -345,8 +362,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidKeyboardAccessibility; int mLidNavigationAccessibility; boolean mLidControlsSleep; - int mShortPressOnPowerBehavior = -1; - int mLongPressOnPowerBehavior = -1; + int mShortPressOnPowerBehavior; + int mLongPressOnPowerBehavior; + int mDoublePressOnPowerBehavior; + int mTriplePressOnPowerBehavior; boolean mAwake; boolean mScreenOnEarly; boolean mScreenOnFully; @@ -462,6 +481,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mShowingLockscreen; boolean mShowingDream; boolean mDreamingLockscreen; + boolean mKeyguardSecure; + boolean mKeyguardSecureIncludingHidden; + volatile boolean mKeyguardOccluded; boolean mHomePressed; boolean mHomeConsumed; boolean mHomeDoubleTapPending; @@ -503,18 +525,30 @@ public class PhoneWindowManager implements WindowManagerPolicy { // What we do when the user double-taps on home private int mDoubleTapOnHomeBehavior; + // Allowed theater mode wake actions + private boolean mAllowTheaterModeWakeFromKey; + private boolean mAllowTheaterModeWakeFromPowerKey; + private boolean mAllowTheaterModeWakeFromMotion; + private boolean mAllowTheaterModeWakeFromMotionWhenNotDreaming; + private boolean mAllowTheaterModeWakeFromCameraLens; + private boolean mAllowTheaterModeWakeFromLidSwitch; + private boolean mAllowTheaterModeWakeFromWakeGesture; + + // Whether to go to sleep entering theater mode from power button + private boolean mGoToSleepOnButtonPressTheaterMode; + // Screenshot trigger states // Time to volume and power must be pressed within this interval of each other. private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150; // Increase the chord delay when taking a screenshot from the keyguard private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f; private boolean mScreenshotChordEnabled; - private boolean mVolumeDownKeyTriggered; - private long mVolumeDownKeyTime; - private boolean mVolumeDownKeyConsumedByScreenshotChord; - private boolean mVolumeUpKeyTriggered; - private boolean mPowerKeyTriggered; - private long mPowerKeyTime; + private boolean mScreenshotChordVolumeDownKeyTriggered; + private long mScreenshotChordVolumeDownKeyTime; + private boolean mScreenshotChordVolumeDownKeyConsumed; + private boolean mScreenshotChordVolumeUpKeyTriggered; + private boolean mScreenshotChordPowerKeyTriggered; + private long mScreenshotChordPowerKeyTime; /* The number of steps between min and max brightness */ private static final int BRIGHTNESS_STEPS = 10; @@ -522,6 +556,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { SettingsObserver mSettingsObserver; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; + PowerManager.WakeLock mPowerKeyWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock; private int mCurrentUserId; @@ -547,6 +582,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10; private static final int MSG_HIDE_BOOT_MESSAGE = 11; private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12; + private static final int MSG_POWER_DELAYED_PRESS = 13; + private static final int MSG_POWER_LONG_PRESS = 14; private class PolicyHandler extends Handler { @Override @@ -588,6 +625,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK: launchVoiceAssistWithWakeLock(msg.arg1 != 0); break; + case MSG_POWER_DELAYED_PRESS: + powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2); + finishPowerKeyPress(); + break; + case MSG_POWER_LONG_PRESS: + powerLongPress(); + break; } } } @@ -656,7 +700,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { if (shouldEnableWakeGestureLp()) { performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture); } } } @@ -781,38 +825,241 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private void interceptPowerKeyDown(boolean handled) { - mPowerKeyHandled = handled; + private void interceptPowerKeyDown(KeyEvent event, boolean interactive) { + // Hold a wake lock until the power key is released. + if (!mPowerKeyWakeLock.isHeld()) { + mPowerKeyWakeLock.acquire(); + } + + // Cancel multi-press detection timeout. + if (mPowerKeyPressCounter != 0) { + mHandler.removeMessages(MSG_POWER_DELAYED_PRESS); + } + + // Detect user pressing the power button in panic when an application has + // taken over the whole screen. + boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, + event.getDownTime(), isImmersiveMode(mLastSystemUiFlags)); + if (panic) { + mHandler.post(mRequestTransientNav); + } + + // Latch power key state to detect screenshot chord. + if (interactive && !mScreenshotChordPowerKeyTriggered + && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { + mScreenshotChordPowerKeyTriggered = true; + mScreenshotChordPowerKeyTime = event.getDownTime(); + interceptScreenshotChord(); + } + + // Stop ringing or end call if configured to do so when power is pressed. + TelecomManager telecomManager = getTelecommService(); + boolean hungUp = false; + if (telecomManager != null) { + if (telecomManager.isRinging()) { + // Pressing Power while there's a ringing incoming + // call should silence the ringer. + telecomManager.silenceRinger(); + } else if ((mIncallPowerBehavior + & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 + && telecomManager.isInCall() && interactive) { + // Otherwise, if "Power button ends call" is enabled, + // the Power button will hang up any current active call. + hungUp = telecomManager.endCall(); + } + } + + // If the power key has still not yet been handled, then detect short + // press, long press, or multi press and decide what to do. + mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered + || mScreenshotChordVolumeUpKeyTriggered; + if (!mPowerKeyHandled) { + if (interactive) { + // When interactive, we're already awake. + // Wait for a long press or for the button to be released to decide what to do. + if (hasLongPressOnPowerBehavior()) { + Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); + msg.setAsynchronous(true); + mHandler.sendMessageDelayed(msg, + ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); + } + } else { + wakeUpFromPowerKey(event.getDownTime()); + final int maxCount = getMaxMultiPressPowerCount(); + + if (maxCount <= 1) { + mPowerKeyHandled = true; + } else { + mBeganFromNonInteractive = true; + } + } + } + } + + private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) { + final boolean handled = canceled || mPowerKeyHandled; + mScreenshotChordPowerKeyTriggered = false; + cancelPendingScreenshotChordAction(); + cancelPendingPowerKeyAction(); + if (!handled) { - mHandler.postDelayed(mPowerLongPress, - ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); + // Figure out how to handle the key now that it has been released. + mPowerKeyPressCounter += 1; + + final int maxCount = getMaxMultiPressPowerCount(); + final long eventTime = event.getDownTime(); + if (mPowerKeyPressCounter < maxCount) { + // This could be a multi-press. Wait a little bit longer to confirm. + // Continue holding the wake lock. + Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS, + interactive ? 1 : 0, mPowerKeyPressCounter, eventTime); + msg.setAsynchronous(true); + mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout()); + return; + } + + // No other actions. Handle it immediately. + powerPress(eventTime, interactive, mPowerKeyPressCounter); } + + // Done. Reset our state. + finishPowerKeyPress(); } - private boolean interceptPowerKeyUp(boolean canceled) { - if (!mPowerKeyHandled) { - mHandler.removeCallbacks(mPowerLongPress); - return !canceled; + private void finishPowerKeyPress() { + mBeganFromNonInteractive = false; + mPowerKeyPressCounter = 0; + if (mPowerKeyWakeLock.isHeld()) { + mPowerKeyWakeLock.release(); } - return false; } private void cancelPendingPowerKeyAction() { if (!mPowerKeyHandled) { - mHandler.removeCallbacks(mPowerLongPress); + mPowerKeyHandled = true; + mHandler.removeMessages(MSG_POWER_LONG_PRESS); + } + } + + private void powerPress(long eventTime, boolean interactive, int count) { + if (mScreenOnEarly && !mScreenOnFully) { + Slog.i(TAG, "Suppressed redundant power key press while " + + "already in the process of turning the screen on."); + return; + } + + if (count == 2) { + powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior); + } else if (count == 3) { + powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior); + } else if (interactive && !mBeganFromNonInteractive) { + switch (mShortPressOnPowerBehavior) { + case SHORT_PRESS_POWER_NOTHING: + break; + case SHORT_PRESS_POWER_GO_TO_SLEEP: + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); + break; + case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP: + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, + PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); + break; + case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME: + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, + PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); + launchHomeFromHotKey(); + break; + } + } + } + + private void powerMultiPressAction(long eventTime, boolean interactive, int behavior) { + switch (behavior) { + case MULTI_PRESS_POWER_NOTHING: + break; + case MULTI_PRESS_POWER_THEATER_MODE: + if (isTheaterModeEnabled()) { + Slog.i(TAG, "Toggling theater mode off."); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0); + if (!interactive) { + wakeUpFromPowerKey(eventTime); + } + } else { + Slog.i(TAG, "Toggling theater mode on."); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 1); + + if (mGoToSleepOnButtonPressTheaterMode && interactive) { + mPowerManager.goToSleep(eventTime, + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); + } + } + break; + case MULTI_PRESS_POWER_BRIGHTNESS_BOOST: + Slog.i(TAG, "Starting brightness boost."); + if (!interactive) { + wakeUpFromPowerKey(eventTime); + } + mPowerManager.boostScreenBrightness(eventTime); + break; + } + } + + private int getMaxMultiPressPowerCount() { + if (mTriplePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) { + return 3; + } + if (mDoublePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) { + return 2; + } + return 1; + } + + private void powerLongPress() { + final int behavior = getResolvedLongPressOnPowerBehavior(); + switch (behavior) { + case LONG_PRESS_POWER_NOTHING: + break; + case LONG_PRESS_POWER_GLOBAL_ACTIONS: + mPowerKeyHandled = true; + if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { + performAuditoryFeedbackForAccessibilityIfNeed(); + } + showGlobalActionsInternal(); + break; + case LONG_PRESS_POWER_SHUT_OFF: + case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: + mPowerKeyHandled = true; + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF); + break; } - if (mPowerKeyTriggered) { - mPendingPowerKeyUpCanceled = true; + } + + private int getResolvedLongPressOnPowerBehavior() { + if (FactoryTest.isLongPressOnPowerOffEnabled()) { + return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; } + return mLongPressOnPowerBehavior; + } + + private boolean hasLongPressOnPowerBehavior() { + return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING; } private void interceptScreenshotChord() { if (mScreenshotChordEnabled - && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) { + && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered + && !mScreenshotChordVolumeUpKeyTriggered) { final long now = SystemClock.uptimeMillis(); - if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS - && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) { - mVolumeDownKeyConsumedByScreenshotChord = true; + if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS + && now <= mScreenshotChordPowerKeyTime + + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) { + mScreenshotChordVolumeDownKeyConsumed = true; cancelPendingPowerKeyAction(); mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay()); @@ -833,64 +1080,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.removeCallbacks(mScreenshotRunnable); } - private void powerShortPress(long eventTime) { - if (mShortPressOnPowerBehavior < 0) { - mShortPressOnPowerBehavior = mContext.getResources().getInteger( - com.android.internal.R.integer.config_shortPressOnPowerBehavior); - } - - switch (mShortPressOnPowerBehavior) { - case SHORT_PRESS_POWER_NOTHING: - break; - case SHORT_PRESS_POWER_GO_TO_SLEEP: - mPowerManager.goToSleep(eventTime, - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); - break; - case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP: - mPowerManager.goToSleep(eventTime, - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, - PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); - break; - case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME: - mPowerManager.goToSleep(eventTime, - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, - PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); - launchHomeFromHotKey(); - break; - } - } - - private final Runnable mPowerLongPress = new Runnable() { + private final Runnable mEndCallLongPress = new Runnable() { @Override public void run() { - // The context isn't read - if (mLongPressOnPowerBehavior < 0) { - mLongPressOnPowerBehavior = mContext.getResources().getInteger( - com.android.internal.R.integer.config_longPressOnPowerBehavior); - } - int resolvedBehavior = mLongPressOnPowerBehavior; - if (FactoryTest.isLongPressOnPowerOffEnabled()) { - resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; - } - - switch (resolvedBehavior) { - case LONG_PRESS_POWER_NOTHING: - break; - case LONG_PRESS_POWER_GLOBAL_ACTIONS: - mPowerKeyHandled = true; - if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { - performAuditoryFeedbackForAccessibilityIfNeed(); - } - showGlobalActionsInternal(); - break; - case LONG_PRESS_POWER_SHUT_OFF: - case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: - mPowerKeyHandled = true; - performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF); - break; + mEndCallKeyHandled = true; + if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { + performAuditoryFeedbackForAccessibilityIfNeed(); } + showGlobalActionsInternal(); } }; @@ -912,7 +1109,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } - final boolean keyguardShowing = keyguardIsShowingTq(); + final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); if (keyguardShowing) { // since it took two seconds of long press to bring this up, @@ -931,6 +1128,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; } + private void handleShortPressOnHome() { + // If there's a dream running then use home to escape the dream + // but don't actually go home. + if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) { + mDreamManagerInternal.stopDream(false /*immediate*/); + return; + } + + // Go home! + launchHomeFromHotKey(); + } + private void handleLongPressOnHome() { if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { mHomeConsumed = true; @@ -956,7 +1165,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void run() { if (mHomeDoubleTapPending) { mHomeDoubleTapPending = false; - launchHomeFromHotKey(); + handleShortPressOnHome(); } } }; @@ -999,6 +1208,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); + mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "PhoneWindowManager.mPowerKeyWakeLock"); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); mSupportAutoRotation = mContext.getResources().getBoolean( com.android.internal.R.bool.config_supportAutoRotation); @@ -1022,6 +1233,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.bool.config_lidControlsSleep); mTranslucentDecorEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableTranslucentDecor); + + mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromKey); + mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey + || mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey); + mAllowTheaterModeWakeFromMotion = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion); + mAllowTheaterModeWakeFromMotionWhenNotDreaming = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromMotionWhenNotDreaming); + mAllowTheaterModeWakeFromCameraLens = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens); + mAllowTheaterModeWakeFromLidSwitch = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch); + mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture); + + mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode); + + mShortPressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_shortPressOnPowerBehavior); + mLongPressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerBehavior); + mDoublePressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_doublePressOnPowerBehavior); + mTriplePressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_triplePressOnPowerBehavior); + readConfigurationDependentBehaviors(); mAccessibilityManager = (AccessibilityManager) context.getSystemService( @@ -1212,6 +1452,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false); + // For demo purposes, allow the rotation of the remote display to be controlled. + // By default, remote display locks rotation to landscape. + if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) { + mDemoRotation = mPortraitRotation; + } else { + mDemoRotation = mLandscapeRotation; + } + mDemoRotationLock = SystemProperties.getBoolean( + "persist.demo.rotationlock", false); + // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per // http://developer.android.com/guide/practices/screens_support.html#range mForceDefaultOrientation = longSizeDp >= 960 && shortSizeDp >= 720 && @@ -1408,6 +1658,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_WALLPAPER: case TYPE_PRIVATE_PRESENTATION: case TYPE_VOICE_INTERACTION: + case TYPE_ACCESSIBILITY_OVERLAY: // The window manager will check these. break; case TYPE_PHONE: @@ -1461,7 +1712,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_PHONE: case TYPE_POINTER: case TYPE_PRIORITY_PHONE: - case TYPE_RECENTS_OVERLAY: case TYPE_SEARCH_BAR: case TYPE_STATUS_BAR: case TYPE_STATUS_BAR_PANEL: @@ -1580,7 +1830,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_VOICE_INTERACTION: // voice interaction layer is almost immediately above apps. return 5; - case TYPE_RECENTS_OVERLAY: case TYPE_SYSTEM_DIALOG: return 6; case TYPE_TOAST: @@ -1639,15 +1888,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows return 25; - case TYPE_SECURE_SYSTEM_OVERLAY: + case TYPE_ACCESSIBILITY_OVERLAY: + // overlay put by accessibility services to intercept user interaction return 26; - case TYPE_BOOT_PROGRESS: + case TYPE_SECURE_SYSTEM_OVERLAY: return 27; + case TYPE_BOOT_PROGRESS: + return 28; case TYPE_POINTER: // the (mouse) pointer layer - return 28; - case TYPE_HIDDEN_NAV_CONSUMER: return 29; + case TYPE_HIDDEN_NAV_CONSUMER: + return 30; } Log.e(TAG, "Unknown window type: " + type); return 2; @@ -1722,7 +1974,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public boolean isForceHiding(WindowManager.LayoutParams attrs) { return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || - (isKeyguardHostWindow(attrs) && isKeyguardSecureIncludingHidden()) || + (isKeyguardHostWindow(attrs) && + (mKeyguardDelegate != null && mKeyguardDelegate.isShowing())) || (attrs.type == TYPE_KEYGUARD_SCRIM); } @@ -1874,11 +2127,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public void removeStartingWindow(IBinder appToken, View window) { - if (DEBUG_STARTING_WINDOW) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Log.v(TAG, "Removing starting window for " + appToken + ": " + window, e); - } + if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing starting window for " + appToken + ": " + + window + " Callers=" + Debug.getCallers(4)); if (window != null) { WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); @@ -1915,7 +2165,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mStatusBar = win; mStatusBarController.setWindow(win); - mKeyguardDelegate.hideScrim(); break; case TYPE_NAVIGATION_BAR: mContext.enforceCallingOrSelfPermission( @@ -1951,7 +2200,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mKeyguardScrim = win; break; - } return WindowManagerGlobal.ADD_OKAY; } @@ -2075,24 +2323,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean goingToNotificationShade) { if (goingToNotificationShade) { return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in); - } else if (onWallpaper) { - Animation a = AnimationUtils.loadAnimation(mContext, - R.anim.lock_screen_behind_enter_wallpaper); - AnimationSet set = (AnimationSet) a; - - // TODO: Use XML interpolators when we have log interpolators available in XML. - set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator); - set.getAnimations().get(1).setInterpolator(mLogDecelerateInterpolator); - return set; - } else { - Animation a = AnimationUtils.loadAnimation(mContext, + } + + AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(mContext, onWallpaper ? + R.anim.lock_screen_behind_enter_wallpaper : R.anim.lock_screen_behind_enter); - AnimationSet set = (AnimationSet) a; - // TODO: Use XML interpolators when we have log interpolators available in XML. - set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator); - return set; + // TODO: Use XML interpolators when we have log interpolators available in XML. + final List<Animation> animations = set.getAnimations(); + for (int i = animations.size() - 1; i >= 0; --i) { + animations.get(i).setInterpolator(mLogDecelerateInterpolator); } + + return set; } @@ -2135,7 +2378,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } boolean keyguardOn() { - return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); + return isKeyguardShowingAndNotOccluded() || inKeyguardRestrictedKeyInputMode(); } private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = { @@ -2164,17 +2407,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { // but we're not sure, then tell the dispatcher to wait a little while and // try again later before dispatching. if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) { - if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) { + if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) { final long now = SystemClock.uptimeMillis(); - final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS; + final long timeoutTime = mScreenshotChordVolumeDownKeyTime + + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS; if (now < timeoutTime) { return timeoutTime - now; } } if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN - && mVolumeDownKeyConsumedByScreenshotChord) { + && mScreenshotChordVolumeDownKeyConsumed) { if (!down) { - mVolumeDownKeyConsumedByScreenshotChord = false; + mScreenshotChordVolumeDownKeyConsumed = false; } return -1; } @@ -2226,15 +2470,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } - // If there's a dream running then use home to escape the dream - // but don't actually go home. - if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) { - mDreamManagerInternal.stopDream(false /*immediate*/); - return -1; - } - - // Go home! - launchHomeFromHotKey(); + handleShortPressOnHome(); return -1; } @@ -2508,7 +2744,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } - if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { + if (isValidGlobalKey(keyCode) + && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { return -1; } @@ -2734,7 +2971,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (mKeyguardDelegate != null && mKeyguardDelegate.isShowingAndNotOccluded()) { + if (isKeyguardShowingAndNotOccluded()) { // don't launch home if keyguard showing } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock @@ -2863,7 +3100,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { + public void getInsetHintLw(WindowManager.LayoutParams attrs, Rect outContentInsets, + Rect outStableInsets) { final int fl = PolicyControl.getWindowFlags(null, attrs); final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs); final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility); @@ -2881,26 +3119,30 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if ((systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) { if ((fl & FLAG_FULLSCREEN) != 0) { - contentInset.set(mStableFullscreenLeft, mStableFullscreenTop, + outContentInsets.set(mStableFullscreenLeft, mStableFullscreenTop, availRight - mStableFullscreenRight, availBottom - mStableFullscreenBottom); } else { - contentInset.set(mStableLeft, mStableTop, + outContentInsets.set(mStableLeft, mStableTop, availRight - mStableRight, availBottom - mStableBottom); } } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) { - contentInset.setEmpty(); + outContentInsets.setEmpty(); } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) { - contentInset.set(mCurLeft, mCurTop, + outContentInsets.set(mCurLeft, mCurTop, availRight - mCurRight, availBottom - mCurBottom); } else { - contentInset.set(mCurLeft, mCurTop, + outContentInsets.set(mCurLeft, mCurTop, availRight - mCurRight, availBottom - mCurBottom); } + + outStableInsets.set(mStableLeft, mStableTop, + availRight - mStableRight, availBottom - mStableBottom); return; } - contentInset.setEmpty(); + outContentInsets.setEmpty(); + outStableInsets.setEmpty(); } /** {@inheritDoc} */ @@ -3192,10 +3434,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { // whether it is taking care of insetting its content. If not, // we need to use the parent's content frame so that the entire // window is positioned within that content. Otherwise we can use - // the display frame and let the attached window take care of + // the overscan frame and let the attached window take care of // positioning its content appropriately. if (adjust != SOFT_INPUT_ADJUST_RESIZE) { - cf.set(attached.getOverscanFrameLw()); + // Set the content frame of the attached window to the parent's decor frame + // (same as content frame when IME isn't present) if specifically requested by + // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag. + // Otherwise, use the overscan frame. + cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0 + ? attached.getContentFrameLw() : attached.getOverscanFrameLw()); } else { // If the window is resizing, then we want to base the content // frame on our attached content frame to resize... however, @@ -3758,11 +4005,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { mShowingLockscreen = false; mShowingDream = false; mWinShowWhenLocked = null; + mKeyguardSecure = isKeyguardSecure(); + mKeyguardSecureIncludingHidden = mKeyguardSecure + && (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()); } /** {@inheritDoc} */ @Override - public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs) { + public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, + WindowState attached) { + if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw=" + win.isVisibleOrBehindKeyguardLw()); final int fl = PolicyControl.getWindowFlags(win, attrs); @@ -3800,20 +4052,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0; final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0; - final boolean secureKeyguard = isKeyguardSecure(); - if (appWindow) { - final IApplicationToken appToken = win.getAppToken(); + final IApplicationToken appToken = win.getAppToken(); + + // For app windows that are not attached, we decide if all windows in the app they + // represent should be hidden or if we should hide the lockscreen. For attached app + // windows we defer the decision to the window it is attached to. + if (appWindow && attached == null) { if (showWhenLocked) { // Remove any previous windows with the same appToken. mAppsToBeHidden.remove(appToken); mAppsThatDismissKeyguard.remove(appToken); - if (mAppsToBeHidden.isEmpty() && isKeyguardSecureIncludingHidden()) { - mWinShowWhenLocked = win; - mHideLockScreen = true; - mForceStatusBarFromKeyguard = false; + if (mAppsToBeHidden.isEmpty()) { + if (dismissKeyguard && !mKeyguardSecure) { + mAppsThatDismissKeyguard.add(appToken); + } else { + mWinShowWhenLocked = win; + mHideLockScreen = true; + mForceStatusBarFromKeyguard = false; + } } } else if (dismissKeyguard) { - if (secureKeyguard) { + if (mKeyguardSecure) { mAppsToBeHidden.add(appToken); } else { mAppsToBeHidden.remove(appToken); @@ -3834,7 +4093,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDismissKeyguard = mWinDismissingKeyguard == win ? DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; mWinDismissingKeyguard = win; - mForceStatusBarFromKeyguard = mShowingLockscreen && secureKeyguard; + mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure; } else if (mAppsToBeHidden.isEmpty() && showWhenLocked) { if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win); @@ -3945,9 +4204,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mKeyguardDelegate != null && mStatusBar != null) { if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard=" + mHideLockScreen); - if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !isKeyguardSecure()) { + if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardSecure) { mKeyguardHidden = true; - if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(true))) { + if (setKeyguardOccludedLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -3962,7 +4221,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else if (mHideLockScreen) { mKeyguardHidden = true; - if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(true))) { + if (setKeyguardOccludedLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -3972,7 +4231,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mDismissKeyguard == DISMISS_KEYGUARD_START) { // Only launch the next keyguard unlock window once per window. mKeyguardHidden = false; - if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(false))) { + if (setKeyguardOccludedLw(false)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -3987,7 +4246,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { mWinDismissingKeyguard = null; mKeyguardHidden = false; - if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(false))) { + if (setKeyguardOccludedLw(false)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -4007,23 +4266,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** - * Processes the result code of {@link IKeyguardService#setOccluded}. This is needed because we - * immediately need to put the wallpaper directly behind the Keyguard when a window with flag - * {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} gets dismissed. If we - * would wait for Keyguard to change the flags, that would be running asynchronously and thus be - * too late so the user might see the window behind. + * Updates the occluded state of the Keyguard. * - * @param setHiddenResult The result code from {@link IKeyguardService#setOccluded}. * @return Whether the flags have changed and we have to redo the layout. */ - private boolean processKeyguardSetHiddenResultLw(int setHiddenResult) { - if (setHiddenResult - == IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_SET_FLAGS) { + private boolean setKeyguardOccludedLw(boolean isOccluded) { + boolean wasOccluded = mKeyguardOccluded; + boolean showing = mKeyguardDelegate.isShowing(); + if (wasOccluded && !isOccluded && showing) { + mKeyguardOccluded = false; + mKeyguardDelegate.setOccluded(false); mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD; mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER; return true; - } else if (setHiddenResult - == IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_UNSET_FLAGS) { + } else if (!wasOccluded && isOccluded && showing) { + mKeyguardOccluded = true; + mKeyguardDelegate.setOccluded(true); mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD; mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER; return true; @@ -4071,7 +4329,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(true); if (lidOpen) { - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch); } else if (!mLidControlsSleep) { mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } @@ -4093,7 +4351,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); } - mPowerManager.wakeUp(whenNanos / 1000000); + wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens); mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); } mCameraLensCoverState = lensCoverState; @@ -4234,7 +4492,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // when the keyguard is hidden by another activity. final boolean keyguardActive = (mKeyguardDelegate == null ? false : (interactive ? - mKeyguardDelegate.isShowingAndNotOccluded() : + isKeyguardShowingAndNotOccluded() : mKeyguardDelegate.isShowing())); if (DEBUG_INPUT) { @@ -4269,9 +4527,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the key would be handled globally, just return the result, don't worry about special // key processing. - if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { + if (isValidGlobalKey(keyCode) + && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { if (isWakeKey) { - mPowerManager.wakeUp(event.getEventTime()); + wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey); } return result; } @@ -4287,28 +4546,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_VOLUME_MUTE: { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { if (down) { - if (interactive && !mVolumeDownKeyTriggered + if (interactive && !mScreenshotChordVolumeDownKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { - mVolumeDownKeyTriggered = true; - mVolumeDownKeyTime = event.getDownTime(); - mVolumeDownKeyConsumedByScreenshotChord = false; + mScreenshotChordVolumeDownKeyTriggered = true; + mScreenshotChordVolumeDownKeyTime = event.getDownTime(); + mScreenshotChordVolumeDownKeyConsumed = false; cancelPendingPowerKeyAction(); interceptScreenshotChord(); } } else { - mVolumeDownKeyTriggered = false; + mScreenshotChordVolumeDownKeyTriggered = false; cancelPendingScreenshotChordAction(); } } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { if (down) { - if (interactive && !mVolumeUpKeyTriggered + if (interactive && !mScreenshotChordVolumeUpKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { - mVolumeUpKeyTriggered = true; + mScreenshotChordVolumeUpKeyTriggered = true; cancelPendingPowerKeyAction(); cancelPendingScreenshotChordAction(); } } else { - mVolumeUpKeyTriggered = false; + mScreenshotChordVolumeUpKeyTriggered = false; cancelPendingScreenshotChordAction(); } } @@ -4365,20 +4624,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (telecomManager != null) { hungUp = telecomManager.endCall(); } - interceptPowerKeyDown(!interactive || hungUp); + if (interactive && !hungUp) { + mEndCallKeyHandled = false; + mHandler.postDelayed(mEndCallLongPress, + ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); + } else { + mEndCallKeyHandled = true; + } } else { - if (interceptPowerKeyUp(canceled)) { - if ((mEndcallBehavior - & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { - if (goHome()) { - break; + if (!mEndCallKeyHandled) { + mHandler.removeCallbacks(mEndCallLongPress); + if (!canceled) { + if ((mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { + if (goHome()) { + break; + } + } + if ((mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { + mPowerManager.goToSleep(event.getEventTime(), + PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); + isWakeKey = false; } - } - if ((mEndcallBehavior - & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { - mPowerManager.goToSleep(event.getEventTime(), - PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); - isWakeKey = false; } } } @@ -4387,49 +4655,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_POWER: { result &= ~ACTION_PASS_TO_USER; + isWakeKey = false; // wake-up will be handled separately if (down) { - boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, - event.getDownTime(), isImmersiveMode(mLastSystemUiFlags)); - if (panic) { - mHandler.post(mRequestTransientNav); - } - if (interactive && !mPowerKeyTriggered - && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { - mPowerKeyTriggered = true; - mPowerKeyTime = event.getDownTime(); - interceptScreenshotChord(); - } - - TelecomManager telecomManager = getTelecommService(); - boolean hungUp = false; - if (telecomManager != null) { - if (telecomManager.isRinging()) { - // Pressing Power while there's a ringing incoming - // call should silence the ringer. - telecomManager.silenceRinger(); - } else if ((mIncallPowerBehavior - & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 - && telecomManager.isInCall() && interactive) { - // Otherwise, if "Power button ends call" is enabled, - // the Power button will hang up any current active call. - hungUp = telecomManager.endCall(); - } - } - interceptPowerKeyDown(!interactive || hungUp - || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered); + interceptPowerKeyDown(event, interactive); } else { - mPowerKeyTriggered = false; - cancelPendingScreenshotChordAction(); - if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) { - if (mScreenOnEarly && !mScreenOnFully) { - Slog.i(TAG, "Suppressed redundant power key press while " - + "already in the process of turning the screen on."); - } else { - powerShortPress(event.getEventTime()); - } - isWakeKey = false; - } - mPendingPowerKeyUpCanceled = false; + interceptPowerKeyUp(event, interactive, canceled); } break; } @@ -4520,12 +4750,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (isWakeKey) { - mPowerManager.wakeUp(event.getEventTime()); + wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey); } + return result; } /** + * Returns true if the key can have global actions attached to it. + * We reserve all power management keys for the system since they require + * very careful handling. + */ + private static boolean isValidGlobalKey(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_POWER: + case KeyEvent.KEYCODE_WAKEUP: + case KeyEvent.KEYCODE_SLEEP: + return false; + default: + return true; + } + } + + /** * When the screen is off we ignore some keys that might otherwise typically * be considered wake keys. We filter them out here. * @@ -4564,18 +4811,47 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) { if ((policyFlags & FLAG_WAKE) != 0) { - mPowerManager.wakeUp(whenNanos / 1000000); - return 0; + if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion)) { + return 0; + } } + if (shouldDispatchInputWhenNonInteractive()) { return ACTION_PASS_TO_USER; } + + // If we have not passed the action up and we are in theater mode without dreaming, + // there will be no dream to intercept the touch and wake into ambient. The device should + // wake up in this case. + if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) { + wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming); + } + return 0; } private boolean shouldDispatchInputWhenNonInteractive() { - return keyguardIsShowingTq() && mDisplay != null && - mDisplay.getState() != Display.STATE_OFF; + // Send events to keyguard while the screen is on. + if (isKeyguardShowingAndNotOccluded() && mDisplay != null + && mDisplay.getState() != Display.STATE_OFF) { + return true; + } + + // Send events to a dozing dream even if the screen is off since the dream + // is in control of the state of the screen. + IDreamManager dreamManager = getDreamManager(); + + try { + if (dreamManager != null && dreamManager.isDreaming()) { + return true; + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when checking if dreaming", e); + } + + // Otherwise, consume events since the user can't see what is being + // interacted with. + return false; } void dispatchMediaKeyWithWakeLock(KeyEvent event) { @@ -4742,6 +5018,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private void wakeUpFromPowerKey(long eventTime) { + wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey); + } + + private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) { + if (!wakeInTheaterMode && isTheaterModeEnabled()) { + return false; + } + + mPowerManager.wakeUp(wakeTime); + return true; + } + // Called on the PowerManager's Notifier thread. @Override public void wakingUp() { @@ -4916,12 +5205,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private boolean keyguardIsShowingTq() { + private boolean isKeyguardShowingAndNotOccluded() { if (mKeyguardDelegate == null) return false; - return mKeyguardDelegate.isShowingAndNotOccluded(); + return mKeyguardDelegate.isShowing() && !mKeyguardOccluded; } - /** {@inheritDoc} */ @Override public boolean isKeyguardLocked() { @@ -4935,11 +5223,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mKeyguardDelegate.isSecure(); } - // Returns true if keyguard is currently locked whether or not it is currently hidden. - private boolean isKeyguardSecureIncludingHidden() { - return mKeyguardDelegate.isSecure() && mKeyguardDelegate.isShowing(); - } - /** {@inheritDoc} */ @Override public boolean inKeyguardRestrictedKeyInputMode() { @@ -4950,6 +5233,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void dismissKeyguardLw() { if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { + if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw"); mHandler.post(new Runnable() { @Override public void run() { @@ -4981,6 +5265,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { if (mKeyguardDelegate != null) { + if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation"); mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration); } } @@ -5054,6 +5339,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // full multi-display support). // Note that the dock orientation overrides the HDMI orientation. preferredRotation = mUndockedHdmiRotation; + } else if (mDemoRotationLock) { + // Ignore sensor when demo rotation lock is enabled. + // Note that the dock orientation and HDMI rotation lock override this. + preferredRotation = mDemoRotation; } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { // Application just wants to remain locked in the last rotation. preferredRotation = lastRotation; @@ -5248,7 +5537,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public void systemReady() { - mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null); + mKeyguardDelegate = new KeyguardServiceDelegate(mContext); mKeyguardDelegate.onSystemReady(); readCameraLensCoverState(); @@ -5321,7 +5610,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } }; - mBootMsgDialog.setTitle(R.string.android_upgrading_title); + if (mContext.getPackageManager().isUpgrade()) { + mBootMsgDialog.setTitle(R.string.android_upgrading_title); + } else { + mBootMsgDialog.setTitle(R.string.android_start_title); + } mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); mBootMsgDialog.setIndeterminate(true); mBootMsgDialog.getWindow().setType( @@ -5620,6 +5913,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { ringTone.play(); } + private boolean isTheaterModeEnabled() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0) == 1; + } + private boolean isGlobalAccessibilityGestureEnabled() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1; @@ -5686,7 +5984,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void keepScreenOnStoppedLw() { - if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotOccluded()) { + if (isKeyguardShowingAndNotOccluded()) { mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } } @@ -5694,7 +5992,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int updateSystemUiVisibilityLw() { // If there is no window focused, there will be nobody to handle the events // anyway, so just hang on in whatever state we're in until things settle down. - WindowState win = mFocusedWindow != null ? mFocusedWindow : mTopFullscreenOpaqueWindowState; + final WindowState win = mFocusedWindow != null ? mFocusedWindow + : mTopFullscreenOpaqueWindowState; if (win == null) { return 0; } @@ -5730,7 +6029,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { try { IStatusBarService statusbar = getStatusBarService(); if (statusbar != null) { - statusbar.setSystemUiVisibility(visibility, 0xffffffff); + statusbar.setSystemUiVisibility(visibility, 0xffffffff, win.toString()); statusbar.topAppWindowChanged(needsMenu); } } catch (RemoteException e) { @@ -5943,6 +6242,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior); pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior); + pw.print(prefix); + pw.print("mDoublePressOnPowerBehavior="); pw.print(mDoublePressOnPowerBehavior); + pw.print(" mTriplePressOnPowerBehavior="); pw.println(mTriplePressOnPowerBehavior); pw.print(prefix); pw.print("mHasSoftInput="); pw.println(mHasSoftInput); pw.print(prefix); pw.print("mAwake="); pw.println(mAwake); pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly); diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java deleted file mode 100644 index bc55ed1..0000000 --- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2008 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.internal.policy.impl; - -import android.app.ActivityManager; -import android.app.Dialog; -import android.app.StatusBarManager; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.KeyEvent; -import android.view.SoundEffectConstants; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.View.OnClickListener; -import android.widget.TextView; - -import java.util.List; - -public class RecentApplicationsDialog extends Dialog implements OnClickListener { - // Elements for debugging support -// private static final String LOG_TAG = "RecentApplicationsDialog"; - private static final boolean DBG_FORCE_EMPTY_LIST = false; - - static private StatusBarManager sStatusBar; - - private static final int NUM_BUTTONS = 8; - private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards - - final TextView[] mIcons = new TextView[NUM_BUTTONS]; - View mNoAppsText; - IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - - class RecentTag { - ActivityManager.RecentTaskInfo info; - Intent intent; - } - - Handler mHandler = new Handler(); - Runnable mCleanup = new Runnable() { - public void run() { - // dump extra memory we're hanging on to - for (TextView icon: mIcons) { - icon.setCompoundDrawables(null, null, null, null); - icon.setTag(null); - } - } - }; - - public RecentApplicationsDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications); - - } - - /** - * We create the recent applications dialog just once, and it stays around (hidden) - * until activated by the user. - * - * @see PhoneWindowManager#showRecentAppsDialog - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Context context = getContext(); - - if (sStatusBar == null) { - sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); - } - - Window window = getWindow(); - window.requestFeature(Window.FEATURE_NO_TITLE); - window.setType(WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY); - window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - window.setTitle("Recents"); - - setContentView(com.android.internal.R.layout.recent_apps_dialog); - - final WindowManager.LayoutParams params = window.getAttributes(); - params.width = WindowManager.LayoutParams.MATCH_PARENT; - params.height = WindowManager.LayoutParams.MATCH_PARENT; - window.setAttributes(params); - window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND); - - mIcons[0] = (TextView)findViewById(com.android.internal.R.id.button0); - mIcons[1] = (TextView)findViewById(com.android.internal.R.id.button1); - mIcons[2] = (TextView)findViewById(com.android.internal.R.id.button2); - mIcons[3] = (TextView)findViewById(com.android.internal.R.id.button3); - mIcons[4] = (TextView)findViewById(com.android.internal.R.id.button4); - mIcons[5] = (TextView)findViewById(com.android.internal.R.id.button5); - mIcons[6] = (TextView)findViewById(com.android.internal.R.id.button6); - mIcons[7] = (TextView)findViewById(com.android.internal.R.id.button7); - mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); - - for (TextView b: mIcons) { - b.setOnClickListener(this); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_TAB) { - // Ignore all meta keys other than SHIFT. The app switch key could be a - // fallback action chorded with ALT, META or even CTRL depending on the key map. - // DPad navigation is handled by the ViewRoot elsewhere. - final boolean backward = event.isShiftPressed(); - final int numIcons = mIcons.length; - int numButtons = 0; - while (numButtons < numIcons && mIcons[numButtons].getVisibility() == View.VISIBLE) { - numButtons += 1; - } - if (numButtons != 0) { - int nextFocus = backward ? numButtons - 1 : 0; - for (int i = 0; i < numButtons; i++) { - if (mIcons[i].hasFocus()) { - if (backward) { - nextFocus = (i + numButtons - 1) % numButtons; - } else { - nextFocus = (i + 1) % numButtons; - } - break; - } - } - final int direction = backward ? View.FOCUS_BACKWARD : View.FOCUS_FORWARD; - if (mIcons[nextFocus].requestFocus(direction)) { - mIcons[nextFocus].playSoundEffect( - SoundEffectConstants.getContantForFocusDirection(direction)); - } - } - - // The dialog always handles the key to prevent the ViewRoot from - // performing the default navigation itself. - return true; - } - - return super.onKeyDown(keyCode, event); - } - - /** - * Dismiss the dialog and switch to the selected application. - */ - public void dismissAndSwitch() { - final int numIcons = mIcons.length; - RecentTag tag = null; - for (int i = 0; i < numIcons; i++) { - if (mIcons[i].getVisibility() != View.VISIBLE) { - break; - } - if (i == 0 || mIcons[i].hasFocus()) { - tag = (RecentTag) mIcons[i].getTag(); - if (mIcons[i].hasFocus()) { - break; - } - } - } - if (tag != null) { - switchTo(tag); - } - dismiss(); - } - - /** - * Handler for user clicks. If a button was clicked, launch the corresponding activity. - */ - public void onClick(View v) { - for (TextView b: mIcons) { - if (b == v) { - RecentTag tag = (RecentTag)b.getTag(); - switchTo(tag); - break; - } - } - dismiss(); - } - - private void switchTo(RecentTag tag) { - if (tag.info.id >= 0) { - // This is an active task; it should just go to the foreground. - final ActivityManager am = (ActivityManager) - getContext().getSystemService(Context.ACTIVITY_SERVICE); - am.moveTaskToFront(tag.info.id, ActivityManager.MOVE_TASK_WITH_HOME); - } else if (tag.intent != null) { - tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY - | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - try { - getContext().startActivity(tag.intent); - } catch (ActivityNotFoundException e) { - Log.w("Recent", "Unable to launch recent task", e); - } - } - } - - /** - * Set up and show the recent activities dialog. - */ - @Override - public void onStart() { - super.onStart(); - reloadButtons(); - if (sStatusBar != null) { - sStatusBar.disable(StatusBarManager.DISABLE_EXPAND); - } - - // receive broadcasts - getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter); - - mHandler.removeCallbacks(mCleanup); - } - - /** - * Dismiss the recent activities dialog. - */ - @Override - public void onStop() { - super.onStop(); - - if (sStatusBar != null) { - sStatusBar.disable(StatusBarManager.DISABLE_NONE); - } - - // stop receiving broadcasts - getContext().unregisterReceiver(mBroadcastReceiver); - - mHandler.postDelayed(mCleanup, 100); - } - - /** - * Reload the 6 buttons with recent activities - */ - private void reloadButtons() { - - final Context context = getContext(); - final PackageManager pm = context.getPackageManager(); - final ActivityManager am = (ActivityManager) - context.getSystemService(Context.ACTIVITY_SERVICE); - final List<ActivityManager.RecentTaskInfo> recentTasks = - am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE); - - ActivityInfo homeInfo = - new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) - .resolveActivityInfo(pm, 0); - - IconUtilities iconUtilities = new IconUtilities(getContext()); - - // Performance note: Our android performance guide says to prefer Iterator when - // using a List class, but because we know that getRecentTasks() always returns - // an ArrayList<>, we'll use a simple index instead. - int index = 0; - int numTasks = recentTasks.size(); - for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) { - final ActivityManager.RecentTaskInfo info = recentTasks.get(i); - - // for debug purposes only, disallow first result to create empty lists - if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue; - - Intent intent = new Intent(info.baseIntent); - if (info.origActivity != null) { - intent.setComponent(info.origActivity); - } - - // Skip the current home activity. - if (homeInfo != null) { - if (homeInfo.packageName.equals( - intent.getComponent().getPackageName()) - && homeInfo.name.equals( - intent.getComponent().getClassName())) { - continue; - } - } - - intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) - | Intent.FLAG_ACTIVITY_NEW_TASK); - final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); - if (resolveInfo != null) { - final ActivityInfo activityInfo = resolveInfo.activityInfo; - final String title = activityInfo.loadLabel(pm).toString(); - Drawable icon = activityInfo.loadIcon(pm); - - if (title != null && title.length() > 0 && icon != null) { - final TextView tv = mIcons[index]; - tv.setText(title); - icon = iconUtilities.createIconDrawable(icon); - tv.setCompoundDrawables(null, icon, null, null); - RecentTag tag = new RecentTag(); - tag.info = info; - tag.intent = intent; - tv.setTag(tag); - tv.setVisibility(View.VISIBLE); - tv.setPressed(false); - tv.clearFocus(); - ++index; - } - } - } - - // handle the case of "no icons to show" - mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE); - - // hide the rest - for (; index < NUM_BUTTONS; ++index) { - mIcons[index].setVisibility(View.GONE); - } - } - - /** - * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that - * we should close ourselves immediately, in order to allow a higher-priority UI to take over - * (e.g. phone call received). - */ - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); - if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) { - dismiss(); - } - } - } - }; -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java index 50fe7c7..6e8f550 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java @@ -18,9 +18,8 @@ import android.view.WindowManager; import android.view.WindowManagerPolicy.OnKeyguardExitResult; import com.android.internal.policy.IKeyguardExitCallback; -import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.policy.IKeyguardService; -import com.android.internal.widget.LockPatternUtils; +import com.android.internal.policy.IKeyguardShowCallback; /** * A local class that keeps a cache of keyguard state that can be restored in the event @@ -28,15 +27,17 @@ import com.android.internal.widget.LockPatternUtils; * local or remote instances of keyguard. */ public class KeyguardServiceDelegate { - // TODO: propagate changes to these to {@link KeyguardTouchDelegate} public static final String KEYGUARD_PACKAGE = "com.android.systemui"; public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService"; private static final String TAG = "KeyguardServiceDelegate"; private static final boolean DEBUG = true; + protected KeyguardServiceWrapper mKeyguardService; - private View mScrim; // shown if keyguard crashes - private KeyguardState mKeyguardState = new KeyguardState(); + private final Context mContext; + private final View mScrim; // shown if keyguard crashes + private final KeyguardState mKeyguardState = new KeyguardState(); + private ShowListener mShowListenerWhenConnect; /* package */ static final class KeyguardState { KeyguardState() { @@ -46,6 +47,7 @@ public class KeyguardServiceDelegate { showing = true; showingAndNotOccluded = true; secure = true; + deviceHasKeyguard = true; } boolean showing; boolean showingAndNotOccluded; @@ -54,6 +56,7 @@ public class KeyguardServiceDelegate { boolean secure; boolean dreaming; boolean systemIsReady; + boolean deviceHasKeyguard; public boolean enabled; public boolean dismissable; public int offReason; @@ -101,7 +104,8 @@ public class KeyguardServiceDelegate { } }; - public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) { + public KeyguardServiceDelegate(Context context) { + mContext = context; mScrim = createScrim(context); } @@ -110,10 +114,12 @@ public class KeyguardServiceDelegate { intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS); if (!context.bindServiceAsUser(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { - if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS); + Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS); mKeyguardState.showing = false; mKeyguardState.showingAndNotOccluded = false; mKeyguardState.secure = false; + mKeyguardState.deviceHasKeyguard = false; + hideScrim(); } else { if (DEBUG) Log.v(TAG, "*** Keyguard started"); } @@ -123,13 +129,15 @@ public class KeyguardServiceDelegate { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)"); - mKeyguardService = new KeyguardServiceWrapper( + mKeyguardService = new KeyguardServiceWrapper(mContext, IKeyguardService.Stub.asInterface(service)); if (mKeyguardState.systemIsReady) { // If the system is ready, it means keyguard crashed and restarted. mKeyguardService.onSystemReady(); // This is used to hide the scrim once keyguard displays. - mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null)); + mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate( + mShowListenerWhenConnect)); + mShowListenerWhenConnect = null; } if (mKeyguardState.bootCompleted) { mKeyguardService.onBootCompleted(); @@ -151,13 +159,6 @@ public class KeyguardServiceDelegate { return mKeyguardState.showing; } - public boolean isShowingAndNotOccluded() { - if (mKeyguardService != null) { - mKeyguardState.showingAndNotOccluded = mKeyguardService.isShowingAndNotOccluded(); - } - return mKeyguardState.showingAndNotOccluded; - } - public boolean isInputRestricted() { if (mKeyguardService != null) { mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted(); @@ -177,13 +178,11 @@ public class KeyguardServiceDelegate { } } - public int setOccluded(boolean isOccluded) { - int result = 0; + public void setOccluded(boolean isOccluded) { if (mKeyguardService != null) { - result = mKeyguardService.setOccluded(isOccluded); + mKeyguardService.setOccluded(isOccluded); } mKeyguardState.occluded = isOccluded; - return result; } public void dismiss() { @@ -220,9 +219,10 @@ public class KeyguardServiceDelegate { } else { // try again when we establish a connection Slog.w(TAG, "onScreenTurnedOn(): no keyguard service!"); - // This shouldn't happen, but if it does, invoke the listener immediately - // to avoid a dark screen... - showListener.onShown(null); + // This shouldn't happen, but if it does, show the scrim immediately and + // invoke the listener's callback after the service actually connects. + mShowListenerWhenConnect = showListener; + showScrim(); } mKeyguardState.screenIsOn = true; } @@ -242,13 +242,6 @@ public class KeyguardServiceDelegate { mKeyguardState.enabled = enabled; } - public boolean isDismissable() { - if (mKeyguardService != null) { - mKeyguardState.dismissable = mKeyguardService.isDismissable(); - } - return mKeyguardState.dismissable; - } - public void onSystemReady() { if (mKeyguardService != null) { mKeyguardService.onSystemReady(); @@ -263,12 +256,6 @@ public class KeyguardServiceDelegate { } } - public void showAssistant() { - if (mKeyguardService != null) { - mKeyguardService.showAssistant(); - } - } - public void setCurrentUser(int newUserId) { if (mKeyguardService != null) { mKeyguardService.setCurrentUser(newUserId); @@ -301,7 +288,6 @@ public class KeyguardServiceDelegate { lp.setTitle("KeyguardScrim"); WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); wm.addView(view, lp); - view.setVisibility(View.GONE); // Disable pretty much everything in statusbar until keyguard comes back and we know // the state of the world. view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME @@ -313,6 +299,7 @@ public class KeyguardServiceDelegate { } public void showScrim() { + if (!mKeyguardState.deviceHasKeyguard) return; mScrim.post(new Runnable() { @Override public void run() { diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java index 2778b15..b3b7684 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java @@ -16,16 +16,16 @@ package com.android.internal.policy.impl.keyguard; +import android.content.Context; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; -import android.view.MotionEvent; -import com.android.internal.policy.IKeyguardServiceConstants; -import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardService; +import com.android.internal.policy.IKeyguardShowCallback; +import com.android.internal.policy.IKeyguardStateCallback; /** * A wrapper class for KeyguardService. It implements IKeyguardService to ensure the interface @@ -33,83 +33,52 @@ import com.android.internal.policy.IKeyguardService; * */ public class KeyguardServiceWrapper implements IKeyguardService { + private KeyguardStateMonitor mKeyguardStateMonitor; private IKeyguardService mService; private String TAG = "KeyguardServiceWrapper"; - public KeyguardServiceWrapper(IKeyguardService service) { + public KeyguardServiceWrapper(Context context, IKeyguardService service) { mService = service; + mKeyguardStateMonitor = new KeyguardStateMonitor(context, service); } - public boolean isShowing() { - try { - return mService.isShowing(); - } catch (RemoteException e) { - Slog.w(TAG , "Remote Exception", e); - } - return false; - } - - public boolean isSecure() { - try { - return mService.isSecure(); - } catch (RemoteException e) { - Slog.w(TAG , "Remote Exception", e); - } - return false; // TODO cache state - } - - public boolean isShowingAndNotOccluded() { - try { - return mService.isShowingAndNotOccluded(); - } catch (RemoteException e) { - Slog.w(TAG , "Remote Exception", e); - } - return false; // TODO cache state - } - - public boolean isInputRestricted() { - try { - return mService.isInputRestricted(); - } catch (RemoteException e) { - Slog.w(TAG , "Remote Exception", e); - } - return false; // TODO cache state - } - - public boolean isDismissable() { + @Override // Binder interface + public void verifyUnlock(IKeyguardExitCallback callback) { try { - return mService.isDismissable(); + mService.verifyUnlock(callback); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } - return true; // TODO cache state } - public void verifyUnlock(IKeyguardExitCallback callback) { + @Override // Binder interface + public void keyguardDone(boolean authenticated, boolean wakeup) { try { - mService.verifyUnlock(callback); + mService.keyguardDone(authenticated, wakeup); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } } - public void keyguardDone(boolean authenticated, boolean wakeup) { + @Override // Binder interface + public void setOccluded(boolean isOccluded) { try { - mService.keyguardDone(authenticated, wakeup); + mService.setOccluded(isOccluded); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } } - public int setOccluded(boolean isOccluded) { + @Override + public void addStateMonitorCallback(IKeyguardStateCallback callback) { try { - return mService.setOccluded(isOccluded); + mService.addStateMonitorCallback(callback); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); - return IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_NONE; } } + @Override // Binder interface public void dismiss() { try { mService.dismiss(); @@ -118,6 +87,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void onDreamingStarted() { try { mService.onDreamingStarted(); @@ -126,6 +96,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void onDreamingStopped() { try { mService.onDreamingStopped(); @@ -134,6 +105,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void onScreenTurnedOff(int reason) { try { mService.onScreenTurnedOff(reason); @@ -142,6 +114,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void onScreenTurnedOn(IKeyguardShowCallback result) { try { mService.onScreenTurnedOn(result); @@ -150,6 +123,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void setKeyguardEnabled(boolean enabled) { try { mService.setKeyguardEnabled(enabled); @@ -158,6 +132,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void onSystemReady() { try { mService.onSystemReady(); @@ -166,6 +141,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void doKeyguardTimeout(Bundle options) { try { mService.doKeyguardTimeout(options); @@ -174,7 +150,9 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void setCurrentUser(int userId) { + mKeyguardStateMonitor.setCurrentUser(userId); try { mService.setCurrentUser(userId); } catch (RemoteException e) { @@ -182,6 +160,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void onBootCompleted() { try { mService.onBootCompleted(); @@ -190,6 +169,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { try { mService.startKeyguardExitAnimation(startTime, fadeoutDuration); @@ -198,6 +178,7 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface public void onActivityDrawn() { try { mService.onActivityDrawn(); @@ -206,21 +187,20 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } - public void showAssistant() { - // Not used by PhoneWindowManager + @Override // Binder interface + public IBinder asBinder() { + return mService.asBinder(); } - public void dispatch(MotionEvent event) { - // Not used by PhoneWindowManager. See code in {@link NavigationBarView} + public boolean isShowing() { + return mKeyguardStateMonitor.isShowing(); } - public void launchCamera() { - // Not used by PhoneWindowManager. See code in {@link NavigationBarView} + public boolean isSecure() { + return mKeyguardStateMonitor.isSecure(); } - @Override - public IBinder asBinder() { - return mService.asBinder(); + public boolean isInputRestricted() { + return mKeyguardStateMonitor.isInputRestricted(); } - }
\ No newline at end of file diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java new file mode 100644 index 0000000..6f9c617 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 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.internal.policy.impl.keyguard; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.policy.IKeyguardService; +import com.android.internal.policy.IKeyguardStateCallback; +import com.android.internal.widget.LockPatternUtils; + +/** + * Maintains a cached copy of Keyguard's state. + * @hide + */ +public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { + private static final String TAG = "KeyguardStateMonitor"; + + // These cache the current state of Keyguard to improve performance and avoid deadlock. After + // Keyguard changes its state, it always triggers a layout in window manager. Because + // IKeyguardStateCallback is synchronous and because these states are declared volatile, it's + // guaranteed that window manager picks up the new state all the time in the layout caused by + // the state change of Keyguard. + private volatile boolean mIsShowing; + private volatile boolean mSimSecure; + private volatile boolean mInputRestricted; + + private final LockPatternUtils mLockPatternUtils; + + public KeyguardStateMonitor(Context context, IKeyguardService service) { + mLockPatternUtils = new LockPatternUtils(context); + mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser()); + try { + service.addStateMonitorCallback(this); + } catch (RemoteException e) { + Slog.w(TAG, "Remote Exception", e); + } + } + + public boolean isShowing() { + return mIsShowing; + } + + public boolean isSecure() { + return mLockPatternUtils.isSecure() || mSimSecure; + } + + public boolean isInputRestricted() { + return mInputRestricted; + } + + @Override // Binder interface + public void onShowingStateChanged(boolean showing) { + mIsShowing = showing; + } + + @Override // Binder interface + public void onSimSecureStateChanged(boolean simSecure) { + mSimSecure = simSecure; + } + + public void setCurrentUser(int userId) { + mLockPatternUtils.setCurrentUser(userId); + } + + @Override // Binder interface + public void onInputRestrictedStateChanged(boolean inputRestricted) { + mInputRestricted = inputRestricted; + } +}
\ No newline at end of file |