diff options
Diffstat (limited to 'policy/src')
9 files changed, 478 insertions, 126 deletions
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 38c85bb..bcba3c2 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -16,16 +16,23 @@ package com.android.internal.policy.impl; -import android.app.Activity; +import com.android.internal.app.ShutdownThread; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; +import com.android.internal.R; + +import android.app.ActivityManagerNative; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.UserInfo; import android.media.AudioManager; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; import android.os.SystemProperties; import android.provider.Settings; import android.telephony.PhoneStateListener; @@ -39,13 +46,9 @@ import android.view.WindowManager; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; -import com.android.internal.R; -import com.android.internal.app.ShutdownThread; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; -import com.google.android.collect.Lists; import java.util.ArrayList; +import java.util.List; /** * Helper to show the global actions dialog. Each item is an {@link Action} that @@ -101,9 +104,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { mKeyguardShowing = keyguardShowing; mDeviceProvisioned = isDeviceProvisioned; - if (mDialog == null) { - mDialog = createDialog(); + if (mDialog != null) { + mDialog.dismiss(); } + mDialog = createDialog(); prepareDialog(); mDialog.show(); @@ -187,6 +191,31 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mItems.add(mSilentModeAction); } + List<UserInfo> users = mContext.getPackageManager().getUsers(); + if (users.size() > 1) { + for (final UserInfo user : users) { + SinglePressAction switchToUser = new SinglePressAction( + com.android.internal.R.drawable.ic_menu_cc, + user.name != null ? user.name : "Primary") { + public void onPress() { + try { + ActivityManagerNative.getDefault().switchUser(user.id); + } catch (RemoteException re) { + Log.e(TAG, "Couldn't switch user " + re); + } + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return false; + } + }; + mItems.add(switchToUser); + } + } mAdapter = new MyAdapter(); final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); @@ -341,12 +370,19 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private static abstract class SinglePressAction implements Action { private final int mIconResId; private final int mMessageResId; + private final CharSequence mMessage; protected SinglePressAction(int iconResId, int messageResId) { mIconResId = iconResId; mMessageResId = messageResId; + mMessage = null; } + protected SinglePressAction(int iconResId, CharSequence message) { + mIconResId = iconResId; + mMessageResId = 0; + mMessage = message; + } public boolean isEnabled() { return true; } @@ -363,7 +399,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac v.findViewById(R.id.status).setVisibility(View.GONE); icon.setImageDrawable(context.getResources().getDrawable(mIconResId)); - messageView.setText(mMessageResId); + if (mMessage != null) { + messageView.setText(mMessage); + } else { + messageView.setText(mMessageResId); + } return v; } diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java index 76d3df0..9f3de69 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java @@ -19,6 +19,7 @@ package com.android.internal.policy.impl; import com.android.internal.R; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCard.State; +import com.android.internal.widget.DigitalClock; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.TransportControlView; import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback; @@ -105,6 +106,7 @@ class KeyguardStatusViewManager implements OnClickListener { private CharSequence mPlmn; private CharSequence mSpn; protected int mPhoneState; + private DigitalClock mDigitalClock; private class TransientTextManager { private TextView mTextView; @@ -181,6 +183,7 @@ class KeyguardStatusViewManager implements OnClickListener { mTransportView = (TransportControlView) findViewById(R.id.transport); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); mEmergencyCallButtonEnabledInScreen = emergencyButtonEnabledInScreen; + mDigitalClock = (DigitalClock) findViewById(R.id.time); // Hide transport control view until we know we need to show it. if (mTransportView != null) { @@ -290,9 +293,19 @@ class KeyguardStatusViewManager implements OnClickListener { /** {@inheritDoc} */ public void onResume() { if (DEBUG) Log.v(TAG, "onResume()"); + + // First update the clock, if present. + if (mDigitalClock != null) { + mDigitalClock.updateTime(); + } + mUpdateMonitor.registerInfoCallback(mInfoCallback); mUpdateMonitor.registerSimStateCallback(mSimStateCallback); resetStatusInfo(); + //Issue the faceunlock failure message in a centralized place + if (mUpdateMonitor.getMaxFaceUnlockAttemptsReached()) { + setInstructionText(getContext().getString(R.string.faceunlock_multiple_failures)); + } } void resetStatusInfo() { diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index d7041fc..91ab053 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -81,6 +81,8 @@ public class KeyguardUpdateMonitor { private CharSequence mTelephonySpn; private int mFailedAttempts = 0; + private int mFailedFaceUnlockAttempts = 0; + private static final int FAILED_FACE_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 15; private boolean mClockVisible; @@ -629,6 +631,7 @@ public class KeyguardUpdateMonitor { public void clearFailedAttempts() { mFailedAttempts = 0; + mFailedFaceUnlockAttempts = 0; } public void reportFailedAttempt() { @@ -642,4 +645,12 @@ public class KeyguardUpdateMonitor { public int getPhoneState() { return mPhoneState; } + + public void reportFailedFaceUnlockAttempt() { + mFailedFaceUnlockAttempts++; + } + + public boolean getMaxFaceUnlockAttemptsReached() { + return mFailedFaceUnlockAttempts >= FAILED_FACE_UNLOCK_ATTEMPTS_BEFORE_BACKUP; + } } diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java index ff8d5ac..4bba71b 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java @@ -118,6 +118,7 @@ public class KeyguardViewManager implements KeyguardWindowController { int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING + | WindowManager.LayoutParams.FLAG_SLIPPERY /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; if (!mNeedsInput) { diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java index d1d9e9a..1e9784c 100644 --- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -52,6 +52,7 @@ import android.os.Handler; import android.os.Message; import android.os.IBinder; import android.os.Parcelable; +import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; @@ -101,8 +102,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler private View mLockScreen; private View mUnlockScreen; - private volatile boolean mScreenOn = false; - private volatile boolean mWindowFocused = false; + private boolean mScreenOn; + private boolean mWindowFocused = false; private boolean mEnableFallback = false; // assume no fallback UI until we know better private boolean mShowLockBeforeUnlock = false; @@ -132,10 +133,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler // So the user has a consistent amount of time when brought to the backup method from FaceLock private final int BACKUP_LOCK_TIMEOUT = 5000; - // Needed to keep track of failed FaceUnlock attempts - private int mFailedFaceUnlockAttempts = 0; - private static final int FAILED_FACE_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 15; - /** * The current {@link KeyguardScreen} will use this to communicate back to us. */ @@ -147,6 +144,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler //Also true if we've activated a phone call, either emergency dialing or incoming //This resets when the phone is turned off with no current call private boolean mHasOverlay; + //True if a dialog is currently displaying on top of this window + //Unlike other overlays, this does not close with a power button cycle + private boolean mHasDialog = false; + //True if this device is currently plugged in + private boolean mPluggedIn; /** @@ -309,6 +311,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler mLockPatternUtils = lockPatternUtils; mWindowController = controller; mHasOverlay = false; + mPluggedIn = mUpdateMonitor.isDevicePluggedIn(); + mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn(); mUpdateMonitor.registerInfoCallback(this); @@ -370,7 +374,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT); } - // FaceLock must be stopped if it is running + // FaceLock must be stopped if it is running when emergency call is pressed stopAndUnbindFromFaceLock(); pokeWakelock(EMERGENCY_CALL_TIMEOUT); @@ -459,7 +463,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler } public void reportSuccessfulUnlockAttempt() { - mFailedFaceUnlockAttempts = 0; mLockPatternUtils.reportSuccessfulPasswordAttempt(); } }; @@ -557,7 +560,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler if (DEBUG) Log.d(TAG, "screen off"); mScreenOn = false; mForgotPattern = false; - mHasOverlay = mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE; + mHasOverlay = mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE || + mHasDialog; // Emulate activity life-cycle for both lock and unlock screen. if (mLockScreen != null) { @@ -577,8 +581,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler * FaceLock, but only if we're not dealing with a call */ private void activateFaceLockIfAble() { - final boolean tooManyFaceUnlockTries = - (mFailedFaceUnlockAttempts >= FAILED_FACE_UNLOCK_ATTEMPTS_BEFORE_BACKUP); + final boolean tooManyFaceUnlockTries = mUpdateMonitor.getMaxFaceUnlockAttemptsReached(); final int failedBackupAttempts = mUpdateMonitor.getFailedAttempts(); final boolean backupIsTimedOut = (failedBackupAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT); @@ -652,8 +655,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler mHasOverlay = true; stopAndUnbindFromFaceLock(); hideFaceLockArea(); - } else if (runFaceLock) { - activateFaceLockIfAble(); + } else { + mHasDialog = false; + if (runFaceLock) activateFaceLockIfAble(); } } @@ -723,10 +727,19 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler post(mRecreateRunnable); } - //Ignore these events; they are implemented only because they come from the same interface + /** When somebody plugs in or unplugs the device, we don't want to display faceunlock */ @Override - public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) - {} + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + mHasOverlay |= mPluggedIn != pluggedIn; + mPluggedIn = pluggedIn; + //If it's already running, don't close it down: the unplug didn't start it + if (!mFaceLockServiceRunning) { + stopAndUnbindFromFaceLock(); + hideFaceLockArea(); + } + } + + //Ignore these events; they are implemented only because they come from the same interface @Override public void onTimeChanged() {} @Override @@ -842,6 +855,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler case Password: secure = mLockPatternUtils.isLockPasswordEnabled(); break; + case Unknown: + // This means no security is set up + break; default: throw new IllegalStateException("unknown unlock mode " + unlockMode); } @@ -864,8 +880,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler // Re-create the unlock screen if necessary. This is primarily required to properly handle // SIM state changes. This typically happens when this method is called by reset() - if (mode == Mode.UnlockScreen) { - final UnlockMode unlockMode = getUnlockMode(); + final UnlockMode unlockMode = getUnlockMode(); + if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) { if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { boolean restartFaceLock = stopFaceLockIfRunning(); recreateUnlockScreen(unlockMode); @@ -1039,11 +1055,15 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler break; case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: - // "forgot pattern" button is only available in the pattern mode... - if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { - currentMode = UnlockMode.Account; + if (mLockPatternUtils.isLockPatternEnabled()) { + // "forgot pattern" button is only available in the pattern mode... + if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) { + currentMode = UnlockMode.Account; + } else { + currentMode = UnlockMode.Pattern; + } } else { - currentMode = UnlockMode.Pattern; + currentMode = UnlockMode.Unknown; } break; default: @@ -1054,6 +1074,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler } private void showDialog(String title, String message) { + mHasDialog = true; final AlertDialog dialog = new AlertDialog.Builder(mContext) .setTitle(title) .setMessage(message) @@ -1389,7 +1410,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler @Override public void reportFailedAttempt() { if (DEBUG) Log.d(TAG, "FaceLock reportFailedAttempt()"); - mFailedFaceUnlockAttempts++; + mUpdateMonitor.reportFailedFaceUnlockAttempt(); hideFaceLockArea(); // Expose fallback stopAndUnbindFromFaceLock(); mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT); diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index 24a2420..3384661 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -23,6 +23,8 @@ import com.android.internal.widget.WaveView; import com.android.internal.widget.multiwaveview.MultiWaveView; import android.app.ActivityManager; +import android.app.ActivityManagerNative; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; @@ -34,6 +36,7 @@ import android.view.ViewGroup; import android.widget.*; import android.util.Log; import android.media.AudioManager; +import android.os.RemoteException; import android.provider.MediaStore; import android.provider.Settings; @@ -229,8 +232,16 @@ class LockScreen extends LinearLayout implements KeyguardScreen { // Start the Camera Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - mCallback.goToUnlockScreen(); + try { + ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); + } catch (RemoteException e) { + Log.w(TAG, "can't dismiss keyguard on launch"); + } + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Camera application not found"); + } } else { toggleRingMode(); mUnlockWidgetMethods.updateResources(); diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java index abed18f..83f7788 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java +++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java @@ -52,8 +52,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { } public void preDispatchKeyEvent(KeyEvent event) { - getAudioManager().preDispatchKeyEvent(event.getKeyCode(), - AudioManager.USE_DEFAULT_STREAM_TYPE); + getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE); } public boolean dispatchKeyEvent(KeyEvent event) { @@ -79,7 +78,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { - getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE); + getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE); return true; } @@ -197,8 +196,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { AudioManager audioManager = (AudioManager)mContext.getSystemService( Context.AUDIO_SERVICE); if (audioManager != null) { - getAudioManager().handleKeyUp(keyCode, - AudioManager.USE_DEFAULT_STREAM_TYPE); + getAudioManager().handleKeyUp(event, AudioManager.USE_DEFAULT_STREAM_TYPE); } } return true; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index f1fe43b..301dbf5 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -115,6 +115,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final TypedValue mMinWidthMajor = new TypedValue(); final TypedValue mMinWidthMinor = new TypedValue(); + TypedValue mFixedWidthMajor; + TypedValue mFixedWidthMinor; + TypedValue mFixedHeightMajor; + TypedValue mFixedHeightMinor; // This is the top-level view of the window, containing the window decor. private DecorView mDecor; @@ -1416,7 +1420,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // doesn't have one of these. In this case, we execute it here and // eat the event instead, because we have mVolumeControlStreamType // and they don't. - getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType); + getAudioManager().handleKeyDown(event, mVolumeControlStreamType); return true; } @@ -1478,7 +1482,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // doesn't have one of these. In this case, we execute it here and // eat the event instead, because we have mVolumeControlStreamType // and they don't. - getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType); + getAudioManager().handleKeyUp(event, mVolumeControlStreamType); return true; } @@ -2088,6 +2092,44 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final boolean isPortrait = metrics.widthPixels < metrics.heightPixels; final int widthMode = getMode(widthMeasureSpec); + final int heightMode = getMode(heightMeasureSpec); + + boolean fixedWidth = false; + if (widthMode == AT_MOST) { + final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor; + if (tvw != null && tvw.type != TypedValue.TYPE_NULL) { + fixedWidth = true; + final int w; + if (tvw.type == TypedValue.TYPE_DIMENSION) { + w = (int) tvw.getDimension(metrics); + } else if (tvw.type == TypedValue.TYPE_FRACTION) { + w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels); + } else { + w = 0; + } + + final int widthSize = MeasureSpec.getSize(widthMeasureSpec); + widthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.min(w, widthSize), EXACTLY); + } + } + + if (heightMode == AT_MOST) { + final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor; + if (tvh != null && tvh.type != TypedValue.TYPE_NULL) { + final int h; + if (tvh.type == TypedValue.TYPE_DIMENSION) { + h = (int) tvh.getDimension(metrics); + } else if (tvh.type == TypedValue.TYPE_FRACTION) { + h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels); + } else { + h = 0; + } + + final int heightSize = MeasureSpec.getSize(heightMeasureSpec); + heightMeasureSpec = + MeasureSpec.makeMeasureSpec(Math.min(h, heightSize), EXACTLY); + } + } super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -2096,21 +2138,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY); - final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor; - - if (widthMode == AT_MOST && tv.type != TypedValue.TYPE_NULL) { - final int min; - if (tv.type == TypedValue.TYPE_DIMENSION) { - min = (int)tv.getDimension(metrics); - } else if (tv.type == TypedValue.TYPE_FRACTION) { - min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels); - } else { - min = 0; - } + if (!fixedWidth && widthMode == AT_MOST) { + final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor; + if (tv.type != TypedValue.TYPE_NULL) { + final int min; + if (tv.type == TypedValue.TYPE_DIMENSION) { + min = (int)tv.getDimension(metrics); + } else if (tv.type == TypedValue.TYPE_FRACTION) { + min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels); + } else { + min = 0; + } - if (width < min) { - widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY); - measure = true; + if (width < min) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY); + measure = true; + } } } @@ -2571,6 +2614,26 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMajor, mMinWidthMajor); a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMinor, mMinWidthMinor); + if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor)) { + if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); + a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor, + mFixedWidthMajor); + } + if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor)) { + if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue(); + a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor, + mFixedWidthMinor); + } + if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor)) { + if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue(); + a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor, + mFixedHeightMajor); + } + if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor)) { + if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue(); + a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor, + mFixedHeightMinor); + } final Context context = getContext(); final int targetSdk = context.getApplicationInfo().targetSdkVersion; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 0de76a7..8f35afb 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -45,6 +45,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.LocalPowerManager; +import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; @@ -61,7 +62,6 @@ import com.android.internal.app.ShutdownThread; import com.android.internal.policy.PolicyManager; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.telephony.ITelephony; -import com.android.internal.view.BaseInputHandler; import com.android.internal.widget.PointerLocationView; import android.util.DisplayMetrics; @@ -75,8 +75,8 @@ import android.view.IApplicationToken; import android.view.IWindowManager; import android.view.InputChannel; import android.view.InputDevice; -import android.view.InputQueue; -import android.view.InputHandler; +import android.view.InputEvent; +import android.view.InputEventReceiver; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; @@ -164,6 +164,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true; static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false; + // Should screen savers use their own timeout, or the SCREEN_OFF_TIMEOUT? + static final boolean SEPARATE_TIMEOUT_FOR_SCREEN_SAVER = false; + static final int LONG_PRESS_POWER_NOTHING = 0; static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; static final int LONG_PRESS_POWER_SHUT_OFF = 2; @@ -283,7 +286,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; - + + boolean mHeadless; boolean mSafeMode; WindowState mStatusBar = null; boolean mStatusBarCanHide; @@ -316,7 +320,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSystemReady; boolean mSystemBooted; boolean mHdmiPlugged; - int mUiMode = Configuration.UI_MODE_TYPE_NORMAL; + int mUiMode; int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; int mLidOpenRotation; int mCarDockRotation; @@ -348,25 +352,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mFocusedWindow; IApplicationToken mFocusedApp; - private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() { + final class PointerLocationInputEventReceiver extends InputEventReceiver { + public PointerLocationInputEventReceiver(InputChannel inputChannel, Looper looper) { + super(inputChannel, looper); + } + @Override - public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { + public void onInputEvent(InputEvent event) { boolean handled = false; try { - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + if (event instanceof MotionEvent + && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + final MotionEvent motionEvent = (MotionEvent)event; synchronized (mLock) { if (mPointerLocationView != null) { - mPointerLocationView.addPointerEvent(event); + mPointerLocationView.addPointerEvent(motionEvent); handled = true; } } } } finally { - finishedCallback.finished(handled); + finishInputEvent(event, handled); } } - }; - + } + PointerLocationInputEventReceiver mPointerLocationInputEventReceiver; + // The current size of the screen; really; (ir)regardless of whether the status // bar can be hidden or not int mUnrestrictedScreenLeft, mUnrestrictedScreenTop; @@ -426,6 +437,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLockScreenTimeout; boolean mLockScreenTimerActive; + // visual screen saver support + int mScreenSaverTimeout = 0; + boolean mScreenSaverEnabledByUser = false; + boolean mScreenSaverMayRun = true; // false if a wakelock is held + boolean mPluggedIn; + // Behavior of ENDCALL Button. (See Settings.System.END_BUTTON_BEHAVIOR.) int mEndcallBehavior; @@ -488,6 +505,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.DEFAULT_INPUT_METHOD), false, this); resolver.registerContentObserver(Settings.System.getUriFor( "fancy_rotation_anim"), false, this); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SCREENSAVER_ENABLED), false, this); + if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) { + resolver.registerContentObserver(Settings.Secure.getUriFor( + "screensaver_timeout"), false, this); + } // otherwise SCREEN_OFF_TIMEOUT will do nicely updateSettings(); } @@ -664,7 +687,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext); } - final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden(); + final boolean keyguardShowing = keyguardIsShowingTq(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); if (keyguardShowing) { // since it took two seconds of long press to bring this up, @@ -761,7 +784,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManager = windowManager; mWindowManagerFuncs = windowManagerFuncs; mPowerManager = powerManager; - mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); + mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); + if (!mHeadless) { + // don't create KeyguardViewMediator if headless + mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); + } mHandler = new Handler(); mOrientationListener = new MyOrientationListener(mContext); try { @@ -771,6 +798,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { settingsObserver.observe(); mShortcutManager = new ShortcutManager(context, mHandler); mShortcutManager.observe(); + mUiMode = context.getResources().getInteger( + com.android.internal.R.integer.config_defaultUiModeType); mHomeIntent = new Intent(Intent.ACTION_MAIN, null); mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK @@ -816,6 +845,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent.EXTRA_DOCK_STATE_UNDOCKED); } + // watch the plug to know whether to trigger the screen saver + filter = new IntentFilter(); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); + intent = context.registerReceiver(mPowerReceiver, filter); + if (intent != null) { + mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)); + } + mVibrator = new Vibrator(); mLongPressVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_longPressVibePattern); @@ -964,6 +1001,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHasSoftInput = hasSoftInput; updateRotation = true; } + + mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver, + Settings.Secure.SCREENSAVER_ENABLED, 1); + + if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) { + mScreenSaverTimeout = Settings.Secure.getInt(resolver, + "screensaver_timeout", 0); + } else { + mScreenSaverTimeout = Settings.System.getInt(resolver, + Settings.System.SCREEN_OFF_TIMEOUT, 0); + if (mScreenSaverTimeout > 0) { + // We actually want to activate the screensaver just before the + // power manager's screen timeout + mScreenSaverTimeout -= 5000; + } + } + updateScreenSaverTimeoutLocked(); } if (updateRotation) { updateRotation(true); @@ -987,9 +1041,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mPointerLocationInputChannel == null) { try { mPointerLocationInputChannel = - mWindowManager.monitorInput("PointerLocationView"); - InputQueue.registerInputChannel(mPointerLocationInputChannel, - mPointerLocationInputHandler, mHandler.getLooper().getQueue()); + mWindowManager.monitorInput("PointerLocationView"); + mPointerLocationInputEventReceiver = + new PointerLocationInputEventReceiver( + mPointerLocationInputChannel, mHandler.getLooper()); } catch (RemoteException ex) { Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.", ex); @@ -997,8 +1052,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } if (removeView != null) { + if (mPointerLocationInputEventReceiver != null) { + mPointerLocationInputEventReceiver.dispose(); + mPointerLocationInputEventReceiver = null; + } if (mPointerLocationInputChannel != null) { - InputQueue.unregisterInputChannel(mPointerLocationInputChannel); mPointerLocationInputChannel.dispose(); mPointerLocationInputChannel = null; } @@ -1458,12 +1516,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } static ITelephony getTelephonyService() { - ITelephony telephonyService = ITelephony.Stub.asInterface( + return ITelephony.Stub.asInterface( ServiceManager.checkService(Context.TELEPHONY_SERVICE)); - if (telephonyService == null) { - Log.w(TAG, "Unable to find ITelephony interface."); - } - return telephonyService; } static IAudioService getAudioService() { @@ -1786,7 +1840,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (mKeyguardMediator.isShowingAndNotHidden()) { + if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) { // don't launch home if keyguard showing } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock @@ -1829,13 +1883,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { * to determine when the nav bar should be shown and prevent applications from * receiving those touches. */ - final InputHandler mHideNavInputHandler = new BaseInputHandler() { + final class HideNavInputEventReceiver extends InputEventReceiver { + public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) { + super(inputChannel, looper); + } + @Override - public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { + public void onInputEvent(InputEvent event) { boolean handled = false; try { - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (event instanceof MotionEvent + && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + final MotionEvent motionEvent = (MotionEvent)event; + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { // When the user taps down, we re-show the nav bar. boolean changed = false; synchronized (mLock) { @@ -1872,9 +1932,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } finally { - finishedCallback.finished(handled); + finishInputEvent(event, handled); } } + } + final InputEventReceiver.Factory mHideNavInputEventReceiverFactory = + new InputEventReceiver.Factory() { + @Override + public InputEventReceiver createInputEventReceiver( + InputChannel inputChannel, Looper looper) { + return new HideNavInputEventReceiver(inputChannel, looper); + } }; @Override @@ -1938,7 +2006,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else if (mHideNavFakeWindow == null) { mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow( - mHandler.getLooper(), mHideNavInputHandler, + mHandler.getLooper(), mHideNavInputEventReceiverFactory, "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 0, false, false, true); } @@ -2330,8 +2398,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public int finishLayoutLw() { - return 0; + @Override + public void finishLayoutLw() { + return; } /** {@inheritDoc} */ @@ -2520,6 +2589,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { + // do nothing if headless + if (mHeadless) return; + // lid changed state mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED; updateKeyboardVisibility(); @@ -2716,9 +2788,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the same as if it were open and in front. // This will prevent any keys other than the power button from waking the screen // when the keyguard is hidden by another activity. - final boolean keyguardActive = (isScreenOn ? - mKeyguardMediator.isShowingAndNotHidden() : - mKeyguardMediator.isShowing()); + final boolean keyguardActive = (mKeyguardMediator == null ? false : + (isScreenOn ? + mKeyguardMediator.isShowingAndNotHidden() : + mKeyguardMediator.isShowing())); if (!mSystemBooted) { // If we have not yet booted, don't let key events do anything. @@ -2735,6 +2808,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); } + if (keyCode == KeyEvent.KEYCODE_POWER) { + policyFlags |= WindowManagerPolicy.FLAG_WAKE; + } + final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE + | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; + // Basic policy based on screen state and keyguard. // FIXME: This policy isn't quite correct. We shouldn't care whether the screen // is on or off, really. We should care about whether the device is in an @@ -2744,16 +2823,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the device some other way (which is why we have an exemption here for injected // events). int result; - if (isScreenOn || isInjected) { + if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) { // When the screen is on or if the key is injected pass the key to the application. result = ACTION_PASS_TO_USER; } else { // When the screen is off and the key is not injected, determine whether // to wake the device but don't pass the key to the application. result = 0; - - final boolean isWakeKey = (policyFlags - & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; if (down && isWakeKey) { if (keyguardActive) { // If the keyguard is showing, let it decide what to do with the wake key. @@ -2983,7 +3059,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean isWakeMotion = (policyFlags & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; if (isWakeMotion) { - if (mKeyguardMediator.isShowing()) { + if (mKeyguardMediator != null && mKeyguardMediator.isShowing()) { // If the keyguard is showing, let it decide what to do with the wake motion. mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq(); } else { @@ -3035,6 +3111,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; + BroadcastReceiver mPowerReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { + mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)); + if (localLOGV) Log.v(TAG, "BATTERY_CHANGED: " + intent + " plugged=" + mPluggedIn); + } + } + }; + /** {@inheritDoc} */ public void screenTurnedOff(int why) { EventLog.writeEvent(70000, 0); @@ -3042,10 +3127,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOnEarly = false; mScreenOnFully = false; } - mKeyguardMediator.onScreenTurnedOff(why); + if (mKeyguardMediator != null) { + mKeyguardMediator.onScreenTurnedOff(why); + } synchronized (mLock) { updateOrientationListenerLp(); updateLockScreenTimeout(); + updateScreenSaverTimeoutLocked(); } } @@ -3058,31 +3146,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.i(TAG, "Screen turning on...", here); } if (screenOnListener != null) { - mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() { - @Override public void onShown(IBinder windowToken) { - if (windowToken != null) { - try { - mWindowManager.waitForWindowDrawn(windowToken, - new IRemoteCallback.Stub() { - @Override public void sendResult(Bundle data) { - Slog.i(TAG, "Lock screen displayed!"); - screenOnListener.onScreenOn(); - synchronized (mLock) { - mScreenOnFully = true; + if (mKeyguardMediator != null) { + mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() { + @Override public void onShown(IBinder windowToken) { + if (windowToken != null) { + try { + mWindowManager.waitForWindowDrawn(windowToken, + new IRemoteCallback.Stub() { + @Override public void sendResult(Bundle data) { + Slog.i(TAG, "Lock screen displayed!"); + screenOnListener.onScreenOn(); + synchronized (mLock) { + mScreenOnFully = true; + } } - } - }); - } catch (RemoteException e) { - } - } else { - Slog.i(TAG, "No lock screen!"); - screenOnListener.onScreenOn(); - synchronized (mLock) { - mScreenOnFully = true; + }); + } catch (RemoteException e) { + } + } else { + Slog.i(TAG, "No lock screen!"); + screenOnListener.onScreenOn(); + synchronized (mLock) { + mScreenOnFully = true; + } } } - } - }); + }); + } } else { synchronized (mLock) { mScreenOnFully = true; @@ -3092,6 +3182,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOnEarly = true; updateOrientationListenerLp(); updateLockScreenTimeout(); + updateScreenSaverTimeoutLocked(); } } @@ -3107,15 +3198,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableKeyguard(boolean enabled) { - mKeyguardMediator.setKeyguardEnabled(enabled); + if (mKeyguardMediator != null) { + mKeyguardMediator.setKeyguardEnabled(enabled); + } } /** {@inheritDoc} */ public void exitKeyguardSecurely(OnKeyguardExitResult callback) { - mKeyguardMediator.verifyUnlock(callback); + if (mKeyguardMediator != null) { + mKeyguardMediator.verifyUnlock(callback); + } } private boolean keyguardIsShowingTq() { + if (mKeyguardMediator == null) return false; return mKeyguardMediator.isShowingAndNotHidden(); } @@ -3127,11 +3223,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public boolean isKeyguardSecure() { + if (mKeyguardMediator == null) return false; return mKeyguardMediator.isSecure(); } /** {@inheritDoc} */ public boolean inKeyguardRestrictedKeyInputMode() { + if (mKeyguardMediator == null) return false; return mKeyguardMediator.isInputRestricted(); } @@ -3387,9 +3485,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void systemReady() { - // tell the keyguard - mKeyguardMediator.onSystemReady(); - android.os.SystemProperties.set("dev.bootcomplete", "1"); + if (mKeyguardMediator != null) { + // tell the keyguard + mKeyguardMediator.onSystemReady(); + } synchronized (mLock) { updateOrientationListenerLp(); mSystemReady = true; @@ -3412,6 +3511,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void showBootMessage(final CharSequence msg, final boolean always) { + if (mHeadless) return; mHandler.post(new Runnable() { @Override public void run() { if (mBootMsgDialog == null) { @@ -3490,13 +3590,94 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); } } + + synchronized (mLock) { + // Only posts messages; holds no additional locks. + updateScreenSaverTimeoutLocked(); + } + } + + Runnable mScreenSaverActivator = new Runnable() { + public void run() { + if (!(mScreenSaverMayRun && mScreenOnEarly)) { + Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?"); + return; + } + if (!mPluggedIn) { + if (localLOGV) Log.v(TAG, "mScreenSaverActivator: not running screen saver when not plugged in"); + return; + } + // Quick fix for automation tests. + // The correct fix is to move this triggering logic to PowerManager, where more complete + // information about wakelocks (including StayOnWhilePluggedIn) is available. + if (Settings.System.getInt(mContext.getContentResolver(), + Settings.System.STAY_ON_WHILE_PLUGGED_IN, + BatteryManager.BATTERY_PLUGGED_AC) != 0) { + Log.v(TAG, "mScreenSaverActivator: not running screen saver when STAY_ON_WHILE_PLUGGED_IN"); + return; + } + + if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland"); + + try { + String component = Settings.Secure.getString( + mContext.getContentResolver(), Settings.Secure.SCREENSAVER_COMPONENT); + if (component == null) { + component = mContext.getResources().getString(R.string.config_defaultDreamComponent); + } + if (component != null) { + // dismiss the notification shade, recents, etc. + mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)); + + ComponentName cn = ComponentName.unflattenFromString(component); + Intent intent = new Intent(Intent.ACTION_MAIN) + .setComponent(cn) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_NO_USER_ACTION + | Intent.FLAG_FROM_BACKGROUND + | Intent.FLAG_ACTIVITY_NO_HISTORY + ); + mContext.startActivity(intent); + } else { + Log.e(TAG, "Couldn't start screen saver: none selected"); + } + } catch (android.content.ActivityNotFoundException exc) { + // no screensaver? give up + Log.e(TAG, "Couldn't start screen saver: none installed"); + } + } + }; + + // Must call while holding mLock + private void updateScreenSaverTimeoutLocked() { + if (mScreenSaverActivator == null) return; + + mHandler.removeCallbacks(mScreenSaverActivator); + if (mScreenSaverEnabledByUser && mScreenSaverMayRun && mScreenOnEarly && mScreenSaverTimeout > 0) { + if (localLOGV) + Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now"); + mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout); + } else { + if (localLOGV) { + if (!mScreenSaverEnabledByUser || mScreenSaverTimeout == 0) + Log.v(TAG, "screen saver disabled by user"); + else if (!mScreenOnEarly) + Log.v(TAG, "screen saver disabled while screen off"); + else + Log.v(TAG, "screen saver disabled by wakelock"); + } + } } Runnable mScreenLockTimeout = new Runnable() { public void run() { synchronized (this) { if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard"); - mKeyguardMediator.doKeyguardTimeout(); + if (mKeyguardMediator != null) { + mKeyguardMediator.doKeyguardTimeout(); + } mLockScreenTimerActive = false; } } @@ -3510,7 +3691,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void updateLockScreenTimeout() { synchronized (mScreenLockTimeout) { - boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && mKeyguardMediator.isSecure()); + boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && + mKeyguardMediator != null && mKeyguardMediator.isSecure()); if (mLockScreenTimerActive != enable) { if (enable) { if (localLOGV) Log.v(TAG, "setting lockscreen timer"); @@ -3701,14 +3883,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public void screenOnStartedLw() { + // The window manager has just grabbed a wake lock. This is our cue to disable the screen + // saver. + synchronized (mLock) { + mScreenSaverMayRun = false; + } } public void screenOnStoppedLw() { if (mPowerManager.isScreenOn()) { - if (!mKeyguardMediator.isShowingAndNotHidden()) { + if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) { long curTime = SystemClock.uptimeMillis(); mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); } + + synchronized (mLock) { + // even if the keyguard is up, now that all the wakelocks have been released, we + // should re-enable the screen saver + mScreenSaverMayRun = true; + updateScreenSaverTimeoutLocked(); + } } } |