diff options
Diffstat (limited to 'policy')
5 files changed, 321 insertions, 20 deletions
diff --git a/policy/src/com/android/internal/policy/impl/BurnInProtectionHelper.java b/policy/src/com/android/internal/policy/impl/BurnInProtectionHelper.java new file mode 100644 index 0000000..ed9a16f --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/BurnInProtectionHelper.java @@ -0,0 +1,201 @@ +package com.android.internal.policy.impl; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManagerInternal; +import android.os.Build; +import android.os.Handler; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.util.Log; +import android.view.Display; + +import com.android.server.LocalServices; + +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +public class BurnInProtectionHelper implements DisplayManager.DisplayListener { + private static final String TAG = "BurnInProtection"; + + // Default value when max burnin radius is not set. + public static final int BURN_IN_MAX_RADIUS_DEFAULT = -1; + + private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1); + private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10); + + private static final String ACTION_BURN_IN_PROTECTION = + "android.internal.policy.action.BURN_IN_PROTECTION"; + + private static final int BURN_IN_SHIFT_STEP = 2; + + private boolean mBurnInProtectionActive; + + private final int mMinHorizontalBurnInOffset; + private final int mMaxHorizontalBurnInOffset; + private final int mMinVerticalBurnInOffset; + private final int mMaxVerticalBurnInOffset; + + private final int mBurnInRadiusMaxSquared; + + private int mLastBurnInXOffset = 0; + /* 1 means increasing, -1 means decreasing */ + private int mXOffsetDirection = 1; + private int mLastBurnInYOffset = 0; + /* 1 means increasing, -1 means decreasing */ + private int mYOffsetDirection = 1; + + private final AlarmManager mAlarmManager; + private final PendingIntent mBurnInProtectionIntent; + private final DisplayManagerInternal mDisplayManagerInternal; + private final Display mDisplay; + + private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateBurnInProtection(); + } + }; + + public BurnInProtectionHelper(Context context, int minHorizontalOffset, + int maxHorizontalOffset, int minVerticalOffset, int maxVerticalOffset, + int maxOffsetRadius) { + final Resources resources = context.getResources(); + mMinHorizontalBurnInOffset = minHorizontalOffset; + mMaxHorizontalBurnInOffset = maxHorizontalOffset; + mMinVerticalBurnInOffset = minVerticalOffset; + mMaxVerticalBurnInOffset = maxHorizontalOffset; + if (maxOffsetRadius != BURN_IN_MAX_RADIUS_DEFAULT) { + mBurnInRadiusMaxSquared = maxOffsetRadius * maxOffsetRadius; + } else { + mBurnInRadiusMaxSquared = BURN_IN_MAX_RADIUS_DEFAULT; + } + + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); + mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + context.registerReceiver(mBurnInProtectionReceiver, + new IntentFilter(ACTION_BURN_IN_PROTECTION)); + Intent intent = new Intent(ACTION_BURN_IN_PROTECTION); + intent.setPackage(context.getPackageName()); + intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0, + intent, PendingIntent.FLAG_UPDATE_CURRENT); + DisplayManager displayManager = + (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); + displayManager.registerDisplayListener(this, null /* handler */); + } + + public void startBurnInProtection() { + if (!mBurnInProtectionActive) { + mBurnInProtectionActive = true; + updateBurnInProtection(); + } + } + + private void updateBurnInProtection() { + if (mBurnInProtectionActive) { + adjustOffsets(); + mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), + mLastBurnInXOffset, mLastBurnInYOffset); + // Next adjustment at least ten seconds in the future. + long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS; + // And aligned to the minute. + next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS + + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS; + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent); + } else { + mAlarmManager.cancel(mBurnInProtectionIntent); + mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0); + } + } + + public void cancelBurnInProtection() { + if (mBurnInProtectionActive) { + mBurnInProtectionActive = false; + updateBurnInProtection(); + } + } + + /** + * Gently shifts current burn-in offsets, minimizing the change for the user. + * + * Shifts are applied in following fashion: + * 1) shift horizontally from minimum to the maximum; + * 2) shift vertically by one from minimum to the maximum; + * 3) shift horizontally from maximum to the minimum; + * 4) shift vertically by one from minimum to the maximum. + * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum. + * + * On top of that, stay within specified radius. If the shift distance from the center is + * higher than the radius, skip these values and go the next position that is within the radius. + */ + private void adjustOffsets() { + do { + // By default, let's just shift the X offset. + final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP; + mLastBurnInXOffset += xChange; + if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset + || mLastBurnInXOffset < mMinHorizontalBurnInOffset) { + // Whoops, we went too far horizontally. Let's retract.. + mLastBurnInXOffset -= xChange; + // change horizontal direction.. + mXOffsetDirection *= -1; + // and let's shift the Y offset. + final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP; + mLastBurnInYOffset += yChange; + if (mLastBurnInYOffset > mMaxVerticalBurnInOffset + || mLastBurnInYOffset < mMinVerticalBurnInOffset) { + // Whoops, we went to far vertically. Let's retract.. + mLastBurnInYOffset -= yChange; + // and change vertical direction. + mYOffsetDirection *= -1; + } + } + // If we are outside of the radius, let's try again. + } while (mBurnInRadiusMaxSquared != BURN_IN_MAX_RADIUS_DEFAULT + && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset + > mBurnInRadiusMaxSquared); + } + + public void dump(String prefix, PrintWriter pw) { + pw.println(prefix + TAG); + prefix += " "; + pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive); + pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", " + + mMaxHorizontalBurnInOffset + ")"); + pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", " + + mMaxVerticalBurnInOffset + ")"); + pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared); + pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", " + + mLastBurnInYOffset + ")"); + pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", " + + mYOffsetDirection + ")"); + } + + @Override + public void onDisplayAdded(int i) { + } + + @Override + public void onDisplayRemoved(int i) { + } + + @Override + public void onDisplayChanged(int displayId) { + if (displayId == mDisplay.getDisplayId()) { + if (mDisplay.getState() == Display.STATE_DOZE + || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) { + startBurnInProtection(); + } else { + cancelBurnInProtection(); + } + } + } +} diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index b0b2886..20a2c9f 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -100,6 +100,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private static final String GLOBAL_ACTION_KEY_USERS = "users"; private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings"; private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown"; + private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist"; private final Context mContext; private final WindowManagerFuncs mWindowManagerFuncs; @@ -291,6 +292,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mItems.add(getSettingsAction()); } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) { mItems.add(getLockdownAction()); + } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) { + mItems.add(getVoiceAssistAction()); } else { Log.e(TAG, "Invalid global action key " + actionKey); } @@ -436,6 +439,28 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac }; } + private Action getVoiceAssistAction() { + return new SinglePressAction(com.android.internal.R.drawable.ic_voice_search, + R.string.global_action_voice_assist) { + @Override + public void onPress() { + Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mContext.startActivity(intent); + } + + @Override + public boolean showDuringKeyguard() { + return true; + } + + @Override + public boolean showBeforeProvisioning() { + return true; + } + }; + } + private Action getLockdownAction() { return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lockdown) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index b4811da..cd26c31 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -4159,12 +4159,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return mMediaController; } - private boolean isTranslucent() { - TypedArray a = getWindowStyle(); - return a.getBoolean(a.getResourceId( - R.styleable.Window_windowIsTranslucent, 0), false); - } - @Override public void setEnterTransition(Transition enterTransition) { mEnterTransition = enterTransition; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 345520a..f2578a5 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -47,6 +47,7 @@ import android.media.IAudioService; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.session.MediaSessionLegacyHelper; +import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.FactoryTest; @@ -91,6 +92,7 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewRootImpl; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -153,6 +155,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1; static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2; static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3; + static final int SHORT_PRESS_POWER_GO_HOME = 4; static final int LONG_PRESS_POWER_NOTHING = 0; static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; @@ -251,6 +254,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Vibrator mVibrator; // Vibrator for giving feedback of orientation changes SearchManager mSearchManager; AccessibilityManager mAccessibilityManager; + BurnInProtectionHelper mBurnInProtectionHelper; // Vibrator pattern for haptic feedback of a long press. long[] mLongPressVibePattern; @@ -534,6 +538,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mAllowTheaterModeWakeFromLidSwitch; private boolean mAllowTheaterModeWakeFromWakeGesture; + // Whether to support long press from power button in non-interactive mode + private boolean mSupportLongPressPowerWhenNonInteractive; + // Whether to go to sleep entering theater mode from power button private boolean mGoToSleepOnButtonPressTheaterMode; @@ -885,12 +892,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else { wakeUpFromPowerKey(event.getDownTime()); - final int maxCount = getMaxMultiPressPowerCount(); - if (maxCount <= 1) { - mPowerKeyHandled = true; - } else { + if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) { + Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); + msg.setAsynchronous(true); + mHandler.sendMessageDelayed(msg, + ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); mBeganFromNonInteractive = true; + } else { + final int maxCount = getMaxMultiPressPowerCount(); + + if (maxCount <= 1) { + mPowerKeyHandled = true; + } else { + mBeganFromNonInteractive = true; + } } } } @@ -971,6 +987,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); launchHomeFromHotKey(); break; + case SHORT_PRESS_POWER_GO_HOME: + launchHomeFromHotKey(); + break; } } } @@ -1170,6 +1189,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; + private boolean isRoundWindow() { + return mContext.getResources().getBoolean(com.android.internal.R.bool.config_windowIsRound) + || (Build.HARDWARE.contains("goldfish") + && SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false)); + } + /** {@inheritDoc} */ @Override public void init(Context context, IWindowManager windowManager, @@ -1180,6 +1205,41 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class); + // Init display burn-in protection + boolean burnInProtectionEnabled = context.getResources().getBoolean( + com.android.internal.R.bool.config_enableBurnInProtection); + // Allow a system property to override this. Used by developer settings. + boolean burnInProtectionDevMode = + SystemProperties.getBoolean("persist.debug.force_burn_in", false); + if (burnInProtectionEnabled || burnInProtectionDevMode) { + final int minHorizontal; + final int maxHorizontal; + final int minVertical; + final int maxVertical; + final int maxRadius; + if (burnInProtectionDevMode) { + minHorizontal = -8; + maxHorizontal = 8; + minVertical = -8; + maxVertical = -4; + maxRadius = (isRoundWindow()) ? 6 : -1; + } else { + Resources resources = context.getResources(); + minHorizontal = resources.getInteger( + com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset); + maxHorizontal = resources.getInteger( + com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset); + minVertical = resources.getInteger( + com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset); + maxVertical = resources.getInteger( + com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset); + maxRadius = resources.getInteger( + com.android.internal.R.integer.config_burnInProtectionMaxRadius); + } + mBurnInProtectionHelper = new BurnInProtectionHelper( + context, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius); + } + mHandler = new PolicyHandler(); mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler); mOrientationListener = new MyOrientationListener(mContext, mHandler); @@ -1253,6 +1313,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean( com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode); + mSupportLongPressPowerWhenNonInteractive = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_supportLongPressPowerWhenNonInteractive); + mShortPressOnPowerBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_shortPressOnPowerBehavior); mLongPressOnPowerBehavior = mContext.getResources().getInteger( @@ -2991,7 +3054,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); - startDockOrHome(); + startDockOrHome(true /*fromHomeKey*/); } } }); @@ -3009,7 +3072,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { // Otherwise, just launch Home sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); - startDockOrHome(); + startDockOrHome(true /*fromHomeKey*/); } } } @@ -5821,19 +5884,31 @@ public class PhoneWindowManager implements WindowManagerPolicy { return null; } - void startDockOrHome() { + void startDockOrHome(boolean fromHomeKey) { awakenDreams(); Intent dock = createHomeDockIntent(); if (dock != null) { try { + if (fromHomeKey) { + dock.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey); + } mContext.startActivityAsUser(dock, UserHandle.CURRENT); return; } catch (ActivityNotFoundException e) { } } - mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT); + Intent intent; + + if (fromHomeKey) { + intent = new Intent(mHomeIntent); + intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey); + } else { + intent = mHomeIntent; + } + + mContext.startActivityAsUser(intent, UserHandle.CURRENT); } /** @@ -5848,7 +5923,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException e) { } sendCloseSystemWindows(); - startDockOrHome(); + startDockOrHome(false /*fromHomeKey*/); } else { // This code brings home to the front or, if it is already // at the front, puts the device to sleep. @@ -6382,5 +6457,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mOrientationListener != null) { mOrientationListener.dump(pw, prefix); } + if (mBurnInProtectionHelper != null) { + mBurnInProtectionHelper.dump(prefix, pw); + } } } 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 6e8f550..6c98e50 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; +import android.content.res.Resources; import android.graphics.PixelFormat; import android.os.Bundle; import android.os.IBinder; @@ -27,9 +28,6 @@ import com.android.internal.policy.IKeyguardShowCallback; * local or remote instances of keyguard. */ public class KeyguardServiceDelegate { - 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; @@ -111,10 +109,15 @@ public class KeyguardServiceDelegate { public void bindService(Context context) { Intent intent = new Intent(); - intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS); + final Resources resources = context.getApplicationContext().getResources(); + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + resources.getString(com.android.internal.R.string.config_keyguardComponent)); + intent.setComponent(keyguardComponent); + if (!context.bindServiceAsUser(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { - Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS); + Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent); mKeyguardState.showing = false; mKeyguardState.showingAndNotOccluded = false; mKeyguardState.secure = false; |