diff options
Diffstat (limited to 'policy')
43 files changed, 1478 insertions, 8784 deletions
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 3dc77d4..761eb2d 100755 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -260,8 +260,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mItems.add(mAirplaneModeOn); // next: bug report, if enabled - if (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.BUGREPORT_IN_POWER_MENU, 0) != 0) { + if (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0) { mItems.add( new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb, R.string.global_action_bug_report) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 41d67bc..e1d9b73 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -20,11 +20,7 @@ import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.getMode; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; -import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; +import static android.view.WindowManager.LayoutParams.*; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; @@ -2266,8 +2262,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mActionModeView = new ActionBarContextView(mContext); mActionModePopup = new PopupWindow(mContext, null, com.android.internal.R.attr.actionModePopupWindowStyle); - mActionModePopup.setLayoutInScreenEnabled(true); - mActionModePopup.setLayoutInsetDecor(true); mActionModePopup.setWindowLayoutType( WindowManager.LayoutParams.TYPE_APPLICATION); mActionModePopup.setContentView(mActionModeView); @@ -2641,7 +2635,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { - setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); + setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags())); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_windowOverscan, false)) { + setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags())); } if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 0f4262a..bb05325 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -17,6 +17,7 @@ package com.android.internal.policy.impl; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.AppOpsManager; import android.app.ProgressDialog; import android.app.SearchManager; import android.app.UiModeManager; @@ -58,15 +59,6 @@ import android.os.UEventObserver; import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; - -import com.android.internal.R; -import com.android.internal.policy.PolicyManager; -import com.android.internal.policy.impl.keyguard.KeyguardViewManager; -import com.android.internal.policy.impl.keyguard.KeyguardViewMediator; -import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.telephony.ITelephony; -import com.android.internal.widget.PointerLocationView; - import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -82,78 +74,38 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.KeyCharacterMap; +import android.view.KeyCharacterMap.FallbackAction; import android.view.KeyEvent; import android.view.MotionEvent; -import android.view.WindowManagerGlobal; -import android.view.WindowOrientationListener; import android.view.Surface; import android.view.View; import android.view.ViewConfiguration; import android.view.Window; import android.view.WindowManager; -import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; -import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; -import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; -import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_DRAG; -import static android.view.WindowManager.LayoutParams.TYPE_DREAM; -import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER; -import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; -import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_PHONE; -import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; -import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_TOAST; -import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND; -import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static android.view.WindowManager.LayoutParams.TYPE_POINTER; -import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; +import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy; -import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; -import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; -import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED; -import android.view.KeyCharacterMap.FallbackAction; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import com.android.internal.R; +import com.android.internal.policy.PolicyManager; +import com.android.internal.policy.impl.keyguard.KeyguardViewManager; +import com.android.internal.policy.impl.keyguard.KeyguardViewMediator; +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.telephony.ITelephony; +import com.android.internal.widget.PointerLocationView; + import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import static android.view.WindowManager.LayoutParams.*; +import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; +import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; +import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED; + /** * WindowManagerPolicy implementation for the Android phone UI. This * introduces a new method suffix, Lp, for an internal lock of the @@ -179,8 +131,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // These need to match the documentation/constant in // core/res/res/values/config.xml static final int LONG_PRESS_HOME_NOTHING = 0; - static final int LONG_PRESS_HOME_RECENT_DIALOG = 1; - static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2; + static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 1; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -228,7 +179,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * manager with lock held. (This lock will be acquired in places * where the window manager is calling in with its own lock held.) */ - final Object mLock = new Object(); + private final Object mLock = new Object(); Context mContext; IWindowManager mWindowManager; @@ -354,10 +305,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { PointerLocationView mPointerLocationView; InputChannel mPointerLocationInputChannel; - // The current size of the screen; really; (ir)regardless of whether the status - // bar can be hidden or not + // The current size of the screen; really; extends into the overscan area of + // the screen and doesn't account for any system elements like the status bar. + int mOverscanScreenLeft, mOverscanScreenTop; + int mOverscanScreenWidth, mOverscanScreenHeight; + // The current visible size of the screen; really; (ir)regardless of whether the status + // bar can be hidden but not extending into the overscan area. int mUnrestrictedScreenLeft, mUnrestrictedScreenTop; int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight; + // Like mOverscanScreen*, but allowed to move into the overscan region where appropriate. + int mRestrictedOverscanScreenLeft, mRestrictedOverscanScreenTop; + int mRestrictedOverscanScreenWidth, mRestrictedOverscanScreenHeight; // The current size of the screen; these may be different than (0,0)-(dw,dh) // if the status bar can't be hidden; in that case it effectively carves out // that area of the display from all other windows. @@ -403,6 +361,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpParentFrame = new Rect(); static final Rect mTmpDisplayFrame = new Rect(); + static final Rect mTmpOverscanFrame = new Rect(); static final Rect mTmpContentFrame = new Rect(); static final Rect mTmpVisibleFrame = new Rect(); static final Rect mTmpNavigationFrame = new Rect(); @@ -456,6 +415,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mPortraitRotation = 0; // default portrait rotation int mUpsideDownRotation = 0; // "other" portrait rotation + int mOverscanLeft = 0; + int mOverscanTop = 0; + int mOverscanRight = 0; + int mOverscanBottom = 0; + // What we do when the user long presses on home private int mLongPressOnHomeBehavior = -1; @@ -555,8 +519,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } class MyOrientationListener extends WindowOrientationListener { - MyOrientationListener(Context context) { - super(context); + MyOrientationListener(Context context, Handler handler) { + super(context, handler); } @Override @@ -686,7 +650,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mVolumeDownKeyConsumedByScreenshotChord = true; cancelPendingPowerKeyAction(); - mHandler.postDelayed(mScreenshotChordLongPress, getScreenshotChordLongPressDelay()); + mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay()); } } } @@ -696,13 +660,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Double the time it takes to take a screenshot from the keyguard return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER * ViewConfiguration.getGlobalActionKeyTimeout()); - } else { - return ViewConfiguration.getGlobalActionKeyTimeout(); } + return ViewConfiguration.getGlobalActionKeyTimeout(); } private void cancelPendingScreenshotChordAction() { - mHandler.removeCallbacks(mScreenshotChordLongPress); + mHandler.removeCallbacks(mScreenshotRunnable); } private final Runnable mPowerLongPress = new Runnable() { @@ -740,7 +703,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - private final Runnable mScreenshotChordLongPress = new Runnable() { + private final Runnable mScreenshotRunnable = new Runnable() { + @Override public void run() { takeScreenshot(); } @@ -782,11 +746,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Eat the longpress so it won't dismiss the recent apps dialog when // the user lets go of the home key mHomeLongPressed = true; - } - - if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) { - showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); - } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) { try { IStatusBarService statusbar = getStatusBarService(); if (statusbar != null) { @@ -847,6 +806,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void init(Context context, IWindowManager windowManager, WindowManagerFuncs windowManagerFuncs) { mContext = context; @@ -858,7 +818,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator = new KeyguardViewMediator(context, null); } mHandler = new PolicyHandler(); - mOrientationListener = new MyOrientationListener(mContext); + mOrientationListener = new MyOrientationListener(mContext, mHandler); try { mOrientationListener.setCurrentRotation(windowManager.getRotation()); } catch (RemoteException ex) { } @@ -949,7 +909,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + @Override public void setInitialDisplaySize(Display display, int width, int height, int density) { + if (display.getDisplayId() != Display.DEFAULT_DISPLAY) { + throw new IllegalArgumentException("Can only set the default display"); + } mDisplay = display; int shortSize, longSize; @@ -1057,7 +1021,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { mHdmiRotation = mLandscapeRotation; } - mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", true); + mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false); + } + + @Override + public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) { + if (display.getDisplayId() == Display.DEFAULT_DISPLAY) { + mOverscanLeft = left; + mOverscanTop = top; + mOverscanRight = right; + mOverscanBottom = bottom; + } } public void updateSettings() { @@ -1189,9 +1163,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override - public int checkAddPermission(WindowManager.LayoutParams attrs) { + public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) { int type = attrs.type; - + + outAppOp[0] = AppOpsManager.OP_NONE; + if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { return WindowManagerGlobal.ADD_OKAY; @@ -1214,6 +1190,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_SYSTEM_ERROR: case TYPE_SYSTEM_OVERLAY: permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW; + outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW; break; default: permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; @@ -1719,31 +1696,40 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean PRINT_ANIM = false; /** {@inheritDoc} */ + @Override public int selectAnimationLw(WindowState win, int transit) { if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win + ": transit=" + transit); if (win == mStatusBar) { - if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { + if (transit == TRANSIT_EXIT + || transit == TRANSIT_HIDE) { return R.anim.dock_top_exit; - } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { + } else if (transit == TRANSIT_ENTER + || transit == TRANSIT_SHOW) { return R.anim.dock_top_enter; } } else if (win == mNavigationBar) { // This can be on either the bottom or the right. if (mNavigationBarOnBottom) { - if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { + if (transit == TRANSIT_EXIT + || transit == TRANSIT_HIDE) { return R.anim.dock_bottom_exit; - } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { + } else if (transit == TRANSIT_ENTER + || transit == TRANSIT_SHOW) { return R.anim.dock_bottom_enter; } } else { - if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { + if (transit == TRANSIT_EXIT + || transit == TRANSIT_HIDE) { return R.anim.dock_right_exit; - } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { + } else if (transit == TRANSIT_ENTER + || transit == TRANSIT_SHOW) { return R.anim.dock_right_enter; } } - } if (transit == TRANSIT_PREVIEW_DONE) { + } + + if (transit == TRANSIT_PREVIEW_DONE) { if (win.hasAppShownWindows()) { if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); return com.android.internal.R.anim.app_starting_exit; @@ -1760,6 +1746,51 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } + @Override + public void selectRotationAnimationLw(int anim[]) { + if (PRINT_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen=" + + mTopFullscreenOpaqueWindowState + " rotationAnimation=" + + (mTopFullscreenOpaqueWindowState == null ? + "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)); + if (mTopFullscreenOpaqueWindowState != null && mTopIsFullscreen) { + switch (mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation) { + case ROTATION_ANIMATION_CROSSFADE: + anim[0] = R.anim.rotation_animation_xfade_exit; + anim[1] = R.anim.rotation_animation_enter; + break; + case ROTATION_ANIMATION_JUMPCUT: + anim[0] = R.anim.rotation_animation_jump_exit; + anim[1] = R.anim.rotation_animation_enter; + break; + case ROTATION_ANIMATION_ROTATE: + default: + anim[0] = anim[1] = 0; + break; + } + } else { + anim[0] = anim[1] = 0; + } + } + + @Override + public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId, + boolean forceDefault) { + switch (exitAnimId) { + case R.anim.rotation_animation_xfade_exit: + case R.anim.rotation_animation_jump_exit: + // These are the only cases that matter. + if (forceDefault) { + return false; + } + int anim[] = new int[2]; + selectRotationAnimationLw(anim); + return (exitAnimId == anim[0] && enterAnimId == anim[1]); + default: + return true; + } + } + + @Override public Animation createForceHideEnterAnimation(boolean onWallpaper) { return AnimationUtils.loadAnimation(mContext, onWallpaper ? com.android.internal.R.anim.lock_screen_wallpaper_behind_enter @@ -1839,7 +1870,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHomePressed = false; mHomeLongPressed = false; if (!homeWasLongPressed) { - if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) { + if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { try { IStatusBarService statusbar = getStatusBarService(); if (statusbar != null) { @@ -1961,8 +1992,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } return 0; } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { - if (down && repeatCount == 0 && !keyguardOn) { - showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); + if (!keyguardOn) { + try { + IStatusBarService statusbar = getStatusBarService(); + if (statusbar != null) { + if (down && repeatCount == 0) { + statusbar.preloadRecentApps(); + } else if (!down) { + statusbar.toggleRecentApps(); + } + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when preloading recent apps", e); + // re-acquire status bar service next time it is needed. + mStatusBarService = null; + } } return -1; } else if (keyCode == KeyEvent.KEYCODE_ASSIST) { @@ -1985,6 +2029,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } return -1; + } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) { + if (down && repeatCount == 0) { + mHandler.post(mScreenshotRunnable); + } + return -1; } // Shortcuts are invoked through Search+key, so intercept those here @@ -2198,7 +2247,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void launchAssistAction() { sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST); Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); if (intent != null) { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP @@ -2370,7 +2419,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { contentInset.set(mStableLeft, mStableTop, availRight - mStableRight, availBottom - mStableBottom); } - } else if ((fl & FLAG_FULLSCREEN) != 0) { + } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) { contentInset.setEmpty(); } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) { @@ -2389,31 +2438,76 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight, int displayRotation) { - mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0; - mUnrestrictedScreenWidth = displayWidth; - mUnrestrictedScreenHeight = displayHeight; - mRestrictedScreenLeft = mRestrictedScreenTop = 0; - mRestrictedScreenWidth = displayWidth; - mRestrictedScreenHeight = displayHeight; + final int overscanLeft, overscanTop, overscanRight, overscanBottom; + if (isDefaultDisplay) { + switch (displayRotation) { + case Surface.ROTATION_90: + overscanLeft = mOverscanTop; + overscanTop = mOverscanRight; + overscanRight = mOverscanBottom; + overscanBottom = mOverscanLeft; + break; + case Surface.ROTATION_180: + overscanLeft = mOverscanRight; + overscanTop = mOverscanBottom; + overscanRight = mOverscanLeft; + overscanBottom = mOverscanTop; + break; + case Surface.ROTATION_270: + overscanLeft = mOverscanBottom; + overscanTop = mOverscanLeft; + overscanRight = mOverscanTop; + overscanBottom = mOverscanRight; + break; + default: + overscanLeft = mOverscanLeft; + overscanTop = mOverscanTop; + overscanRight = mOverscanRight; + overscanBottom = mOverscanBottom; + break; + } + } else { + overscanLeft = 0; + overscanTop = 0; + overscanRight = 0; + overscanBottom = 0; + } + mOverscanScreenLeft = mRestrictedOverscanScreenLeft = 0; + mOverscanScreenTop = mRestrictedOverscanScreenTop = 0; + mOverscanScreenWidth = mRestrictedOverscanScreenWidth = displayWidth; + mOverscanScreenHeight = mRestrictedOverscanScreenHeight = displayHeight; + mSystemLeft = 0; + mSystemTop = 0; + mSystemRight = displayWidth; + mSystemBottom = displayHeight; + mUnrestrictedScreenLeft = overscanLeft; + mUnrestrictedScreenTop = overscanTop; + mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight; + mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom; + mRestrictedScreenLeft = mUnrestrictedScreenLeft; + mRestrictedScreenTop = mUnrestrictedScreenTop; + mRestrictedScreenWidth = mUnrestrictedScreenWidth; + mRestrictedScreenHeight = mUnrestrictedScreenHeight; mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft - = mSystemLeft = mCurLeft = 0; + = mCurLeft = mUnrestrictedScreenLeft; mDockTop = mContentTop = mStableTop = mStableFullscreenTop - = mSystemTop = mCurTop = 0; + = mCurTop = mUnrestrictedScreenTop; mDockRight = mContentRight = mStableRight = mStableFullscreenRight - = mSystemRight = mCurRight = displayWidth; + = mCurRight = displayWidth - overscanRight; mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom - = mSystemBottom = mCurBottom = displayHeight; + = mCurBottom = displayHeight - overscanBottom; mDockLayer = 0x10000000; mStatusBarLayer = -1; // start with the current dock rect, which will be (0,0,displayWidth,displayHeight) final Rect pf = mTmpParentFrame; final Rect df = mTmpDisplayFrame; + final Rect of = mTmpOverscanFrame; final Rect vf = mTmpVisibleFrame; - pf.left = df.left = vf.left = mDockLeft; - pf.top = df.top = vf.top = mDockTop; - pf.right = df.right = vf.right = mDockRight; - pf.bottom = df.bottom = vf.bottom = mDockBottom; + pf.left = df.left = of.left = vf.left = mDockLeft; + pf.top = df.top = of.top = vf.top = mDockTop; + pf.right = df.right = of.right = vf.right = mDockRight; + pf.bottom = df.bottom = of.bottom = vf.bottom = mDockBottom; if (isDefaultDisplay) { // For purposes of putting out fake window up to steal focus, we will @@ -2449,13 +2543,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight); if (mNavigationBarOnBottom) { // It's a system nav bar or a portrait screen; nav bar goes on bottom. - int top = displayHeight - mNavigationBarHeightForRotation[displayRotation]; - mTmpNavigationFrame.set(0, top, displayWidth, displayHeight); + int top = displayHeight - overscanBottom + - mNavigationBarHeightForRotation[displayRotation]; + mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom); mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top; if (navVisible) { mNavigationBar.showLw(true); mDockBottom = mTmpNavigationFrame.top; - mRestrictedScreenHeight = mDockBottom - mDockTop; + mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop; + mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop; } else { // We currently want to hide the navigation UI. mNavigationBar.hideLw(true); @@ -2468,13 +2564,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else { // Landscape screen; nav bar goes to the right. - int left = displayWidth - mNavigationBarWidthForRotation[displayRotation]; - mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight); + int left = displayWidth - overscanRight + - mNavigationBarWidthForRotation[displayRotation]; + mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight); mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left; if (navVisible) { mNavigationBar.showLw(true); mDockRight = mTmpNavigationFrame.left; - mRestrictedScreenWidth = mDockRight - mDockLeft; + mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft; + mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft; } else { // We currently want to hide the navigation UI. mNavigationBar.hideLw(true); @@ -2495,7 +2593,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBarLayer = mNavigationBar.getSurfaceLayer(); // And compute the final frame. mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, - mTmpNavigationFrame, mTmpNavigationFrame); + mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame); if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); } if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", @@ -2504,10 +2602,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // decide where the status bar goes ahead of time if (mStatusBar != null) { // apply any navigation bar insets - pf.left = df.left = mUnrestrictedScreenLeft; - pf.top = df.top = mUnrestrictedScreenTop; - pf.right = df.right = mUnrestrictedScreenWidth - mUnrestrictedScreenLeft; - pf.bottom = df.bottom = mUnrestrictedScreenHeight - mUnrestrictedScreenTop; + pf.left = df.left = of.left = mUnrestrictedScreenLeft; + pf.top = df.top = of.top = mUnrestrictedScreenTop; + pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft; + pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight + + mUnrestrictedScreenTop; vf.left = mStableLeft; vf.top = mStableTop; vf.right = mStableRight; @@ -2516,7 +2615,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBarLayer = mStatusBar.getSurfaceLayer(); // Let the status bar determine its size. - mStatusBar.computeFrameLw(pf, df, vf, vf); + mStatusBar.computeFrameLw(pf, df, vf, vf, vf); // For layout, the status bar is always at the top with our fixed height. mStableTop = mUnrestrictedScreenTop + mStatusBarHeight; @@ -2562,8 +2661,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } - void setAttachedWindowFrames(WindowState win, int fl, int adjust, - WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) { + void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached, + boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf) { if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) { // Here's a special case: if this attached window is a panel that is // above the dock window, and the window it is attached to is below @@ -2572,10 +2671,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // of the underlying window and the attached window is floating on top // of the whole thing. So, we ignore the attached window and explicitly // compute the frames that would be appropriate without the dock. - df.left = cf.left = vf.left = mDockLeft; - df.top = cf.top = vf.top = mDockTop; - df.right = cf.right = vf.right = mDockRight; - df.bottom = cf.bottom = vf.bottom = mDockBottom; + df.left = of.left = cf.left = vf.left = mDockLeft; + df.top = of.top = cf.top = vf.top = mDockTop; + df.right = of.right = cf.right = vf.right = mDockRight; + df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom; } else { // The effective display frame of the attached window depends on // whether it is taking care of insetting its content. If not, @@ -2584,7 +2683,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the display frame and let the attached window take care of // positioning its content appropriately. if (adjust != SOFT_INPUT_ADJUST_RESIZE) { - cf.set(attached.getDisplayFrameLw()); + cf.set(attached.getOverscanFrameLw()); } else { // If the window is resizing, then we want to base the content // frame on our attached content frame to resize... however, @@ -2601,6 +2700,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } df.set(insetDecors ? attached.getDisplayFrameLw() : cf); + of.set(insetDecors ? attached.getOverscanFrameLw() : cf); vf.set(attached.getVisibleFrameLw()); } // The LAYOUT_IN_SCREEN flag is used to determine whether the attached @@ -2652,6 +2752,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Rect pf = mTmpParentFrame; final Rect df = mTmpDisplayFrame; + final Rect of = mTmpOverscanFrame; final Rect cf = mTmpContentFrame; final Rect vf = mTmpVisibleFrame; @@ -2664,31 +2765,30 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (attached != null) { // If this window is attached to another, our display // frame is the same as the one we are attached to. - setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf); + setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf); } else { // Give the window full screen. - pf.left = df.left = cf.left = mUnrestrictedScreenLeft; - pf.top = df.top = cf.top = mUnrestrictedScreenTop; - pf.right = df.right = cf.right - = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom - = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; + pf.left = df.left = of.left = cf.left = mOverscanScreenLeft; + pf.top = df.top = of.top = cf.top = mOverscanScreenTop; + pf.right = df.right = of.right = cf.right + = mOverscanScreenLeft + mOverscanScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom + = mOverscanScreenTop + mOverscanScreenHeight; } } else if (attrs.type == TYPE_INPUT_METHOD) { - pf.left = df.left = cf.left = vf.left = mDockLeft; - pf.top = df.top = cf.top = vf.top = mDockTop; - pf.right = df.right = cf.right = vf.right = mDockRight; - pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom; + pf.left = df.left = of.left = cf.left = vf.left = mDockLeft; + pf.top = df.top = of.top = cf.top = vf.top = mDockTop; + pf.right = df.right = of.right = cf.right = vf.right = mDockRight; + pf.bottom = df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom; // IM dock windows always go to the bottom of the screen. attrs.gravity = Gravity.BOTTOM; mDockLayer = win.getSurfaceLayer(); } else { - if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) - == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR) - && (sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) + == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { if (DEBUG_LAYOUT) Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() - + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN"); + + "): IN_SCREEN, INSET_DECOR"); // This is the case for a normal activity window: we want it // to cover all of the screen space, and it can take care of // moving its contents to account for screen decorations that @@ -2696,7 +2796,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (attached != null) { // If this window is attached to another, our display // frame is the same as the one we are attached to. - setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf); + setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf); } else { if (attrs.type == TYPE_STATUS_BAR_PANEL || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { @@ -2707,49 +2807,87 @@ public class PhoneWindowManager implements WindowManagerPolicy { // // However, they should still dodge the navigation bar if it exists. - pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; - pf.top = df.top = mUnrestrictedScreenTop; - pf.right = df.right = hasNavBar - ? mRestrictedScreenLeft+mRestrictedScreenWidth - : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = hasNavBar - ? mRestrictedScreenTop+mRestrictedScreenHeight - : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.left = df.left = of.left = hasNavBar + ? mDockLeft : mUnrestrictedScreenLeft; + pf.top = df.top = of.top = mUnrestrictedScreenTop; + pf.right = df.right = of.right = hasNavBar + ? mRestrictedScreenLeft+mRestrictedScreenWidth + : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; + pf.bottom = df.bottom = of.bottom = hasNavBar + ? mRestrictedScreenTop+mRestrictedScreenHeight + : mUnrestrictedScreenTop + mUnrestrictedScreenHeight; if (DEBUG_LAYOUT) { Log.v(TAG, String.format( "Laying out status bar window: (%d,%d - %d,%d)", pf.left, pf.top, pf.right, pf.bottom)); } + } else if ((attrs.flags&FLAG_LAYOUT_IN_OVERSCAN) != 0 + && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW + && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { + // Asking to layout into the overscan region, so give it that pure + // unrestricted area. + pf.left = df.left = of.left = mOverscanScreenLeft; + pf.top = df.top = of.top = mOverscanScreenTop; + pf.right = df.right = of.right = mOverscanScreenLeft + mOverscanScreenWidth; + pf.bottom = df.bottom = of.bottom = mOverscanScreenTop + + mOverscanScreenHeight; } else if (mCanHideNavigationBar && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { // Asking for layout as if the nav bar is hidden, lets the - // application extend into the unrestricted screen area. We + // application extend into the unrestricted overscan screen area. We // only do this for application windows to ensure no window that // can be above the nav bar can do this. - pf.left = df.left = mUnrestrictedScreenLeft; - pf.top = df.top = mUnrestrictedScreenTop; - pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.left = df.left = mOverscanScreenLeft; + pf.top = df.top = mOverscanScreenTop; + pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth; + pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight; + // We need to tell the app about where the frame inside the overscan + // is, so it can inset its content by that amount -- it didn't ask + // to actually extend itself into the overscan region. + of.left = mUnrestrictedScreenLeft; + of.top = mUnrestrictedScreenTop; + of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; + of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; } else { - pf.left = df.left = mRestrictedScreenLeft; - pf.top = df.top = mRestrictedScreenTop; - pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth; - pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight; + pf.left = df.left = mRestrictedOverscanScreenLeft; + pf.top = df.top = mRestrictedOverscanScreenTop; + pf.right = df.right = mRestrictedOverscanScreenLeft + + mRestrictedOverscanScreenWidth; + pf.bottom = df.bottom = mRestrictedOverscanScreenTop + + mRestrictedOverscanScreenHeight; + // We need to tell the app about where the frame inside the overscan + // is, so it can inset its content by that amount -- it didn't ask + // to actually extend itself into the overscan region. + of.left = mUnrestrictedScreenLeft; + of.top = mUnrestrictedScreenTop; + of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; + of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; } - if (adjust != SOFT_INPUT_ADJUST_RESIZE) { - cf.left = mDockLeft; - cf.top = mDockTop; - cf.right = mDockRight; - cf.bottom = mDockBottom; + if ((attrs.flags&FLAG_FULLSCREEN) == 0) { + if (adjust != SOFT_INPUT_ADJUST_RESIZE) { + cf.left = mDockLeft; + cf.top = mDockTop; + cf.right = mDockRight; + cf.bottom = mDockBottom; + } else { + cf.left = mContentLeft; + cf.top = mContentTop; + cf.right = mContentRight; + cf.bottom = mContentBottom; + } } else { - cf.left = mContentLeft; - cf.top = mContentTop; - cf.right = mContentRight; - cf.bottom = mContentBottom; + // Full screen windows are always given a layout that is as if the + // status bar and other transient decors are gone. This is to avoid + // bad states when moving from a window that is not hding the + // status bar to one that is. + cf.left = mRestrictedScreenLeft; + cf.top = mRestrictedScreenTop; + cf.right = mRestrictedScreenLeft + mRestrictedScreenWidth; + cf.bottom = mRestrictedScreenTop + mRestrictedScreenHeight; } applyStableConstraints(sysUiFl, fl, cf); @@ -2771,14 +2909,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { // gets everything, period. if (attrs.type == TYPE_STATUS_BAR_PANEL || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { - pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; - pf.top = df.top = cf.top = mUnrestrictedScreenTop; - pf.right = df.right = cf.right = hasNavBar + pf.left = df.left = of.left = cf.left = hasNavBar + ? mDockLeft : mUnrestrictedScreenLeft; + pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop; + pf.right = df.right = of.right = cf.right = hasNavBar ? mRestrictedScreenLeft+mRestrictedScreenWidth - : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom = hasNavBar + : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom = hasNavBar ? mRestrictedScreenTop+mRestrictedScreenHeight - : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + : mUnrestrictedScreenTop + mUnrestrictedScreenHeight; if (DEBUG_LAYOUT) { Log.v(TAG, String.format( "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)", @@ -2787,10 +2926,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (attrs.type == TYPE_NAVIGATION_BAR || attrs.type == TYPE_NAVIGATION_BAR_PANEL) { // The navigation bar has Real Ultimate Power. - pf.left = df.left = mUnrestrictedScreenLeft; - pf.top = df.top = mUnrestrictedScreenTop; - pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.left = df.left = of.left = mUnrestrictedScreenLeft; + pf.top = df.top = of.top = mUnrestrictedScreenTop; + pf.right = df.right = of.right = mUnrestrictedScreenLeft + + mUnrestrictedScreenWidth; + pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + + mUnrestrictedScreenHeight; if (DEBUG_LAYOUT) { Log.v(TAG, String.format( "Laying out navigation bar window: (%d,%d - %d,%d)", @@ -2800,18 +2941,40 @@ public class PhoneWindowManager implements WindowManagerPolicy { || attrs.type == TYPE_BOOT_PROGRESS) && ((fl & FLAG_FULLSCREEN) != 0)) { // Fullscreen secure system overlays get what they ask for. - pf.left = df.left = mUnrestrictedScreenLeft; - pf.top = df.top = mUnrestrictedScreenTop; - pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.left = df.left = of.left = cf.left = mOverscanScreenLeft; + pf.top = df.top = of.top = cf.top = mOverscanScreenTop; + pf.right = df.right = of.right = cf.right = mOverscanScreenLeft + + mOverscanScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop + + mOverscanScreenHeight; } else if (attrs.type == TYPE_BOOT_PROGRESS || attrs.type == TYPE_UNIVERSE_BACKGROUND) { // Boot progress screen always covers entire display. - pf.left = df.left = cf.left = mUnrestrictedScreenLeft; - pf.top = df.top = cf.top = mUnrestrictedScreenTop; - pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom - = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.left = df.left = of.left = cf.left = mOverscanScreenLeft; + pf.top = df.top = of.top = cf.top = mOverscanScreenTop; + pf.right = df.right = of.right = cf.right = mOverscanScreenLeft + + mOverscanScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop + + mOverscanScreenHeight; + } else if (attrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) { + // The wallpaper mostly goes into the overscan region. + pf.left = df.left = of.left = cf.left = mRestrictedOverscanScreenLeft; + pf.top = df.top = of.top = cf.top = mRestrictedOverscanScreenTop; + pf.right = df.right = of.right = cf.right + = mRestrictedOverscanScreenLeft + mRestrictedOverscanScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom + = mRestrictedOverscanScreenTop + mRestrictedOverscanScreenHeight; + } else if ((attrs.flags & FLAG_LAYOUT_IN_OVERSCAN) != 0 + && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW + && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { + // Asking to layout into the overscan region, so give it that pure + // unrestricted area. + pf.left = df.left = of.left = cf.left = mOverscanScreenLeft; + pf.top = df.top = of.top = cf.top = mOverscanScreenTop; + pf.right = df.right = of.right = cf.right + = mOverscanScreenLeft + mOverscanScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom + = mOverscanScreenTop + mOverscanScreenHeight; } else if (mCanHideNavigationBar && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW @@ -2823,17 +2986,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { // XXX This assumes that an app asking for this will also // ask for layout in only content. We can't currently figure out // what the screen would be if only laying out to hide the nav bar. - pf.left = df.left = cf.left = mUnrestrictedScreenLeft; - pf.top = df.top = cf.top = mUnrestrictedScreenTop; - pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom - = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft; + pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop; + pf.right = df.right = of.right = cf.right = mUnrestrictedScreenLeft + + mUnrestrictedScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop + + mUnrestrictedScreenHeight; } else { - pf.left = df.left = cf.left = mRestrictedScreenLeft; - pf.top = df.top = cf.top = mRestrictedScreenTop; - pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom - = mRestrictedScreenTop+mRestrictedScreenHeight; + pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft; + pf.top = df.top = of.top = cf.top = mRestrictedScreenTop; + pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft + + mRestrictedScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop + + mRestrictedScreenHeight; } applyStableConstraints(sysUiFl, fl, cf); @@ -2851,7 +3016,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached); // A child window should be placed inside of the same visible // frame that its parent had. - setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf); + setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf); } else { if (DEBUG_LAYOUT) Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window"); @@ -2862,26 +3027,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the status bar. They are protected by the STATUS_BAR_SERVICE // permission, so they have the same privileges as the status // bar itself. - pf.left = df.left = cf.left = mRestrictedScreenLeft; - pf.top = df.top = cf.top = mRestrictedScreenTop; - pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom - = mRestrictedScreenTop+mRestrictedScreenHeight; + pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft; + pf.top = df.top = of.top = cf.top = mRestrictedScreenTop; + pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft + + mRestrictedScreenWidth; + pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop + + mRestrictedScreenHeight; } else { pf.left = mContentLeft; pf.top = mContentTop; pf.right = mContentRight; pf.bottom = mContentBottom; if (adjust != SOFT_INPUT_ADJUST_RESIZE) { - df.left = cf.left = mDockLeft; - df.top = cf.top = mDockTop; - df.right = cf.right = mDockRight; - df.bottom = cf.bottom = mDockBottom; + df.left = of.left = cf.left = mDockLeft; + df.top = of.top = cf.top = mDockTop; + df.right = of.right = cf.right = mDockRight; + df.bottom = of.bottom = cf.bottom = mDockBottom; } else { - df.left = cf.left = mContentLeft; - df.top = cf.top = mContentTop; - df.right = cf.right = mContentRight; - df.bottom = cf.bottom = mContentBottom; + df.left = of.left = cf.left = mContentLeft; + df.top = of.top = cf.top = mContentTop; + df.right = of.right = cf.right = mContentRight; + df.bottom = of.bottom = cf.bottom = mContentBottom; } if (adjust != SOFT_INPUT_ADJUST_NOTHING) { vf.left = mCurLeft; @@ -2896,8 +3062,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { - df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000; - df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; + df.left = df.top = of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000; + df.right = df.bottom = of.right = of.bottom = cf.right = cf.bottom + = vf.right = vf.bottom = 10000; } if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle() @@ -2905,9 +3072,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { + " attach=" + attached + " type=" + attrs.type + String.format(" flags=0x%08x", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString() + + " of=" + of.toShortString() + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); - win.computeFrameLw(pf, df, cf, vf); + win.computeFrameLw(pf, df, of, cf, vf); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. @@ -3341,8 +3509,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onServiceDisconnected(ComponentName name) {} }; - if (mContext.bindService( - intent, conn, Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) { + if (mContext.bindServiceAsUser( + intent, conn, Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) { mScreenshotConnection = conn; mHandler.postDelayed(mScreenshotTimeout, 10000); } @@ -3741,13 +3909,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { } BroadcastReceiver mDockReceiver = new BroadcastReceiver() { + @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) { mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); } updateRotation(true); - updateOrientationListenerLp(); + synchronized (mLock) { + updateOrientationListenerLp(); + } } }; @@ -4126,6 +4297,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return rotation == mPortraitRotation || rotation == mUpsideDownRotation; } + public int getUserRotationMode() { + return Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.USER_ROTATION, WindowManagerPolicy.USER_ROTATION_FREE, + UserHandle.USER_CURRENT); + } // User rotation: to be used when all else fails in assigning an orientation to the device public void setUserRotationMode(int mode, int rot) { @@ -4388,7 +4564,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { sendCloseSystemWindows(); } int result = ActivityManagerNative.getDefault() - .startActivityAsUser(null, mHomeIntent, + .startActivityAsUser(null, null, mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), null, null, 0, ActivityManager.START_FLAG_ONLY_IF_NEEDED, @@ -4460,12 +4636,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { default: return false; } + int owningUid; + String owningPackage; + if (win != null) { + owningUid = win.getOwningUid(); + owningPackage = win.getOwningPackage(); + } else { + owningUid = android.os.Process.myUid(); + owningPackage = mContext.getBasePackageName(); + } if (pattern.length == 1) { // One-shot vibration - mVibrator.vibrate(pattern[0]); + mVibrator.vibrate(owningUid, owningPackage, pattern[0]); } else { // Pattern vibration - mVibrator.vibrate(pattern, -1); + mVibrator.vibrate(owningUid, owningPackage, pattern, -1); } return true; } @@ -4543,19 +4728,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public boolean canMagnifyWindowLw(WindowManager.LayoutParams attrs) { - switch (attrs.type) { - case WindowManager.LayoutParams.TYPE_INPUT_METHOD: - case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: - case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: - case WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY: { - return false; - } - } - return true; - } - - @Override public void setCurrentUserLw(int newUserId) { if (mKeyguardMediator != null) { mKeyguardMediator.setCurrentUser(newUserId); @@ -4576,6 +4748,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public boolean canMagnifyWindow(int windowType) { + switch (windowType) { + case WindowManager.LayoutParams.TYPE_INPUT_METHOD: + case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: + case WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY: { + return false; + } + } + return true; + } + + @Override + public boolean isTopLevelWindow(int windowType) { + if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW + && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { + return (windowType == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG); + } + return true; + } + + @Override public void dump(String prefix, PrintWriter pw, String[] args) { pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode); pw.print(" mSystemReady="); pw.print(mSystemReady); @@ -4617,6 +4811,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly); pw.print(" mScreenOnFully="); pw.print(mScreenOnFully); pw.print(" mOrientationSensorEnabled="); pw.println(mOrientationSensorEnabled); + pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft); + pw.print(","); pw.print(mOverscanScreenTop); + pw.print(") "); pw.print(mOverscanScreenWidth); + pw.print("x"); pw.println(mOverscanScreenHeight); + if (mOverscanLeft != 0 || mOverscanTop != 0 + || mOverscanRight != 0 || mOverscanBottom != 0) { + pw.print(prefix); pw.print("mOverscan left="); pw.print(mOverscanLeft); + pw.print(" top="); pw.print(mOverscanTop); + pw.print(" right="); pw.print(mOverscanRight); + pw.print(" bottom="); pw.println(mOverscanBottom); + } + pw.print(prefix); pw.print("mRestrictedOverscanScreen=("); + pw.print(mRestrictedOverscanScreenLeft); + pw.print(","); pw.print(mRestrictedOverscanScreenTop); + pw.print(") "); pw.print(mRestrictedOverscanScreenWidth); + pw.print("x"); pw.println(mRestrictedOverscanScreenHeight); pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft); pw.print(","); pw.print(mUnrestrictedScreenTop); pw.print(") "); pw.print(mUnrestrictedScreenWidth); diff --git a/policy/src/com/android/internal/policy/impl/Policy.java b/policy/src/com/android/internal/policy/impl/Policy.java index 153ef0f..42bfc5f 100644 --- a/policy/src/com/android/internal/policy/impl/Policy.java +++ b/policy/src/com/android/internal/policy/impl/Policy.java @@ -24,9 +24,6 @@ import android.view.Window; import android.view.WindowManagerPolicy; import com.android.internal.policy.IPolicy; -import com.android.internal.policy.impl.PhoneLayoutInflater; -import com.android.internal.policy.impl.PhoneWindow; -import com.android.internal.policy.impl.PhoneWindowManager; /** * {@hide} diff --git a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java new file mode 100644 index 0000000..0c77556 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java @@ -0,0 +1,733 @@ +/* + * 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.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Handler; +import android.os.SystemProperties; +import android.util.FloatMath; +import android.util.Log; +import android.util.Slog; + +/** + * A special helper class used by the WindowManager + * for receiving notifications from the SensorManager when + * the orientation of the device has changed. + * + * NOTE: If changing anything here, please run the API demo + * "App/Activity/Screen Orientation" to ensure that all orientation + * modes still work correctly. + * + * You can also visualize the behavior of the WindowOrientationListener. + * Refer to frameworks/base/tools/orientationplot/README.txt for details. + * + * @hide + */ +public abstract class WindowOrientationListener { + private static final String TAG = "WindowOrientationListener"; + private static final boolean LOG = SystemProperties.getBoolean( + "debug.orientation.log", false); + + private static final boolean USE_GRAVITY_SENSOR = false; + + private Handler mHandler; + private SensorManager mSensorManager; + private boolean mEnabled; + private int mRate; + private Sensor mSensor; + private SensorEventListenerImpl mSensorEventListener; + private int mCurrentRotation = -1; + + private final Object mLock = new Object(); + + /** + * Creates a new WindowOrientationListener. + * + * @param context for the WindowOrientationListener. + * @param handler Provides the Looper for receiving sensor updates. + */ + public WindowOrientationListener(Context context, Handler handler) { + this(context, handler, SensorManager.SENSOR_DELAY_UI); + } + + /** + * Creates a new WindowOrientationListener. + * + * @param context for the WindowOrientationListener. + * @param handler Provides the Looper for receiving sensor updates. + * @param rate at which sensor events are processed (see also + * {@link android.hardware.SensorManager SensorManager}). Use the default + * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL + * SENSOR_DELAY_NORMAL} for simple screen orientation change detection. + * + * This constructor is private since no one uses it. + */ + private WindowOrientationListener(Context context, Handler handler, int rate) { + mHandler = handler; + mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); + mRate = rate; + mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR + ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER); + if (mSensor != null) { + // Create listener only if sensors do exist + mSensorEventListener = new SensorEventListenerImpl(); + } + } + + /** + * Enables the WindowOrientationListener so it will monitor the sensor and call + * {@link #onProposedRotationChanged(int)} when the device orientation changes. + */ + public void enable() { + synchronized (mLock) { + if (mSensor == null) { + Log.w(TAG, "Cannot detect sensors. Not enabled"); + return; + } + if (mEnabled == false) { + if (LOG) { + Log.d(TAG, "WindowOrientationListener enabled"); + } + mSensorEventListener.resetLocked(); + mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler); + mEnabled = true; + } + } + } + + /** + * Disables the WindowOrientationListener. + */ + public void disable() { + synchronized (mLock) { + if (mSensor == null) { + Log.w(TAG, "Cannot detect sensors. Invalid disable"); + return; + } + if (mEnabled == true) { + if (LOG) { + Log.d(TAG, "WindowOrientationListener disabled"); + } + mSensorManager.unregisterListener(mSensorEventListener); + mEnabled = false; + } + } + } + + /** + * Sets the current rotation. + * + * @param rotation The current rotation. + */ + public void setCurrentRotation(int rotation) { + synchronized (mLock) { + mCurrentRotation = rotation; + } + } + + /** + * Gets the proposed rotation. + * + * This method only returns a rotation if the orientation listener is certain + * of its proposal. If the rotation is indeterminate, returns -1. + * + * @return The proposed rotation, or -1 if unknown. + */ + public int getProposedRotation() { + synchronized (mLock) { + if (mEnabled) { + return mSensorEventListener.getProposedRotationLocked(); + } + return -1; + } + } + + /** + * Returns true if sensor is enabled and false otherwise + */ + public boolean canDetectOrientation() { + synchronized (mLock) { + return mSensor != null; + } + } + + /** + * Called when the rotation view of the device has changed. + * + * This method is called whenever the orientation becomes certain of an orientation. + * It is called each time the orientation determination transitions from being + * uncertain to being certain again, even if it is the same orientation as before. + * + * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants. + * @see android.view.Surface + */ + public abstract void onProposedRotationChanged(int rotation); + + /** + * This class filters the raw accelerometer data and tries to detect actual changes in + * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters, + * but here's the outline: + * + * - Low-pass filter the accelerometer vector in cartesian coordinates. We do it in + * cartesian space because the orientation calculations are sensitive to the + * absolute magnitude of the acceleration. In particular, there are singularities + * in the calculation as the magnitude approaches 0. By performing the low-pass + * filtering early, we can eliminate most spurious high-frequency impulses due to noise. + * + * - Convert the acceleromter vector from cartesian to spherical coordinates. + * Since we're dealing with rotation of the device, this is the sensible coordinate + * system to work in. The zenith direction is the Z-axis, the direction the screen + * is facing. The radial distance is referred to as the magnitude below. + * The elevation angle is referred to as the "tilt" below. + * The azimuth angle is referred to as the "orientation" below (and the azimuth axis is + * the Y-axis). + * See http://en.wikipedia.org/wiki/Spherical_coordinate_system for reference. + * + * - If the tilt angle is too close to horizontal (near 90 or -90 degrees), do nothing. + * The orientation angle is not meaningful when the device is nearly horizontal. + * The tilt angle thresholds are set differently for each orientation and different + * limits are applied when the device is facing down as opposed to when it is facing + * forward or facing up. + * + * - When the orientation angle reaches a certain threshold, consider transitioning + * to the corresponding orientation. These thresholds have some hysteresis built-in + * to avoid oscillations between adjacent orientations. + * + * - Wait for the device to settle for a little bit. Once that happens, issue the + * new orientation proposal. + * + * Details are explained inline. + * + * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for + * signal processing background. + */ + final class SensorEventListenerImpl implements SensorEventListener { + // We work with all angles in degrees in this class. + private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI); + + // Number of nanoseconds per millisecond. + private static final long NANOS_PER_MS = 1000000; + + // Indices into SensorEvent.values for the accelerometer sensor. + private static final int ACCELEROMETER_DATA_X = 0; + private static final int ACCELEROMETER_DATA_Y = 1; + private static final int ACCELEROMETER_DATA_Z = 2; + + // The minimum amount of time that a predicted rotation must be stable before it + // is accepted as a valid rotation proposal. This value can be quite small because + // the low-pass filter already suppresses most of the noise so we're really just + // looking for quick confirmation that the last few samples are in agreement as to + // the desired orientation. + private static final long PROPOSAL_SETTLE_TIME_NANOS = 40 * NANOS_PER_MS; + + // The minimum amount of time that must have elapsed since the device last exited + // the flat state (time since it was picked up) before the proposed rotation + // can change. + private static final long PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS = 500 * NANOS_PER_MS; + + // The minimum amount of time that must have elapsed since the device stopped + // swinging (time since device appeared to be in the process of being put down + // or put away into a pocket) before the proposed rotation can change. + private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS; + + // The minimum amount of time that must have elapsed since the device stopped + // undergoing external acceleration before the proposed rotation can change. + private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS = + 500 * NANOS_PER_MS; + + // If the tilt angle remains greater than the specified angle for a minimum of + // the specified time, then the device is deemed to be lying flat + // (just chillin' on a table). + private static final float FLAT_ANGLE = 75; + private static final long FLAT_TIME_NANOS = 1000 * NANOS_PER_MS; + + // If the tilt angle has increased by at least delta degrees within the specified amount + // of time, then the device is deemed to be swinging away from the user + // down towards flat (tilt = 90). + private static final float SWING_AWAY_ANGLE_DELTA = 20; + private static final long SWING_TIME_NANOS = 300 * NANOS_PER_MS; + + // The maximum sample inter-arrival time in milliseconds. + // If the acceleration samples are further apart than this amount in time, we reset the + // state of the low-pass filter and orientation properties. This helps to handle + // boundary conditions when the device is turned on, wakes from suspend or there is + // a significant gap in samples. + private static final long MAX_FILTER_DELTA_TIME_NANOS = 1000 * NANOS_PER_MS; + + // The acceleration filter time constant. + // + // This time constant is used to tune the acceleration filter such that + // impulses and vibrational noise (think car dock) is suppressed before we + // try to calculate the tilt and orientation angles. + // + // The filter time constant is related to the filter cutoff frequency, which is the + // frequency at which signals are attenuated by 3dB (half the passband power). + // Each successive octave beyond this frequency is attenuated by an additional 6dB. + // + // Given a time constant t in seconds, the filter cutoff frequency Fc in Hertz + // is given by Fc = 1 / (2pi * t). + // + // The higher the time constant, the lower the cutoff frequency, so more noise + // will be suppressed. + // + // Filtering adds latency proportional the time constant (inversely proportional + // to the cutoff frequency) so we don't want to make the time constant too + // large or we can lose responsiveness. Likewise we don't want to make it too + // small or we do a poor job suppressing acceleration spikes. + // Empirically, 100ms seems to be too small and 500ms is too large. + private static final float FILTER_TIME_CONSTANT_MS = 200.0f; + + /* State for orientation detection. */ + + // Thresholds for minimum and maximum allowable deviation from gravity. + // + // If the device is undergoing external acceleration (being bumped, in a car + // that is turning around a corner or a plane taking off) then the magnitude + // may be substantially more or less than gravity. This can skew our orientation + // detection by making us think that up is pointed in a different direction. + // + // Conversely, if the device is in freefall, then there will be no gravity to + // measure at all. This is problematic because we cannot detect the orientation + // without gravity to tell us which way is up. A magnitude near 0 produces + // singularities in the tilt and orientation calculations. + // + // In both cases, we postpone choosing an orientation. + // + // However, we need to tolerate some acceleration because the angular momentum + // of turning the device can skew the observed acceleration for a short period of time. + private static final float NEAR_ZERO_MAGNITUDE = 1; // m/s^2 + private static final float ACCELERATION_TOLERANCE = 4; // m/s^2 + private static final float MIN_ACCELERATION_MAGNITUDE = + SensorManager.STANDARD_GRAVITY - ACCELERATION_TOLERANCE; + private static final float MAX_ACCELERATION_MAGNITUDE = + SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE; + + // Maximum absolute tilt angle at which to consider orientation data. Beyond this (i.e. + // when screen is facing the sky or ground), we completely ignore orientation data. + private static final int MAX_TILT = 75; + + // The tilt angle range in degrees for each orientation. + // Beyond these tilt angles, we don't even consider transitioning into the + // specified orientation. We place more stringent requirements on unnatural + // orientations than natural ones to make it less likely to accidentally transition + // into those states. + // The first value of each pair is negative so it applies a limit when the device is + // facing down (overhead reading in bed). + // The second value of each pair is positive so it applies a limit when the device is + // facing up (resting on a table). + // The ideal tilt angle is 0 (when the device is vertical) so the limits establish + // how close to vertical the device must be in order to change orientation. + private final int[][] TILT_TOLERANCE = new int[][] { + /* ROTATION_0 */ { -25, 70 }, + /* ROTATION_90 */ { -25, 65 }, + /* ROTATION_180 */ { -25, 60 }, + /* ROTATION_270 */ { -25, 65 } + }; + + // The gap angle in degrees between adjacent orientation angles for hysteresis. + // This creates a "dead zone" between the current orientation and a proposed + // adjacent orientation. No orientation proposal is made when the orientation + // angle is within the gap between the current orientation and the adjacent + // orientation. + private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45; + + // Timestamp and value of the last accelerometer sample. + private long mLastFilteredTimestampNanos; + private float mLastFilteredX, mLastFilteredY, mLastFilteredZ; + + // The last proposed rotation, -1 if unknown. + private int mProposedRotation; + + // Value of the current predicted rotation, -1 if unknown. + private int mPredictedRotation; + + // Timestamp of when the predicted rotation most recently changed. + private long mPredictedRotationTimestampNanos; + + // Timestamp when the device last appeared to be flat for sure (the flat delay elapsed). + private long mFlatTimestampNanos; + + // Timestamp when the device last appeared to be swinging. + private long mSwingTimestampNanos; + + // Timestamp when the device last appeared to be undergoing external acceleration. + private long mAccelerationTimestampNanos; + + // History of observed tilt angles. + private static final int TILT_HISTORY_SIZE = 40; + private float[] mTiltHistory = new float[TILT_HISTORY_SIZE]; + private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE]; + private int mTiltHistoryIndex; + + public int getProposedRotationLocked() { + return mProposedRotation; + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + + @Override + public void onSensorChanged(SensorEvent event) { + int proposedRotation; + int oldProposedRotation; + + synchronized (mLock) { + // The vector given in the SensorEvent points straight up (towards the sky) under + // ideal conditions (the phone is not accelerating). I'll call this up vector + // elsewhere. + float x = event.values[ACCELEROMETER_DATA_X]; + float y = event.values[ACCELEROMETER_DATA_Y]; + float z = event.values[ACCELEROMETER_DATA_Z]; + + if (LOG) { + Slog.v(TAG, "Raw acceleration vector: " + + "x=" + x + ", y=" + y + ", z=" + z + + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z)); + } + + // Apply a low-pass filter to the acceleration up vector in cartesian space. + // Reset the orientation listener state if the samples are too far apart in time + // or when we see values of (0, 0, 0) which indicates that we polled the + // accelerometer too soon after turning it on and we don't have any data yet. + final long now = event.timestamp; + final long then = mLastFilteredTimestampNanos; + final float timeDeltaMS = (now - then) * 0.000001f; + final boolean skipSample; + if (now < then + || now > then + MAX_FILTER_DELTA_TIME_NANOS + || (x == 0 && y == 0 && z == 0)) { + if (LOG) { + Slog.v(TAG, "Resetting orientation listener."); + } + resetLocked(); + skipSample = true; + } else { + final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS); + x = alpha * (x - mLastFilteredX) + mLastFilteredX; + y = alpha * (y - mLastFilteredY) + mLastFilteredY; + z = alpha * (z - mLastFilteredZ) + mLastFilteredZ; + if (LOG) { + Slog.v(TAG, "Filtered acceleration vector: " + + "x=" + x + ", y=" + y + ", z=" + z + + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z)); + } + skipSample = false; + } + mLastFilteredTimestampNanos = now; + mLastFilteredX = x; + mLastFilteredY = y; + mLastFilteredZ = z; + + boolean isAccelerating = false; + boolean isFlat = false; + boolean isSwinging = false; + if (!skipSample) { + // Calculate the magnitude of the acceleration vector. + final float magnitude = FloatMath.sqrt(x * x + y * y + z * z); + if (magnitude < NEAR_ZERO_MAGNITUDE) { + if (LOG) { + Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero."); + } + clearPredictedRotationLocked(); + } else { + // Determine whether the device appears to be undergoing external + // acceleration. + if (isAcceleratingLocked(magnitude)) { + isAccelerating = true; + mAccelerationTimestampNanos = now; + } + + // Calculate the tilt angle. + // This is the angle between the up vector and the x-y plane (the plane of + // the screen) in a range of [-90, 90] degrees. + // -90 degrees: screen horizontal and facing the ground (overhead) + // 0 degrees: screen vertical + // 90 degrees: screen horizontal and facing the sky (on table) + final int tiltAngle = (int) Math.round( + Math.asin(z / magnitude) * RADIANS_TO_DEGREES); + addTiltHistoryEntryLocked(now, tiltAngle); + + // Determine whether the device appears to be flat or swinging. + if (isFlatLocked(now)) { + isFlat = true; + mFlatTimestampNanos = now; + } + if (isSwingingLocked(now, tiltAngle)) { + isSwinging = true; + mSwingTimestampNanos = now; + } + + // If the tilt angle is too close to horizontal then we cannot determine + // the orientation angle of the screen. + if (Math.abs(tiltAngle) > MAX_TILT) { + if (LOG) { + Slog.v(TAG, "Ignoring sensor data, tilt angle too high: " + + "tiltAngle=" + tiltAngle); + } + clearPredictedRotationLocked(); + } else { + // Calculate the orientation angle. + // This is the angle between the x-y projection of the up vector onto + // the +y-axis, increasing clockwise in a range of [0, 360] degrees. + int orientationAngle = (int) Math.round( + -Math.atan2(-x, y) * RADIANS_TO_DEGREES); + if (orientationAngle < 0) { + // atan2 returns [-180, 180]; normalize to [0, 360] + orientationAngle += 360; + } + + // Find the nearest rotation. + int nearestRotation = (orientationAngle + 45) / 90; + if (nearestRotation == 4) { + nearestRotation = 0; + } + + // Determine the predicted orientation. + if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle) + && isOrientationAngleAcceptableLocked(nearestRotation, + orientationAngle)) { + updatePredictedRotationLocked(now, nearestRotation); + if (LOG) { + Slog.v(TAG, "Predicted: " + + "tiltAngle=" + tiltAngle + + ", orientationAngle=" + orientationAngle + + ", predictedRotation=" + mPredictedRotation + + ", predictedRotationAgeMS=" + + ((now - mPredictedRotationTimestampNanos) + * 0.000001f)); + } + } else { + if (LOG) { + Slog.v(TAG, "Ignoring sensor data, no predicted rotation: " + + "tiltAngle=" + tiltAngle + + ", orientationAngle=" + orientationAngle); + } + clearPredictedRotationLocked(); + } + } + } + } + + // Determine new proposed rotation. + oldProposedRotation = mProposedRotation; + if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) { + mProposedRotation = mPredictedRotation; + } + proposedRotation = mProposedRotation; + + // Write final statistics about where we are in the orientation detection process. + if (LOG) { + Slog.v(TAG, "Result: currentRotation=" + mCurrentRotation + + ", proposedRotation=" + proposedRotation + + ", predictedRotation=" + mPredictedRotation + + ", timeDeltaMS=" + timeDeltaMS + + ", isAccelerating=" + isAccelerating + + ", isFlat=" + isFlat + + ", isSwinging=" + isSwinging + + ", timeUntilSettledMS=" + remainingMS(now, + mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) + + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now, + mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) + + ", timeUntilFlatDelayExpiredMS=" + remainingMS(now, + mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) + + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now, + mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS)); + } + } + + // Tell the listener. + if (proposedRotation != oldProposedRotation && proposedRotation >= 0) { + if (LOG) { + Slog.v(TAG, "Proposed rotation changed! proposedRotation=" + proposedRotation + + ", oldProposedRotation=" + oldProposedRotation); + } + onProposedRotationChanged(proposedRotation); + } + } + + /** + * Returns true if the tilt angle is acceptable for a given predicted rotation. + */ + private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) { + return tiltAngle >= TILT_TOLERANCE[rotation][0] + && tiltAngle <= TILT_TOLERANCE[rotation][1]; + } + + /** + * Returns true if the orientation angle is acceptable for a given predicted rotation. + * + * This function takes into account the gap between adjacent orientations + * for hysteresis. + */ + private boolean isOrientationAngleAcceptableLocked(int rotation, int orientationAngle) { + // If there is no current rotation, then there is no gap. + // The gap is used only to introduce hysteresis among advertised orientation + // changes to avoid flapping. + final int currentRotation = mCurrentRotation; + if (currentRotation >= 0) { + // If the specified rotation is the same or is counter-clockwise adjacent + // to the current rotation, then we set a lower bound on the orientation angle. + // For example, if currentRotation is ROTATION_0 and proposed is ROTATION_90, + // then we want to check orientationAngle > 45 + GAP / 2. + if (rotation == currentRotation + || rotation == (currentRotation + 1) % 4) { + int lowerBound = rotation * 90 - 45 + + ADJACENT_ORIENTATION_ANGLE_GAP / 2; + if (rotation == 0) { + if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) { + return false; + } + } else { + if (orientationAngle < lowerBound) { + return false; + } + } + } + + // If the specified rotation is the same or is clockwise adjacent, + // then we set an upper bound on the orientation angle. + // For example, if currentRotation is ROTATION_0 and rotation is ROTATION_270, + // then we want to check orientationAngle < 315 - GAP / 2. + if (rotation == currentRotation + || rotation == (currentRotation + 3) % 4) { + int upperBound = rotation * 90 + 45 + - ADJACENT_ORIENTATION_ANGLE_GAP / 2; + if (rotation == 0) { + if (orientationAngle <= 45 && orientationAngle > upperBound) { + return false; + } + } else { + if (orientationAngle > upperBound) { + return false; + } + } + } + } + return true; + } + + /** + * Returns true if the predicted rotation is ready to be advertised as a + * proposed rotation. + */ + private boolean isPredictedRotationAcceptableLocked(long now) { + // The predicted rotation must have settled long enough. + if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) { + return false; + } + + // The last flat state (time since picked up) must have been sufficiently long ago. + if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) { + return false; + } + + // The last swing state (time since last movement to put down) must have been + // sufficiently long ago. + if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) { + return false; + } + + // The last acceleration state must have been sufficiently long ago. + if (now < mAccelerationTimestampNanos + + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) { + return false; + } + + // Looks good! + return true; + } + + private void resetLocked() { + mLastFilteredTimestampNanos = Long.MIN_VALUE; + mProposedRotation = -1; + mFlatTimestampNanos = Long.MIN_VALUE; + mSwingTimestampNanos = Long.MIN_VALUE; + mAccelerationTimestampNanos = Long.MIN_VALUE; + clearPredictedRotationLocked(); + clearTiltHistoryLocked(); + } + + private void clearPredictedRotationLocked() { + mPredictedRotation = -1; + mPredictedRotationTimestampNanos = Long.MIN_VALUE; + } + + private void updatePredictedRotationLocked(long now, int rotation) { + if (mPredictedRotation != rotation) { + mPredictedRotation = rotation; + mPredictedRotationTimestampNanos = now; + } + } + + private boolean isAcceleratingLocked(float magnitude) { + return magnitude < MIN_ACCELERATION_MAGNITUDE + || magnitude > MAX_ACCELERATION_MAGNITUDE; + } + + private void clearTiltHistoryLocked() { + mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE; + mTiltHistoryIndex = 1; + } + + private void addTiltHistoryEntryLocked(long now, float tilt) { + mTiltHistory[mTiltHistoryIndex] = tilt; + mTiltHistoryTimestampNanos[mTiltHistoryIndex] = now; + mTiltHistoryIndex = (mTiltHistoryIndex + 1) % TILT_HISTORY_SIZE; + mTiltHistoryTimestampNanos[mTiltHistoryIndex] = Long.MIN_VALUE; + } + + private boolean isFlatLocked(long now) { + for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) { + if (mTiltHistory[i] < FLAT_ANGLE) { + break; + } + if (mTiltHistoryTimestampNanos[i] + FLAT_TIME_NANOS <= now) { + // Tilt has remained greater than FLAT_TILT_ANGLE for FLAT_TIME_NANOS. + return true; + } + } + return false; + } + + private boolean isSwingingLocked(long now, float tilt) { + for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) { + if (mTiltHistoryTimestampNanos[i] + SWING_TIME_NANOS < now) { + break; + } + if (mTiltHistory[i] + SWING_AWAY_ANGLE_DELTA <= tilt) { + // Tilted away by SWING_AWAY_ANGLE_DELTA within SWING_TIME_NANOS. + return true; + } + } + return false; + } + + private int nextTiltHistoryIndexLocked(int index) { + index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1; + return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1; + } + + private float remainingMS(long now, long until) { + return now >= until ? 0 : (until - now) * 0.000001f; + } + } +} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java index 830471a..e58eb5b 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java @@ -128,10 +128,10 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback { if (!mBoundToService) { Log.d(TAG, "Binding to Face Unlock service for user=" + mLockPatternUtils.getCurrentUser()); - mContext.bindService(new Intent(IFaceLockInterface.class.getName()), + mContext.bindServiceAsUser(new Intent(IFaceLockInterface.class.getName()), mConnection, Context.BIND_AUTO_CREATE, - mLockPatternUtils.getCurrentUser()); + new UserHandle(mLockPatternUtils.getCurrentUser())); mBoundToService = true; } else { Log.w(TAG, "Attempt to bind to Face Unlock when already bound"); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java index 4c19caa..6539db3 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java @@ -219,6 +219,7 @@ public abstract class KeyguardActivityLauncher { try { WaitResult result = ActivityManagerNative.getDefault().startActivityAndWait( null /*caller*/, + null /*caller pkg*/, intent, intent.resolveTypeIfNeeded(getContext().getContentResolver()), null /*resultTo*/, diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java index de3354a..4df434c 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java @@ -197,7 +197,7 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu } @Override - public void onUserSwitched(int userId) { + public void onUserSwitching(int userId) { if (DEBUG) Log.d(TAG, "onUserSwitched(" + userId + ")"); if (mBiometricUnlock != null) { mBiometricUnlock.stop(); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index b05d111..06f06b5 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -30,6 +30,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Canvas; @@ -101,8 +102,12 @@ public class KeyguardHostView extends KeyguardViewBase { private boolean mSafeModeEnabled; private boolean mUserSetupCompleted; - // User for whom this host view was created - private int mUserId; + + // User for whom this host view was created. Final because we should never change the + // id without reconstructing an instance of KeyguardHostView. See note below... + private final int mUserId; + + private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView; /*package*/ interface TransportCallback { void onListenerDetached(); @@ -129,25 +134,52 @@ public class KeyguardHostView extends KeyguardViewBase { public KeyguardHostView(Context context, AttributeSet attrs) { super(context, attrs); mLockPatternUtils = new LockPatternUtils(context); + + // Note: This depends on KeyguardHostView getting reconstructed every time the + // user switches, since mUserId will be used for the entire session. + // Once created, keyguard should *never* re-use this instance with another user. + // In other words, mUserId should never change - hence it's marked final. mUserId = mLockPatternUtils.getCurrentUser(); - mAppWidgetHost = new AppWidgetHost( - context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); - mAppWidgetHost.setUserId(mUserId); + + Context userContext = null; + try { + final String packageName = "system"; + userContext = mContext.createPackageContextAsUser(packageName, 0, + new UserHandle(mUserId)); + + } catch (NameNotFoundException e) { + e.printStackTrace(); + // This should never happen, but it's better to have no widgets than to crash. + userContext = context; + } + + // These need to be created with the user context... + mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler, + Looper.myLooper()); + mAppWidgetManager = AppWidgetManager.getInstance(userContext); + cleanupAppWidgetIds(); - mAppWidgetManager = AppWidgetManager.getInstance(mContext); mSecurityModel = new KeyguardSecurityModel(context); mViewStateManager = new KeyguardViewStateManager(this); DevicePolicyManager dpm = - (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); if (dpm != null) { mDisabledFeatures = getDisabledFeatures(dpm); mCameraDisabled = dpm.getCameraDisabled(null); } mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled(); + + cleanupAppWidgetIds(); + + mAppWidgetManager = AppWidgetManager.getInstance(mContext); + mSecurityModel = new KeyguardSecurityModel(context); + + mViewStateManager = new KeyguardViewStateManager(this); + mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; @@ -169,19 +201,21 @@ public class KeyguardHostView extends KeyguardViewBase { mCleanupAppWidgetsOnBootCompleted = true; return; } - // Clean up appWidgetIds that are bound to lockscreen, but not actually used - // This is only to clean up after another bug: we used to not call - // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code - // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks - // that are triggered by deleteAppWidgetId, which is why we're doing this - int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets(); - int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds(); - for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) { - int appWidgetId = appWidgetIdsBoundToHost[i]; - if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) { - Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id " - + appWidgetId); - mAppWidgetHost.deleteAppWidgetId(appWidgetId); + if (!mSafeModeEnabled && !widgetsDisabledByDpm()) { + // Clean up appWidgetIds that are bound to lockscreen, but not actually used + // This is only to clean up after another bug: we used to not call + // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code + // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks + // that are triggered by deleteAppWidgetId, which is why we're doing this + int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets(); + int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds(); + for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) { + int appWidgetId = appWidgetIdsBoundToHost[i]; + if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) { + Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id " + + appWidgetId); + mAppWidgetHost.deleteAppWidgetId(appWidgetId); + } } } } @@ -209,6 +243,12 @@ public class KeyguardHostView extends KeyguardViewBase { mCleanupAppWidgetsOnBootCompleted = false; } } + @Override + public void onUserSwitchComplete(int userId) { + if (mKeyguardMultiUserSelectorView != null) { + mKeyguardMultiUserSelectorView.finalizeActiveUserView(true); + } + } }; private SlidingChallengeLayout mSlidingChallengeLayout; @@ -342,21 +382,17 @@ public class KeyguardHostView extends KeyguardViewBase { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mAppWidgetHost.startListeningAsUser(mUserId); + mAppWidgetHost.startListening(); KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mAppWidgetHost.stopListeningAsUser(mUserId); + mAppWidgetHost.stopListening(); KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks); } - private AppWidgetHost getAppWidgetHost() { - return mAppWidgetHost; - } - void addWidget(AppWidgetHostView view, int pageIndex) { mAppWidgetContainer.addWidget(view, pageIndex); } @@ -399,6 +435,12 @@ public class KeyguardHostView extends KeyguardViewBase { } }; + public void initializeSwitchingUserState(boolean switching) { + if (!switching && mKeyguardMultiUserSelectorView != null) { + mKeyguardMultiUserSelectorView.finalizeActiveUserView(false); + } + } + public void userActivity() { if (mViewMediatorCallback != null) { mViewMediatorCallback.userActivity(); @@ -1001,12 +1043,13 @@ public class KeyguardHostView extends KeyguardViewBase { private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) { AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId); if (appWidgetInfo != null) { - AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo); + AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo); addWidget(view, pageIndex); return true; } else { if (updateDbIfFailed) { - Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting"); + Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + " was null for user" + + mUserId + ", deleting"); mAppWidgetHost.deleteAppWidgetId(appId); mLockPatternUtils.removeAppWidget(appId); } @@ -1452,10 +1495,9 @@ public class KeyguardHostView extends KeyguardViewBase { if (users.size() > 1) { if (multiUserView instanceof KeyguardMultiUserSelectorView) { - KeyguardMultiUserSelectorView multiUser = - (KeyguardMultiUserSelectorView) multiUserView; - multiUser.setVisibility(View.VISIBLE); - multiUser.addUsers(users); + mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView; + mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE); + mKeyguardMultiUserSelectorView.addUsers(users); UserSwitcherCallback callback = new UserSwitcherCallback() { @Override public void hideSecurityView(int duration) { @@ -1481,7 +1523,7 @@ public class KeyguardHostView extends KeyguardViewBase { } } }; - multiUser.setCallback(callback); + mKeyguardMultiUserSelectorView.setCallback(callback); } else { Throwable t = new Throwable(); t.fillInStackTrace(); @@ -1553,7 +1595,7 @@ public class KeyguardHostView extends KeyguardViewBase { public void showAssistant() { final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); if (intent == null) return; diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java index 210312a..77359ff 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java @@ -24,6 +24,7 @@ import android.content.Context; import android.os.BatteryManager; import android.os.Handler; import android.os.Looper; +import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -33,12 +34,23 @@ import android.widget.TextView; import libcore.util.MutableInt; +import java.lang.ref.WeakReference; + import com.android.internal.R; /*** * Manages a number of views inside of the given layout. See below for a list of widgets. */ class KeyguardMessageArea extends TextView { + /** Handler token posted with accessibility announcement runnables. */ + private static final Object ANNOUNCE_TOKEN = new Object(); + + /** + * Delay before speaking an accessibility announcement. Used to prevent + * lift-to-type from interrupting itself. + */ + private static final long ANNOUNCEMENT_DELAY = 250; + static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging; static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery; @@ -174,7 +186,9 @@ class KeyguardMessageArea extends TextView { if (mTimeout > 0) { mHandler.postDelayed(mClearMessageRunnable, mTimeout); } - announceForAccessibility(getText()); + mHandler.removeCallbacksAndMessages(ANNOUNCE_TOKEN); + mHandler.postAtTime(new AnnounceRunnable(this, getText()), ANNOUNCE_TOKEN, + (SystemClock.uptimeMillis() + ANNOUNCEMENT_DELAY)); } /** @@ -271,4 +285,25 @@ class KeyguardMessageArea extends TextView { setAlpha(1f); } } + + /** + * Runnable used to delay accessibility announcements. + */ + private static class AnnounceRunnable implements Runnable { + private final WeakReference<View> mHost; + private final CharSequence mTextToAnnounce; + + public AnnounceRunnable(View host, CharSequence textToAnnounce) { + mHost = new WeakReference<View>(host); + mTextToAnnounce = textToAnnounce; + } + + @Override + public void run() { + final View host = mHost.get(); + if (host != null) { + host.announceForAccessibility(mTextToAnnounce); + } + } + } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java index 7bf2bf9..9d1f041 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java @@ -69,6 +69,7 @@ class KeyguardMultiUserAvatar extends FrameLayout { private boolean mInit = true; private KeyguardMultiUserSelectorView mUserSelector; private KeyguardCircleFramedDrawable mFramed; + private boolean mPressLock; public static KeyguardMultiUserAvatar fromXml(int resId, Context context, KeyguardMultiUserSelectorView userSelector, UserInfo info) { @@ -212,13 +213,22 @@ class KeyguardMultiUserAvatar extends FrameLayout { @Override public void setPressed(boolean pressed) { - if (!pressed || isClickable()) { + if (mPressLock && !pressed) { + return; + } + + if (mPressLock || !pressed || isClickable()) { super.setPressed(pressed); mFramed.setPressed(pressed); mUserImage.invalidate(); } } + public void lockPressed(boolean pressed) { + mPressLock = pressed; + setPressed(pressed); + } + public UserInfo getUserInfo() { return mUserInfo; } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java index 728e87c..f9ea5bb 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java @@ -81,13 +81,30 @@ public class KeyguardMultiUserSelectorView extends FrameLayout implements View.O KeyguardMultiUserAvatar uv = createAndAddUser(user); if (user.id == activeUser.id) { mActiveUserAvatar = uv; - mActiveUserAvatar.setActive(true, false, null); - } else { - uv.setActive(false, false, null); } + uv.setActive(false, false, null); + } + mActiveUserAvatar.lockPressed(true); + } + + public void finalizeActiveUserView(boolean animate) { + if (animate) { + getHandler().postDelayed(new Runnable() { + @Override + public void run() { + finalizeActiveUserNow(true); + } + }, 500); + } else { + finalizeActiveUserNow(animate); } } + void finalizeActiveUserNow(boolean animate) { + mActiveUserAvatar.lockPressed(false); + mActiveUserAvatar.setActive(true, animate, null); + } + Comparator<UserInfo> mOrderAddedComparator = new Comparator<UserInfo>() { @Override public int compare(UserInfo lhs, UserInfo rhs) { @@ -132,25 +149,21 @@ public class KeyguardMultiUserSelectorView extends FrameLayout implements View.O // Reset the previously active user to appear inactive mCallback.hideSecurityView(FADE_OUT_ANIMATION_DURATION); setAllClickable(false); + avatar.lockPressed(true); mActiveUserAvatar.setActive(false, true, new Runnable() { @Override public void run() { mActiveUserAvatar = avatar; - mActiveUserAvatar.setActive(true, true, new Runnable() { - @Override - public void run() { - if (this.getClass().getName().contains("internal")) { - try { - ActivityManagerNative.getDefault() - .switchUser(avatar.getUserInfo().id); - } catch (RemoteException re) { - Log.e(TAG, "Couldn't switch user " + re); - } - } else { - setAllClickable(true); - } + if (this.getClass().getName().contains("internal")) { + try { + ActivityManagerNative.getDefault() + .switchUser(avatar.getUserInfo().id); + } catch (RemoteException re) { + Log.e(TAG, "Couldn't switch user " + re); } - }); + } else { + setAllClickable(true); + } } }); } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java index 76cbbd5..6859042 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java @@ -61,7 +61,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri case com.android.internal.R.drawable.ic_action_assist_generic: Intent assistIntent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); if (assistIntent != null) { mActivityLauncher.launchActivity(assistIntent, false, true, null, null); } else { @@ -195,7 +195,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri currentUserHandle); boolean searchActionAvailable = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent || !currentUserSetup; mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent @@ -207,7 +207,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri // Update the search icon with drawable from the search .apk if (!mSearchDisabled) { Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT); if (intent != null) { // XXX Hack. We need to substitute the icon here but haven't formalized // the public API. The "_google" metadata will be going away, so diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java index 35b8509..d938cec 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Typeface; import android.text.TextUtils; -import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.Slog; import android.view.View; @@ -30,7 +29,11 @@ import android.widget.TextView; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; +import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; + +import libcore.icu.ICU; public class KeyguardStatusView extends GridLayout { private static final boolean DEBUG = KeyguardViewMediator.DEBUG; @@ -41,7 +44,7 @@ public class KeyguardStatusView extends GridLayout { public static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging; public static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery; - private CharSequence mDateFormatString; + private SimpleDateFormat mDateFormat; private LockPatternUtils mLockPatternUtils; private TextView mDateView; @@ -80,8 +83,11 @@ public class KeyguardStatusView extends GridLayout { protected void onFinishInflate() { super.onFinishInflate(); Resources res = getContext().getResources(); - mDateFormatString = - res.getText(com.android.internal.R.string.abbrev_wday_month_day_no_year); + final Locale locale = Locale.getDefault(); + final String datePattern = + res.getString(com.android.internal.R.string.system_ui_date_pattern); + final String bestFormat = ICU.getBestDateTimePattern(datePattern, locale.toString()); + mDateFormat = new SimpleDateFormat(bestFormat, locale); mDateView = (TextView) findViewById(R.id.date); mAlarmStatusView = (TextView) findViewById(R.id.alarm_status); mClockView = (ClockView) findViewById(R.id.clock_view); @@ -121,7 +127,7 @@ public class KeyguardStatusView extends GridLayout { } void refreshDate() { - maybeSetUpperCaseText(mDateView, DateFormat.format(mDateFormatString, new Date())); + maybeSetUpperCaseText(mDateView, mDateFormat.format(new Date())); } @Override @@ -141,8 +147,7 @@ public class KeyguardStatusView extends GridLayout { } private void maybeSetUpperCaseText(TextView textView, CharSequence text) { - if (KeyguardViewManager.USE_UPPER_CASE - && textView.getId() != R.id.owner_info) { // currently only required for date view + if (KeyguardViewManager.USE_UPPER_CASE) { textView.setText(text != null ? text.toString().toUpperCase() : null); } else { textView.setText(text); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java index ad6f55c..c9bffbe 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java @@ -79,10 +79,11 @@ public class KeyguardUpdateMonitor { private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307; private static final int MSG_DEVICE_PROVISIONED = 308; private static final int MSG_DPM_STATE_CHANGED = 309; - private static final int MSG_USER_SWITCHED = 310; + private static final int MSG_USER_SWITCHING = 310; private static final int MSG_USER_REMOVED = 311; private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312; protected static final int MSG_BOOT_COMPLETED = 313; + private static final int MSG_USER_SWITCH_COMPLETE = 314; private static KeyguardUpdateMonitor sInstance; @@ -147,8 +148,11 @@ public class KeyguardUpdateMonitor { case MSG_DPM_STATE_CHANGED: handleDevicePolicyManagerStateChanged(); break; - case MSG_USER_SWITCHED: - handleUserSwitched(msg.arg1, (IRemoteCallback)msg.obj); + case MSG_USER_SWITCHING: + handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj); + break; + case MSG_USER_SWITCH_COMPLETE: + handleUserSwitchComplete(msg.arg1); break; case MSG_USER_REMOVED: handleUserRemoved(msg.arg1); @@ -359,11 +363,13 @@ public class KeyguardUpdateMonitor { new IUserSwitchObserver.Stub() { @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, + mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0, reply)); } @Override public void onUserSwitchComplete(int newUserId) throws RemoteException { + mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE, + newUserId)); } }); } catch (RemoteException e) { @@ -418,13 +424,13 @@ public class KeyguardUpdateMonitor { } /** - * Handle {@link #MSG_USER_SWITCHED} + * Handle {@link #MSG_USER_SWITCHING} */ - protected void handleUserSwitched(int userId, IRemoteCallback reply) { + protected void handleUserSwitching(int userId, IRemoteCallback reply) { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onUserSwitched(userId); + cb.onUserSwitching(userId); } } setAlternateUnlockEnabled(false); @@ -435,6 +441,18 @@ public class KeyguardUpdateMonitor { } /** + * Handle {@link #MSG_USER_SWITCH_COMPLETE} + */ + protected void handleUserSwitchComplete(int userId) { + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onUserSwitchComplete(userId); + } + } + } + + /** * Handle {@link #MSG_BOOT_COMPLETED} */ protected void handleBootCompleted() { @@ -456,7 +474,7 @@ public class KeyguardUpdateMonitor { } /** - * Handle {@link #MSG_USER_SWITCHED} + * Handle {@link #MSG_USER_REMOVED} */ protected void handleUserRemoved(int userId) { for (int i = 0; i < mCallbacks.size(); i++) { diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java index 1ba1388..2126f06 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java @@ -85,9 +85,14 @@ class KeyguardUpdateMonitorCallback { void onDevicePolicyManagerStateChanged() { } /** - * Called when the user changes. + * Called when the user change begins. */ - void onUserSwitched(int userId) { } + void onUserSwitching(int userId) { } + + /** + * Called when the user change is complete. + */ + void onUserSwitchComplete(int userId) { } /** * Called when the SIM state changes. diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java index b6cf4da..8562f0c 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java @@ -53,6 +53,7 @@ public class KeyguardViewManager { private final static boolean DEBUG = KeyguardViewMediator.DEBUG; private static String TAG = "KeyguardViewManager"; public static boolean USE_UPPER_CASE = true; + public final static String IS_SWITCHING_USER = "is_switching_user"; // Timeout used for keypresses static final int DIGIT_PRESS_WAKE_MILLIS = 5000; @@ -136,19 +137,12 @@ public class KeyguardViewManager { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - post(new Runnable() { - @Override - public void run() { - synchronized (KeyguardViewManager.this) { - if (mKeyguardHost.getVisibility() == View.VISIBLE) { - // only propagate configuration messages if we're currently showing - maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null); - } else { - if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible"); - } - } - } - }); + if (mKeyguardHost.getVisibility() == View.VISIBLE) { + // only propagate configuration messages if we're currently showing + maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null); + } else { + if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible"); + } } @Override @@ -244,6 +238,8 @@ public class KeyguardViewManager { mKeyguardView = (KeyguardHostView) view.findViewById(R.id.keyguard_host_view); mKeyguardView.setLockPatternUtils(mLockPatternUtils); mKeyguardView.setViewMediatorCallback(mViewMediatorCallback); + mKeyguardView.initializeSwitchingUserState(options != null && + options.getBoolean(IS_SWITCHING_USER)); // HACK // The keyguard view will have set up window flags in onFinishInflate before we set diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java index 7d757ff..8e10528 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java @@ -153,6 +153,7 @@ public class KeyguardViewMediator { private StatusBarManager mStatusBarManager; private boolean mShowLockIcon; private boolean mShowingLockIcon; + private boolean mSwitchingUser; private boolean mSystemReady; @@ -310,11 +311,12 @@ public class KeyguardViewMediator { KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @Override - public void onUserSwitched(int userId) { + public void onUserSwitching(int userId) { // Note that the mLockPatternUtils user has already been updated from setCurrentUser. // We need to force a reset of the views, since lockNow (called by // ActivityManagerService) will not reconstruct the keyguard if it is already showing. synchronized (KeyguardViewMediator.this) { + mSwitchingUser = true; resetStateLocked(null); adjustStatusBarLocked(); // Disable face unlock when the user switches. @@ -323,6 +325,11 @@ public class KeyguardViewMediator { } @Override + public void onUserSwitchComplete(int userId) { + mSwitchingUser = false; + } + + @Override public void onUserRemoved(int userId) { mLockPatternUtils.removeUser(userId); } @@ -1361,6 +1368,10 @@ public class KeyguardViewMediator { * @see #RESET */ private void handleReset(Bundle options) { + if (options == null) { + options = new Bundle(); + } + options.putBoolean(KeyguardViewManager.IS_SWITCHING_USER, mSwitchingUser); synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleReset"); mKeyguardViewManager.reset(options); @@ -1417,6 +1428,6 @@ public class KeyguardViewMediator { private boolean isAssistantAvailable() { return mSearchManager != null - && mSearchManager.getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; + && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java index b4fe0c7..ad5e257 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java @@ -27,6 +27,7 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.os.Handler; import android.os.HandlerThread; +import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.Slog; import android.view.Gravity; @@ -38,10 +39,12 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; +import android.widget.TextClock; import com.android.internal.widget.LockPatternUtils; import java.util.ArrayList; +import java.util.TimeZone; public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener, OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener { @@ -51,6 +54,9 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit protected static float OVERSCROLL_MAX_ROTATION = 30; private static final boolean PERFORM_OVERSCROLL_ROTATION = true; + private static final int FLAG_HAS_LOCAL_HOUR = 0x1; + private static final int FLAG_HAS_LOCAL_MINUTE = 0x2; + protected KeyguardViewStateManager mViewStateManager; private LockPatternUtils mLockPatternUtils; @@ -131,16 +137,21 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit @Override public void onPageSwitched(View newPage, int newPageIndex) { - boolean showingStatusWidget = false; + boolean showingClock = false; if (newPage instanceof ViewGroup) { ViewGroup vg = (ViewGroup) newPage; if (vg.getChildAt(0) instanceof KeyguardStatusView) { - showingStatusWidget = true; + showingClock = true; } } + if (newPage != null && + findClockInHierarchy(newPage) == (FLAG_HAS_LOCAL_HOUR | FLAG_HAS_LOCAL_MINUTE)) { + showingClock = true; + } + // Disable the status bar clock if we're showing the default status widget - if (showingStatusWidget) { + if (showingClock) { setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK); } else { setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK); @@ -857,4 +868,53 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) { return !isCameraPage(childIndex) && super.shouldSetTopAlignedPivotForWidget(childIndex); } + + /** + * Search given {@link View} hierarchy for {@link TextClock} instances that + * show various time components. Returns combination of + * {@link #FLAG_HAS_LOCAL_HOUR} and {@link #FLAG_HAS_LOCAL_MINUTE}. + */ + private static int findClockInHierarchy(View view) { + if (view instanceof TextClock) { + return getClockFlags((TextClock) view); + } else if (view instanceof ViewGroup) { + int flags = 0; + final ViewGroup group = (ViewGroup) view; + final int size = group.getChildCount(); + for (int i = 0; i < size; i++) { + flags |= findClockInHierarchy(group.getChildAt(i)); + } + return flags; + } else { + return 0; + } + } + + /** + * Return combination of {@link #FLAG_HAS_LOCAL_HOUR} and + * {@link #FLAG_HAS_LOCAL_MINUTE} describing the time represented described + * by the given {@link TextClock}. + */ + private static int getClockFlags(TextClock clock) { + int flags = 0; + + final String timeZone = clock.getTimeZone(); + if (timeZone != null && !TimeZone.getDefault().equals(TimeZone.getTimeZone(timeZone))) { + // Ignore clocks showing another timezone + return 0; + } + + final CharSequence format = clock.getFormat(); + final char hour = clock.is24HourModeEnabled() ? DateFormat.HOUR_OF_DAY + : DateFormat.HOUR; + + if (DateFormat.hasDesignator(format, hour)) { + flags |= FLAG_HAS_LOCAL_HOUR; + } + if (DateFormat.hasDesignator(format, DateFormat.MINUTE)) { + flags |= FLAG_HAS_LOCAL_MINUTE; + } + + return flags; + } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/AccountUnlockScreen.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/AccountUnlockScreen.java deleted file mode 100644 index d6a31b8..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/AccountUnlockScreen.java +++ /dev/null @@ -1,317 +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.keyguard_obsolete; - -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.OperationCanceledException; -import android.accounts.AccountManagerFuture; -import android.accounts.AuthenticatorException; -import android.accounts.AccountManagerCallback; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.text.Editable; -import android.text.InputFilter; -import android.text.LoginFilter; -import android.text.TextWatcher; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.EditText; -import android.widget.RelativeLayout; -import android.widget.TextView; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.os.Bundle; - -import java.io.IOException; - -/** - * When the user forgets their password a bunch of times, we fall back on their - * account's login/password to unlock the phone (and reset their lock pattern). - */ -public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen, - View.OnClickListener, TextWatcher { - private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; - private static final String LOCK_PATTERN_CLASS = LOCK_PATTERN_PACKAGE + ".ChooseLockGeneric"; - - /** - * The amount of millis to stay awake once this screen detects activity - */ - private static final int AWAKE_POKE_MILLIS = 30000; - - private KeyguardScreenCallback mCallback; - private LockPatternUtils mLockPatternUtils; - private KeyguardUpdateMonitor mUpdateMonitor; - - private TextView mTopHeader; - private TextView mInstructions; - private EditText mLogin; - private EditText mPassword; - private Button mOk; - - /** - * Shown while making asynchronous check of password. - */ - private ProgressDialog mCheckingDialog; - private KeyguardStatusViewManager mKeyguardStatusViewManager; - - /** - * AccountUnlockScreen constructor. - * @param configuration - * @param updateMonitor - */ - public AccountUnlockScreen(Context context, Configuration configuration, - KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, - LockPatternUtils lockPatternUtils) { - super(context); - mCallback = callback; - mLockPatternUtils = lockPatternUtils; - - LayoutInflater.from(context).inflate( - R.layout.keyguard_screen_glogin_unlock, this, true); - - mTopHeader = (TextView) findViewById(R.id.topHeader); - mTopHeader.setText(mLockPatternUtils.isPermanentlyLocked() ? - R.string.lockscreen_glogin_too_many_attempts : - R.string.lockscreen_glogin_forgot_pattern); - - mInstructions = (TextView) findViewById(R.id.instructions); - - mLogin = (EditText) findViewById(R.id.login); - mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } ); - mLogin.addTextChangedListener(this); - - mPassword = (EditText) findViewById(R.id.password); - mPassword.addTextChangedListener(this); - - mOk = (Button) findViewById(R.id.ok); - mOk.setOnClickListener(this); - - mUpdateMonitor = updateMonitor; - - mKeyguardStatusViewManager = new KeyguardStatusViewManager(this, updateMonitor, - lockPatternUtils, callback, true); - } - - public void afterTextChanged(Editable s) { - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - mCallback.pokeWakelock(AWAKE_POKE_MILLIS); - } - - @Override - protected boolean onRequestFocusInDescendants(int direction, - Rect previouslyFocusedRect) { - // send focus to the login field - return mLogin.requestFocus(direction, previouslyFocusedRect); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return true; - } - - /** {@inheritDoc} */ - public void onPause() { - mKeyguardStatusViewManager.onPause(); - } - - /** {@inheritDoc} */ - public void onResume() { - // start fresh - mLogin.setText(""); - mPassword.setText(""); - mLogin.requestFocus(); - mKeyguardStatusViewManager.onResume(); - } - - /** {@inheritDoc} */ - public void cleanUp() { - if (mCheckingDialog != null) { - mCheckingDialog.hide(); - } - mUpdateMonitor.removeCallback(this); // this must be first - mCallback = null; - mLockPatternUtils = null; - mUpdateMonitor = null; - } - - /** {@inheritDoc} */ - public void onClick(View v) { - mCallback.pokeWakelock(); - if (v == mOk) { - asyncCheckPassword(); - } - } - - private void postOnCheckPasswordResult(final boolean success) { - // ensure this runs on UI thread - mLogin.post(new Runnable() { - public void run() { - if (success) { - // clear out forgotten password - mLockPatternUtils.setPermanentlyLocked(false); - mLockPatternUtils.setLockPatternEnabled(false); - mLockPatternUtils.saveLockPattern(null); - - // launch the 'choose lock pattern' activity so - // the user can pick a new one if they want to - Intent intent = new Intent(); - intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - mCallback.reportSuccessfulUnlockAttempt(); - - // close the keyguard - mCallback.keyguardDone(true); - } else { - mInstructions.setText(R.string.lockscreen_glogin_invalid_input); - mPassword.setText(""); - mCallback.reportFailedUnlockAttempt(); - } - } - }); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_DOWN - && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - if (mLockPatternUtils.isPermanentlyLocked()) { - mCallback.goToLockScreen(); - } else { - mCallback.forgotPattern(false); - } - return true; - } - return super.dispatchKeyEvent(event); - } - - /** - * Given the string the user entered in the 'username' field, find - * the stored account that they probably intended. Prefer, in order: - * - * - an exact match for what was typed, or - * - a case-insensitive match for what was typed, or - * - if they didn't include a domain, an exact match of the username, or - * - if they didn't include a domain, a case-insensitive - * match of the username. - * - * If there is a tie for the best match, choose neither -- - * the user needs to be more specific. - * - * @return an account name from the database, or null if we can't - * find a single best match. - */ - private Account findIntendedAccount(String username) { - Account[] accounts = AccountManager.get(mContext).getAccountsByType("com.google"); - - // Try to figure out which account they meant if they - // typed only the username (and not the domain), or got - // the case wrong. - - Account bestAccount = null; - int bestScore = 0; - for (Account a: accounts) { - int score = 0; - if (username.equals(a.name)) { - score = 4; - } else if (username.equalsIgnoreCase(a.name)) { - score = 3; - } else if (username.indexOf('@') < 0) { - int i = a.name.indexOf('@'); - if (i >= 0) { - String aUsername = a.name.substring(0, i); - if (username.equals(aUsername)) { - score = 2; - } else if (username.equalsIgnoreCase(aUsername)) { - score = 1; - } - } - } - if (score > bestScore) { - bestAccount = a; - bestScore = score; - } else if (score == bestScore) { - bestAccount = null; - } - } - return bestAccount; - } - - private void asyncCheckPassword() { - mCallback.pokeWakelock(AWAKE_POKE_MILLIS); - final String login = mLogin.getText().toString(); - final String password = mPassword.getText().toString(); - Account account = findIntendedAccount(login); - if (account == null) { - postOnCheckPasswordResult(false); - return; - } - getProgressDialog().show(); - Bundle options = new Bundle(); - options.putString(AccountManager.KEY_PASSWORD, password); - AccountManager.get(mContext).confirmCredentials(account, options, null /* activity */, - new AccountManagerCallback<Bundle>() { - public void run(AccountManagerFuture<Bundle> future) { - try { - mCallback.pokeWakelock(AWAKE_POKE_MILLIS); - final Bundle result = future.getResult(); - final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT); - postOnCheckPasswordResult(verified); - } catch (OperationCanceledException e) { - postOnCheckPasswordResult(false); - } catch (IOException e) { - postOnCheckPasswordResult(false); - } catch (AuthenticatorException e) { - postOnCheckPasswordResult(false); - } finally { - mLogin.post(new Runnable() { - public void run() { - getProgressDialog().hide(); - } - }); - } - } - }, null /* handler */); - } - - private Dialog getProgressDialog() { - if (mCheckingDialog == null) { - mCheckingDialog = new ProgressDialog(mContext); - mCheckingDialog.setMessage( - mContext.getString(R.string.lockscreen_glogin_checking_password)); - mCheckingDialog.setIndeterminate(true); - mCheckingDialog.setCancelable(false); - mCheckingDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - return mCheckingDialog; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/BiometricSensorUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/BiometricSensorUnlock.java deleted file mode 100644 index c38525e..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/BiometricSensorUnlock.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2012 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_obsolete; - -import android.view.View; - -interface BiometricSensorUnlock { - /** - * Initializes the view provided for the biometric unlock UI to work within. The provided area - * completely covers the backup unlock mechanism. - * @param biometricUnlockView View provided for the biometric unlock UI. - */ - public void initializeView(View biometricUnlockView); - - /** - * Indicates whether the biometric unlock is running. Before - * {@link BiometricSensorUnlock#start} is called, isRunning() returns false. After a successful - * call to {@link BiometricSensorUnlock#start}, isRunning() returns true until the biometric - * unlock completes, {@link BiometricSensorUnlock#stop} has been called, or an error has - * forced the biometric unlock to stop. - * @return whether the biometric unlock is currently running. - */ - public boolean isRunning(); - - /** - * Covers the backup unlock mechanism by showing the contents of the view initialized in - * {@link BiometricSensorUnlock#initializeView(View)}. The view should disappear after the - * specified timeout. If the timeout is 0, the interface shows until another event, such as - * calling {@link BiometricSensorUnlock#hide()}, causes it to disappear. Called on the UI - * thread. - * @param timeoutMilliseconds Amount of time in milliseconds to display the view before - * disappearing. A value of 0 means the view should remain visible. - */ - public void show(long timeoutMilliseconds); - - /** - * Uncovers the backup unlock mechanism by hiding the contents of the view initialized in - * {@link BiometricSensorUnlock#initializeView(View)}. - */ - public void hide(); - - /** - * Binds to the biometric unlock service and starts the unlock procedure. Called on the UI - * thread. - * @return false if it can't be started or the backup should be used. - */ - public boolean start(); - - /** - * Stops the biometric unlock procedure and unbinds from the service. Called on the UI thread. - * @return whether the biometric unlock was running when called. - */ - public boolean stop(); - - /** - * Cleans up any resources used by the biometric unlock. - */ - public void cleanUp(); - - /** - * Gets the Device Policy Manager quality of the biometric unlock sensor - * (e.g., PASSWORD_QUALITY_BIOMETRIC_WEAK). - * @return biometric unlock sensor quality, as defined by Device Policy Manager. - */ - public int getQuality(); -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/FaceUnlock.java deleted file mode 100644 index e4768e2..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/FaceUnlock.java +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright (C) 2011 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_obsolete; - -import com.android.internal.R; -import com.android.internal.policy.IFaceLockCallback; -import com.android.internal.policy.IFaceLockInterface; -import com.android.internal.widget.LockPatternUtils; - -import android.app.admin.DevicePolicyManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.telephony.TelephonyManager; -import android.util.Log; -import android.view.View; - -public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback { - - private static final boolean DEBUG = false; - private static final String TAG = "FULLockscreen"; - - private final Context mContext; - private final LockPatternUtils mLockPatternUtils; - private final KeyguardUpdateMonitor mUpdateMonitor; - - // TODO: is mServiceRunning needed or can we just use mIsRunning or check if mService is null? - private boolean mServiceRunning = false; - // TODO: now that the code has been restructure to do almost all operations from a handler, this - // lock may no longer be necessary. - private final Object mServiceRunningLock = new Object(); - private IFaceLockInterface mService; - private boolean mBoundToService = false; - private View mFaceUnlockView; - - private Handler mHandler; - private final int MSG_SHOW_FACE_UNLOCK_VIEW = 0; - private final int MSG_HIDE_FACE_UNLOCK_VIEW = 1; - private final int MSG_SERVICE_CONNECTED = 2; - private final int MSG_SERVICE_DISCONNECTED = 3; - private final int MSG_UNLOCK = 4; - private final int MSG_CANCEL = 5; - private final int MSG_REPORT_FAILED_ATTEMPT = 6; - //private final int MSG_EXPOSE_FALLBACK = 7; - private final int MSG_POKE_WAKELOCK = 8; - - // TODO: This was added for the purpose of adhering to what the biometric interface expects - // the isRunning() function to return. However, it is probably not necessary to have both - // mRunning and mServiceRunning. I'd just rather wait to change that logic. - private volatile boolean mIsRunning = false; - - // Long enough to stay visible while the service starts - // Short enough to not have to wait long for backup if service fails to start or crashes - // The service can take a couple of seconds to start on the first try after boot - private final int SERVICE_STARTUP_VIEW_TIMEOUT = 3000; - - // So the user has a consistent amount of time when brought to the backup method from Face - // Unlock - private final int BACKUP_LOCK_TIMEOUT = 5000; - - KeyguardScreenCallback mKeyguardScreenCallback; - - /** - * Stores some of the structures that Face Unlock will need to access and creates the handler - * will be used to execute messages on the UI thread. - */ - public FaceUnlock(Context context, KeyguardUpdateMonitor updateMonitor, - LockPatternUtils lockPatternUtils, KeyguardScreenCallback keyguardScreenCallback) { - mContext = context; - mUpdateMonitor = updateMonitor; - mLockPatternUtils = lockPatternUtils; - mKeyguardScreenCallback = keyguardScreenCallback; - mHandler = new Handler(this); - } - - /** - * Stores and displays the view that Face Unlock is allowed to draw within. - * TODO: since the layout object will eventually be shared by multiple biometric unlock - * methods, we will have to add our other views (background, cancel button) here. - */ - public void initializeView(View biometricUnlockView) { - Log.d(TAG, "initializeView()"); - mFaceUnlockView = biometricUnlockView; - } - - /** - * Indicates whether Face Unlock is currently running. - */ - public boolean isRunning() { - return mIsRunning; - } - - /** - * Sets the Face Unlock view to visible, hiding it after the specified amount of time. If - * timeoutMillis is 0, no hide is performed. Called on the UI thread. - */ - public void show(long timeoutMillis) { - if (DEBUG) Log.d(TAG, "show()"); - if (mHandler.getLooper() != Looper.myLooper()) { - Log.e(TAG, "show() called off of the UI thread"); - } - - removeDisplayMessages(); - if (mFaceUnlockView != null) { - mFaceUnlockView.setVisibility(View.VISIBLE); - } - if (timeoutMillis > 0) { - mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACE_UNLOCK_VIEW, timeoutMillis); - } - } - - /** - * Hides the Face Unlock view. - */ - public void hide() { - if (DEBUG) Log.d(TAG, "hide()"); - // Remove messages to prevent a delayed show message from undo-ing the hide - removeDisplayMessages(); - mHandler.sendEmptyMessage(MSG_HIDE_FACE_UNLOCK_VIEW); - } - - /** - * Binds to the Face Unlock service. Face Unlock will be started when the bind completes. The - * Face Unlock view is displayed to hide the backup lock while the service is starting up. - * Called on the UI thread. - */ - public boolean start() { - if (DEBUG) Log.d(TAG, "start()"); - if (mHandler.getLooper() != Looper.myLooper()) { - Log.e(TAG, "start() called off of the UI thread"); - } - - if (mIsRunning) { - Log.w(TAG, "start() called when already running"); - } - - // Show Face Unlock view, but only for a little bit so lockpattern will become visible if - // Face Unlock fails to start or crashes - // This must show before bind to guarantee that Face Unlock has a place to display - show(SERVICE_STARTUP_VIEW_TIMEOUT); - if (!mBoundToService) { - Log.d(TAG, "Binding to Face Unlock service"); - mContext.bindService(new Intent(IFaceLockInterface.class.getName()), - mConnection, - Context.BIND_AUTO_CREATE, - mLockPatternUtils.getCurrentUser()); - mBoundToService = true; - } else { - Log.w(TAG, "Attempt to bind to Face Unlock when already bound"); - } - - mIsRunning = true; - return true; - } - - /** - * Stops Face Unlock and unbinds from the service. Called on the UI thread. - */ - public boolean stop() { - if (DEBUG) Log.d(TAG, "stop()"); - if (mHandler.getLooper() != Looper.myLooper()) { - Log.e(TAG, "stop() called off of the UI thread"); - } - - boolean mWasRunning = mIsRunning; - stopUi(); - - if (mBoundToService) { - if (mService != null) { - try { - mService.unregisterCallback(mFaceUnlockCallback); - } catch (RemoteException e) { - // Not much we can do - } - } - Log.d(TAG, "Unbinding from Face Unlock service"); - mContext.unbindService(mConnection); - mBoundToService = false; - } else { - // This is usually not an error when this happens. Sometimes we will tell it to - // unbind multiple times because it's called from both onWindowFocusChanged and - // onDetachedFromWindow. - if (DEBUG) Log.d(TAG, "Attempt to unbind from Face Unlock when not bound"); - } - mIsRunning = false; - return mWasRunning; - } - - /** - * Frees up resources used by Face Unlock and stops it if it is still running. - */ - public void cleanUp() { - if (DEBUG) Log.d(TAG, "cleanUp()"); - if (mService != null) { - try { - mService.unregisterCallback(mFaceUnlockCallback); - } catch (RemoteException e) { - // Not much we can do - } - stopUi(); - mService = null; - } - } - - /** - * Returns the Device Policy Manager quality for Face Unlock, which is BIOMETRIC_WEAK. - */ - public int getQuality() { - return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK; - } - - /** - * Handles messages such that everything happens on the UI thread in a deterministic order. - * Calls from the Face Unlock service come from binder threads. Calls from lockscreen typically - * come from the UI thread. This makes sure there are no race conditions between those calls. - */ - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_SHOW_FACE_UNLOCK_VIEW: - handleShowFaceUnlockView(); - break; - case MSG_HIDE_FACE_UNLOCK_VIEW: - handleHideFaceUnlockView(); - break; - case MSG_SERVICE_CONNECTED: - handleServiceConnected(); - break; - case MSG_SERVICE_DISCONNECTED: - handleServiceDisconnected(); - break; - case MSG_UNLOCK: - handleUnlock(); - break; - case MSG_CANCEL: - handleCancel(); - break; - case MSG_REPORT_FAILED_ATTEMPT: - handleReportFailedAttempt(); - break; - //case MSG_EXPOSE_FALLBACK: - //handleExposeFallback(); - //break; - case MSG_POKE_WAKELOCK: - handlePokeWakelock(msg.arg1); - break; - default: - Log.e(TAG, "Unhandled message"); - return false; - } - return true; - } - - /** - * Sets the Face Unlock view to visible, thus covering the backup lock. - */ - void handleShowFaceUnlockView() { - if (DEBUG) Log.d(TAG, "handleShowFaceUnlockView()"); - if (mFaceUnlockView != null) { - mFaceUnlockView.setVisibility(View.VISIBLE); - } else { - Log.e(TAG, "mFaceUnlockView is null in handleShowFaceUnlockView()"); - } - } - - /** - * Sets the Face Unlock view to invisible, thus exposing the backup lock. - */ - void handleHideFaceUnlockView() { - if (DEBUG) Log.d(TAG, "handleHideFaceUnlockView()"); - if (mFaceUnlockView != null) { - mFaceUnlockView.setVisibility(View.INVISIBLE); - } else { - Log.e(TAG, "mFaceUnlockView is null in handleHideFaceUnlockView()"); - } - } - - /** - * Tells the service to start its UI via an AIDL interface. Called when the - * onServiceConnected() callback is received. - */ - void handleServiceConnected() { - Log.d(TAG, "handleServiceConnected()"); - - // It is possible that an unbind has occurred in the time between the bind and when this - // function is reached. If an unbind has already occurred, proceeding on to call startUi() - // can result in a fatal error. Note that the onServiceConnected() callback is - // asynchronous, so this possibility would still exist if we executed this directly in - // onServiceConnected() rather than using a handler. - if (!mBoundToService) { - Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound"); - return; - } - - try { - mService.registerCallback(mFaceUnlockCallback); - } catch (RemoteException e) { - Log.e(TAG, "Caught exception connecting to Face Unlock: " + e.toString()); - mService = null; - mBoundToService = false; - mIsRunning = false; - return; - } - - if (mFaceUnlockView != null) { - IBinder windowToken = mFaceUnlockView.getWindowToken(); - if (windowToken != null) { - // When switching between portrait and landscape view while Face Unlock is running, - // the screen will eventually go dark unless we poke the wakelock when Face Unlock - // is restarted. - mKeyguardScreenCallback.pokeWakelock(); - - int[] position; - position = new int[2]; - mFaceUnlockView.getLocationInWindow(position); - startUi(windowToken, position[0], position[1], mFaceUnlockView.getWidth(), - mFaceUnlockView.getHeight()); - } else { - Log.e(TAG, "windowToken is null in handleServiceConnected()"); - } - } - } - - /** - * Called when the onServiceDisconnected() callback is received. This should not happen during - * normal operation. It indicates an error has occurred. - */ - void handleServiceDisconnected() { - Log.e(TAG, "handleServiceDisconnected()"); - // TODO: this lock may no longer be needed now that everything is being called from a - // handler - synchronized (mServiceRunningLock) { - mService = null; - mServiceRunning = false; - } - mBoundToService = false; - mIsRunning = false; - } - - /** - * Stops the Face Unlock service and tells the device to grant access to the user. Shows the - * Face Unlock view to keep the backup lock covered while the device unlocks. - */ - void handleUnlock() { - if (DEBUG) Log.d(TAG, "handleUnlock()"); - removeDisplayMessages(); - if (mFaceUnlockView != null) { - mFaceUnlockView.setVisibility(View.VISIBLE); - } else { - Log.e(TAG, "mFaceUnlockView is null in handleUnlock()"); - } - stop(); - mKeyguardScreenCallback.keyguardDone(true); - mKeyguardScreenCallback.reportSuccessfulUnlockAttempt(); - } - - /** - * Stops the Face Unlock service and exposes the backup lock. - */ - void handleCancel() { - if (DEBUG) Log.d(TAG, "handleCancel()"); - if (mFaceUnlockView != null) { - mFaceUnlockView.setVisibility(View.INVISIBLE); - } else { - Log.e(TAG, "mFaceUnlockView is null in handleCancel()"); - } - stop(); - mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT); - } - - /** - * Increments the number of failed Face Unlock attempts. - */ - void handleReportFailedAttempt() { - if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()"); - mUpdateMonitor.reportFailedBiometricUnlockAttempt(); - } - - /** - * Hides the Face Unlock view to expose the backup lock. Called when the Face Unlock service UI - * is started, indicating there is no need to continue displaying the underlying view because - * the service UI is now covering the backup lock. - */ - //void handleExposeFallback() { - // if (DEBUG) Log.d(TAG, "handleExposeFallback()"); - // if (mFaceUnlockView != null) { - // mFaceUnlockView.setVisibility(View.INVISIBLE); - // } else { - // Log.e(TAG, "mFaceUnlockView is null in handleExposeFallback()"); - // } - //} - - /** - * Pokes the wakelock to keep the screen alive and active for a specific amount of time. - */ - void handlePokeWakelock(int millis) { - mKeyguardScreenCallback.pokeWakelock(millis); - } - - /** - * Removes show and hide messages from the message queue. Called to prevent delayed show/hide - * messages from undoing a new message. - */ - private void removeDisplayMessages() { - mHandler.removeMessages(MSG_SHOW_FACE_UNLOCK_VIEW); - mHandler.removeMessages(MSG_HIDE_FACE_UNLOCK_VIEW); - } - - /** - * Implements service connection methods. - */ - private ServiceConnection mConnection = new ServiceConnection() { - /** - * Called when the Face Unlock service connects after calling bind(). - */ - @Override - public void onServiceConnected(ComponentName className, IBinder iservice) { - Log.d(TAG, "Connected to Face Unlock service"); - mService = IFaceLockInterface.Stub.asInterface(iservice); - mHandler.sendEmptyMessage(MSG_SERVICE_CONNECTED); - } - - /** - * Called if the Face Unlock service unexpectedly disconnects. This indicates an error. - */ - @Override - public void onServiceDisconnected(ComponentName className) { - Log.e(TAG, "Unexpected disconnect from Face Unlock service"); - mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED); - } - }; - - /** - * Tells the Face Unlock service to start displaying its UI and start processing. - */ - private void startUi(IBinder windowToken, int x, int y, int w, int h) { - if (DEBUG) Log.d(TAG, "startUi()"); - synchronized (mServiceRunningLock) { - if (!mServiceRunning) { - Log.d(TAG, "Starting Face Unlock"); - try { - mService.startUi(windowToken, x, y, w, h, - mLockPatternUtils.isBiometricWeakLivelinessEnabled()); - } catch (RemoteException e) { - Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString()); - return; - } - mServiceRunning = true; - } else { - Log.w(TAG, "startUi() attempted while running"); - } - } - } - - /** - * Tells the Face Unlock service to stop displaying its UI and stop processing. - */ - private void stopUi() { - if (DEBUG) Log.d(TAG, "stopUi()"); - // Note that attempting to stop Face Unlock when it's not running is not an issue. - // Face Unlock can return, which stops it and then we try to stop it when the - // screen is turned off. That's why we check. - synchronized (mServiceRunningLock) { - if (mServiceRunning) { - Log.d(TAG, "Stopping Face Unlock"); - try { - mService.stopUi(); - } catch (RemoteException e) { - Log.e(TAG, "Caught exception stopping Face Unlock: " + e.toString()); - } - mServiceRunning = false; - } else { - // This is usually not an error when this happens. Sometimes we will tell it to - // stop multiple times because it's called from both onWindowFocusChanged and - // onDetachedFromWindow. - if (DEBUG) Log.d(TAG, "stopUi() attempted while not running"); - } - } - } - - /** - * Implements the AIDL biometric unlock service callback interface. - */ - private final IFaceLockCallback mFaceUnlockCallback = new IFaceLockCallback.Stub() { - /** - * Called when Face Unlock wants to grant access to the user. - */ - @Override - public void unlock() { - if (DEBUG) Log.d(TAG, "unlock()"); - mHandler.sendEmptyMessage(MSG_UNLOCK); - } - - /** - * Called when Face Unlock wants to go to the backup. - */ - @Override - public void cancel() { - if (DEBUG) Log.d(TAG, "cancel()"); - mHandler.sendEmptyMessage(MSG_CANCEL); - } - - /** - * Called when Face Unlock wants to increment the number of failed attempts. - */ - @Override - public void reportFailedAttempt() { - if (DEBUG) Log.d(TAG, "reportFailedAttempt()"); - mHandler.sendEmptyMessage(MSG_REPORT_FAILED_ATTEMPT); - } - - /** - * Called when the Face Unlock service starts displaying the UI, indicating that the backup - * unlock can be exposed because the Face Unlock service is now covering the backup with its - * UI. - **/ - //@Override - //public void exposeFallback() { - // if (DEBUG) Log.d(TAG, "exposeFallback()"); - // mHandler.sendEmptyMessage(MSG_EXPOSE_FALLBACK); - //} - - /** - * Called when Face Unlock wants to keep the screen alive and active for a specific amount - * of time. - */ - public void pokeWakelock(int millis) { - if (DEBUG) Log.d(TAG, "pokeWakelock() for " + millis + "ms"); - Message message = mHandler.obtainMessage(MSG_POKE_WAKELOCK, millis, -1); - mHandler.sendMessage(message); - } - - }; -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardScreen.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardScreen.java deleted file mode 100644 index ba5b7ff..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardScreen.java +++ /dev/null @@ -1,45 +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.keyguard_obsolete; - -/** - * Common interface of each {@link android.view.View} that is a screen of - * {@link LockPatternKeyguardView}. - */ -public interface KeyguardScreen { - - /** - * Return true if your view needs input, so should allow the soft - * keyboard to be displayed. - */ - boolean needsInput(); - - /** - * This screen is no longer in front of the user. - */ - void onPause(); - - /** - * This screen is going to be in front of the user. - */ - void onResume(); - - /** - * This view is going away; a hook to do cleanup. - */ - void cleanUp(); -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardScreenCallback.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardScreenCallback.java deleted file mode 100644 index be505a1..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardScreenCallback.java +++ /dev/null @@ -1,82 +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.keyguard_obsolete; - -import android.content.res.Configuration; - -/** - * Within a keyguard, there may be several screens that need a callback - * to the host keyguard view. - */ -public interface KeyguardScreenCallback extends KeyguardViewCallback { - - /** - * Transition to the lock screen. - */ - void goToLockScreen(); - - /** - * Transition to the unlock screen. - */ - void goToUnlockScreen(); - - /** - * The user reported that they forgot their pattern (or not, when they want to back out of the - * forgot pattern screen). - * - * @param isForgotten True if the user hit the forgot pattern, false if they want to back out - * of the account screen. - */ - void forgotPattern(boolean isForgotten); - - /** - * @return Whether the keyguard requires some sort of PIN. - */ - boolean isSecure(); - - /** - * @return Whether we are in a mode where we only want to verify the - * user can get past the keyguard. - */ - boolean isVerifyUnlockOnly(); - - /** - * Stay on me, but recreate me (so I can use a different layout). - */ - void recreateMe(Configuration config); - - /** - * Take action to send an emergency call. - */ - void takeEmergencyCallAction(); - - /** - * Report that the user had a failed attempt to unlock with password or pattern. - */ - void reportFailedUnlockAttempt(); - - /** - * Report that the user successfully entered their password or pattern. - */ - void reportSuccessfulUnlockAttempt(); - - /** - * Report whether we there's another way to unlock the device. - * @return true - */ - boolean doesFallbackUnlockScreenExist(); -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java deleted file mode 100644 index b6ffde0..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Copyright (C) 2011 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_obsolete; - -import com.android.internal.R; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.widget.DigitalClock; -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.TransportControlView; - -import java.util.ArrayList; -import java.util.Date; - -import libcore.util.MutableInt; - -import android.content.ContentResolver; -import android.content.Context; -import android.provider.Settings; -import android.text.TextUtils; -import android.text.format.DateFormat; -import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.TextView; - -/*** - * Manages a number of views inside of LockScreen layouts. See below for a list of widgets - * - */ -class KeyguardStatusViewManager implements OnClickListener { - private static final boolean DEBUG = false; - private static final String TAG = "KeyguardStatusView"; - - public static final int LOCK_ICON = 0; // R.drawable.ic_lock_idle_lock; - public static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm; - public static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging; - public static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery; - private static final long INSTRUCTION_RESET_DELAY = 2000; // time until instruction text resets - - private static final int INSTRUCTION_TEXT = 10; - private static final int CARRIER_TEXT = 11; - private static final int CARRIER_HELP_TEXT = 12; - private static final int HELP_MESSAGE_TEXT = 13; - private static final int OWNER_INFO = 14; - private static final int BATTERY_INFO = 15; - - private StatusMode mStatus; - private String mDateFormatString; - private TransientTextManager mTransientTextManager; - - // Views that this class controls. - // NOTE: These may be null in some LockScreen screens and should protect from NPE - private TextView mCarrierView; - private TextView mDateView; - private TextView mStatus1View; - private TextView mOwnerInfoView; - private TextView mAlarmStatusView; - private TransportControlView mTransportView; - - // Top-level container view for above views - private View mContainer; - - // are we showing battery information? - private boolean mShowingBatteryInfo = false; - - // last known plugged in state - private boolean mPluggedIn = false; - - // last known battery level - private int mBatteryLevel = 100; - - // last known SIM state - protected IccCardConstants.State mSimState; - - private LockPatternUtils mLockPatternUtils; - private KeyguardUpdateMonitor mUpdateMonitor; - private Button mEmergencyCallButton; - private boolean mEmergencyButtonEnabledBecauseSimLocked; - - // Shadowed text values - private CharSequence mCarrierText; - private CharSequence mCarrierHelpText; - private String mHelpMessageText; - private String mInstructionText; - private CharSequence mOwnerInfoText; - private boolean mShowingStatus; - private KeyguardScreenCallback mCallback; - private final boolean mEmergencyCallButtonEnabledInScreen; - private CharSequence mPlmn; - private CharSequence mSpn; - protected int mPhoneState; - private DigitalClock mDigitalClock; - protected boolean mBatteryCharged; - protected boolean mBatteryIsLow; - - private class TransientTextManager { - private TextView mTextView; - private class Data { - final int icon; - final CharSequence text; - Data(CharSequence t, int i) { - text = t; - icon = i; - } - }; - private ArrayList<Data> mMessages = new ArrayList<Data>(5); - - TransientTextManager(TextView textView) { - mTextView = textView; - } - - /* Show given message with icon for up to duration ms. Newer messages override older ones. - * The most recent message with the longest duration is shown as messages expire until - * nothing is left, in which case the text/icon is defined by a call to - * getAltTextMessage() */ - void post(final CharSequence message, final int icon, long duration) { - if (mTextView == null) { - return; - } - mTextView.setText(message); - mTextView.setCompoundDrawablesWithIntrinsicBounds(icon, 0, 0, 0); - final Data data = new Data(message, icon); - mContainer.postDelayed(new Runnable() { - public void run() { - mMessages.remove(data); - int last = mMessages.size() - 1; - final CharSequence lastText; - final int lastIcon; - if (last > 0) { - final Data oldData = mMessages.get(last); - lastText = oldData.text; - lastIcon = oldData.icon; - } else { - final MutableInt tmpIcon = new MutableInt(0); - lastText = getAltTextMessage(tmpIcon); - lastIcon = tmpIcon.value; - } - mTextView.setText(lastText); - mTextView.setCompoundDrawablesWithIntrinsicBounds(lastIcon, 0, 0, 0); - } - }, duration); - } - }; - - /** - * - * @param view the containing view of all widgets - * @param updateMonitor the update monitor to use - * @param lockPatternUtils lock pattern util object - * @param callback used to invoke emergency dialer - * @param emergencyButtonEnabledInScreen whether emergency button is enabled by default - */ - public KeyguardStatusViewManager(View view, KeyguardUpdateMonitor updateMonitor, - LockPatternUtils lockPatternUtils, KeyguardScreenCallback callback, - boolean emergencyButtonEnabledInScreen) { - if (DEBUG) Log.v(TAG, "KeyguardStatusViewManager()"); - mContainer = view; - mDateFormatString = getContext().getString(R.string.abbrev_wday_month_day_no_year); - mLockPatternUtils = lockPatternUtils; - mUpdateMonitor = updateMonitor; - mCallback = callback; - - mCarrierView = (TextView) findViewById(R.id.carrier); - mDateView = (TextView) findViewById(R.id.date); - mStatus1View = (TextView) findViewById(R.id.status1); - mAlarmStatusView = (TextView) findViewById(R.id.alarm_status); - mOwnerInfoView = (TextView) findViewById(R.id.owner_info); - 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) { - mTransportView.setVisibility(View.GONE); - } - - if (mEmergencyCallButton != null) { - mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); - mEmergencyCallButton.setOnClickListener(this); - mEmergencyCallButton.setFocusable(false); // touch only! - } - - mTransientTextManager = new TransientTextManager(mCarrierView); - - // Registering this callback immediately updates the battery state, among other things. - mUpdateMonitor.registerCallback(mInfoCallback); - - resetStatusInfo(); - refreshDate(); - updateOwnerInfo(); - - // Required to get Marquee to work. - final View scrollableViews[] = { mCarrierView, mDateView, mStatus1View, mOwnerInfoView, - mAlarmStatusView }; - for (View v : scrollableViews) { - if (v != null) { - v.setSelected(true); - } - } - } - - private boolean inWidgetMode() { - return mTransportView != null && mTransportView.getVisibility() == View.VISIBLE; - } - - void setInstructionText(String string) { - mInstructionText = string; - update(INSTRUCTION_TEXT, string); - } - - void setCarrierText(CharSequence string) { - mCarrierText = string; - update(CARRIER_TEXT, string); - } - - void setOwnerInfo(CharSequence string) { - mOwnerInfoText = string; - update(OWNER_INFO, string); - } - - /** - * Sets the carrier help text message, if view is present. Carrier help text messages are - * typically for help dealing with SIMS and connectivity. - * - * @param resId resource id of the message - */ - public void setCarrierHelpText(int resId) { - mCarrierHelpText = getText(resId); - update(CARRIER_HELP_TEXT, mCarrierHelpText); - } - - private CharSequence getText(int resId) { - return resId == 0 ? null : getContext().getText(resId); - } - - /** - * Unlock help message. This is typically for help with unlock widgets, e.g. "wrong password" - * or "try again." - * - * @param textResId - * @param lockIcon - */ - public void setHelpMessage(int textResId, int lockIcon) { - final CharSequence tmp = getText(textResId); - mHelpMessageText = tmp == null ? null : tmp.toString(); - update(HELP_MESSAGE_TEXT, mHelpMessageText); - } - - private void update(int what, CharSequence string) { - if (inWidgetMode()) { - if (DEBUG) Log.v(TAG, "inWidgetMode() is true"); - // Use Transient text for messages shown while widget is shown. - switch (what) { - case INSTRUCTION_TEXT: - case CARRIER_HELP_TEXT: - case HELP_MESSAGE_TEXT: - case BATTERY_INFO: - mTransientTextManager.post(string, 0, INSTRUCTION_RESET_DELAY); - break; - - case OWNER_INFO: - case CARRIER_TEXT: - default: - if (DEBUG) Log.w(TAG, "Not showing message id " + what + ", str=" + string); - } - } else { - updateStatusLines(mShowingStatus); - } - } - - public void onPause() { - if (DEBUG) Log.v(TAG, "onPause()"); - mUpdateMonitor.removeCallback(mInfoCallback); - } - - /** {@inheritDoc} */ - public void onResume() { - if (DEBUG) Log.v(TAG, "onResume()"); - - // First update the clock, if present. - if (mDigitalClock != null) { - mDigitalClock.updateTime(); - } - - mUpdateMonitor.registerCallback(mInfoCallback); - resetStatusInfo(); - // Issue the biometric unlock failure message in a centralized place - // TODO: we either need to make the Face Unlock multiple failures string a more general - // 'biometric unlock' or have each biometric unlock handle this on their own. - if (mUpdateMonitor.getMaxBiometricUnlockAttemptsReached()) { - setInstructionText(getContext().getString(R.string.faceunlock_multiple_failures)); - } - } - - void resetStatusInfo() { - mInstructionText = null; - updateStatusLines(true); - } - - /** - * Update the status lines based on these rules: - * AlarmStatus: Alarm state always gets it's own line. - * Status1 is shared between help, battery status and generic unlock instructions, - * prioritized in that order. - * @param showStatusLines status lines are shown if true - */ - void updateStatusLines(boolean showStatusLines) { - if (DEBUG) Log.v(TAG, "updateStatusLines(" + showStatusLines + ")"); - mShowingStatus = showStatusLines; - updateAlarmInfo(); - updateOwnerInfo(); - updateStatus1(); - updateCarrierText(); - } - - private void updateAlarmInfo() { - if (mAlarmStatusView != null) { - String nextAlarm = mLockPatternUtils.getNextAlarm(); - boolean showAlarm = mShowingStatus && !TextUtils.isEmpty(nextAlarm); - mAlarmStatusView.setText(nextAlarm); - mAlarmStatusView.setCompoundDrawablesWithIntrinsicBounds(ALARM_ICON, 0, 0, 0); - mAlarmStatusView.setVisibility(showAlarm ? View.VISIBLE : View.GONE); - } - } - - private void updateOwnerInfo() { - final ContentResolver res = getContext().getContentResolver(); - final boolean ownerInfoEnabled = Settings.Secure.getInt(res, - Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1) != 0; - mOwnerInfoText = ownerInfoEnabled ? - Settings.Secure.getString(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO) : null; - if (mOwnerInfoView != null) { - mOwnerInfoView.setText(mOwnerInfoText); - mOwnerInfoView.setVisibility(TextUtils.isEmpty(mOwnerInfoText) ? View.GONE:View.VISIBLE); - } - } - - private void updateStatus1() { - if (mStatus1View != null) { - MutableInt icon = new MutableInt(0); - CharSequence string = getPriorityTextMessage(icon); - mStatus1View.setText(string); - mStatus1View.setCompoundDrawablesWithIntrinsicBounds(icon.value, 0, 0, 0); - mStatus1View.setVisibility(mShowingStatus ? View.VISIBLE : View.INVISIBLE); - } - } - - private void updateCarrierText() { - if (!inWidgetMode() && mCarrierView != null) { - mCarrierView.setText(mCarrierText); - } - } - - private CharSequence getAltTextMessage(MutableInt icon) { - // If we have replaced the status area with a single widget, then this code - // prioritizes what to show in that space when all transient messages are gone. - CharSequence string = null; - if (mShowingBatteryInfo) { - // Battery status - if (mPluggedIn) { - // Charging, charged or waiting to charge. - string = getContext().getString(mBatteryCharged ? R.string.lockscreen_charged - :R.string.lockscreen_plugged_in, mBatteryLevel); - icon.value = CHARGING_ICON; - } else if (mBatteryIsLow) { - // Battery is low - string = getContext().getString(R.string.lockscreen_low_battery); - icon.value = BATTERY_LOW_ICON; - } - } else { - string = mCarrierText; - } - return string; - } - - private CharSequence getPriorityTextMessage(MutableInt icon) { - CharSequence string = null; - if (!TextUtils.isEmpty(mInstructionText)) { - // Instructions only - string = mInstructionText; - icon.value = LOCK_ICON; - } else if (mShowingBatteryInfo) { - // Battery status - if (mPluggedIn) { - // Charging, charged or waiting to charge. - string = getContext().getString(mBatteryCharged ? R.string.lockscreen_charged - :R.string.lockscreen_plugged_in, mBatteryLevel); - icon.value = CHARGING_ICON; - } else if (mBatteryIsLow) { - // Battery is low - string = getContext().getString(R.string.lockscreen_low_battery); - icon.value = BATTERY_LOW_ICON; - } - } else if (!inWidgetMode() && mOwnerInfoView == null && mOwnerInfoText != null) { - // OwnerInfo shows in status if we don't have a dedicated widget - string = mOwnerInfoText; - } - return string; - } - - void refreshDate() { - if (mDateView != null) { - mDateView.setText(DateFormat.format(mDateFormatString, new Date())); - } - } - - /** - * Determine the current status of the lock screen given the sim state and other stuff. - */ - public StatusMode getStatusForIccState(IccCardConstants.State simState) { - // Since reading the SIM may take a while, we assume it is present until told otherwise. - if (simState == null) { - return StatusMode.Normal; - } - - final boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() - && (simState == IccCardConstants.State.ABSENT || - simState == IccCardConstants.State.PERM_DISABLED)); - - // Assume we're NETWORK_LOCKED if not provisioned - simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState; - switch (simState) { - case ABSENT: - return StatusMode.SimMissing; - case NETWORK_LOCKED: - return StatusMode.SimMissingLocked; - case NOT_READY: - return StatusMode.SimMissing; - case PIN_REQUIRED: - return StatusMode.SimLocked; - case PUK_REQUIRED: - return StatusMode.SimPukLocked; - case READY: - return StatusMode.Normal; - case PERM_DISABLED: - return StatusMode.SimPermDisabled; - case UNKNOWN: - return StatusMode.SimMissing; - } - return StatusMode.SimMissing; - } - - private Context getContext() { - return mContainer.getContext(); - } - - /** - * Update carrier text, carrier help and emergency button to match the current status based - * on SIM state. - * - * @param simState - */ - private void updateCarrierStateWithSimStatus(IccCardConstants.State simState) { - if (DEBUG) Log.d(TAG, "updateCarrierTextWithSimStatus(), simState = " + simState); - - CharSequence carrierText = null; - int carrierHelpTextId = 0; - mEmergencyButtonEnabledBecauseSimLocked = false; - mStatus = getStatusForIccState(simState); - mSimState = simState; - switch (mStatus) { - case Normal: - carrierText = makeCarierString(mPlmn, mSpn); - break; - - case NetworkLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_network_locked_message), - mPlmn); - carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled; - break; - - case SimMissing: - // Shows "No SIM card | Emergency calls only" on devices that are voice-capable. - // This depends on mPlmn containing the text "Emergency calls only" when the radio - // has some connectivity. Otherwise, it should be null or empty and just show - // "No SIM card" - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_missing_sim_message_short), - mPlmn); - carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long; - break; - - case SimPermDisabled: - carrierText = getContext().getText( - R.string.lockscreen_permanent_disabled_sim_message_short); - carrierHelpTextId = R.string.lockscreen_permanent_disabled_sim_instructions; - mEmergencyButtonEnabledBecauseSimLocked = true; - break; - - case SimMissingLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_missing_sim_message_short), - mPlmn); - carrierHelpTextId = R.string.lockscreen_missing_sim_instructions; - mEmergencyButtonEnabledBecauseSimLocked = true; - break; - - case SimLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_sim_locked_message), - mPlmn); - mEmergencyButtonEnabledBecauseSimLocked = true; - break; - - case SimPukLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_sim_puk_locked_message), - mPlmn); - if (!mLockPatternUtils.isPukUnlockScreenEnable()) { - // This means we're showing the PUK unlock screen - mEmergencyButtonEnabledBecauseSimLocked = true; - } - break; - } - - setCarrierText(carrierText); - setCarrierHelpText(carrierHelpTextId); - updateEmergencyCallButtonState(mPhoneState); - } - - - /* - * Add emergencyCallMessage to carrier string only if phone supports emergency calls. - */ - private CharSequence makeCarrierStringOnEmergencyCapable( - CharSequence simMessage, CharSequence emergencyCallMessage) { - if (mLockPatternUtils.isEmergencyCallCapable()) { - return makeCarierString(simMessage, emergencyCallMessage); - } - return simMessage; - } - - private View findViewById(int id) { - return mContainer.findViewById(id); - } - - /** - * The status of this lock screen. Primarily used for widgets on LockScreen. - */ - enum StatusMode { - /** - * Normal case (sim card present, it's not locked) - */ - Normal(true), - - /** - * The sim card is 'network locked'. - */ - NetworkLocked(true), - - /** - * The sim card is missing. - */ - SimMissing(false), - - /** - * The sim card is missing, and this is the device isn't provisioned, so we don't let - * them get past the screen. - */ - SimMissingLocked(false), - - /** - * The sim card is PUK locked, meaning they've entered the wrong sim unlock code too many - * times. - */ - SimPukLocked(false), - - /** - * The sim card is locked. - */ - SimLocked(true), - - /** - * The sim card is permanently disabled due to puk unlock failure - */ - SimPermDisabled(false); - - private final boolean mShowStatusLines; - - StatusMode(boolean mShowStatusLines) { - this.mShowStatusLines = mShowStatusLines; - } - - /** - * @return Whether the status lines (battery level and / or next alarm) are shown while - * in this state. Mostly dictated by whether this is room for them. - */ - public boolean shouldShowStatusLines() { - return mShowStatusLines; - } - } - - private void updateEmergencyCallButtonState(int phoneState) { - if (mEmergencyCallButton != null) { - boolean enabledBecauseSimLocked = - mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked() - && mEmergencyButtonEnabledBecauseSimLocked; - boolean shown = mEmergencyCallButtonEnabledInScreen || enabledBecauseSimLocked; - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton, - phoneState, shown); - } - } - - private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { - mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow(); - mPluggedIn = status.isPluggedIn(); - mBatteryLevel = status.level; - mBatteryCharged = status.isCharged(); - mBatteryIsLow = status.isBatteryLow(); - final MutableInt tmpIcon = new MutableInt(0); - update(BATTERY_INFO, getAltTextMessage(tmpIcon)); - } - - @Override - public void onTimeChanged() { - refreshDate(); - } - - @Override - public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - mPlmn = plmn; - mSpn = spn; - updateCarrierStateWithSimStatus(mSimState); - } - - @Override - public void onPhoneStateChanged(int phoneState) { - mPhoneState = phoneState; - updateEmergencyCallButtonState(phoneState); - } - - @Override - public void onSimStateChanged(IccCardConstants.State simState) { - updateCarrierStateWithSimStatus(simState); - } - }; - - public void onClick(View v) { - if (v == mEmergencyCallButton) { - mCallback.takeEmergencyCallAction(); - } - } - - /** - * Performs concentenation of PLMN/SPN - * @param plmn - * @param spn - * @return - */ - private static CharSequence makeCarierString(CharSequence plmn, CharSequence spn) { - final boolean plmnValid = !TextUtils.isEmpty(plmn); - final boolean spnValid = !TextUtils.isEmpty(spn); - if (plmnValid && spnValid) { - return plmn + "|" + spn; - } else if (plmnValid) { - return plmn; - } else if (spnValid) { - return spn; - } else { - return ""; - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardUpdateMonitor.java deleted file mode 100644 index 67dc8a7..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardUpdateMonitor.java +++ /dev/null @@ -1,642 +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.keyguard_obsolete; - -import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.database.ContentObserver; -import static android.os.BatteryManager.BATTERY_STATUS_FULL; -import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; -import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN; -import static android.os.BatteryManager.EXTRA_STATUS; -import static android.os.BatteryManager.EXTRA_PLUGGED; -import static android.os.BatteryManager.EXTRA_LEVEL; -import static android.os.BatteryManager.EXTRA_HEALTH; -import android.media.AudioManager; -import android.os.BatteryManager; -import android.os.Handler; -import android.os.Message; -import android.provider.Settings; - -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.TelephonyIntents; - -import android.telephony.TelephonyManager; -import android.util.Log; -import com.android.internal.R; -import com.google.android.collect.Lists; - -import java.util.ArrayList; - -/** - * Watches for updates that may be interesting to the keyguard, and provides - * the up to date information as well as a registration for callbacks that care - * to be updated. - * - * Note: under time crunch, this has been extended to include some stuff that - * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns - * the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()} - * and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'... - */ -public class KeyguardUpdateMonitor { - - private static final String TAG = "KeyguardUpdateMonitor"; - private static final boolean DEBUG = false; - private static final boolean DEBUG_SIM_STATES = DEBUG || false; - private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3; - private static final int LOW_BATTERY_THRESHOLD = 20; - - // Callback messages - private static final int MSG_TIME_UPDATE = 301; - private static final int MSG_BATTERY_UPDATE = 302; - private static final int MSG_CARRIER_INFO_UPDATE = 303; - private static final int MSG_SIM_STATE_CHANGE = 304; - private static final int MSG_RINGER_MODE_CHANGED = 305; - private static final int MSG_PHONE_STATE_CHANGED = 306; - private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307; - private static final int MSG_DEVICE_PROVISIONED = 308; - protected static final int MSG_DPM_STATE_CHANGED = 309; - protected static final int MSG_USER_SWITCHED = 310; - protected static final int MSG_USER_REMOVED = 311; - - private final Context mContext; - - // Telephony state - private IccCardConstants.State mSimState = IccCardConstants.State.READY; - private CharSequence mTelephonyPlmn; - private CharSequence mTelephonySpn; - private int mRingMode; - private int mPhoneState; - - private boolean mDeviceProvisioned; - - private BatteryStatus mBatteryStatus; - - private int mFailedAttempts = 0; - private int mFailedBiometricUnlockAttempts = 0; - - private boolean mClockVisible; - - private ArrayList<KeyguardUpdateMonitorCallback> mCallbacks = Lists.newArrayList(); - private ContentObserver mContentObserver; - - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_TIME_UPDATE: - handleTimeUpdate(); - break; - case MSG_BATTERY_UPDATE: - handleBatteryUpdate((BatteryStatus) msg.obj); - break; - case MSG_CARRIER_INFO_UPDATE: - handleCarrierInfoUpdate(); - break; - case MSG_SIM_STATE_CHANGE: - handleSimStateChange((SimArgs) msg.obj); - break; - case MSG_RINGER_MODE_CHANGED: - handleRingerModeChange(msg.arg1); - break; - case MSG_PHONE_STATE_CHANGED: - handlePhoneStateChanged((String)msg.obj); - break; - case MSG_CLOCK_VISIBILITY_CHANGED: - handleClockVisibilityChanged(); - break; - case MSG_DEVICE_PROVISIONED: - handleDeviceProvisioned(); - break; - case MSG_DPM_STATE_CHANGED: - handleDevicePolicyManagerStateChanged(); - break; - case MSG_USER_SWITCHED: - handleUserSwitched(msg.arg1); - break; - case MSG_USER_REMOVED: - handleUserRemoved(msg.arg1); - break; - } - } - }; - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (DEBUG) Log.d(TAG, "received broadcast " + action); - - if (Intent.ACTION_TIME_TICK.equals(action) - || Intent.ACTION_TIME_CHANGED.equals(action) - || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE)); - } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) { - mTelephonyPlmn = getTelephonyPlmnFrom(intent); - mTelephonySpn = getTelephonySpnFrom(intent); - mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE)); - } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { - final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN); - final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0); - final int level = intent.getIntExtra(EXTRA_LEVEL, 0); - final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); - final Message msg = mHandler.obtainMessage( - MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health)); - mHandler.sendMessage(msg); - } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) { - if (DEBUG_SIM_STATES) { - Log.v(TAG, "action " + action + " state" + - intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)); - } - mHandler.sendMessage(mHandler.obtainMessage( - MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent))); - } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, - intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); - } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { - String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); - mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); - } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED - .equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED)); - } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, - intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); - } else if (Intent.ACTION_USER_REMOVED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED, - intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); - } - } - }; - - /** - * When we receive a - * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, - * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, - * we need a single object to pass to the handler. This class helps decode - * the intent and provide a {@link SimCard.State} result. - */ - private static class SimArgs { - public final IccCardConstants.State simState; - - SimArgs(IccCardConstants.State state) { - simState = state; - } - - static SimArgs fromIntent(Intent intent) { - IccCardConstants.State state; - if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { - throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); - } - String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); - if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { - final String absentReason = intent - .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); - - if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals( - absentReason)) { - state = IccCardConstants.State.PERM_DISABLED; - } else { - state = IccCardConstants.State.ABSENT; - } - } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { - state = IccCardConstants.State.READY; - } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { - final String lockedReason = intent - .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); - if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - state = IccCardConstants.State.PIN_REQUIRED; - } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - state = IccCardConstants.State.PUK_REQUIRED; - } else { - state = IccCardConstants.State.UNKNOWN; - } - } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { - state = IccCardConstants.State.NETWORK_LOCKED; - } else { - state = IccCardConstants.State.UNKNOWN; - } - return new SimArgs(state); - } - - public String toString() { - return simState.toString(); - } - } - - /* package */ static class BatteryStatus { - public final int status; - public final int level; - public final int plugged; - public final int health; - public BatteryStatus(int status, int level, int plugged, int health) { - this.status = status; - this.level = level; - this.plugged = plugged; - this.health = health; - } - - /** - * Determine whether the device is plugged in (USB or power). - * @return true if the device is plugged in. - */ - boolean isPluggedIn() { - return plugged == BatteryManager.BATTERY_PLUGGED_AC - || plugged == BatteryManager.BATTERY_PLUGGED_USB - || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS; - } - - /** - * Whether or not the device is charged. Note that some devices never return 100% for - * battery level, so this allows either battery level or status to determine if the - * battery is charged. - * @return true if the device is charged - */ - public boolean isCharged() { - return status == BATTERY_STATUS_FULL || level >= 100; - } - - /** - * Whether battery is low and needs to be charged. - * @return true if battery is low - */ - public boolean isBatteryLow() { - return level < LOW_BATTERY_THRESHOLD; - } - - } - - public KeyguardUpdateMonitor(Context context) { - mContext = context; - - mDeviceProvisioned = Settings.Global.getInt( - mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0; - - // Since device can't be un-provisioned, we only need to register a content observer - // to update mDeviceProvisioned when we are... - if (!mDeviceProvisioned) { - watchForDeviceProvisioning(); - } - - // Take a guess at initial SIM state, battery status and PLMN until we get an update - mSimState = IccCardConstants.State.NOT_READY; - mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0); - mTelephonyPlmn = getDefaultPlmn(); - - // Watch for interesting updates - final IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_TIME_TICK); - filter.addAction(Intent.ACTION_TIME_CHANGED); - filter.addAction(Intent.ACTION_BATTERY_CHANGED); - filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); - filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); - filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); - filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); - filter.addAction(Intent.ACTION_USER_SWITCHED); - filter.addAction(Intent.ACTION_USER_REMOVED); - context.registerReceiver(mBroadcastReceiver, filter); - } - - private void watchForDeviceProvisioning() { - mContentObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DEVICE_PROVISIONED, 0) != 0; - if (mDeviceProvisioned) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED)); - } - if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); - } - }; - - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), - false, mContentObserver); - - // prevent a race condition between where we check the flag and where we register the - // observer by grabbing the value once again... - boolean provisioned = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DEVICE_PROVISIONED, 0) != 0; - if (provisioned != mDeviceProvisioned) { - mDeviceProvisioned = provisioned; - if (mDeviceProvisioned) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED)); - } - } - } - - /** - * Handle {@link #MSG_DPM_STATE_CHANGED} - */ - protected void handleDevicePolicyManagerStateChanged() { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onDevicePolicyManagerStateChanged(); - } - } - - /** - * Handle {@link #MSG_USER_SWITCHED} - */ - protected void handleUserSwitched(int userId) { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onUserSwitched(userId); - } - } - - /** - * Handle {@link #MSG_USER_SWITCHED} - */ - protected void handleUserRemoved(int userId) { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onUserRemoved(userId); - } - } - - /** - * Handle {@link #MSG_DEVICE_PROVISIONED} - */ - protected void handleDeviceProvisioned() { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onDeviceProvisioned(); - } - if (mContentObserver != null) { - // We don't need the observer anymore... - mContext.getContentResolver().unregisterContentObserver(mContentObserver); - mContentObserver = null; - } - } - - /** - * Handle {@link #MSG_PHONE_STATE_CHANGED} - */ - protected void handlePhoneStateChanged(String newState) { - if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); - if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) { - mPhoneState = TelephonyManager.CALL_STATE_IDLE; - } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) { - mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK; - } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) { - mPhoneState = TelephonyManager.CALL_STATE_RINGING; - } - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onPhoneStateChanged(mPhoneState); - } - } - - /** - * Handle {@link #MSG_RINGER_MODE_CHANGED} - */ - protected void handleRingerModeChange(int mode) { - if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); - mRingMode = mode; - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onRingerModeChanged(mode); - } - } - - /** - * Handle {@link #MSG_TIME_UPDATE} - */ - private void handleTimeUpdate() { - if (DEBUG) Log.d(TAG, "handleTimeUpdate"); - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onTimeChanged(); - } - } - - /** - * Handle {@link #MSG_BATTERY_UPDATE} - */ - private void handleBatteryUpdate(BatteryStatus status) { - if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); - final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status); - mBatteryStatus = status; - if (batteryUpdateInteresting) { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onRefreshBatteryInfo(status); - } - } - } - - /** - * Handle {@link #MSG_CARRIER_INFO_UPDATE} - */ - private void handleCarrierInfoUpdate() { - if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn - + ", spn = " + mTelephonySpn); - - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); - } - } - - /** - * Handle {@link #MSG_SIM_STATE_CHANGE} - */ - private void handleSimStateChange(SimArgs simArgs) { - final IccCardConstants.State state = simArgs.simState; - - if (DEBUG) { - Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " - + "state resolved to " + state.toString()); - } - - if (state != IccCardConstants.State.UNKNOWN && state != mSimState) { - mSimState = state; - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onSimStateChanged(state); - } - } - } - - /** - * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED} - */ - private void handleClockVisibilityChanged() { - if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()"); - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onClockVisibilityChanged(); - } - } - - private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) { - final boolean nowPluggedIn = current.isPluggedIn(); - final boolean wasPluggedIn = old.isPluggedIn(); - final boolean stateChangedWhilePluggedIn = - wasPluggedIn == true && nowPluggedIn == true - && (old.status != current.status); - - // change in plug state is always interesting - if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { - return true; - } - - // change in battery level while plugged in - if (nowPluggedIn && old.level != current.level) { - return true; - } - - // change where battery needs charging - if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) { - return true; - } - return false; - } - - /** - * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION} - * @return The string to use for the plmn, or null if it should not be shown. - */ - private CharSequence getTelephonyPlmnFrom(Intent intent) { - if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) { - final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN); - return (plmn != null) ? plmn : getDefaultPlmn(); - } - return null; - } - - /** - * @return The default plmn (no service) - */ - private CharSequence getDefaultPlmn() { - return mContext.getResources().getText(R.string.lockscreen_carrier_default); - } - - /** - * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} - * @return The string to use for the plmn, or null if it should not be shown. - */ - private CharSequence getTelephonySpnFrom(Intent intent) { - if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) { - final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN); - if (spn != null) { - return spn; - } - } - return null; - } - - /** - * Remove the given observer's callback. - * - * @param observer The observer to remove - */ - public void removeCallback(Object observer) { - mCallbacks.remove(observer); - } - - /** - * Register to receive notifications about general keyguard information - * (see {@link InfoCallback}. - * @param callback The callback. - */ - public void registerCallback(KeyguardUpdateMonitorCallback callback) { - if (!mCallbacks.contains(callback)) { - mCallbacks.add(callback); - // Notify listener of the current state - callback.onRefreshBatteryInfo(mBatteryStatus); - callback.onTimeChanged(); - callback.onRingerModeChanged(mRingMode); - callback.onPhoneStateChanged(mPhoneState); - callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); - callback.onClockVisibilityChanged(); - callback.onSimStateChanged(mSimState); - } else { - if (DEBUG) Log.e(TAG, "Object tried to add another callback", - new Exception("Called by")); - } - } - - public void reportClockVisible(boolean visible) { - mClockVisible = visible; - mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget(); - } - - public IccCardConstants.State getSimState() { - return mSimState; - } - - /** - * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we - * have the information earlier than waiting for the intent - * broadcast from the telephony code. - * - * NOTE: Because handleSimStateChange() invokes callbacks immediately without going - * through mHandler, this *must* be called from the UI thread. - */ - public void reportSimUnlocked() { - handleSimStateChange(new SimArgs(IccCardConstants.State.READY)); - } - - public CharSequence getTelephonyPlmn() { - return mTelephonyPlmn; - } - - public CharSequence getTelephonySpn() { - return mTelephonySpn; - } - - /** - * @return Whether the device is provisioned (whether they have gone through - * the setup wizard) - */ - public boolean isDeviceProvisioned() { - return mDeviceProvisioned; - } - - public int getFailedAttempts() { - return mFailedAttempts; - } - - public void clearFailedAttempts() { - mFailedAttempts = 0; - mFailedBiometricUnlockAttempts = 0; - } - - public void reportFailedAttempt() { - mFailedAttempts++; - } - - public boolean isClockVisible() { - return mClockVisible; - } - - public int getPhoneState() { - return mPhoneState; - } - - public void reportFailedBiometricUnlockAttempt() { - mFailedBiometricUnlockAttempts++; - } - - public boolean getMaxBiometricUnlockAttemptsReached() { - return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP; - } - - public boolean isSimLocked() { - return mSimState == IccCardConstants.State.PIN_REQUIRED - || mSimState == IccCardConstants.State.PUK_REQUIRED - || mSimState == IccCardConstants.State.PERM_DISABLED; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardUpdateMonitorCallback.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardUpdateMonitorCallback.java deleted file mode 100644 index 79233e8..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardUpdateMonitorCallback.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2012 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_obsolete; - -import android.app.admin.DevicePolicyManager; -import android.media.AudioManager; - -import com.android.internal.telephony.IccCardConstants; - -/** - * Callback for general information relevant to lock screen. - */ -class KeyguardUpdateMonitorCallback { - /** - * Called when the battery status changes, e.g. when plugged in or unplugged, charge - * level, etc. changes. - * - * @param status current battery status - */ - void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { } - - /** - * Called once per minute or when the time changes. - */ - void onTimeChanged() { } - - /** - * Called when the carrier PLMN or SPN changes. - * - * @param plmn The operator name of the registered network. May be null if it shouldn't - * be displayed. - * @param spn The service provider name. May be null if it shouldn't be displayed. - */ - void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { } - - /** - * Called when the ringer mode changes. - * @param state the current ringer state, as defined in - * {@link AudioManager#RINGER_MODE_CHANGED_ACTION} - */ - void onRingerModeChanged(int state) { } - - /** - * Called when the phone state changes. String will be one of: - * {@link TelephonyManager#EXTRA_STATE_IDLE} - * {@link TelephonyManager@EXTRA_STATE_RINGING} - * {@link TelephonyManager#EXTRA_STATE_OFFHOOK - */ - void onPhoneStateChanged(int phoneState) { } - - /** - * Called when visibility of lockscreen clock changes, such as when - * obscured by a widget. - */ - void onClockVisibilityChanged() { } - - /** - * Called when the device becomes provisioned - */ - void onDeviceProvisioned() { } - - /** - * Called when the device policy changes. - * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED} - */ - void onDevicePolicyManagerStateChanged() { } - - /** - * Called when the user changes. - */ - void onUserSwitched(int userId) { } - - /** - * Called when the SIM state changes. - * @param simState - */ - void onSimStateChanged(IccCardConstants.State simState) { } - - /** - * Called when a user is removed. - */ - void onUserRemoved(int userId) { } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewBase.java deleted file mode 100644 index f9fe797..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewBase.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2007 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_obsolete; - -import android.content.Context; -import android.content.Intent; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.media.AudioManager; -import android.media.IAudioService; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.telephony.TelephonyManager; -import android.view.KeyEvent; -import android.view.View; -import android.view.Gravity; -import android.widget.FrameLayout; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; - -/** - * Base class for keyguard views. {@link #reset} is where you should - * reset the state of your view. Use the {@link KeyguardViewCallback} via - * {@link #getCallback()} to send information back (such as poking the wake lock, - * or finishing the keyguard). - * - * Handles intercepting of media keys that still work when the keyguard is - * showing. - */ -public abstract class KeyguardViewBase extends FrameLayout { - - private static final int BACKGROUND_COLOR = 0x70000000; - private KeyguardViewCallback mCallback; - private AudioManager mAudioManager; - private TelephonyManager mTelephonyManager = null; - // Whether the volume keys should be handled by keyguard. If true, then - // they will be handled here for specific media types such as music, otherwise - // the audio service will bring up the volume dialog. - private static final boolean KEYGUARD_MANAGES_VOLUME = true; - - // This is a faster way to draw the background on devices without hardware acceleration - Drawable mBackgroundDrawable = new Drawable() { - @Override - public void draw(Canvas canvas) { - canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC); - } - - @Override - public void setAlpha(int alpha) { - } - - @Override - public void setColorFilter(ColorFilter cf) { - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - }; - - public KeyguardViewBase(Context context, KeyguardViewCallback callback) { - super(context); - mCallback = callback; - resetBackground(); - } - - public void resetBackground() { - setBackgroundDrawable(mBackgroundDrawable); - } - - public KeyguardViewCallback getCallback() { - return mCallback; - } - - /** - * Called when you need to reset the state of your view. - */ - abstract public void reset(); - - /** - * Called when the screen turned off. - */ - abstract public void onScreenTurnedOff(); - - /** - * Called when the screen turned on. - */ - abstract public void onScreenTurnedOn(); - - /** - * Called when the view needs to be shown. - */ - abstract public void show(); - - /** - * Called when a key has woken the device to give us a chance to adjust our - * state according the the key. We are responsible for waking the device - * (by poking the wake lock) once we are ready. - * - * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. - * Be sure not to take any action that takes a long time; any significant - * action should be posted to a handler. - * - * @param keyCode The wake key, which may be relevant for configuring the - * keyguard. May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking for a reason - * other than a key press. - */ - abstract public void wakeWhenReadyTq(int keyCode); - - /** - * Verify that the user can get past the keyguard securely. This is called, - * for example, when the phone disables the keyguard but then wants to launch - * something else that requires secure access. - * - * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)} - */ - abstract public void verifyUnlock(); - - /** - * Called before this view is being removed. - */ - abstract public void cleanUp(); - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) { - mCallback.pokeWakelock(); - } - - if (interceptMediaKey(event)) { - return true; - } - return super.dispatchKeyEvent(event); - } - - private boolean shouldEventKeepScreenOnWhileKeyguardShowing(KeyEvent event) { - if (event.getAction() != KeyEvent.ACTION_DOWN) { - return false; - } - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_UP: - return false; - default: - return true; - } - } - - /** - * Allows the media keys to work when the keyguard is showing. - * The media keys should be of no interest to the actual keyguard view(s), - * so intercepting them here should not be of any harm. - * @param event The key event - * @return whether the event was consumed as a media key. - */ - private boolean interceptMediaKey(KeyEvent event) { - final int keyCode = event.getKeyCode(); - if (event.getAction() == KeyEvent.ACTION_DOWN) { - switch (keyCode) { - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - /* Suppress PLAY/PAUSE toggle when phone is ringing or - * in-call to avoid music playback */ - if (mTelephonyManager == null) { - mTelephonyManager = (TelephonyManager) getContext().getSystemService( - Context.TELEPHONY_SERVICE); - } - if (mTelephonyManager != null && - mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) { - return true; // suppress key event - } - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { - handleMediaKeyEvent(event); - return true; - } - - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_VOLUME_MUTE: { - if (KEYGUARD_MANAGES_VOLUME) { - synchronized (this) { - if (mAudioManager == null) { - mAudioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - } - } - // Volume buttons should only function for music (local or remote). - // TODO: Actually handle MUTE. - mAudioManager.adjustLocalOrRemoteStreamVolume( - AudioManager.STREAM_MUSIC, - keyCode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER); - // Don't execute default volume behavior - return true; - } else { - return false; - } - } - } - } else if (event.getAction() == KeyEvent.ACTION_UP) { - switch (keyCode) { - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { - handleMediaKeyEvent(event); - return true; - } - } - } - return false; - } - - void handleMediaKeyEvent(KeyEvent keyEvent) { - IAudioService audioService = IAudioService.Stub.asInterface( - ServiceManager.checkService(Context.AUDIO_SERVICE)); - if (audioService != null) { - try { - audioService.dispatchMediaKeyEvent(keyEvent); - } catch (RemoteException e) { - Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e); - } - } else { - Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event"); - } - } - - @Override - public void dispatchSystemUiVisibilityChanged(int visibility) { - super.dispatchSystemUiVisibilityChanged(visibility); - setSystemUiVisibility(STATUS_BAR_DISABLE_BACK); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewCallback.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewCallback.java deleted file mode 100644 index 4cc0f30..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewCallback.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007 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_obsolete; - -/** - * The callback used by the keyguard view to tell the {@link KeyguardViewMediator} - * various things. - */ -public interface KeyguardViewCallback { - - /** - * Request the wakelock to be poked for the default amount of time. - */ - void pokeWakelock(); - - /** - * Request the wakelock to be poked for a specific amount of time. - * @param millis The amount of time in millis. - */ - void pokeWakelock(int millis); - - /** - * Report that the keyguard is done. - * @param authenticated Whether the user securely got past the keyguard. - * the only reason for this to be false is if the keyguard was instructed - * to appear temporarily to verify the user is supposed to get past the - * keyguard, and the user fails to do so. - */ - void keyguardDone(boolean authenticated); - - /** - * Report that the keyguard is done drawing. - */ - void keyguardDoneDrawing(); -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewManager.java deleted file mode 100644 index 5dbef48..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewManager.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (C) 2007 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_obsolete; - -import com.android.internal.R; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.res.Resources; -import android.graphics.PixelFormat; -import android.graphics.Canvas; -import android.os.IBinder; -import android.os.SystemProperties; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewManager; -import android.view.WindowManager; -import android.widget.FrameLayout; - -import android.graphics.Color; - -/** - * Manages creating, showing, hiding and resetting the keyguard. Calls back - * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke - * the wake lock and report that the keyguard is done, which is in turn, - * reported to this class by the current {@link KeyguardViewBase}. - */ -public class KeyguardViewManager implements KeyguardWindowController { - private final static boolean DEBUG = false; - private static String TAG = "KeyguardViewManager"; - - private final Context mContext; - private final ViewManager mViewManager; - private final KeyguardViewCallback mCallback; - private final KeyguardViewProperties mKeyguardViewProperties; - - private final KeyguardUpdateMonitor mUpdateMonitor; - - private WindowManager.LayoutParams mWindowLayoutParams; - private boolean mNeedsInput = false; - - private FrameLayout mKeyguardHost; - private KeyguardViewBase mKeyguardView; - - private boolean mScreenOn = false; - - public interface ShowListener { - void onShown(IBinder windowToken); - }; - - /** - * @param context Used to create views. - * @param viewManager Keyguard will be attached to this. - * @param callback Used to notify of changes. - */ - public KeyguardViewManager(Context context, ViewManager viewManager, - KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, - KeyguardUpdateMonitor updateMonitor) { - mContext = context; - mViewManager = viewManager; - mCallback = callback; - mKeyguardViewProperties = keyguardViewProperties; - - mUpdateMonitor = updateMonitor; - } - - /** - * Helper class to host the keyguard view. - */ - private static class KeyguardViewHost extends FrameLayout { - private final KeyguardViewCallback mCallback; - - private KeyguardViewHost(Context context, KeyguardViewCallback callback) { - super(context); - mCallback = callback; - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - mCallback.keyguardDoneDrawing(); - } - } - - /** - * Show the keyguard. Will handle creating and attaching to the view manager - * lazily. - */ - public synchronized void show() { - if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView); - - Resources res = mContext.getResources(); - boolean enableScreenRotation = - SystemProperties.getBoolean("lockscreen.rot_override",false) - || res.getBoolean(R.bool.config_enableLockScreenRotation); - if (mKeyguardHost == null) { - if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); - - mKeyguardHost = new KeyguardViewHost(mContext, mCallback); - - final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; - int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN - | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER - | WindowManager.LayoutParams.FLAG_SLIPPERY - /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; - if (!mNeedsInput) { - flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - } - if (ActivityManager.isHighEndGfx()) { - flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; - } - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, - flags, PixelFormat.TRANSLUCENT); - lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; - if (ActivityManager.isHighEndGfx()) { - lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; - lp.privateFlags |= - WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED; - } - lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY; - lp.setTitle("Keyguard"); - mWindowLayoutParams = lp; - - mViewManager.addView(mKeyguardHost, lp); - } - - if (enableScreenRotation) { - if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!"); - mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER; - } else { - if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!"); - mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; - } - - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - - if (mKeyguardView == null) { - if (DEBUG) Log.d(TAG, "keyguard view is null, creating it..."); - mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mCallback, - mUpdateMonitor, this); - mKeyguardView.setId(R.id.lock_screen); - - final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - - mKeyguardHost.addView(mKeyguardView, lp); - - if (mScreenOn) { - mKeyguardView.show(); - } - } - - // Disable aspects of the system/status/navigation bars that are not appropriate or - // useful for the lockscreen but can be re-shown by dialogs or SHOW_WHEN_LOCKED activities. - // Other disabled bits are handled by the KeyguardViewMediator talking directly to the - // status bar service. - int visFlags = - ( View.STATUS_BAR_DISABLE_BACK - | View.STATUS_BAR_DISABLE_HOME - ); - Log.v(TAG, "KGVM: Set visibility on " + mKeyguardHost + " to " + visFlags); - mKeyguardHost.setSystemUiVisibility(visFlags); - - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - mKeyguardHost.setVisibility(View.VISIBLE); - mKeyguardView.requestFocus(); - } - - public void setNeedsInput(boolean needsInput) { - mNeedsInput = needsInput; - if (mWindowLayoutParams != null) { - if (needsInput) { - mWindowLayoutParams.flags &= - ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - } else { - mWindowLayoutParams.flags |= - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - } - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - } - } - - /** - * Reset the state of the view. - */ - public synchronized void reset() { - if (DEBUG) Log.d(TAG, "reset()"); - if (mKeyguardView != null) { - mKeyguardView.reset(); - } - } - - public synchronized void onScreenTurnedOff() { - if (DEBUG) Log.d(TAG, "onScreenTurnedOff()"); - mScreenOn = false; - if (mKeyguardView != null) { - mKeyguardView.onScreenTurnedOff(); - } - } - - public synchronized void onScreenTurnedOn( - final KeyguardViewManager.ShowListener showListener) { - if (DEBUG) Log.d(TAG, "onScreenTurnedOn()"); - mScreenOn = true; - if (mKeyguardView != null) { - mKeyguardView.onScreenTurnedOn(); - - // Caller should wait for this window to be shown before turning - // on the screen. - if (mKeyguardHost.getVisibility() == View.VISIBLE) { - // Keyguard may be in the process of being shown, but not yet - // updated with the window manager... give it a chance to do so. - mKeyguardHost.post(new Runnable() { - public void run() { - if (mKeyguardHost.getVisibility() == View.VISIBLE) { - showListener.onShown(mKeyguardHost.getWindowToken()); - } else { - showListener.onShown(null); - } - } - }); - } else { - showListener.onShown(null); - } - } else { - showListener.onShown(null); - } - } - - public synchronized void verifyUnlock() { - if (DEBUG) Log.d(TAG, "verifyUnlock()"); - show(); - mKeyguardView.verifyUnlock(); - } - - /** - * A key has woken the device. We use this to potentially adjust the state - * of the lock screen based on the key. - * - * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}. - * Be sure not to take any action that takes a long time; any significant - * action should be posted to a handler. - * - * @param keyCode The wake key. May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking - * for a reason other than a key press. - */ - public boolean wakeWhenReadyTq(int keyCode) { - if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")"); - if (mKeyguardView != null) { - mKeyguardView.wakeWhenReadyTq(keyCode); - return true; - } else { - Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq"); - return false; - } - } - - /** - * Hides the keyguard view - */ - public synchronized void hide() { - if (DEBUG) Log.d(TAG, "hide()"); - - if (mKeyguardHost != null) { - mKeyguardHost.setVisibility(View.GONE); - // Don't do this right away, so we can let the view continue to animate - // as it goes away. - if (mKeyguardView != null) { - final KeyguardViewBase lastView = mKeyguardView; - mKeyguardView = null; - mKeyguardHost.postDelayed(new Runnable() { - public void run() { - synchronized (KeyguardViewManager.this) { - lastView.cleanUp(); - mKeyguardHost.removeView(lastView); - } - } - }, 500); - } - } - } - - /** - * @return Whether the keyguard is showing - */ - public synchronized boolean isShowing() { - return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java deleted file mode 100644 index 3de1428..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java +++ /dev/null @@ -1,1302 +0,0 @@ -/* - * Copyright (C) 2007 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_obsolete; - -import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; - -import com.android.internal.policy.impl.PhoneWindowManager; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.widget.LockPatternUtils; - -import android.app.ActivityManagerNative; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.StatusBarManager; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.AudioManager; -import android.media.SoundPool; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.provider.Settings; -import android.telephony.TelephonyManager; -import android.util.EventLog; -import android.util.Log; -import android.view.KeyEvent; -import android.view.WindowManager; -import android.view.WindowManagerPolicy; - - -/** - * Mediates requests related to the keyguard. This includes queries about the - * state of the keyguard, power management events that effect whether the keyguard - * should be shown or reset, callbacks to the phone window manager to notify - * it of when the keyguard is showing, and events from the keyguard view itself - * stating that the keyguard was succesfully unlocked. - * - * Note that the keyguard view is shown when the screen is off (as appropriate) - * so that once the screen comes on, it will be ready immediately. - * - * Example queries about the keyguard: - * - is {movement, key} one that should wake the keygaurd? - * - is the keyguard showing? - * - are input events restricted due to the state of the keyguard? - * - * Callbacks to the phone window manager: - * - the keyguard is showing - * - * Example external events that translate to keyguard view changes: - * - screen turned off -> reset the keyguard, and show it so it will be ready - * next time the screen turns on - * - keyboard is slid open -> if the keyguard is not secure, hide it - * - * Events from the keyguard view: - * - user succesfully unlocked keyguard -> hide keyguard view, and no longer - * restrict input events. - * - * Note: in addition to normal power managment events that effect the state of - * whether the keyguard should be showing, external apps and services may request - * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}. When - * false, this will override all other conditions for turning on the keyguard. - * - * Threading and synchronization: - * This class is created by the initialization routine of the {@link WindowManagerPolicy}, - * and runs on its thread. The keyguard UI is created from that thread in the - * constructor of this class. The apis may be called from other threads, including the - * {@link com.android.server.input.InputManagerService}'s and {@link android.view.WindowManager}'s. - * Therefore, methods on this class are synchronized, and any action that is pointed - * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI - * thread of the keyguard. - */ -public class KeyguardViewMediator implements KeyguardViewCallback { - private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; - private final static boolean DEBUG = false; - private final static boolean DBG_WAKE = false; - - private final static String TAG = "KeyguardViewMediator"; - - private static final String DELAYED_KEYGUARD_ACTION = - "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; - - // used for handler messages - private static final int TIMEOUT = 1; - private static final int SHOW = 2; - private static final int HIDE = 3; - private static final int RESET = 4; - private static final int VERIFY_UNLOCK = 5; - private static final int NOTIFY_SCREEN_OFF = 6; - private static final int NOTIFY_SCREEN_ON = 7; - private static final int WAKE_WHEN_READY = 8; - private static final int KEYGUARD_DONE = 9; - private static final int KEYGUARD_DONE_DRAWING = 10; - private static final int KEYGUARD_DONE_AUTHENTICATING = 11; - private static final int SET_HIDDEN = 12; - private static final int KEYGUARD_TIMEOUT = 13; - - /** - * The default amount of time we stay awake (used for all key input) - */ - protected static final int AWAKE_INTERVAL_DEFAULT_MS = 10000; - - /** - * How long to wait after the screen turns off due to timeout before - * turning on the keyguard (i.e, the user has this much time to turn - * the screen back on without having to face the keyguard). - */ - private static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000; - - /** - * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()} - * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)} - * that is reenabling the keyguard. - */ - private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000; - - /** - * Allow the user to expand the status bar when the keyguard is engaged - * (without a pattern or password). - */ - private static final boolean ENABLE_INSECURE_STATUS_BAR_EXPAND = true; - - /** The stream type that the lock sounds are tied to. */ - private int mMasterStreamType; - - private Context mContext; - private AlarmManager mAlarmManager; - private AudioManager mAudioManager; - private StatusBarManager mStatusBarManager; - private boolean mShowLockIcon; - private boolean mShowingLockIcon; - - private boolean mSystemReady; - - // Whether the next call to playSounds() should be skipped. Defaults to - // true because the first lock (on boot) should be silent. - private boolean mSuppressNextLockSound = true; - - - /** High level access to the power manager for WakeLocks */ - private PowerManager mPM; - - /** - * Used to keep the device awake while the keyguard is showing, i.e for - * calls to {@link #pokeWakelock()} - */ - private PowerManager.WakeLock mWakeLock; - - /** - * Used to keep the device awake while to ensure the keyguard finishes opening before - * we sleep. - */ - private PowerManager.WakeLock mShowKeyguardWakeLock; - - /** - * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)} - * is called to make sure the device doesn't sleep before it has a chance to poke - * the wake lock. - * @see #wakeWhenReadyLocked(int) - */ - private PowerManager.WakeLock mWakeAndHandOff; - - private KeyguardViewManager mKeyguardViewManager; - - // these are protected by synchronized (this) - - /** - * External apps (like the phone app) can tell us to disable the keygaurd. - */ - private boolean mExternallyEnabled = true; - - /** - * Remember if an external call to {@link #setKeyguardEnabled} with value - * false caused us to hide the keyguard, so that we need to reshow it once - * the keygaurd is reenabled with another call with value true. - */ - private boolean mNeedToReshowWhenReenabled = false; - - // cached value of whether we are showing (need to know this to quickly - // answer whether the input should be restricted) - private boolean mShowing = false; - - // true if the keyguard is hidden by another window - private boolean mHidden = false; - - /** - * Helps remember whether the screen has turned on since the last time - * it turned off due to timeout. see {@link #onScreenTurnedOff(int)} - */ - private int mDelayedShowingSequence; - - private int mWakelockSequence; - - private PhoneWindowManager mCallback; - - /** - * If the user has disabled the keyguard, then requests to exit, this is - * how we'll ultimately let them know whether it was successful. We use this - * var being non-null as an indicator that there is an in progress request. - */ - private WindowManagerPolicy.OnKeyguardExitResult mExitSecureCallback; - - // the properties of the keyguard - private KeyguardViewProperties mKeyguardViewProperties; - - private KeyguardUpdateMonitor mUpdateMonitor; - - private boolean mScreenOn; - - // last known state of the cellular connection - private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE; - - /** - * we send this intent when the keyguard is dismissed. - */ - private Intent mUserPresentIntent; - - /** - * {@link #setKeyguardEnabled} waits on this condition when it reenables - * the keyguard. - */ - private boolean mWaitingUntilKeyguardVisible = false; - private LockPatternUtils mLockPatternUtils; - - private SoundPool mLockSounds; - private int mLockSoundId; - private int mUnlockSoundId; - private int mLockSoundStreamId; - - /** - * The volume applied to the lock/unlock sounds. - */ - private final float mLockSoundVolume; - - KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onUserSwitched(int userId) { - mLockPatternUtils.setCurrentUser(userId); - synchronized (KeyguardViewMediator.this) { - resetStateLocked(); - } - } - - @Override - public void onUserRemoved(int userId) { - mLockPatternUtils.removeUser(userId); - } - - @Override - void onPhoneStateChanged(int phoneState) { - synchronized (KeyguardViewMediator.this) { - if (TelephonyManager.CALL_STATE_IDLE == phoneState // call ending - && !mScreenOn // screen off - && mExternallyEnabled) { // not disabled by any app - - // note: this is a way to gracefully reenable the keyguard when the call - // ends and the screen is off without always reenabling the keyguard - // each time the screen turns off while in call (and having an occasional ugly - // flicker while turning back on the screen and disabling the keyguard again). - if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " - + "keyguard is showing"); - doKeyguardLocked(); - } - } - }; - - @Override - public void onClockVisibilityChanged() { - adjustStatusBarLocked(); - } - - @Override - public void onDeviceProvisioned() { - mContext.sendBroadcastAsUser(mUserPresentIntent, UserHandle.ALL); - } - - @Override - public void onSimStateChanged(IccCardConstants.State simState) { - if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); - - switch (simState) { - case NOT_READY: - case ABSENT: - // only force lock screen in case of missing sim if user hasn't - // gone through setup wizard - synchronized (this) { - if (!mUpdateMonitor.isDeviceProvisioned()) { - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing," - + " we need to show the keyguard since the " - + "device isn't provisioned yet."); - doKeyguardLocked(); - } else { - resetStateLocked(); - } - } - } - break; - case PIN_REQUIRED: - case PUK_REQUIRED: - synchronized (this) { - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't " - + "showing; need to show keyguard so user can enter sim pin"); - doKeyguardLocked(); - } else { - resetStateLocked(); - } - } - break; - case PERM_DISABLED: - synchronized (this) { - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "PERM_DISABLED and " - + "keygaurd isn't showing."); - doKeyguardLocked(); - } else { - if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to" - + "show permanently disabled message in lockscreen."); - resetStateLocked(); - } - } - break; - case READY: - synchronized (this) { - if (isShowing()) { - resetStateLocked(); - } - } - break; - } - } - - }; - - public KeyguardViewMediator(Context context, PhoneWindowManager callback) { - mContext = context; - mCallback = callback; - mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mWakeLock = mPM.newWakeLock( - PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard"); - mWakeLock.setReferenceCounted(false); - mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); - mShowKeyguardWakeLock.setReferenceCounted(false); - - mWakeAndHandOff = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "keyguardWakeAndHandOff"); - mWakeAndHandOff.setReferenceCounted(false); - - mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION)); - - mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - - mUpdateMonitor = new KeyguardUpdateMonitor(context); - - mLockPatternUtils = new LockPatternUtils(mContext); - mKeyguardViewProperties - = new LockPatternKeyguardViewProperties(mLockPatternUtils, mUpdateMonitor); - - WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); - mKeyguardViewManager = new KeyguardViewManager( - context, wm, this, mKeyguardViewProperties, mUpdateMonitor); - - mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT); - mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING - | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - - final ContentResolver cr = mContext.getContentResolver(); - mShowLockIcon = (Settings.System.getInt(cr, "show_status_bar_lock", 0) == 1); - - mScreenOn = mPM.isScreenOn(); - - mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0); - String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND); - if (soundPath != null) { - mLockSoundId = mLockSounds.load(soundPath, 1); - } - if (soundPath == null || mLockSoundId == 0) { - if (DEBUG) Log.d(TAG, "failed to load sound from " + soundPath); - } - soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND); - if (soundPath != null) { - mUnlockSoundId = mLockSounds.load(soundPath, 1); - } - if (soundPath == null || mUnlockSoundId == 0) { - if (DEBUG) Log.d(TAG, "failed to load sound from " + soundPath); - } - int lockSoundDefaultAttenuation = context.getResources().getInteger( - com.android.internal.R.integer.config_lockSoundVolumeDb); - mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20); - } - - /** - * Let us know that the system is ready after startup. - */ - public void onSystemReady() { - synchronized (this) { - if (DEBUG) Log.d(TAG, "onSystemReady"); - mSystemReady = true; - mUpdateMonitor.registerCallback(mUpdateCallback); - doKeyguardLocked(); - } - } - - /** - * Called to let us know the screen was turned off. - * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or - * {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}. - */ - public void onScreenTurnedOff(int why) { - synchronized (this) { - mScreenOn = false; - if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); - - // Lock immediately based on setting if secure (user has a pin/pattern/password). - // This also "locks" the device when not secure to provide easy access to the - // camera while preventing unwanted input. - final boolean lockImmediately = - mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure(); - - if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled"); - mExitSecureCallback.onKeyguardExitResult(false); - mExitSecureCallback = null; - if (!mExternallyEnabled) { - hideLocked(); - } - } else if (mShowing) { - notifyScreenOffLocked(); - resetStateLocked(); - } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT - || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) { - // if the screen turned off because of timeout or the user hit the power button - // and we don't need to lock immediately, set an alarm - // to enable it a little bit later (i.e, give the user a chance - // to turn the screen back on within a certain window without - // having to unlock the screen) - final ContentResolver cr = mContext.getContentResolver(); - - // From DisplaySettings - long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT, - KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT); - - // From SecuritySettings - final long lockAfterTimeout = Settings.Secure.getInt(cr, - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, - KEYGUARD_LOCK_AFTER_DELAY_DEFAULT); - - // From DevicePolicyAdmin - final long policyTimeout = mLockPatternUtils.getDevicePolicyManager() - .getMaximumTimeToLock(null); - - long timeout; - if (policyTimeout > 0) { - // policy in effect. Make sure we don't go beyond policy limit. - displayTimeout = Math.max(displayTimeout, 0); // ignore negative values - timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout); - } else { - timeout = lockAfterTimeout; - } - - if (timeout <= 0) { - // Lock now - mSuppressNextLockSound = true; - doKeyguardLocked(); - } else { - // Lock in the future - long when = SystemClock.elapsedRealtime() + timeout; - Intent intent = new Intent(DELAYED_KEYGUARD_ACTION); - intent.putExtra("seq", mDelayedShowingSequence); - PendingIntent sender = PendingIntent.getBroadcast(mContext, - 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender); - if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " - + mDelayedShowingSequence); - } - } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) { - // Do not enable the keyguard if the prox sensor forced the screen off. - } else { - doKeyguardLocked(); - } - } - } - - /** - * Let's us know the screen was turned on. - */ - public void onScreenTurnedOn(KeyguardViewManager.ShowListener showListener) { - synchronized (this) { - mScreenOn = true; - mDelayedShowingSequence++; - if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); - if (showListener != null) { - notifyScreenOnLocked(showListener); - } - } - } - - /** - * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide - * a way for external stuff to override normal keyguard behavior. For instance - * the phone app disables the keyguard when it receives incoming calls. - */ - public void setKeyguardEnabled(boolean enabled) { - synchronized (this) { - if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")"); - - - mExternallyEnabled = enabled; - - if (!enabled && mShowing) { - if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring"); - // we're in the process of handling a request to verify the user - // can get past the keyguard. ignore extraneous requests to disable / reenable - return; - } - - // hiding keyguard that is showing, remember to reshow later - if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, " - + "disabling status bar expansion"); - mNeedToReshowWhenReenabled = true; - hideLocked(); - } else if (enabled && mNeedToReshowWhenReenabled) { - // reenabled after previously hidden, reshow - if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling " - + "status bar expansion"); - mNeedToReshowWhenReenabled = false; - - if (mExitSecureCallback != null) { - if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting"); - mExitSecureCallback.onKeyguardExitResult(false); - mExitSecureCallback = null; - resetStateLocked(); - } else { - showLocked(); - - // block until we know the keygaurd is done drawing (and post a message - // to unblock us after a timeout so we don't risk blocking too long - // and causing an ANR). - mWaitingUntilKeyguardVisible = true; - mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS); - if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false"); - while (mWaitingUntilKeyguardVisible) { - try { - wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible"); - } - } - } - } - - /** - * @see android.app.KeyguardManager#exitKeyguardSecurely - */ - public void verifyUnlock(WindowManagerPolicy.OnKeyguardExitResult callback) { - synchronized (this) { - if (DEBUG) Log.d(TAG, "verifyUnlock"); - if (!mUpdateMonitor.isDeviceProvisioned()) { - // don't allow this api when the device isn't provisioned - if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned"); - callback.onKeyguardExitResult(false); - } else if (mExternallyEnabled) { - // this only applies when the user has externally disabled the - // keyguard. this is unexpected and means the user is not - // using the api properly. - Log.w(TAG, "verifyUnlock called when not externally disabled"); - callback.onKeyguardExitResult(false); - } else if (mExitSecureCallback != null) { - // already in progress with someone else - callback.onKeyguardExitResult(false); - } else { - mExitSecureCallback = callback; - verifyUnlockLocked(); - } - } - } - - /** - * Is the keyguard currently showing? - */ - public boolean isShowing() { - return mShowing; - } - - /** - * Is the keyguard currently showing and not being force hidden? - */ - public boolean isShowingAndNotHidden() { - return mShowing && !mHidden; - } - - /** - * Notify us when the keyguard is hidden by another window - */ - public void setHidden(boolean isHidden) { - if (DEBUG) Log.d(TAG, "setHidden " + isHidden); - mHandler.removeMessages(SET_HIDDEN); - Message msg = mHandler.obtainMessage(SET_HIDDEN, (isHidden ? 1 : 0), 0); - mHandler.sendMessage(msg); - } - - /** - * Handles SET_HIDDEN message sent by setHidden() - */ - private void handleSetHidden(boolean isHidden) { - synchronized (KeyguardViewMediator.this) { - if (mHidden != isHidden) { - mHidden = isHidden; - updateActivityLockScreenState(); - adjustUserActivityLocked(); - adjustStatusBarLocked(); - } - } - } - - /** - * Used by PhoneWindowManager to enable the keyguard due to a user activity timeout. - * This must be safe to call from any thread and with any window manager locks held. - */ - public void doKeyguardTimeout() { - mHandler.removeMessages(KEYGUARD_TIMEOUT); - Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT); - mHandler.sendMessage(msg); - } - - /** - * Given the state of the keyguard, is the input restricted? - * Input is restricted when the keyguard is showing, or when the keyguard - * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet. - */ - public boolean isInputRestricted() { - return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned(); - } - - /** - * Enable the keyguard if the settings are appropriate. Return true if all - * work that will happen is done; returns false if the caller can wait for - * the keyguard to be shown. - */ - private void doKeyguardLocked() { - // if another app is disabling us, don't show - if (!mExternallyEnabled) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); - - // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes - // for an occasional ugly flicker in this situation: - // 1) receive a call with the screen on (no keyguard) or make a call - // 2) screen times out - // 3) user hits key to turn screen back on - // instead, we reenable the keyguard when we know the screen is off and the call - // ends (see the broadcast receiver below) - // TODO: clean this up when we have better support at the window manager level - // for apps that wish to be on top of the keyguard - return; - } - - // if the keyguard is already showing, don't bother - if (mKeyguardViewManager.isShowing()) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); - return; - } - - // if the setup wizard hasn't run yet, don't show - final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", - false); - final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); - final IccCardConstants.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() - || ((state == IccCardConstants.State.ABSENT - || state == IccCardConstants.State.PERM_DISABLED) - && requireSim); - - if (!lockedOrMissing && !provisioned) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" - + " and the sim is not locked or missing"); - return; - } - - if (mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); - return; - } - - if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); - showLocked(); - } - - /** - * Send message to keyguard telling it to reset its state. - * @see #handleReset() - */ - private void resetStateLocked() { - if (DEBUG) Log.d(TAG, "resetStateLocked"); - Message msg = mHandler.obtainMessage(RESET); - mHandler.sendMessage(msg); - } - - /** - * Send message to keyguard telling it to verify unlock - * @see #handleVerifyUnlock() - */ - private void verifyUnlockLocked() { - if (DEBUG) Log.d(TAG, "verifyUnlockLocked"); - mHandler.sendEmptyMessage(VERIFY_UNLOCK); - } - - - /** - * Send a message to keyguard telling it the screen just turned on. - * @see #onScreenTurnedOff(int) - * @see #handleNotifyScreenOff - */ - private void notifyScreenOffLocked() { - if (DEBUG) Log.d(TAG, "notifyScreenOffLocked"); - mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF); - } - - /** - * Send a message to keyguard telling it the screen just turned on. - * @see #onScreenTurnedOn() - * @see #handleNotifyScreenOn - */ - private void notifyScreenOnLocked(KeyguardViewManager.ShowListener showListener) { - if (DEBUG) Log.d(TAG, "notifyScreenOnLocked"); - Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_ON, showListener); - mHandler.sendMessage(msg); - } - - /** - * Send message to keyguard telling it about a wake key so it can adjust - * its state accordingly and then poke the wake lock when it is ready. - * @param keyCode The wake key. - * @see #handleWakeWhenReady - * @see #onWakeKeyWhenKeyguardShowingTq(int) - */ - private void wakeWhenReadyLocked(int keyCode) { - if (DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")"); - - /** - * acquire the handoff lock that will keep the cpu running. this will - * be released once the keyguard has set itself up and poked the other wakelock - * in {@link #handleWakeWhenReady(int)} - */ - mWakeAndHandOff.acquire(); - - Message msg = mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0); - mHandler.sendMessage(msg); - } - - /** - * Send message to keyguard telling it to show itself - * @see #handleShow() - */ - private void showLocked() { - if (DEBUG) Log.d(TAG, "showLocked"); - // ensure we stay awake until we are finished displaying the keyguard - mShowKeyguardWakeLock.acquire(); - Message msg = mHandler.obtainMessage(SHOW); - mHandler.sendMessage(msg); - } - - /** - * Send message to keyguard telling it to hide itself - * @see #handleHide() - */ - private void hideLocked() { - if (DEBUG) Log.d(TAG, "hideLocked"); - Message msg = mHandler.obtainMessage(HIDE); - mHandler.sendMessage(msg); - } - - public boolean isSecure() { - return mKeyguardViewProperties.isSecure(); - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (DELAYED_KEYGUARD_ACTION.equals(intent.getAction())) { - final int sequence = intent.getIntExtra("seq", 0); - if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = " - + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence); - synchronized (KeyguardViewMediator.this) { - if (mDelayedShowingSequence == sequence) { - // Don't play lockscreen SFX if the screen went off due to timeout. - mSuppressNextLockSound = true; - doKeyguardLocked(); - } - } - } - } - }; - - /** - * When a key is received when the screen is off and the keyguard is showing, - * we need to decide whether to actually turn on the screen, and if so, tell - * the keyguard to prepare itself and poke the wake lock when it is ready. - * - * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. - * Be sure not to take any action that takes a long time; any significant - * action should be posted to a handler. - * - * @param keyCode The keycode of the key that woke the device - * @param isDocked True if the device is in the dock - * @return Whether we poked the wake lock (and turned the screen on) - */ - public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode, boolean isDocked) { - if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")"); - - if (isWakeKeyWhenKeyguardShowing(keyCode, isDocked)) { - // give the keyguard view manager a chance to adjust the state of the - // keyguard based on the key that woke the device before poking - // the wake lock - wakeWhenReadyLocked(keyCode); - return true; - } else { - return false; - } - } - - /** - * When the keyguard is showing we ignore some keys that might otherwise typically - * be considered wake keys. We filter them out here. - * - * {@link KeyEvent#KEYCODE_POWER} is notably absent from this list because it - * is always considered a wake key. - */ - private boolean isWakeKeyWhenKeyguardShowing(int keyCode, boolean isDocked) { - switch (keyCode) { - // ignore volume keys unless docked - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_VOLUME_MUTE: - return isDocked; - - // ignore media and camera keys - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: - case KeyEvent.KEYCODE_CAMERA: - return false; - } - return true; - } - - /** - * When a wake motion such as an external mouse movement is received when the screen - * is off and the keyguard is showing, we need to decide whether to actually turn - * on the screen, and if so, tell the keyguard to prepare itself and poke the wake - * lock when it is ready. - * - * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. - * Be sure not to take any action that takes a long time; any significant - * action should be posted to a handler. - * - * @return Whether we poked the wake lock (and turned the screen on) - */ - public boolean onWakeMotionWhenKeyguardShowingTq() { - if (DEBUG) Log.d(TAG, "onWakeMotionWhenKeyguardShowing()"); - - // give the keyguard view manager a chance to adjust the state of the - // keyguard based on the key that woke the device before poking - // the wake lock - wakeWhenReadyLocked(KeyEvent.KEYCODE_UNKNOWN); - return true; - } - - /** - * Callbacks from {@link KeyguardViewManager}. - */ - - /** {@inheritDoc} */ - public void pokeWakelock() { - pokeWakelock(AWAKE_INTERVAL_DEFAULT_MS); - } - - /** {@inheritDoc} */ - public void pokeWakelock(int holdMs) { - synchronized (this) { - if (DBG_WAKE) Log.d(TAG, "pokeWakelock(" + holdMs + ")"); - mWakeLock.acquire(); - mHandler.removeMessages(TIMEOUT); - mWakelockSequence++; - Message msg = mHandler.obtainMessage(TIMEOUT, mWakelockSequence, 0); - mHandler.sendMessageDelayed(msg, holdMs); - } - } - - /** - * {@inheritDoc} - * - * @see #handleKeyguardDone - */ - public void keyguardDone(boolean authenticated) { - keyguardDone(authenticated, true); - } - - public void keyguardDone(boolean authenticated, boolean wakeup) { - synchronized (this) { - EventLog.writeEvent(70000, 2); - if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); - Message msg = mHandler.obtainMessage(KEYGUARD_DONE); - msg.arg1 = wakeup ? 1 : 0; - mHandler.sendMessage(msg); - - if (authenticated) { - mUpdateMonitor.clearFailedAttempts(); - } - - if (mExitSecureCallback != null) { - mExitSecureCallback.onKeyguardExitResult(authenticated); - mExitSecureCallback = null; - - if (authenticated) { - // after succesfully exiting securely, no need to reshow - // the keyguard when they've released the lock - mExternallyEnabled = true; - mNeedToReshowWhenReenabled = false; - } - } - } - } - - /** - * {@inheritDoc} - * - * @see #handleKeyguardDoneDrawing - */ - public void keyguardDoneDrawing() { - mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING); - } - - /** - * This handler will be associated with the policy thread, which will also - * be the UI thread of the keyguard. Since the apis of the policy, and therefore - * this class, can be called by other threads, any action that directly - * interacts with the keyguard ui should be posted to this handler, rather - * than called directly. - */ - private Handler mHandler = new Handler(true /*async*/) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case TIMEOUT: - handleTimeout(msg.arg1); - return ; - case SHOW: - handleShow(); - return ; - case HIDE: - handleHide(); - return ; - case RESET: - handleReset(); - return ; - case VERIFY_UNLOCK: - handleVerifyUnlock(); - return; - case NOTIFY_SCREEN_OFF: - handleNotifyScreenOff(); - return; - case NOTIFY_SCREEN_ON: - handleNotifyScreenOn((KeyguardViewManager.ShowListener)msg.obj); - return; - case WAKE_WHEN_READY: - handleWakeWhenReady(msg.arg1); - return; - case KEYGUARD_DONE: - handleKeyguardDone(msg.arg1 != 0); - return; - case KEYGUARD_DONE_DRAWING: - handleKeyguardDoneDrawing(); - return; - case KEYGUARD_DONE_AUTHENTICATING: - keyguardDone(true); - return; - case SET_HIDDEN: - handleSetHidden(msg.arg1 != 0); - break; - case KEYGUARD_TIMEOUT: - synchronized (KeyguardViewMediator.this) { - doKeyguardLocked(); - } - break; - } - } - }; - - /** - * @see #keyguardDone - * @see #KEYGUARD_DONE - */ - private void handleKeyguardDone(boolean wakeup) { - if (DEBUG) Log.d(TAG, "handleKeyguardDone"); - handleHide(); - if (wakeup) { - mPM.wakeUp(SystemClock.uptimeMillis()); - } - mWakeLock.release(); - - final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser()); - mContext.sendBroadcastAsUser(mUserPresentIntent, currentUser); - } - - /** - * @see #keyguardDoneDrawing - * @see #KEYGUARD_DONE_DRAWING - */ - private void handleKeyguardDoneDrawing() { - synchronized(this) { - if (false) Log.d(TAG, "handleKeyguardDoneDrawing"); - if (mWaitingUntilKeyguardVisible) { - if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible"); - mWaitingUntilKeyguardVisible = false; - notifyAll(); - - // there will usually be two of these sent, one as a timeout, and one - // as a result of the callback, so remove any remaining messages from - // the queue - mHandler.removeMessages(KEYGUARD_DONE_DRAWING); - } - } - } - - /** - * Handles the message sent by {@link #pokeWakelock} - * @param seq used to determine if anything has changed since the message - * was sent. - * @see #TIMEOUT - */ - private void handleTimeout(int seq) { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleTimeout"); - if (seq == mWakelockSequence) { - mWakeLock.release(); - } - } - } - - private void playSounds(boolean locked) { - // User feedback for keyguard. - - if (mSuppressNextLockSound) { - mSuppressNextLockSound = false; - return; - } - - final ContentResolver cr = mContext.getContentResolver(); - if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) { - final int whichSound = locked - ? mLockSoundId - : mUnlockSoundId; - mLockSounds.stop(mLockSoundStreamId); - // Init mAudioManager - if (mAudioManager == null) { - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - if (mAudioManager == null) return; - mMasterStreamType = mAudioManager.getMasterStreamType(); - } - // If the stream is muted, don't play the sound - if (mAudioManager.isStreamMute(mMasterStreamType)) return; - - mLockSoundStreamId = mLockSounds.play(whichSound, - mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/); - } - } - - private void updateActivityLockScreenState() { - try { - ActivityManagerNative.getDefault().setLockScreenShown( - mShowing && !mHidden); - } catch (RemoteException e) { - } - } - - /** - * Handle message sent by {@link #showLocked}. - * @see #SHOW - */ - private void handleShow() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleShow"); - if (!mSystemReady) return; - - mKeyguardViewManager.show(); - mShowing = true; - updateActivityLockScreenState(); - adjustUserActivityLocked(); - adjustStatusBarLocked(); - try { - ActivityManagerNative.getDefault().closeSystemDialogs("lock"); - } catch (RemoteException e) { - } - - // Do this at the end to not slow down display of the keyguard. - playSounds(true); - - mShowKeyguardWakeLock.release(); - } - } - - /** - * Handle message sent by {@link #hideLocked()} - * @see #HIDE - */ - private void handleHide() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleHide"); - if (mWakeAndHandOff.isHeld()) { - Log.w(TAG, "attempt to hide the keyguard while waking, ignored"); - return; - } - - // only play "unlock" noises if not on a call (since the incall UI - // disables the keyguard) - if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) { - playSounds(false); - } - - mKeyguardViewManager.hide(); - mShowing = false; - updateActivityLockScreenState(); - adjustUserActivityLocked(); - adjustStatusBarLocked(); - } - } - - private void adjustUserActivityLocked() { - // disable user activity if we are shown and not hidden - if (DEBUG) Log.d(TAG, "adjustUserActivityLocked mShowing: " + mShowing + " mHidden: " + mHidden); - boolean enabled = !mShowing || mHidden; - // FIXME: Replace this with a new timeout control mechanism. - //mRealPowerManager.enableUserActivity(enabled); - if (!enabled && mScreenOn) { - // reinstate our short screen timeout policy - pokeWakelock(); - } - } - - private void adjustStatusBarLocked() { - if (mStatusBarManager == null) { - mStatusBarManager = (StatusBarManager) - mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - if (mStatusBarManager == null) { - Log.w(TAG, "Could not get status bar manager"); - } else { - if (mShowLockIcon) { - // Give feedback to user when secure keyguard is active and engaged - if (mShowing && isSecure()) { - if (!mShowingLockIcon) { - String contentDescription = mContext.getString( - com.android.internal.R.string.status_bar_device_locked); - mStatusBarManager.setIcon("secure", - com.android.internal.R.drawable.stat_sys_secure, 0, - contentDescription); - mShowingLockIcon = true; - } - } else { - if (mShowingLockIcon) { - mStatusBarManager.removeIcon("secure"); - mShowingLockIcon = false; - } - } - } - - // Disable aspects of the system/status/navigation bars that must not be re-enabled by - // windows that appear on top, ever - int flags = StatusBarManager.DISABLE_NONE; - if (mShowing) { - // disable navigation status bar components (home, recents) if lock screen is up - flags |= StatusBarManager.DISABLE_RECENT; - if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) { - // showing secure lockscreen; disable expanding. - flags |= StatusBarManager.DISABLE_EXPAND; - } - if (isSecure()) { - // showing secure lockscreen; disable ticker. - flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER; - } - } - - if (DEBUG) { - Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden - + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags)); - } - - mStatusBarManager.disable(flags); - } - } - - /** - * Handle message sent by {@link #wakeWhenReadyLocked(int)} - * @param keyCode The key that woke the device. - * @see #WAKE_WHEN_READY - */ - private void handleWakeWhenReady(int keyCode) { - synchronized (KeyguardViewMediator.this) { - if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")"); - - // this should result in a call to 'poke wakelock' which will set a timeout - // on releasing the wakelock - if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) { - // poke wakelock ourselves if keyguard is no longer active - Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves"); - pokeWakelock(); - } - - /** - * Now that the keyguard is ready and has poked the wake lock, we can - * release the handoff wakelock - */ - mWakeAndHandOff.release(); - - if (!mWakeLock.isHeld()) { - Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq"); - } - } - } - - /** - * Handle message sent by {@link #resetStateLocked()} - * @see #RESET - */ - private void handleReset() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleReset"); - mKeyguardViewManager.reset(); - } - } - - /** - * Handle message sent by {@link #verifyUnlock} - * @see #RESET - */ - private void handleVerifyUnlock() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); - mKeyguardViewManager.verifyUnlock(); - mShowing = true; - updateActivityLockScreenState(); - } - } - - /** - * Handle message sent by {@link #notifyScreenOffLocked()} - * @see #NOTIFY_SCREEN_OFF - */ - private void handleNotifyScreenOff() { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenOff"); - mKeyguardViewManager.onScreenTurnedOff(); - } - } - - /** - * Handle message sent by {@link #notifyScreenOnLocked()} - * @see #NOTIFY_SCREEN_ON - */ - private void handleNotifyScreenOn(KeyguardViewManager.ShowListener showListener) { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenOn"); - mKeyguardViewManager.onScreenTurnedOn(showListener); - } - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewProperties.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewProperties.java deleted file mode 100644 index 676574d..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewProperties.java +++ /dev/null @@ -1,47 +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.keyguard_obsolete; - -import android.content.Context; - -/** - * Defines operations necessary for showing a keyguard, including how to create - * it, and various properties that are useful to be able to query independant - * of whether the keyguard instance is around or not. - */ -public interface KeyguardViewProperties { - - /** - * Create a keyguard view. - * @param context the context to use when creating the view. - * @param callback keyguard callback object for pokewakelock(), etc. - * @param updateMonitor configuration may be based on this. - * @param controller for talking back with the containing window. - * @return the view. - */ - KeyguardViewBase createKeyguardView(Context context, - KeyguardViewCallback mCallback, KeyguardUpdateMonitor updateMonitor, - KeyguardWindowController controller); - - /** - * Would the keyguard be secure right now? - * @return Whether the keyguard is currently secure, meaning it will block - * the user from getting past it until the user enters some sort of PIN. - */ - boolean isSecure(); - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardWindowController.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardWindowController.java deleted file mode 100644 index 98e3209..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardWindowController.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2009 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_obsolete; - -/** - * Interface passed to the keyguard view, for it to call up to control - * its containing window. - */ -public interface KeyguardWindowController { - /** - * Control whether the window needs input -- that is if it has - * text fields and thus should allow input method interaction. - */ - void setNeedsInput(boolean needsInput); -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardView.java deleted file mode 100644 index 4dc83b6..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardView.java +++ /dev/null @@ -1,1220 +0,0 @@ -/* - * Copyright (C) 2007 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_obsolete; - -import com.android.internal.R; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.LockScreenWidgetCallback; -import com.android.internal.widget.TransportControlView; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.app.AlertDialog; -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PixelFormat; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Parcelable; -import android.os.PowerManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; -import android.util.Slog; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityManager; - -import java.io.IOException; - - -/** - * The host view for all of the screens of the pattern unlock screen. There are - * two {@link Mode}s of operation, lock and unlock. This will show the appropriate - * screen, and listen for callbacks via - * {@link com.android.internal.policy.impl.KeyguardScreenCallback} - * from the current screen. - * - * This view, in turn, communicates back to - * {@link com.android.internal.policy.impl.KeyguardViewManager} - * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate. - */ -public class LockPatternKeyguardView extends KeyguardViewBase { - - private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000; - - static final boolean DEBUG_CONFIGURATION = false; - - // time after launching EmergencyDialer before the screen goes blank. - private static final int EMERGENCY_CALL_TIMEOUT = 10000; - - // intent action for launching emergency dialer activity. - static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; - - private static final boolean DEBUG = false; - private static final String TAG = "LockPatternKeyguardView"; - - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardWindowController mWindowController; - - private View mLockScreen; - private View mUnlockScreen; - - private boolean mScreenOn; - private boolean mWindowFocused = false; - private boolean mEnableFallback = false; // assume no fallback UI until we know better - - private boolean mShowLockBeforeUnlock = false; - - // Interface to a biometric sensor that can optionally be used to unlock the device - private BiometricSensorUnlock mBiometricUnlock; - private final Object mBiometricUnlockStartupLock = new Object(); - // Long enough to stay visible while dialer comes up - // Short enough to not be visible if the user goes back immediately - private final int BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT = 1000; - - private boolean mRequiresSim; - // True if the biometric unlock should not be displayed. For example, if there is an overlay on - // lockscreen or the user is plugging in / unplugging the device. - private boolean mSuppressBiometricUnlock; - //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; - // True the first time lockscreen is showing after boot - private static boolean sIsFirstAppearanceAfterBoot = true; - - // The music control widget - private TransportControlView mTransportControlView; - - private Parcelable mSavedState; - - /** - * Either a lock screen (an informational keyguard screen), or an unlock - * screen (a means for unlocking the device) is shown at any given time. - */ - enum Mode { - LockScreen, - UnlockScreen - } - - /** - * The different types screens available for {@link Mode#UnlockScreen}. - * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() - */ - enum UnlockMode { - - /** - * Unlock by drawing a pattern. - */ - Pattern, - - /** - * Unlock by entering a sim pin. - */ - SimPin, - - /** - * Unlock by entering a sim puk. - */ - SimPuk, - - /** - * Unlock by entering an account's login and password. - */ - Account, - - /** - * Unlock by entering a password or PIN - */ - Password, - - /** - * Unknown (uninitialized) value - */ - Unknown - } - - /** - * The current mode. - */ - private Mode mMode = Mode.LockScreen; - - /** - * Keeps track of what mode the current unlock screen is (cached from most recent computation in - * {@link #getUnlockMode}). - */ - private UnlockMode mUnlockScreenMode = UnlockMode.Unknown; - - private boolean mForgotPattern; - - /** - * If true, it means we are in the process of verifying that the user - * can get past the lock screen per {@link #verifyUnlock()} - */ - private boolean mIsVerifyUnlockOnly = false; - - /** - * Used to lookup the state of the lock pattern - */ - private final LockPatternUtils mLockPatternUtils; - - /** - * The current configuration. - */ - private Configuration mConfiguration; - - private Runnable mRecreateRunnable = new Runnable() { - public void run() { - Mode mode = mMode; - // If we were previously in a locked state but now it's Unknown, it means the phone - // was previously locked because of SIM state and has since been resolved. This - // bit of code checks this condition and dismisses keyguard. - boolean dismissAfterCreation = false; - if (mode == Mode.UnlockScreen && getUnlockMode() == UnlockMode.Unknown) { - if (DEBUG) Log.v(TAG, "Switch to Mode.LockScreen because SIM unlocked"); - mode = Mode.LockScreen; - dismissAfterCreation = true; - } - updateScreen(mode, true); - restoreWidgetState(); - if (dismissAfterCreation) { - mKeyguardScreenCallback.keyguardDone(false); - } - } - }; - - private LockScreenWidgetCallback mWidgetCallback = new LockScreenWidgetCallback() { - public void userActivity(View self) { - mKeyguardScreenCallback.pokeWakelock(TRANSPORT_USERACTIVITY_TIMEOUT); - } - - public void requestShow(View view) { - if (DEBUG) Log.v(TAG, "View " + view + " requested show transports"); - view.setVisibility(View.VISIBLE); - - // TODO: examine all widgets to derive clock status - mUpdateMonitor.reportClockVisible(false); - - // If there's not a bg protection view containing the transport, then show a black - // background. Otherwise, allow the normal background to show. - if (findViewById(R.id.transport_bg_protect) == null) { - // TODO: We should disable the wallpaper instead - setBackgroundColor(0xff000000); - } else { - resetBackground(); - } - } - - public void requestHide(View view) { - if (DEBUG) Log.v(TAG, "View " + view + " requested hide transports"); - view.setVisibility(View.GONE); - - // TODO: examine all widgets to derive clock status - mUpdateMonitor.reportClockVisible(true); - resetBackground(); - } - - public boolean isVisible(View self) { - // TODO: this should be up to the lockscreen to determine if the view - // is currently showing. The idea is it can be used for the widget to - // avoid doing work if it's not visible. For now just returns the view's - // actual visibility. - return self.getVisibility() == View.VISIBLE; - } - }; - - /** - * @return Whether we are stuck on the lock screen because the sim is - * missing. - */ - private boolean stuckOnLockScreenBecauseSimMissing() { - return mRequiresSim - && (!mUpdateMonitor.isDeviceProvisioned()) - && (mUpdateMonitor.getSimState() == IccCardConstants.State.ABSENT || - mUpdateMonitor.getSimState() == IccCardConstants.State.PERM_DISABLED); - } - - /** - * The current {@link KeyguardScreen} will use this to communicate back to us. - */ - KeyguardScreenCallback mKeyguardScreenCallback = new KeyguardScreenCallback() { - - public void goToLockScreen() { - mForgotPattern = false; - if (mIsVerifyUnlockOnly) { - // navigating away from unlock screen during verify mode means - // we are done and the user failed to authenticate. - mIsVerifyUnlockOnly = false; - getCallback().keyguardDone(false); - } else { - updateScreen(Mode.LockScreen, false); - } - } - - public void goToUnlockScreen() { - final IccCardConstants.State simState = mUpdateMonitor.getSimState(); - if (stuckOnLockScreenBecauseSimMissing() - || (simState == IccCardConstants.State.PUK_REQUIRED - && !mLockPatternUtils.isPukUnlockScreenEnable())){ - // stuck on lock screen when sim missing or - // puk'd but puk unlock screen is disabled - return; - } - if (!isSecure()) { - getCallback().keyguardDone(true); - } else { - updateScreen(Mode.UnlockScreen, false); - } - } - - public void forgotPattern(boolean isForgotten) { - if (mEnableFallback) { - mForgotPattern = isForgotten; - updateScreen(Mode.UnlockScreen, false); - } - } - - public boolean isSecure() { - return LockPatternKeyguardView.this.isSecure(); - } - - public boolean isVerifyUnlockOnly() { - return mIsVerifyUnlockOnly; - } - - public void recreateMe(Configuration config) { - if (DEBUG) Log.v(TAG, "recreateMe()"); - removeCallbacks(mRecreateRunnable); - post(mRecreateRunnable); - } - - public void takeEmergencyCallAction() { - mSuppressBiometricUnlock = true; - - if (mBiometricUnlock != null) { - if (mBiometricUnlock.isRunning()) { - // Continue covering backup lock until dialer comes up or call is resumed - mBiometricUnlock.show(BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT); - } - - // We must ensure the biometric unlock is stopped when emergency call is pressed - mBiometricUnlock.stop(); - } - - pokeWakelock(EMERGENCY_CALL_TIMEOUT); - if (TelephonyManager.getDefault().getCallState() - == TelephonyManager.CALL_STATE_OFFHOOK) { - mLockPatternUtils.resumeCall(); - } else { - Intent intent = new Intent(ACTION_EMERGENCY_DIAL); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - getContext().startActivity(intent); - } - } - - public void pokeWakelock() { - getCallback().pokeWakelock(); - } - - public void pokeWakelock(int millis) { - getCallback().pokeWakelock(millis); - } - - public void keyguardDone(boolean authenticated) { - getCallback().keyguardDone(authenticated); - mSavedState = null; // clear state so we re-establish when locked again - } - - public void keyguardDoneDrawing() { - // irrelevant to keyguard screen, they shouldn't be calling this - } - - public void reportFailedUnlockAttempt() { - mUpdateMonitor.reportFailedAttempt(); - final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts + - " (enableFallback=" + mEnableFallback + ")"); - - final boolean usingPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality() - == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; - - final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager() - .getMaximumFailedPasswordsForWipe(null); - - final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; - - final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? - (failedAttemptsBeforeWipe - failedAttempts) - : Integer.MAX_VALUE; // because DPM returns 0 if no restriction - - if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { - // If we reach this code, it means the user has installed a DevicePolicyManager - // that requests device wipe after N attempts. Once we get below the grace - // period, we'll post this dialog every time as a clear warning until the - // bombshell hits and the device is wiped. - if (remainingBeforeWipe > 0) { - showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe); - } else { - // Too many attempts. The device will be wiped shortly. - Slog.i(TAG, "Too many unlock attempts; device will be wiped!"); - showWipeDialog(failedAttempts); - } - } else { - boolean showTimeout = - (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0; - if (usingPattern && mEnableFallback) { - if (failedAttempts == failedAttemptWarning) { - showAlmostAtAccountLoginDialog(); - showTimeout = false; // don't show both dialogs - } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { - mLockPatternUtils.setPermanentlyLocked(true); - updateScreen(mMode, false); - // don't show timeout dialog because we show account unlock screen next - showTimeout = false; - } - } - if (showTimeout) { - showTimeoutDialog(); - } - } - mLockPatternUtils.reportFailedPasswordAttempt(); - } - - public boolean doesFallbackUnlockScreenExist() { - return mEnableFallback; - } - - public void reportSuccessfulUnlockAttempt() { - mLockPatternUtils.reportSuccessfulPasswordAttempt(); - } - }; - - /** - * @param context Used to inflate, and create views. - * @param callback Keyguard callback object for pokewakelock(), etc. - * @param updateMonitor Knows the state of the world, and passed along to each - * screen so they can use the knowledge, and also register for callbacks - * on dynamic information. - * @param lockPatternUtils Used to look up state of lock pattern. - */ - public LockPatternKeyguardView( - Context context, KeyguardViewCallback callback, KeyguardUpdateMonitor updateMonitor, - LockPatternUtils lockPatternUtils, KeyguardWindowController controller) { - super(context, callback); - - mConfiguration = context.getResources().getConfiguration(); - mEnableFallback = false; - mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); - mUpdateMonitor = updateMonitor; - mLockPatternUtils = lockPatternUtils; - mWindowController = controller; - mSuppressBiometricUnlock = sIsFirstAppearanceAfterBoot; - sIsFirstAppearanceAfterBoot = false; - mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn(); - mUpdateMonitor.registerCallback(mInfoCallback); - - /** - * We'll get key events the current screen doesn't use. see - * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} - */ - setFocusableInTouchMode(true); - setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - - updateScreen(getInitialMode(), false); - maybeEnableFallback(context); - } - - private class AccountAnalyzer implements AccountManagerCallback<Bundle> { - private final AccountManager mAccountManager; - private final Account[] mAccounts; - private int mAccountIndex; - - private AccountAnalyzer(AccountManager accountManager) { - mAccountManager = accountManager; - mAccounts = accountManager.getAccountsByType("com.google"); - } - - private void next() { - // if we are ready to enable the fallback or if we depleted the list of accounts - // then finish and get out - if (mEnableFallback || mAccountIndex >= mAccounts.length) { - if (mUnlockScreen == null) { - if (DEBUG) Log.w(TAG, "no unlock screen when trying to enable fallback"); - } else if (mUnlockScreen instanceof PatternUnlockScreen) { - ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); - } - return; - } - - // lookup the confirmCredentials intent for the current account - mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null); - } - - public void start() { - mEnableFallback = false; - mAccountIndex = 0; - next(); - } - - public void run(AccountManagerFuture<Bundle> future) { - try { - Bundle result = future.getResult(); - if (result.getParcelable(AccountManager.KEY_INTENT) != null) { - mEnableFallback = true; - } - } catch (OperationCanceledException e) { - // just skip the account if we are unable to query it - } catch (IOException e) { - // just skip the account if we are unable to query it - } catch (AuthenticatorException e) { - // just skip the account if we are unable to query it - } finally { - mAccountIndex++; - next(); - } - } - } - - private void maybeEnableFallback(Context context) { - // Ask the account manager if we have an account that can be used as a - // fallback in case the user forgets his pattern. - AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context)); - accountAnalyzer.start(); - } - - - // TODO: - // This overloaded method was added to workaround a race condition in the framework between - // notification for orientation changed, layout() and switching resources. This code attempts - // to avoid drawing the incorrect layout while things are in transition. The method can just - // be removed once the race condition is fixed. See bugs 2262578 and 2292713. - @Override - protected void dispatchDraw(Canvas canvas) { - if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime()); - super.dispatchDraw(canvas); - } - - @Override - public void reset() { - mIsVerifyUnlockOnly = false; - mForgotPattern = false; - if (DEBUG) Log.v(TAG, "reset()"); - post(mRecreateRunnable); - } - - @Override - public void onScreenTurnedOff() { - if (DEBUG) Log.d(TAG, "screen off"); - mScreenOn = false; - mForgotPattern = false; - - // Emulate activity life-cycle for both lock and unlock screen. - if (mLockScreen != null) { - ((KeyguardScreen) mLockScreen).onPause(); - } - if (mUnlockScreen != null) { - ((KeyguardScreen) mUnlockScreen).onPause(); - } - - saveWidgetState(); - - if (mBiometricUnlock != null) { - // The biometric unlock must stop when screen turns off. - mBiometricUnlock.stop(); - } - } - - @Override - public void onScreenTurnedOn() { - if (DEBUG) Log.d(TAG, "screen on"); - boolean startBiometricUnlock = false; - // Start the biometric unlock if and only if the screen is both on and focused - synchronized(mBiometricUnlockStartupLock) { - mScreenOn = true; - startBiometricUnlock = mWindowFocused; - } - - show(); - - restoreWidgetState(); - - if (mBiometricUnlock != null && startBiometricUnlock) { - maybeStartBiometricUnlock(); - } - } - - private void saveWidgetState() { - if (mTransportControlView != null) { - if (DEBUG) Log.v(TAG, "Saving widget state"); - mSavedState = mTransportControlView.onSaveInstanceState(); - } - } - - private void restoreWidgetState() { - if (mTransportControlView != null) { - if (DEBUG) Log.v(TAG, "Restoring widget state"); - if (mSavedState != null) { - mTransportControlView.onRestoreInstanceState(mSavedState); - } - } - } - - /** - * Stop the biometric unlock if something covers this window (such as an alarm) - * Start the biometric unlock if the lockscreen window just came into focus and the screen is on - */ - @Override - public void onWindowFocusChanged (boolean hasWindowFocus) { - if (DEBUG) Log.d(TAG, hasWindowFocus ? "focused" : "unfocused"); - - boolean startBiometricUnlock = false; - // Start the biometric unlock if and only if the screen is both on and focused - synchronized(mBiometricUnlockStartupLock) { - if (mScreenOn && !mWindowFocused) startBiometricUnlock = hasWindowFocus; - mWindowFocused = hasWindowFocus; - } - if (!hasWindowFocus) { - if (mBiometricUnlock != null) { - mSuppressBiometricUnlock = true; - mBiometricUnlock.stop(); - mBiometricUnlock.hide(); - } - } else { - mHasDialog = false; - if (mBiometricUnlock != null && startBiometricUnlock) { - maybeStartBiometricUnlock(); - } - } - } - - @Override - public void show() { - // Emulate activity life-cycle for both lock and unlock screen. - if (mLockScreen != null) { - ((KeyguardScreen) mLockScreen).onResume(); - } - if (mUnlockScreen != null) { - ((KeyguardScreen) mUnlockScreen).onResume(); - } - - if (mBiometricUnlock != null && mSuppressBiometricUnlock) { - mBiometricUnlock.hide(); - } - } - - private void recreateLockScreen() { - if (mLockScreen != null) { - ((KeyguardScreen) mLockScreen).onPause(); - ((KeyguardScreen) mLockScreen).cleanUp(); - removeView(mLockScreen); - } - - mLockScreen = createLockScreen(); - mLockScreen.setVisibility(View.INVISIBLE); - addView(mLockScreen); - } - - private void recreateUnlockScreen(UnlockMode unlockMode) { - if (mUnlockScreen != null) { - ((KeyguardScreen) mUnlockScreen).onPause(); - ((KeyguardScreen) mUnlockScreen).cleanUp(); - removeView(mUnlockScreen); - } - - mUnlockScreen = createUnlockScreenFor(unlockMode); - mUnlockScreen.setVisibility(View.INVISIBLE); - addView(mUnlockScreen); - } - - @Override - protected void onDetachedFromWindow() { - mUpdateMonitor.removeCallback(mInfoCallback); - - removeCallbacks(mRecreateRunnable); - - if (mBiometricUnlock != null) { - // When view is hidden, we need to stop the biometric unlock - // e.g., when device becomes unlocked - mBiometricUnlock.stop(); - } - - super.onDetachedFromWindow(); - } - - protected void onConfigurationChanged(Configuration newConfig) { - Resources resources = getResources(); - mShowLockBeforeUnlock = resources.getBoolean(R.bool.config_enableLockBeforeUnlockScreen); - mConfiguration = newConfig; - if (DEBUG_CONFIGURATION) Log.v(TAG, "**** re-creating lock screen since config changed"); - saveWidgetState(); - removeCallbacks(mRecreateRunnable); - if (DEBUG) Log.v(TAG, "recreating lockscreen because config changed"); - post(mRecreateRunnable); - } - - KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { - // When someone plugs in or unplugs the device, we hide the biometric sensor area and - // suppress its startup for the next onScreenTurnedOn(). Since plugging/unplugging - // causes the screen to turn on, the biometric unlock would start if it wasn't - // suppressed. - // - // However, if the biometric unlock is already running, we do not want to interrupt it. - final boolean pluggedIn = status.isPluggedIn(); - if (mBiometricUnlock != null && mPluggedIn != pluggedIn - && !mBiometricUnlock.isRunning()) { - mBiometricUnlock.stop(); - mBiometricUnlock.hide(); - mSuppressBiometricUnlock = true; - } - mPluggedIn = pluggedIn; - } - - @Override - public void onClockVisibilityChanged() { - int visFlags = (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK) - | (mUpdateMonitor.isClockVisible() ? View.STATUS_BAR_DISABLE_CLOCK : 0); - Log.v(TAG, "Set visibility on " + this + " to " + visFlags); - setSystemUiVisibility(visFlags); - } - - // We need to stop the biometric unlock when a phone call comes in - @Override - public void onPhoneStateChanged(int phoneState) { - if (DEBUG) Log.d(TAG, "phone state: " + phoneState); - if (mBiometricUnlock != null && phoneState == TelephonyManager.CALL_STATE_RINGING) { - mSuppressBiometricUnlock = true; - mBiometricUnlock.stop(); - mBiometricUnlock.hide(); - } - } - - @Override - public void onUserSwitched(int userId) { - if (mBiometricUnlock != null) { - mBiometricUnlock.stop(); - } - mLockPatternUtils.setCurrentUser(userId); - updateScreen(getInitialMode(), true); - } - }; - - @Override - protected boolean dispatchHoverEvent(MotionEvent event) { - // Do not let the screen to get locked while the user is disabled and touch - // exploring. A blind user will need significantly more time to find and - // interact with the lock screen views. - AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext); - if (accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled()) { - getCallback().pokeWakelock(); - } - return super.dispatchHoverEvent(event); - } - - @Override - public void wakeWhenReadyTq(int keyCode) { - if (DEBUG) Log.d(TAG, "onWakeKey"); - if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen) - && (mUpdateMonitor.getSimState() != IccCardConstants.State.PUK_REQUIRED)) { - if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); - updateScreen(Mode.UnlockScreen, false); - getCallback().pokeWakelock(); - } else { - if (DEBUG) Log.d(TAG, "poking wake lock immediately"); - getCallback().pokeWakelock(); - } - } - - @Override - public void verifyUnlock() { - if (!isSecure()) { - // non-secure keyguard screens are successfull by default - getCallback().keyguardDone(true); - } else if (mUnlockScreenMode != UnlockMode.Pattern - && mUnlockScreenMode != UnlockMode.Password) { - // can only verify unlock when in pattern/password mode - getCallback().keyguardDone(false); - } else { - // otherwise, go to the unlock screen, see if they can verify it - mIsVerifyUnlockOnly = true; - updateScreen(Mode.UnlockScreen, false); - } - } - - @Override - public void cleanUp() { - if (mLockScreen != null) { - ((KeyguardScreen) mLockScreen).onPause(); - ((KeyguardScreen) mLockScreen).cleanUp(); - this.removeView(mLockScreen); - mLockScreen = null; - } - if (mUnlockScreen != null) { - ((KeyguardScreen) mUnlockScreen).onPause(); - ((KeyguardScreen) mUnlockScreen).cleanUp(); - this.removeView(mUnlockScreen); - mUnlockScreen = null; - } - mUpdateMonitor.removeCallback(this); - if (mBiometricUnlock != null) { - mBiometricUnlock.cleanUp(); - } - } - - private boolean isSecure() { - UnlockMode unlockMode = getUnlockMode(); - boolean secure = false; - switch (unlockMode) { - case Pattern: - secure = mLockPatternUtils.isLockPatternEnabled(); - break; - case SimPin: - secure = mUpdateMonitor.getSimState() == IccCardConstants.State.PIN_REQUIRED; - break; - case SimPuk: - secure = mUpdateMonitor.getSimState() == IccCardConstants.State.PUK_REQUIRED; - break; - case Account: - secure = true; - break; - case Password: - secure = mLockPatternUtils.isLockPasswordEnabled(); - break; - case Unknown: - // This means no security is set up - break; - default: - throw new IllegalStateException("unknown unlock mode " + unlockMode); - } - return secure; - } - - private void updateScreen(Mode mode, boolean force) { - - if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode - + " last mode=" + mMode + ", force = " + force, new RuntimeException()); - - mMode = mode; - - // Re-create the lock screen if necessary - if (mode == Mode.LockScreen || mShowLockBeforeUnlock) { - if (force || mLockScreen == null) { - recreateLockScreen(); - } - } - - // Re-create the unlock screen if necessary. - final UnlockMode unlockMode = getUnlockMode(); - if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) { - if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { - recreateUnlockScreen(unlockMode); - } - } - - // visibleScreen should never be null - final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; - final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; - - // do this before changing visibility so focus isn't requested before the input - // flag is set - mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput()); - - if (DEBUG_CONFIGURATION) { - Log.v(TAG, "Gone=" + goneScreen); - Log.v(TAG, "Visible=" + visibleScreen); - } - - if (mScreenOn) { - if (goneScreen != null && goneScreen.getVisibility() == View.VISIBLE) { - ((KeyguardScreen) goneScreen).onPause(); - } - if (visibleScreen.getVisibility() != View.VISIBLE) { - ((KeyguardScreen) visibleScreen).onResume(); - } - } - - if (goneScreen != null) { - goneScreen.setVisibility(View.GONE); - } - visibleScreen.setVisibility(View.VISIBLE); - requestLayout(); - - if (!visibleScreen.requestFocus()) { - throw new IllegalStateException("keyguard screen must be able to take " - + "focus when shown " + visibleScreen.getClass().getCanonicalName()); - } - } - - View createLockScreen() { - View lockView = new LockScreen( - mContext, - mConfiguration, - mLockPatternUtils, - mUpdateMonitor, - mKeyguardScreenCallback); - initializeTransportControlView(lockView); - return lockView; - } - - View createUnlockScreenFor(UnlockMode unlockMode) { - View unlockView = null; - - if (DEBUG) Log.d(TAG, - "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback); - - if (unlockMode == UnlockMode.Pattern) { - PatternUnlockScreen view = new PatternUnlockScreen( - mContext, - mConfiguration, - mLockPatternUtils, - mUpdateMonitor, - mKeyguardScreenCallback, - mUpdateMonitor.getFailedAttempts()); - view.setEnableFallback(mEnableFallback); - unlockView = view; - } else if (unlockMode == UnlockMode.SimPuk) { - unlockView = new SimPukUnlockScreen( - mContext, - mConfiguration, - mUpdateMonitor, - mKeyguardScreenCallback, - mLockPatternUtils); - } else if (unlockMode == UnlockMode.SimPin) { - unlockView = new SimUnlockScreen( - mContext, - mConfiguration, - mUpdateMonitor, - mKeyguardScreenCallback, - mLockPatternUtils); - } else if (unlockMode == UnlockMode.Account) { - try { - unlockView = new AccountUnlockScreen( - mContext, - mConfiguration, - mUpdateMonitor, - mKeyguardScreenCallback, - mLockPatternUtils); - } catch (IllegalStateException e) { - Log.i(TAG, "Couldn't instantiate AccountUnlockScreen" - + " (IAccountsService isn't available)"); - // TODO: Need a more general way to provide a - // platform-specific fallback UI here. - // For now, if we can't display the account login - // unlock UI, just bring back the regular "Pattern" unlock mode. - - // (We do this by simply returning a regular UnlockScreen - // here. This means that the user will still see the - // regular pattern unlock UI, regardless of the value of - // mUnlockScreenMode or whether or not we're in the - // "permanently locked" state.) - return createUnlockScreenFor(UnlockMode.Pattern); - } - } else if (unlockMode == UnlockMode.Password) { - unlockView = new PasswordUnlockScreen( - mContext, - mConfiguration, - mLockPatternUtils, - mUpdateMonitor, - mKeyguardScreenCallback); - } else { - throw new IllegalArgumentException("unknown unlock mode " + unlockMode); - } - initializeTransportControlView(unlockView); - initializeBiometricUnlockView(unlockView); - - mUnlockScreenMode = unlockMode; - return unlockView; - } - - private void initializeTransportControlView(View view) { - mTransportControlView = (TransportControlView) view.findViewById(R.id.transport); - if (mTransportControlView == null) { - if (DEBUG) Log.w(TAG, "Couldn't find transport control widget"); - } else { - mUpdateMonitor.reportClockVisible(true); - mTransportControlView.setVisibility(View.GONE); // hide until it requests being shown. - mTransportControlView.setCallback(mWidgetCallback); - } - } - - /** - * This returns false if there is any condition that indicates that the biometric unlock should - * not be used before the next time the unlock screen is recreated. In other words, if this - * returns false there is no need to even construct the biometric unlock. - */ - private boolean useBiometricUnlock() { - final UnlockMode unlockMode = getUnlockMode(); - final boolean backupIsTimedOut = (mUpdateMonitor.getFailedAttempts() >= - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT); - return (mLockPatternUtils.usingBiometricWeak() && - mLockPatternUtils.isBiometricWeakInstalled() && - !mUpdateMonitor.getMaxBiometricUnlockAttemptsReached() && - !backupIsTimedOut && - (unlockMode == UnlockMode.Pattern || unlockMode == UnlockMode.Password)); - } - - private void initializeBiometricUnlockView(View view) { - boolean restartBiometricUnlock = false; - - if (mBiometricUnlock != null) { - restartBiometricUnlock = mBiometricUnlock.stop(); - } - - // Prevents biometric unlock from coming up immediately after a phone call or if there - // is a dialog on top of lockscreen. It is only updated if the screen is off because if the - // screen is on it's either because of an orientation change, or when it first boots. - // In both those cases, we don't want to override the current value of - // mSuppressBiometricUnlock and instead want to use the previous value. - if (!mScreenOn) { - mSuppressBiometricUnlock = - mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE - || mHasDialog; - } - - // If the biometric unlock is not being used, we don't bother constructing it. Then we can - // simply check if it is null when deciding whether we should make calls to it. - mBiometricUnlock = null; - if (useBiometricUnlock()) { - // TODO: make faceLockAreaView a more general biometricUnlockView - // We will need to add our Face Unlock specific child views programmatically in - // initializeView rather than having them in the XML files. - View biometricUnlockView = view.findViewById(R.id.face_unlock_area_view); - if (biometricUnlockView != null) { - mBiometricUnlock = new FaceUnlock(mContext, mUpdateMonitor, mLockPatternUtils, - mKeyguardScreenCallback); - mBiometricUnlock.initializeView(biometricUnlockView); - - // If this is being called because the screen turned off, we want to cover the - // backup lock so it is covered when the screen turns back on. - if (!mScreenOn) mBiometricUnlock.show(0); - } else { - Log.w(TAG, "Couldn't find biometric unlock view"); - } - } - - if (mBiometricUnlock != null && restartBiometricUnlock) { - maybeStartBiometricUnlock(); - } - } - - /** - * Given the current state of things, what should be the initial mode of - * the lock screen (lock or unlock). - */ - private Mode getInitialMode() { - final IccCardConstants.State simState = mUpdateMonitor.getSimState(); - if (stuckOnLockScreenBecauseSimMissing() || - (simState == IccCardConstants.State.PUK_REQUIRED && - !mLockPatternUtils.isPukUnlockScreenEnable())) { - return Mode.LockScreen; - } else { - if (!isSecure() || mShowLockBeforeUnlock) { - return Mode.LockScreen; - } else { - return Mode.UnlockScreen; - } - } - } - - /** - * Given the current state of things, what should the unlock screen be? - */ - private UnlockMode getUnlockMode() { - final IccCardConstants.State simState = mUpdateMonitor.getSimState(); - UnlockMode currentMode; - if (simState == IccCardConstants.State.PIN_REQUIRED) { - currentMode = UnlockMode.SimPin; - } else if (simState == IccCardConstants.State.PUK_REQUIRED) { - currentMode = UnlockMode.SimPuk; - } else { - final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality(); - switch (mode) { - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: - case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: - currentMode = UnlockMode.Password; - break; - case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: - case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: - 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.Unknown; - } - break; - default: - throw new IllegalStateException("Unknown unlock mode:" + mode); - } - } - return currentMode; - } - - private void showDialog(String title, String message) { - mHasDialog = true; - final AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(title) - .setMessage(message) - .setNeutralButton(R.string.ok, null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - dialog.show(); - } - - private void showTimeoutDialog() { - int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; - int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message; - if (getUnlockMode() == UnlockMode.Password) { - if(mLockPatternUtils.getKeyguardStoredPasswordQuality() == - DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { - messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message; - } else { - messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message; - } - } - String message = mContext.getString(messageId, mUpdateMonitor.getFailedAttempts(), - timeoutInSeconds); - - showDialog(null, message); - } - - private void showAlmostAtAccountLoginDialog() { - final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; - final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; - String message = mContext.getString(R.string.lockscreen_failed_attempts_almost_glogin, - count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); - showDialog(null, message); - } - - private void showAlmostAtWipeDialog(int attempts, int remaining) { - int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; - String message = mContext.getString( - R.string.lockscreen_failed_attempts_almost_at_wipe, attempts, remaining); - showDialog(null, message); - } - - private void showWipeDialog(int attempts) { - String message = mContext.getString( - R.string.lockscreen_failed_attempts_now_wiping, attempts); - showDialog(null, message); - } - - /** - * Used to put wallpaper on the background of the lock screen. Centers it - * Horizontally and pins the bottom (assuming that the lock screen is aligned - * with the bottom, so the wallpaper should extend above the top into the - * status bar). - */ - static private class FastBitmapDrawable extends Drawable { - private Bitmap mBitmap; - private int mOpacity; - - private FastBitmapDrawable(Bitmap bitmap) { - mBitmap = bitmap; - mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; - } - - @Override - public void draw(Canvas canvas) { - canvas.drawBitmap( - mBitmap, - (getBounds().width() - mBitmap.getWidth()) / 2, - (getBounds().height() - mBitmap.getHeight()), - null); - } - - @Override - public int getOpacity() { - return mOpacity; - } - - @Override - public void setAlpha(int alpha) { - } - - @Override - public void setColorFilter(ColorFilter cf) { - } - - @Override - public int getIntrinsicWidth() { - return mBitmap.getWidth(); - } - - @Override - public int getIntrinsicHeight() { - return mBitmap.getHeight(); - } - - @Override - public int getMinimumWidth() { - return mBitmap.getWidth(); - } - - @Override - public int getMinimumHeight() { - return mBitmap.getHeight(); - } - } - - /** - * Starts the biometric unlock if it should be started based on a number of factors including - * the mSuppressBiometricUnlock flag. If it should not be started, it hides the biometric - * unlock area. - */ - private void maybeStartBiometricUnlock() { - if (mBiometricUnlock != null) { - final boolean backupIsTimedOut = (mUpdateMonitor.getFailedAttempts() >= - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT); - if (!mSuppressBiometricUnlock - && mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE - && !mUpdateMonitor.getMaxBiometricUnlockAttemptsReached() - && !backupIsTimedOut) { - mBiometricUnlock.start(); - } else { - mBiometricUnlock.hide(); - } - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardViewProperties.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardViewProperties.java deleted file mode 100644 index 5d9cc8e..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardViewProperties.java +++ /dev/null @@ -1,64 +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.keyguard_obsolete; - -import com.android.internal.widget.LockPatternUtils; - -import android.content.Context; -import com.android.internal.telephony.IccCardConstants; - -/** - * Knows how to create a lock pattern keyguard view, and answer questions about - * it (even if it hasn't been created, per the interface specs). - */ -public class LockPatternKeyguardViewProperties implements KeyguardViewProperties { - - private final LockPatternUtils mLockPatternUtils; - private final KeyguardUpdateMonitor mUpdateMonitor; - - /** - * @param lockPatternUtils Used to know whether the pattern enabled, and passed - * onto the keygaurd view when it is created. - * @param updateMonitor Used to know whether the sim pin is enabled, and passed - * onto the keyguard view when it is created. - */ - public LockPatternKeyguardViewProperties(LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor) { - mLockPatternUtils = lockPatternUtils; - mUpdateMonitor = updateMonitor; - } - - public KeyguardViewBase createKeyguardView(Context context, - KeyguardViewCallback callback, - KeyguardUpdateMonitor updateMonitor, - KeyguardWindowController controller) { - return new LockPatternKeyguardView(context, callback, updateMonitor, - mLockPatternUtils, controller); - } - - public boolean isSecure() { - return mLockPatternUtils.isSecure() || isSimPinSecure(); - } - - private boolean isSimPinSecure() { - final IccCardConstants.State simState = mUpdateMonitor.getSimState(); - return (simState == IccCardConstants.State.PIN_REQUIRED - || simState == IccCardConstants.State.PUK_REQUIRED - || simState == IccCardConstants.State.PERM_DISABLED); - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockScreen.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockScreen.java deleted file mode 100644 index 4e9a1f7..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/LockScreen.java +++ /dev/null @@ -1,619 +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.keyguard_obsolete; - -import com.android.internal.R; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.SlidingTab; -import com.android.internal.widget.WaveView; -import com.android.internal.widget.multiwaveview.GlowPadView; - -import android.app.ActivityManager; -import android.app.ActivityManagerNative; -import android.app.SearchManager; -import android.content.ActivityNotFoundException; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.UserHandle; -import android.os.Vibrator; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.*; -import android.util.Log; -import android.util.Slog; -import android.media.AudioManager; -import android.os.RemoteException; -import android.provider.MediaStore; - -import java.io.File; - -/** - * The screen within {@link LockPatternKeyguardView} that shows general - * information about the device depending on its state, and how to get - * past it, as applicable. - */ -class LockScreen extends LinearLayout implements KeyguardScreen { - - private static final int ON_RESUME_PING_DELAY = 500; // delay first ping until the screen is on - private static final boolean DBG = false; - private static final String TAG = "LockScreen"; - private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; - private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0; - private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; - private static final String ASSIST_ICON_METADATA_NAME = - "com.android.systemui.action_assist_icon"; - - private LockPatternUtils mLockPatternUtils; - private KeyguardUpdateMonitor mUpdateMonitor; - private KeyguardScreenCallback mCallback; - - // set to 'true' to show the ring/silence target when camera isn't available - private boolean mEnableRingSilenceFallback = false; - - // current configuration state of keyboard and display - private int mCreationOrientation; - - private boolean mSilentMode; - private AudioManager mAudioManager; - private boolean mEnableMenuKeyInLockScreen; - - private KeyguardStatusViewManager mStatusViewManager; - private UnlockWidgetCommonMethods mUnlockWidgetMethods; - private View mUnlockWidget; - private boolean mCameraDisabled; - private boolean mSearchDisabled; - // Is there a vibrator - private final boolean mHasVibrator; - - KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onRingerModeChanged(int state) { - boolean silent = AudioManager.RINGER_MODE_NORMAL != state; - if (silent != mSilentMode) { - mSilentMode = silent; - mUnlockWidgetMethods.updateResources(); - } - } - - @Override - public void onDevicePolicyManagerStateChanged() { - updateTargets(); - } - - @Override - public void onSimStateChanged(IccCardConstants.State simState) { - updateTargets(); - } - }; - - private interface UnlockWidgetCommonMethods { - // Update resources based on phone state - public void updateResources(); - - // Get the view associated with this widget - public View getView(); - - // Reset the view - public void reset(boolean animate); - - // Animate the widget if it supports ping() - public void ping(); - - // Enable or disable a target. ResourceId is the id of the *drawable* associated with the - // target. - public void setEnabled(int resourceId, boolean enabled); - - // Get the target position for the given resource. Returns -1 if not found. - public int getTargetPosition(int resourceId); - - // Clean up when this widget is going away - public void cleanUp(); - } - - class SlidingTabMethods implements SlidingTab.OnTriggerListener, UnlockWidgetCommonMethods { - private final SlidingTab mSlidingTab; - - SlidingTabMethods(SlidingTab slidingTab) { - mSlidingTab = slidingTab; - } - - public void updateResources() { - boolean vibe = mSilentMode - && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); - - mSlidingTab.setRightTabResources( - mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on - : R.drawable.ic_jog_dial_sound_off ) - : R.drawable.ic_jog_dial_sound_on, - mSilentMode ? R.drawable.jog_tab_target_yellow - : R.drawable.jog_tab_target_gray, - mSilentMode ? R.drawable.jog_tab_bar_right_sound_on - : R.drawable.jog_tab_bar_right_sound_off, - mSilentMode ? R.drawable.jog_tab_right_sound_on - : R.drawable.jog_tab_right_sound_off); - } - - /** {@inheritDoc} */ - public void onTrigger(View v, int whichHandle) { - if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { - mCallback.goToUnlockScreen(); - } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - toggleRingMode(); - mCallback.pokeWakelock(); - } - } - - /** {@inheritDoc} */ - public void onGrabbedStateChange(View v, int grabbedState) { - if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - mSilentMode = isSilentMode(); - mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label - : R.string.lockscreen_sound_off_label); - } - // Don't poke the wake lock when returning to a state where the handle is - // not grabbed since that can happen when the system (instead of the user) - // cancels the grab. - if (grabbedState != SlidingTab.OnTriggerListener.NO_HANDLE) { - mCallback.pokeWakelock(); - } - } - - public View getView() { - return mSlidingTab; - } - - public void reset(boolean animate) { - mSlidingTab.reset(animate); - } - - public void ping() { - } - - public void setEnabled(int resourceId, boolean enabled) { - // Not used - } - - public int getTargetPosition(int resourceId) { - return -1; // Not supported - } - - public void cleanUp() { - mSlidingTab.setOnTriggerListener(null); - } - } - - class WaveViewMethods implements WaveView.OnTriggerListener, UnlockWidgetCommonMethods { - - private final WaveView mWaveView; - - WaveViewMethods(WaveView waveView) { - mWaveView = waveView; - } - /** {@inheritDoc} */ - public void onTrigger(View v, int whichHandle) { - if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) { - requestUnlockScreen(); - } - } - - /** {@inheritDoc} */ - public void onGrabbedStateChange(View v, int grabbedState) { - // Don't poke the wake lock when returning to a state where the handle is - // not grabbed since that can happen when the system (instead of the user) - // cancels the grab. - if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) { - mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT); - } - } - - public void updateResources() { - } - - public View getView() { - return mWaveView; - } - public void reset(boolean animate) { - mWaveView.reset(); - } - public void ping() { - } - public void setEnabled(int resourceId, boolean enabled) { - // Not used - } - public int getTargetPosition(int resourceId) { - return -1; // Not supported - } - public void cleanUp() { - mWaveView.setOnTriggerListener(null); - } - } - - class GlowPadViewMethods implements GlowPadView.OnTriggerListener, - UnlockWidgetCommonMethods { - private final GlowPadView mGlowPadView; - - GlowPadViewMethods(GlowPadView glowPadView) { - mGlowPadView = glowPadView; - } - - public boolean isTargetPresent(int resId) { - return mGlowPadView.getTargetPosition(resId) != -1; - } - - public void updateResources() { - int resId; - if (mCameraDisabled && mEnableRingSilenceFallback) { - // Fall back to showing ring/silence if camera is disabled... - resId = mSilentMode ? R.array.lockscreen_targets_when_silent - : R.array.lockscreen_targets_when_soundon; - } else { - resId = R.array.lockscreen_targets_with_camera; - } - if (mGlowPadView.getTargetResourceId() != resId) { - mGlowPadView.setTargetResources(resId); - } - - // Update the search icon with drawable from the search .apk - if (!mSearchDisabled) { - Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); - if (intent != null) { - // XXX Hack. We need to substitute the icon here but haven't formalized - // the public API. The "_google" metadata will be going away, so - // DON'T USE IT! - ComponentName component = intent.getComponent(); - boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component, - ASSIST_ICON_METADATA_NAME + "_google", - com.android.internal.R.drawable.ic_action_assist_generic); - - if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component, - ASSIST_ICON_METADATA_NAME, - com.android.internal.R.drawable.ic_action_assist_generic)) { - Slog.w(TAG, "Couldn't grab icon from package " + component); - } - } - } - - setEnabled(com.android.internal.R.drawable.ic_lockscreen_camera, !mCameraDisabled); - setEnabled(com.android.internal.R.drawable.ic_action_assist_generic, !mSearchDisabled); - } - - public void onGrabbed(View v, int handle) { - - } - - public void onReleased(View v, int handle) { - - } - - public void onTrigger(View v, int target) { - final int resId = mGlowPadView.getResourceIdForTarget(target); - switch (resId) { - case com.android.internal.R.drawable.ic_action_assist_generic: - Intent assistIntent = - ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT); - if (assistIntent != null) { - launchActivity(assistIntent); - } else { - Log.w(TAG, "Failed to get intent for assist activity"); - } - mCallback.pokeWakelock(); - break; - - case com.android.internal.R.drawable.ic_lockscreen_camera: - launchActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA)); - mCallback.pokeWakelock(); - break; - - case com.android.internal.R.drawable.ic_lockscreen_silent: - toggleRingMode(); - mCallback.pokeWakelock(); - break; - - case com.android.internal.R.drawable.ic_lockscreen_unlock_phantom: - case com.android.internal.R.drawable.ic_lockscreen_unlock: - mCallback.goToUnlockScreen(); - break; - } - } - - /** - * Launches the said intent for the current foreground user. - * @param intent - */ - private void launchActivity(Intent intent) { - intent.setFlags( - Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_SINGLE_TOP - | Intent.FLAG_ACTIVITY_CLEAR_TOP); - try { - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); - } catch (RemoteException e) { - Log.w(TAG, "can't dismiss keyguard on launch"); - } - try { - mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "Activity not found for intent + " + intent.getAction()); - } - } - - public void onGrabbedStateChange(View v, int handle) { - // Don't poke the wake lock when returning to a state where the handle is - // not grabbed since that can happen when the system (instead of the user) - // cancels the grab. - if (handle != GlowPadView.OnTriggerListener.NO_HANDLE) { - mCallback.pokeWakelock(); - } - } - - public View getView() { - return mGlowPadView; - } - - public void reset(boolean animate) { - mGlowPadView.reset(animate); - } - - public void ping() { - mGlowPadView.ping(); - } - - public void setEnabled(int resourceId, boolean enabled) { - mGlowPadView.setEnableTarget(resourceId, enabled); - } - - public int getTargetPosition(int resourceId) { - return mGlowPadView.getTargetPosition(resourceId); - } - - public void cleanUp() { - mGlowPadView.setOnTriggerListener(null); - } - - public void onFinishFinalAnimation() { - - } - } - - private void requestUnlockScreen() { - // Delay hiding lock screen long enough for animation to finish - postDelayed(new Runnable() { - public void run() { - mCallback.goToUnlockScreen(); - } - }, WAIT_FOR_ANIMATION_TIMEOUT); - } - - private void toggleRingMode() { - // toggle silent mode - mSilentMode = !mSilentMode; - if (mSilentMode) { - mAudioManager.setRingerMode(mHasVibrator - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - } - } - - /** - * In general, we enable unlocking the insecure key guard with the menu key. However, there are - * some cases where we wish to disable it, notably when the menu button placement or technology - * is prone to false positives. - * - * @return true if the menu key should be enabled - */ - private boolean shouldEnableMenuKey() { - final Resources res = getResources(); - final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); - final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); - final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); - return !configDisabled || isTestHarness || fileOverride; - } - - /** - * @param context Used to setup the view. - * @param configuration The current configuration. Used to use when selecting layout, etc. - * @param lockPatternUtils Used to know the state of the lock pattern settings. - * @param updateMonitor Used to register for updates on various keyguard related - * state, and query the initial state at setup. - * @param callback Used to communicate back to the host keyguard view. - */ - LockScreen(Context context, Configuration configuration, LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback) { - super(context); - mLockPatternUtils = lockPatternUtils; - mUpdateMonitor = updateMonitor; - mCallback = callback; - mEnableMenuKeyInLockScreen = shouldEnableMenuKey(); - mCreationOrientation = configuration.orientation; - - if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { - Log.v(TAG, "***** CREATING LOCK SCREEN", new RuntimeException()); - Log.v(TAG, "Cur orient=" + mCreationOrientation - + " res orient=" + context.getResources().getConfiguration().orientation); - } - - final LayoutInflater inflater = LayoutInflater.from(context); - if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation); - if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { - inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true); - } else { - inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true); - } - - mStatusViewManager = new KeyguardStatusViewManager(this, mUpdateMonitor, mLockPatternUtils, - mCallback, false); - - setFocusable(true); - setFocusableInTouchMode(true); - setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - - Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - mSilentMode = isSilentMode(); - mUnlockWidget = findViewById(R.id.unlock_widget); - mUnlockWidgetMethods = createUnlockMethods(mUnlockWidget); - - if (DBG) Log.v(TAG, "*** LockScreen accel is " - + (mUnlockWidget.isHardwareAccelerated() ? "on":"off")); - } - - private UnlockWidgetCommonMethods createUnlockMethods(View unlockWidget) { - if (unlockWidget instanceof SlidingTab) { - SlidingTab slidingTabView = (SlidingTab) unlockWidget; - slidingTabView.setHoldAfterTrigger(true, false); - slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label); - slidingTabView.setLeftTabResources( - R.drawable.ic_jog_dial_unlock, - R.drawable.jog_tab_target_green, - R.drawable.jog_tab_bar_left_unlock, - R.drawable.jog_tab_left_unlock); - SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView); - slidingTabView.setOnTriggerListener(slidingTabMethods); - return slidingTabMethods; - } else if (unlockWidget instanceof WaveView) { - WaveView waveView = (WaveView) unlockWidget; - WaveViewMethods waveViewMethods = new WaveViewMethods(waveView); - waveView.setOnTriggerListener(waveViewMethods); - return waveViewMethods; - } else if (unlockWidget instanceof GlowPadView) { - GlowPadView glowPadView = (GlowPadView) unlockWidget; - GlowPadViewMethods glowPadViewMethods = new GlowPadViewMethods(glowPadView); - glowPadView.setOnTriggerListener(glowPadViewMethods); - return glowPadViewMethods; - } else { - throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget); - } - } - - private void updateTargets() { - boolean disabledByAdmin = mLockPatternUtils.getDevicePolicyManager() - .getCameraDisabled(null); - boolean disabledBySimState = mUpdateMonitor.isSimLocked(); - boolean cameraTargetPresent = (mUnlockWidgetMethods instanceof GlowPadViewMethods) - ? ((GlowPadViewMethods) mUnlockWidgetMethods) - .isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_camera) - : false; - boolean searchTargetPresent = (mUnlockWidgetMethods instanceof GlowPadViewMethods) - ? ((GlowPadViewMethods) mUnlockWidgetMethods) - .isTargetPresent(com.android.internal.R.drawable.ic_action_assist_generic) - : false; - - if (disabledByAdmin) { - Log.v(TAG, "Camera disabled by Device Policy"); - } else if (disabledBySimState) { - Log.v(TAG, "Camera disabled by Sim State"); - } - boolean searchActionAvailable = - ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; - mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent; - mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent; - mUnlockWidgetMethods.updateResources(); - } - - private boolean isSilentMode() { - return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) { - mCallback.goToUnlockScreen(); - } - return false; - } - - void updateConfiguration() { - Configuration newConfig = getResources().getConfiguration(); - if (newConfig.orientation != mCreationOrientation) { - mCallback.recreateMe(newConfig); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { - Log.v(TAG, "***** LOCK ATTACHED TO WINDOW"); - Log.v(TAG, "Cur orient=" + mCreationOrientation - + ", new config=" + getResources().getConfiguration()); - } - updateConfiguration(); - } - - /** {@inheritDoc} */ - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { - Log.w(TAG, "***** LOCK CONFIG CHANGING", new RuntimeException()); - Log.v(TAG, "Cur orient=" + mCreationOrientation - + ", new config=" + newConfig); - } - updateConfiguration(); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return false; - } - - /** {@inheritDoc} */ - public void onPause() { - mUpdateMonitor.removeCallback(mInfoCallback); - mStatusViewManager.onPause(); - mUnlockWidgetMethods.reset(false); - } - - private final Runnable mOnResumePing = new Runnable() { - public void run() { - mUnlockWidgetMethods.ping(); - } - }; - - /** {@inheritDoc} */ - public void onResume() { - // We don't want to show the camera target if SIM state prevents us from - // launching the camera. So watch for SIM changes... - mUpdateMonitor.registerCallback(mInfoCallback); - - mStatusViewManager.onResume(); - postDelayed(mOnResumePing, ON_RESUME_PING_DELAY); - } - - /** {@inheritDoc} */ - public void cleanUp() { - mUpdateMonitor.removeCallback(mInfoCallback); // this must be first - mUnlockWidgetMethods.cleanUp(); - mLockPatternUtils = null; - mUpdateMonitor = null; - mCallback = null; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/PasswordUnlockScreen.java deleted file mode 100644 index 87a7371..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/PasswordUnlockScreen.java +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Copyright (C) 2010 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_obsolete; - -import java.util.List; - -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Rect; - -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.PasswordEntryKeyboardView; - -import android.os.CountDownTimer; -import android.os.SystemClock; -import android.provider.Settings; -import android.security.KeyStore; -import android.text.Editable; -import android.text.InputType; -import android.text.TextWatcher; -import android.text.method.DigitsKeyListener; -import android.text.method.TextKeyListener; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.Space; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; - -import com.android.internal.R; -import com.android.internal.widget.PasswordEntryKeyboardHelper; - -/** - * Displays a dialer-like interface or alphanumeric (latin-1) key entry for the user to enter - * an unlock password - */ -public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, - OnEditorActionListener { - - private static final String TAG = "PasswordUnlockScreen"; - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardScreenCallback mCallback; - - private final boolean mIsAlpha; - - private final EditText mPasswordEntry; - private final LockPatternUtils mLockPatternUtils; - private final PasswordEntryKeyboardView mKeyboardView; - private final PasswordEntryKeyboardHelper mKeyboardHelper; - - private final int mCreationOrientation; - private final int mCreationHardKeyboardHidden; - - private final KeyguardStatusViewManager mStatusViewManager; - private final boolean mUseSystemIME = true; // TODO: Make configurable - private boolean mResuming; // used to prevent poking the wakelock during onResume() - - // To avoid accidental lockout due to events while the device in in the pocket, ignore - // any passwords with length less than or equal to this length. - private static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; - - public PasswordUnlockScreen(Context context, Configuration configuration, - LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback) { - super(context); - - mCreationHardKeyboardHidden = configuration.hardKeyboardHidden; - mCreationOrientation = configuration.orientation; - mUpdateMonitor = updateMonitor; - mCallback = callback; - mLockPatternUtils = lockPatternUtils; - - LayoutInflater layoutInflater = LayoutInflater.from(context); - if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { - layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true); - } else { - layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); - } - - mStatusViewManager = new KeyguardStatusViewManager(this, mUpdateMonitor, mLockPatternUtils, - mCallback, true); - - final int quality = lockPatternUtils.getKeyguardStoredPasswordQuality(); - mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality - || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality - || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == quality; - - mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard); - mPasswordEntry = (EditText) findViewById(R.id.passwordEntry); - mPasswordEntry.setOnEditorActionListener(this); - - mKeyboardHelper = new PasswordEntryKeyboardHelper(context, mKeyboardView, this, false); - mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled()); - boolean imeOrDeleteButtonVisible = false; - if (mIsAlpha) { - // We always use the system IME for alpha keyboard, so hide lockscreen's soft keyboard - mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA); - mKeyboardView.setVisibility(View.GONE); - } else { - // Use lockscreen's numeric keyboard if the physical keyboard isn't showing - mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC); - mKeyboardView.setVisibility(mCreationHardKeyboardHidden - == Configuration.HARDKEYBOARDHIDDEN_NO ? View.INVISIBLE : View.VISIBLE); - - // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts, - // not a separate view - View pinDelete = findViewById(R.id.pinDel); - if (pinDelete != null) { - pinDelete.setVisibility(View.VISIBLE); - imeOrDeleteButtonVisible = true; - pinDelete.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mKeyboardHelper.handleBackspace(); - } - }); - } - } - - mPasswordEntry.requestFocus(); - - // This allows keyboards with overlapping qwerty/numeric keys to choose just numeric keys. - if (mIsAlpha) { - mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); - mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_PASSWORD); - //mStatusViewManager.setHelpMessage(R.string.keyguard_password_enter_password_code, - //KeyguardStatusViewManager.LOCK_ICON); - } else { - mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); - mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER - | InputType.TYPE_NUMBER_VARIATION_PASSWORD); - //mStatusViewManager.setHelpMessage(R.string.keyguard_password_enter_pin_code, - //KeyguardStatusViewManager.LOCK_ICON); - } - - // Poke the wakelock any time the text is selected or modified - mPasswordEntry.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.pokeWakelock(); - } - }); - mPasswordEntry.addTextChangedListener(new TextWatcher() { - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - public void afterTextChanged(Editable s) { - if (!mResuming) { - mCallback.pokeWakelock(); - } - } - }); - - // If there's more than one IME, enable the IME switcher button - View switchImeButton = findViewById(R.id.switch_ime_button); - final InputMethodManager imm = (InputMethodManager) getContext().getSystemService( - Context.INPUT_METHOD_SERVICE); - if (mIsAlpha && switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) { - switchImeButton.setVisibility(View.VISIBLE); - imeOrDeleteButtonVisible = true; - switchImeButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.pokeWakelock(); // Leave the screen on a bit longer - imm.showInputMethodPicker(); - } - }); - } - - // If no icon is visible, reset the left margin on the password field so the text is - // still centered. - if (!imeOrDeleteButtonVisible) { - android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams(); - if (params instanceof MarginLayoutParams) { - ((MarginLayoutParams)params).leftMargin = 0; - mPasswordEntry.setLayoutParams(params); - } - } - } - - /** - * Method adapted from com.android.inputmethod.latin.Utils - * - * @param imm The input method manager - * @param shouldIncludeAuxiliarySubtypes - * @return true if we have multiple IMEs to choose from - */ - private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm, - final boolean shouldIncludeAuxiliarySubtypes) { - final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList(); - - // Number of the filtered IMEs - int filteredImisCount = 0; - - for (InputMethodInfo imi : enabledImis) { - // We can return true immediately after we find two or more filtered IMEs. - if (filteredImisCount > 1) return true; - final List<InputMethodSubtype> subtypes = - imm.getEnabledInputMethodSubtypeList(imi, true); - // IMEs that have no subtypes should be counted. - if (subtypes.isEmpty()) { - ++filteredImisCount; - continue; - } - - int auxCount = 0; - for (InputMethodSubtype subtype : subtypes) { - if (subtype.isAuxiliary()) { - ++auxCount; - } - } - final int nonAuxCount = subtypes.size() - auxCount; - - // IMEs that have one or more non-auxiliary subtypes should be counted. - // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary - // subtypes should be counted as well. - if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { - ++filteredImisCount; - continue; - } - } - - return filteredImisCount > 1 - // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled - // input method subtype (The current IME should be LatinIME.) - || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; - } - - @Override - protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { - // send focus to the password field - return mPasswordEntry.requestFocus(direction, previouslyFocusedRect); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return mUseSystemIME && mIsAlpha; - } - - /** {@inheritDoc} */ - public void onPause() { - mStatusViewManager.onPause(); - } - - /** {@inheritDoc} */ - public void onResume() { - mResuming = true; - // reset status - mStatusViewManager.onResume(); - - // start fresh - mPasswordEntry.setText(""); - mPasswordEntry.requestFocus(); - - // if the user is currently locked out, enforce it. - long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); - if (deadline != 0) { - handleAttemptLockout(deadline); - } - mResuming = false; - } - - /** {@inheritDoc} */ - public void cleanUp() { - mUpdateMonitor.removeCallback(this); - } - - private void verifyPasswordAndUnlock() { - String entry = mPasswordEntry.getText().toString(); - if (mLockPatternUtils.checkPassword(entry)) { - mCallback.keyguardDone(true); - mCallback.reportSuccessfulUnlockAttempt(); - mStatusViewManager.setInstructionText(null); - KeyStore.getInstance().password(entry); - } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) { - // to avoid accidental lockout, only count attempts that are long enough to be a - // real password. This may require some tweaking. - mCallback.reportFailedUnlockAttempt(); - if (0 == (mUpdateMonitor.getFailedAttempts() - % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { - long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); - handleAttemptLockout(deadline); - } - mStatusViewManager.setInstructionText( - mContext.getString(R.string.lockscreen_password_wrong)); - } else if (entry.length() > 0) { - mStatusViewManager.setInstructionText( - mContext.getString(R.string.lockscreen_password_wrong)); - } - mPasswordEntry.setText(""); - } - - // Prevent user from using the PIN/Password entry until scheduled deadline. - private void handleAttemptLockout(long elapsedRealtimeDeadline) { - mPasswordEntry.setEnabled(false); - mKeyboardView.setEnabled(false); - long elapsedRealtime = SystemClock.elapsedRealtime(); - new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { - - @Override - public void onTick(long millisUntilFinished) { - int secondsRemaining = (int) (millisUntilFinished / 1000); - String instructions = getContext().getString( - R.string.lockscreen_too_many_failed_attempts_countdown, - secondsRemaining); - mStatusViewManager.setInstructionText(instructions); - } - - @Override - public void onFinish() { - mPasswordEntry.setEnabled(true); - mKeyboardView.setEnabled(true); - mStatusViewManager.resetStatusInfo(); - } - }.start(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - mCallback.pokeWakelock(); - return false; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Configuration config = getResources().getConfiguration(); - if (config.orientation != mCreationOrientation - || config.hardKeyboardHidden != mCreationHardKeyboardHidden) { - mCallback.recreateMe(config); - } - } - - /** {@inheritDoc} */ - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - if (newConfig.orientation != mCreationOrientation - || newConfig.hardKeyboardHidden != mCreationHardKeyboardHidden) { - mCallback.recreateMe(newConfig); - } - } - - public void onKeyboardChange(boolean isKeyboardOpen) { - // Don't show the soft keyboard when the real keyboard is open - mKeyboardView.setVisibility(isKeyboardOpen ? View.INVISIBLE : View.VISIBLE); - } - - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - // Check if this was the result of hitting the enter key - if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE - || actionId == EditorInfo.IME_ACTION_NEXT) { - verifyPasswordAndUnlock(); - return true; - } - return false; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/PatternUnlockScreen.java deleted file mode 100644 index 6d5706b..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/PatternUnlockScreen.java +++ /dev/null @@ -1,416 +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.keyguard_obsolete; - -import android.content.Context; -import android.content.res.Configuration; -import android.os.CountDownTimer; -import android.os.SystemClock; -import android.security.KeyStore; -import android.view.LayoutInflater; -import android.view.View; -import android.view.MotionEvent; -import android.widget.Button; -import android.util.Log; -import com.android.internal.R; -import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient; -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.LockPatternView; -import com.android.internal.widget.LockPatternView.Cell; - -import java.util.List; - -/** - * This is the screen that shows the 9 circle unlock widget and instructs - * the user how to unlock their device, or make an emergency call. - */ -class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient - implements KeyguardScreen { - - private static final boolean DEBUG = false; - private static final String TAG = "UnlockScreen"; - - // how long before we clear the wrong pattern - private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; - - // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK - private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; - - // how long we stay awake after the user hits the first dot. - private static final int UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS = 2000; - - // how many cells the user has to cross before we poke the wakelock - private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; - - private int mFailedPatternAttemptsSinceLastTimeout = 0; - private int mTotalFailedPatternAttempts = 0; - private CountDownTimer mCountdownTimer = null; - - private LockPatternUtils mLockPatternUtils; - private KeyguardUpdateMonitor mUpdateMonitor; - private KeyguardScreenCallback mCallback; - - /** - * whether there is a fallback option available when the pattern is forgotten. - */ - private boolean mEnableFallback; - - private KeyguardStatusViewManager mKeyguardStatusViewManager; - private LockPatternView mLockPatternView; - - /** - * Keeps track of the last time we poked the wake lock during dispatching - * of the touch event, initalized to something gauranteed to make us - * poke it when the user starts drawing the pattern. - * @see #dispatchTouchEvent(android.view.MotionEvent) - */ - private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS; - - /** - * Useful for clearing out the wrong pattern after a delay - */ - private Runnable mCancelPatternRunnable = new Runnable() { - public void run() { - mLockPatternView.clearPattern(); - } - }; - - private final OnClickListener mForgotPatternClick = new OnClickListener() { - public void onClick(View v) { - mCallback.forgotPattern(true); - } - }; - - private Button mForgotPatternButton; - private int mCreationOrientation; - - enum FooterMode { - Normal, - ForgotLockPattern, - VerifyUnlocked - } - - private void hideForgotPatternButton() { - mForgotPatternButton.setVisibility(View.GONE); - } - - private void showForgotPatternButton() { - mForgotPatternButton.setVisibility(View.VISIBLE); - } - - private void updateFooter(FooterMode mode) { - switch (mode) { - case Normal: - if (DEBUG) Log.d(TAG, "mode normal"); - hideForgotPatternButton(); - break; - case ForgotLockPattern: - if (DEBUG) Log.d(TAG, "mode ForgotLockPattern"); - showForgotPatternButton(); - break; - case VerifyUnlocked: - if (DEBUG) Log.d(TAG, "mode VerifyUnlocked"); - hideForgotPatternButton(); - } - } - - /** - * @param context The context. - * @param configuration - * @param lockPatternUtils Used to lookup lock pattern settings. - * @param updateMonitor Used to lookup state affecting keyguard. - * @param callback Used to notify the manager when we're done, etc. - * @param totalFailedAttempts The current number of failed attempts. - * @param enableFallback True if a backup unlock option is available when the user has forgotten - * their pattern (e.g they have a google account so we can show them the account based - * backup option). - */ - PatternUnlockScreen(Context context, - Configuration configuration, LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor updateMonitor, - KeyguardScreenCallback callback, - int totalFailedAttempts) { - super(context); - mLockPatternUtils = lockPatternUtils; - mUpdateMonitor = updateMonitor; - mCallback = callback; - mTotalFailedPatternAttempts = totalFailedAttempts; - mFailedPatternAttemptsSinceLastTimeout = - totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; - - if (DEBUG) Log.d(TAG, - "UnlockScreen() ctor: totalFailedAttempts=" - + totalFailedAttempts + ", mFailedPat...=" - + mFailedPatternAttemptsSinceLastTimeout - ); - - mCreationOrientation = configuration.orientation; - - LayoutInflater inflater = LayoutInflater.from(context); - - if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { - Log.d(TAG, "portrait mode"); - inflater.inflate(R.layout.keyguard_screen_unlock_portrait, this, true); - } else { - Log.d(TAG, "landscape mode"); - inflater.inflate(R.layout.keyguard_screen_unlock_landscape, this, true); - } - - mKeyguardStatusViewManager = new KeyguardStatusViewManager(this, mUpdateMonitor, - mLockPatternUtils, mCallback, true); - - mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern); - - mForgotPatternButton = (Button) findViewById(R.id.forgotPatternButton); - mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text); - mForgotPatternButton.setOnClickListener(mForgotPatternClick); - - // make it so unhandled touch events within the unlock screen go to the - // lock pattern view. - setDefaultTouchRecepient(mLockPatternView); - - mLockPatternView.setSaveEnabled(false); - mLockPatternView.setFocusable(false); - mLockPatternView.setOnPatternListener(new UnlockPatternListener()); - - // stealth mode will be the same for the life of this screen - mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled()); - - // vibrate mode will be the same for the life of this screen - mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); - - // assume normal footer mode for now - updateFooter(FooterMode.Normal); - - setFocusableInTouchMode(true); - } - - public void setEnableFallback(boolean state) { - if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")"); - mEnableFallback = state; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - // as long as the user is entering a pattern (i.e sending a touch - // event that was handled by this screen), keep poking the - // wake lock so that the screen will stay on. - final boolean result = super.dispatchTouchEvent(ev); - if (result && - ((SystemClock.elapsedRealtime() - mLastPokeTime) - > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) { - mLastPokeTime = SystemClock.elapsedRealtime(); - } - return result; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { - Log.v(TAG, "***** PATTERN ATTACHED TO WINDOW"); - Log.v(TAG, "Cur orient=" + mCreationOrientation - + ", new config=" + getResources().getConfiguration()); - } - if (getResources().getConfiguration().orientation != mCreationOrientation) { - mCallback.recreateMe(getResources().getConfiguration()); - } - } - - - /** {@inheritDoc} */ - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { - Log.v(TAG, "***** PATTERN CONFIGURATION CHANGED"); - Log.v(TAG, "Cur orient=" + mCreationOrientation - + ", new config=" + getResources().getConfiguration()); - } - if (newConfig.orientation != mCreationOrientation) { - mCallback.recreateMe(newConfig); - } - } - - /** {@inheritDoc} */ - public void onKeyboardChange(boolean isKeyboardOpen) {} - - /** {@inheritDoc} */ - public boolean needsInput() { - return false; - } - - /** {@inheritDoc} */ - public void onPause() { - if (mCountdownTimer != null) { - mCountdownTimer.cancel(); - mCountdownTimer = null; - } - mKeyguardStatusViewManager.onPause(); - } - - /** {@inheritDoc} */ - public void onResume() { - // reset status - mKeyguardStatusViewManager.onResume(); - - // reset lock pattern - mLockPatternView.enableInput(); - mLockPatternView.setEnabled(true); - mLockPatternView.clearPattern(); - - // show "forgot pattern?" button if we have an alternate authentication method - if (mCallback.doesFallbackUnlockScreenExist()) { - showForgotPatternButton(); - } else { - hideForgotPatternButton(); - } - - // if the user is currently locked out, enforce it. - long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); - if (deadline != 0) { - handleAttemptLockout(deadline); - } - - // the footer depends on how many total attempts the user has failed - if (mCallback.isVerifyUnlockOnly()) { - updateFooter(FooterMode.VerifyUnlocked); - } else if (mEnableFallback && - (mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { - updateFooter(FooterMode.ForgotLockPattern); - } else { - updateFooter(FooterMode.Normal); - } - - } - - /** {@inheritDoc} */ - public void cleanUp() { - if (DEBUG) Log.v(TAG, "Cleanup() called on " + this); - mUpdateMonitor.removeCallback(this); - mLockPatternUtils = null; - mUpdateMonitor = null; - mCallback = null; - mLockPatternView.setOnPatternListener(null); - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - super.onWindowFocusChanged(hasWindowFocus); - if (hasWindowFocus) { - // when timeout dialog closes we want to update our state - onResume(); - } - } - - private class UnlockPatternListener - implements LockPatternView.OnPatternListener { - - public void onPatternStart() { - mLockPatternView.removeCallbacks(mCancelPatternRunnable); - } - - public void onPatternCleared() { - } - - public void onPatternCellAdded(List<Cell> pattern) { - // To guard against accidental poking of the wakelock, look for - // the user actually trying to draw a pattern of some minimal length. - if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); - } else { - // Give just a little extra time if they hit one of the first few dots - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS); - } - } - - public void onPatternDetected(List<LockPatternView.Cell> pattern) { - if (mLockPatternUtils.checkPattern(pattern)) { - mLockPatternView - .setDisplayMode(LockPatternView.DisplayMode.Correct); - mKeyguardStatusViewManager.setInstructionText(""); - mKeyguardStatusViewManager.updateStatusLines(true); - mCallback.keyguardDone(true); - mCallback.reportSuccessfulUnlockAttempt(); - KeyStore.getInstance().password(LockPatternUtils.patternToString(pattern)); - } else { - boolean reportFailedAttempt = false; - if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { - mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); - } - mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); - if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { - mTotalFailedPatternAttempts++; - mFailedPatternAttemptsSinceLastTimeout++; - reportFailedAttempt = true; - } - if (mFailedPatternAttemptsSinceLastTimeout - >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { - long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); - handleAttemptLockout(deadline); - } else { - // TODO mUnlockIcon.setVisibility(View.VISIBLE); - mKeyguardStatusViewManager.setInstructionText( - getContext().getString(R.string.lockscreen_pattern_wrong)); - mKeyguardStatusViewManager.updateStatusLines(true); - mLockPatternView.postDelayed( - mCancelPatternRunnable, - PATTERN_CLEAR_TIMEOUT_MS); - } - - // Because the following can result in cleanUp() being called on this screen, - // member variables reset in cleanUp() shouldn't be accessed after this call. - if (reportFailedAttempt) { - mCallback.reportFailedUnlockAttempt(); - } - } - } - } - - private void handleAttemptLockout(long elapsedRealtimeDeadline) { - mLockPatternView.clearPattern(); - mLockPatternView.setEnabled(false); - long elapsedRealtime = SystemClock.elapsedRealtime(); - mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { - - @Override - public void onTick(long millisUntilFinished) { - int secondsRemaining = (int) (millisUntilFinished / 1000); - mKeyguardStatusViewManager.setInstructionText(getContext().getString( - R.string.lockscreen_too_many_failed_attempts_countdown, - secondsRemaining)); - mKeyguardStatusViewManager.updateStatusLines(true); - } - - @Override - public void onFinish() { - mLockPatternView.setEnabled(true); - mKeyguardStatusViewManager.setInstructionText(getContext().getString( - R.string.lockscreen_pattern_instructions)); - mKeyguardStatusViewManager.updateStatusLines(true); - // TODO mUnlockIcon.setVisibility(View.VISIBLE); - mFailedPatternAttemptsSinceLastTimeout = 0; - if (mEnableFallback) { - updateFooter(FooterMode.ForgotLockPattern); - } else { - updateFooter(FooterMode.Normal); - } - } - }.start(); - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/SimPukUnlockScreen.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/SimPukUnlockScreen.java deleted file mode 100644 index 3c1703a..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/SimPukUnlockScreen.java +++ /dev/null @@ -1,422 +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.keyguard_obsolete; - -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.res.Configuration; -import android.os.RemoteException; -import android.os.ServiceManager; - -import com.android.internal.telephony.ITelephony; -import com.android.internal.widget.LockPatternUtils; - -import android.text.Editable; -import android.util.Log; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.android.internal.R; - -/** - * Displays a dialer like interface to unlock the SIM PUK. - */ -public class SimPukUnlockScreen extends LinearLayout implements KeyguardScreen, - View.OnClickListener, View.OnFocusChangeListener { - - private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; - - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardScreenCallback mCallback; - private KeyguardStatusViewManager mKeyguardStatusViewManager; - - private TextView mHeaderText; - private TextView mPukText; - private TextView mPinText; - private TextView mFocusedEntry; - - private View mOkButton; - private View mDelPukButton; - private View mDelPinButton; - - private ProgressDialog mSimUnlockProgressDialog = null; - - private LockPatternUtils mLockPatternUtils; - - private int mCreationOrientation; - - private int mKeyboardHidden; - - private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - - public SimPukUnlockScreen(Context context, Configuration configuration, - KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, - LockPatternUtils lockpatternutils) { - super(context); - mUpdateMonitor = updateMonitor; - mCallback = callback;; - - mCreationOrientation = configuration.orientation; - mKeyboardHidden = configuration.hardKeyboardHidden; - mLockPatternUtils = lockpatternutils; - - LayoutInflater inflater = LayoutInflater.from(context); - if (mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { - inflater.inflate( - R.layout.keyguard_screen_sim_puk_landscape, this, true); - } else { - inflater.inflate( - R.layout.keyguard_screen_sim_puk_portrait, this, true); - new TouchInput(); - } - - mHeaderText = (TextView) findViewById(R.id.headerText); - - mPukText = (TextView) findViewById(R.id.pukDisplay); - mPinText = (TextView) findViewById(R.id.pinDisplay); - mDelPukButton = findViewById(R.id.pukDel); - mDelPinButton = findViewById(R.id.pinDel); - mOkButton = findViewById(R.id.ok); - - mDelPinButton.setOnClickListener(this); - mDelPukButton.setOnClickListener(this); - mOkButton.setOnClickListener(this); - - mHeaderText.setText(R.string.keyguard_password_enter_puk_code); - // To make marquee work - mHeaderText.setSelected(true); - - mKeyguardStatusViewManager = new KeyguardStatusViewManager(this, updateMonitor, - lockpatternutils, callback, true); - - mPinText.setFocusableInTouchMode(true); - mPinText.setOnFocusChangeListener(this); - mPukText.setFocusableInTouchMode(true); - mPukText.setOnFocusChangeListener(this); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return false; - } - - /** {@inheritDoc} */ - public void onPause() { - mKeyguardStatusViewManager.onPause(); - } - - /** {@inheritDoc} */ - public void onResume() { - // start fresh - mHeaderText.setText(R.string.keyguard_password_enter_puk_code); - mKeyguardStatusViewManager.onResume(); - } - - /** {@inheritDoc} */ - public void cleanUp() { - // dismiss the dialog. - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.dismiss(); - mSimUnlockProgressDialog = null; - } - mUpdateMonitor.removeCallback(this); - } - - - /** - * Since the IPC can block, we want to run the request in a separate thread - * with a callback. - */ - private abstract class CheckSimPuk extends Thread { - - private final String mPin, mPuk; - - protected CheckSimPuk(String puk, String pin) { - mPuk = puk; - mPin = pin; - } - - abstract void onSimLockChangedResponse(boolean success); - - @Override - public void run() { - try { - final boolean result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPuk(mPuk, mPin); - - post(new Runnable() { - public void run() { - onSimLockChangedResponse(result); - } - }); - } catch (RemoteException e) { - post(new Runnable() { - public void run() { - onSimLockChangedResponse(false); - } - }); - } - } - } - - public void onClick(View v) { - if (v == mDelPukButton) { - if (mFocusedEntry != mPukText) - mPukText.requestFocus(); - final Editable digits = mPukText.getEditableText(); - final int len = digits.length(); - if (len > 0) { - digits.delete(len-1, len); - } - } else if (v == mDelPinButton) { - if (mFocusedEntry != mPinText) - mPinText.requestFocus(); - final Editable digits = mPinText.getEditableText(); - final int len = digits.length(); - if (len > 0) { - digits.delete(len-1, len); - } - } else if (v == mOkButton) { - checkPuk(); - } - mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); - - } - - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) - mFocusedEntry = (TextView)v; - } - - private Dialog getSimUnlockProgressDialog() { - if (mSimUnlockProgressDialog == null) { - mSimUnlockProgressDialog = new ProgressDialog(mContext); - mSimUnlockProgressDialog.setMessage( - mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message)); - mSimUnlockProgressDialog.setIndeterminate(true); - mSimUnlockProgressDialog.setCancelable(false); - mSimUnlockProgressDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - return mSimUnlockProgressDialog; - } - - private void checkPuk() { - // make sure that the puk is at least 8 digits long. - if (mPukText.getText().length() < 8) { - // otherwise, display a message to the user, and don't submit. - mHeaderText.setText(R.string.invalidPuk); - mPukText.setText(""); - return; - } - - if (mPinText.getText().length() < 4 - || mPinText.getText().length() > 8) { - // otherwise, display a message to the user, and don't submit. - mHeaderText.setText(R.string.invalidPin); - mPinText.setText(""); - return; - } - - getSimUnlockProgressDialog().show(); - - new CheckSimPuk(mPukText.getText().toString(), - mPinText.getText().toString()) { - void onSimLockChangedResponse(final boolean success) { - mPinText.post(new Runnable() { - public void run() { - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - if (success) { - // before closing the keyguard, report back that - // the sim is unlocked so it knows right away - mUpdateMonitor.reportSimUnlocked(); - mCallback.goToUnlockScreen(); - } else { - mHeaderText.setText(R.string.badPuk); - mPukText.setText(""); - mPinText.setText(""); - } - } - }); - } - }.start(); - } - - - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); - return true; - } - final char match = event.getMatch(DIGITS); - if (match != 0) { - reportDigit(match - '0'); - return true; - } - if (keyCode == KeyEvent.KEYCODE_DEL) { - mFocusedEntry.onKeyDown(keyCode, event); - final Editable digits = mFocusedEntry.getEditableText(); - final int len = digits.length(); - if (len > 0) { - digits.delete(len-1, len); - } - mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); - return true; - } - - if (keyCode == KeyEvent.KEYCODE_ENTER) { - checkPuk(); - return true; - } - - return false; - } - - private void reportDigit(int digit) { - mFocusedEntry.append(Integer.toString(digit)); - } - - void updateConfiguration() { - Configuration newConfig = getResources().getConfiguration(); - if (newConfig.orientation != mCreationOrientation) { - mCallback.recreateMe(newConfig); - } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) { - mKeyboardHidden = newConfig.hardKeyboardHidden; - } - - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - updateConfiguration(); - } - - /** {@inheritDoc} */ - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateConfiguration(); - } - - /** - * Helper class to handle input from touch dialer. Only relevant when - * the keyboard is shut. - */ - private class TouchInput implements View.OnClickListener { - private TextView mZero; - private TextView mOne; - private TextView mTwo; - private TextView mThree; - private TextView mFour; - private TextView mFive; - private TextView mSix; - private TextView mSeven; - private TextView mEight; - private TextView mNine; - private TextView mCancelButton; - - private TouchInput() { - mZero = (TextView) findViewById(R.id.zero); - mOne = (TextView) findViewById(R.id.one); - mTwo = (TextView) findViewById(R.id.two); - mThree = (TextView) findViewById(R.id.three); - mFour = (TextView) findViewById(R.id.four); - mFive = (TextView) findViewById(R.id.five); - mSix = (TextView) findViewById(R.id.six); - mSeven = (TextView) findViewById(R.id.seven); - mEight = (TextView) findViewById(R.id.eight); - mNine = (TextView) findViewById(R.id.nine); - mCancelButton = (TextView) findViewById(R.id.cancel); - - mZero.setText("0"); - mOne.setText("1"); - mTwo.setText("2"); - mThree.setText("3"); - mFour.setText("4"); - mFive.setText("5"); - mSix.setText("6"); - mSeven.setText("7"); - mEight.setText("8"); - mNine.setText("9"); - - mZero.setOnClickListener(this); - mOne.setOnClickListener(this); - mTwo.setOnClickListener(this); - mThree.setOnClickListener(this); - mFour.setOnClickListener(this); - mFive.setOnClickListener(this); - mSix.setOnClickListener(this); - mSeven.setOnClickListener(this); - mEight.setOnClickListener(this); - mNine.setOnClickListener(this); - mCancelButton.setOnClickListener(this); - } - - - public void onClick(View v) { - if (v == mCancelButton) { - // clear the PIN/PUK entry fields if the user cancels - mPinText.setText(""); - mPukText.setText(""); - mCallback.goToLockScreen(); - return; - } - - final int digit = checkDigit(v); - if (digit >= 0) { - mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); - reportDigit(digit); - } - } - - private int checkDigit(View v) { - int digit = -1; - if (v == mZero) { - digit = 0; - } else if (v == mOne) { - digit = 1; - } else if (v == mTwo) { - digit = 2; - } else if (v == mThree) { - digit = 3; - } else if (v == mFour) { - digit = 4; - } else if (v == mFive) { - digit = 5; - } else if (v == mSix) { - digit = 6; - } else if (v == mSeven) { - digit = 7; - } else if (v == mEight) { - digit = 8; - } else if (v == mNine) { - digit = 9; - } - return digit; - } - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/SimUnlockScreen.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/SimUnlockScreen.java deleted file mode 100644 index 13c040c..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/SimUnlockScreen.java +++ /dev/null @@ -1,396 +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.keyguard_obsolete; - -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.res.Configuration; -import android.os.RemoteException; -import android.os.ServiceManager; - -import com.android.internal.telephony.ITelephony; -import com.android.internal.widget.LockPatternUtils; - -import android.text.Editable; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.android.internal.R; - -/** - * Displays a dialer like interface to unlock the SIM PIN. - */ -public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener { - - private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; - - private final KeyguardUpdateMonitor mUpdateMonitor; - private final KeyguardScreenCallback mCallback; - - private TextView mHeaderText; - private TextView mPinText; - - private TextView mOkButton; - - private View mBackSpaceButton; - - private final int[] mEnteredPin = {0, 0, 0, 0, 0, 0, 0, 0}; - private int mEnteredDigits = 0; - - private ProgressDialog mSimUnlockProgressDialog = null; - - private LockPatternUtils mLockPatternUtils; - - private int mCreationOrientation; - - private int mKeyboardHidden; - - private KeyguardStatusViewManager mKeyguardStatusViewManager; - - private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - - public SimUnlockScreen(Context context, Configuration configuration, - KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback, - LockPatternUtils lockpatternutils) { - super(context); - mUpdateMonitor = updateMonitor; - mCallback = callback; - - mCreationOrientation = configuration.orientation; - mKeyboardHidden = configuration.hardKeyboardHidden; - mLockPatternUtils = lockpatternutils; - - LayoutInflater inflater = LayoutInflater.from(context); - if (mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { - inflater.inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true); - } else { - inflater.inflate(R.layout.keyguard_screen_sim_pin_portrait, this, true); - new TouchInput(); - } - - mHeaderText = (TextView) findViewById(R.id.headerText); - mPinText = (TextView) findViewById(R.id.pinDisplay); - mBackSpaceButton = findViewById(R.id.backspace); - mBackSpaceButton.setOnClickListener(this); - - mOkButton = (TextView) findViewById(R.id.ok); - - mHeaderText.setText(R.string.keyguard_password_enter_pin_code); - mPinText.setFocusable(false); - - mOkButton.setOnClickListener(this); - - mKeyguardStatusViewManager = new KeyguardStatusViewManager(this, updateMonitor, - lockpatternutils, callback, false); - - setFocusableInTouchMode(true); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return true; - } - - /** {@inheritDoc} */ - public void onPause() { - mKeyguardStatusViewManager.onPause(); - } - - /** {@inheritDoc} */ - public void onResume() { - // start fresh - mHeaderText.setText(R.string.keyguard_password_enter_pin_code); - - // make sure that the number of entered digits is consistent when we - // erase the SIM unlock code, including orientation changes. - mPinText.setText(""); - mEnteredDigits = 0; - - mKeyguardStatusViewManager.onResume(); - } - - /** {@inheritDoc} */ - public void cleanUp() { - // dismiss the dialog. - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.dismiss(); - mSimUnlockProgressDialog = null; - } - mUpdateMonitor.removeCallback(this); - } - - - /** - * Since the IPC can block, we want to run the request in a separate thread - * with a callback. - */ - private abstract class CheckSimPin extends Thread { - - private final String mPin; - - protected CheckSimPin(String pin) { - mPin = pin; - } - - abstract void onSimLockChangedResponse(boolean success); - - @Override - public void run() { - try { - final boolean result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPin(mPin); - post(new Runnable() { - public void run() { - onSimLockChangedResponse(result); - } - }); - } catch (RemoteException e) { - post(new Runnable() { - public void run() { - onSimLockChangedResponse(false); - } - }); - } - } - } - - public void onClick(View v) { - if (v == mBackSpaceButton) { - final Editable digits = mPinText.getEditableText(); - final int len = digits.length(); - if (len > 0) { - digits.delete(len-1, len); - mEnteredDigits--; - } - mCallback.pokeWakelock(); - } else if (v == mOkButton) { - checkPin(); - } - } - - private Dialog getSimUnlockProgressDialog() { - if (mSimUnlockProgressDialog == null) { - mSimUnlockProgressDialog = new ProgressDialog(mContext); - mSimUnlockProgressDialog.setMessage( - mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message)); - mSimUnlockProgressDialog.setIndeterminate(true); - mSimUnlockProgressDialog.setCancelable(false); - mSimUnlockProgressDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - return mSimUnlockProgressDialog; - } - - private void checkPin() { - - // make sure that the pin is at least 4 digits long. - if (mEnteredDigits < 4) { - // otherwise, display a message to the user, and don't submit. - mHeaderText.setText(R.string.invalidPin); - mPinText.setText(""); - mEnteredDigits = 0; - mCallback.pokeWakelock(); - return; - } - getSimUnlockProgressDialog().show(); - - new CheckSimPin(mPinText.getText().toString()) { - void onSimLockChangedResponse(final boolean success) { - mPinText.post(new Runnable() { - public void run() { - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - if (success) { - // before closing the keyguard, report back that - // the sim is unlocked so it knows right away - mUpdateMonitor.reportSimUnlocked(); - mCallback.goToUnlockScreen(); - } else { - mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); - mPinText.setText(""); - mEnteredDigits = 0; - } - mCallback.pokeWakelock(); - } - }); - } - }.start(); - } - - - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - mCallback.goToLockScreen(); - return true; - } - - final char match = event.getMatch(DIGITS); - if (match != 0) { - reportDigit(match - '0'); - return true; - } - if (keyCode == KeyEvent.KEYCODE_DEL) { - if (mEnteredDigits > 0) { - mPinText.onKeyDown(keyCode, event); - mEnteredDigits--; - } - return true; - } - - if (keyCode == KeyEvent.KEYCODE_ENTER) { - checkPin(); - return true; - } - - return false; - } - - private void reportDigit(int digit) { - if (mEnteredDigits == 0) { - mPinText.setText(""); - } - if (mEnteredDigits == 8) { - return; - } - mPinText.append(Integer.toString(digit)); - mEnteredPin[mEnteredDigits++] = digit; - } - - void updateConfiguration() { - Configuration newConfig = getResources().getConfiguration(); - if (newConfig.orientation != mCreationOrientation) { - mCallback.recreateMe(newConfig); - } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) { - mKeyboardHidden = newConfig.hardKeyboardHidden; - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - updateConfiguration(); - } - - /** {@inheritDoc} */ - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateConfiguration(); - } - - /** - * Helper class to handle input from touch dialer. Only relevant when - * the keyboard is shut. - */ - private class TouchInput implements View.OnClickListener { - private TextView mZero; - private TextView mOne; - private TextView mTwo; - private TextView mThree; - private TextView mFour; - private TextView mFive; - private TextView mSix; - private TextView mSeven; - private TextView mEight; - private TextView mNine; - private TextView mCancelButton; - - private TouchInput() { - mZero = (TextView) findViewById(R.id.zero); - mOne = (TextView) findViewById(R.id.one); - mTwo = (TextView) findViewById(R.id.two); - mThree = (TextView) findViewById(R.id.three); - mFour = (TextView) findViewById(R.id.four); - mFive = (TextView) findViewById(R.id.five); - mSix = (TextView) findViewById(R.id.six); - mSeven = (TextView) findViewById(R.id.seven); - mEight = (TextView) findViewById(R.id.eight); - mNine = (TextView) findViewById(R.id.nine); - mCancelButton = (TextView) findViewById(R.id.cancel); - - mZero.setText("0"); - mOne.setText("1"); - mTwo.setText("2"); - mThree.setText("3"); - mFour.setText("4"); - mFive.setText("5"); - mSix.setText("6"); - mSeven.setText("7"); - mEight.setText("8"); - mNine.setText("9"); - - mZero.setOnClickListener(this); - mOne.setOnClickListener(this); - mTwo.setOnClickListener(this); - mThree.setOnClickListener(this); - mFour.setOnClickListener(this); - mFive.setOnClickListener(this); - mSix.setOnClickListener(this); - mSeven.setOnClickListener(this); - mEight.setOnClickListener(this); - mNine.setOnClickListener(this); - mCancelButton.setOnClickListener(this); - } - - - public void onClick(View v) { - if (v == mCancelButton) { - mPinText.setText(""); // clear the PIN entry field if the user cancels - mCallback.goToLockScreen(); - return; - } - - final int digit = checkDigit(v); - if (digit >= 0) { - mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); - reportDigit(digit); - } - } - - private int checkDigit(View v) { - int digit = -1; - if (v == mZero) { - digit = 0; - } else if (v == mOne) { - digit = 1; - } else if (v == mTwo) { - digit = 2; - } else if (v == mThree) { - digit = 3; - } else if (v == mFour) { - digit = 4; - } else if (v == mFive) { - digit = 5; - } else if (v == mSix) { - digit = 6; - } else if (v == mSeven) { - digit = 7; - } else if (v == mEight) { - digit = 8; - } else if (v == mNine) { - digit = 9; - } - return digit; - } - } -} diff --git a/policy/tests/Android.mk b/policy/tests/Android.mk deleted file mode 100644 index ffb60b1..0000000 --- a/policy/tests/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2010, 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. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests - -LOCAL_JAVA_LIBRARIES := android.policy android.test.runner - -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_PACKAGE_NAME := FrameworkPolicyTests - -include $(BUILD_PACKAGE) - diff --git a/policy/tests/AndroidManifest.xml b/policy/tests/AndroidManifest.xml deleted file mode 100644 index dbdabfa..0000000 --- a/policy/tests/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2010 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. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.policy.tests"> - - <application> - <uses-library android:name="android.test.runner" /> - </application> - - <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> - - <instrumentation - android:name="android.test.InstrumentationTestRunner" - android:targetPackage="com.android.frameworks.policy.tests" - android:label="Framework policy tests" /> -</manifest> diff --git a/policy/tests/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardViewTest.java b/policy/tests/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardViewTest.java deleted file mode 100644 index 97c5672..0000000 --- a/policy/tests/src/com/android/internal/policy/impl/keyguard_obsolete/LockPatternKeyguardViewTest.java +++ /dev/null @@ -1,356 +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.keyguard_obsolete; - -import android.content.Context; - -import com.android.internal.policy.impl.keyguard_obsolete.KeyguardScreen; -import com.android.internal.policy.impl.keyguard_obsolete.KeyguardUpdateMonitor; -import com.android.internal.policy.impl.keyguard_obsolete.KeyguardViewCallback; -import com.android.internal.policy.impl.keyguard_obsolete.KeyguardWindowController; -import com.android.internal.policy.impl.keyguard_obsolete.LockPatternKeyguardView; -import com.android.internal.telephony.IccCardConstants; -import android.content.res.Configuration; -import android.test.AndroidTestCase; -import android.view.View; -import android.view.KeyEvent; -import com.android.internal.widget.LockPatternUtils; -import com.google.android.collect.Lists; - -import java.util.List; - -/** - * Tests for {@link com.android.internal.policy.impl.LockPatternKeyguardView}, - * which handles the management of screens while the keyguard is showing. - */ -public class LockPatternKeyguardViewTest extends AndroidTestCase { - private MockUpdateMonitor mUpdateMonitor; - private LockPatternUtils mLockPatternUtils; - private TestableLockPatternKeyguardView mLPKV; - private MockKeyguardCallback mKeyguardViewCallback; - - private static class MockUpdateMonitor extends KeyguardUpdateMonitor { - - public IccCardConstants.State simState = IccCardConstants.State.READY; - - private MockUpdateMonitor(Context context) { - super(context); - } - - @Override - public IccCardConstants.State getSimState() { - return simState; - } - } - - private static class MockLockPatternUtils extends LockPatternUtils { - boolean isLockPatternEnabled = true; - public boolean isPermanentlyLocked = false; - - public MockLockPatternUtils(Context context) { - super(context); - } - - @Override - public boolean isLockPatternEnabled() { - return isLockPatternEnabled; - } - - @Override - public void setLockPatternEnabled(boolean lockPatternEnabled) { - isLockPatternEnabled = lockPatternEnabled; - } - - @Override - public boolean isPermanentlyLocked() { - return isPermanentlyLocked; - } - - public void setPermanentlyLocked(boolean permanentlyLocked) { - isPermanentlyLocked = permanentlyLocked; - } - } - - private static class MockKeyguardScreen extends View implements KeyguardScreen { - - private int mOnPauseCount = 0; - private int mOnResumeCount = 0; - private int mCleanupCount = 0; - - private MockKeyguardScreen(Context context) { - super(context); - setFocusable(true); - } - - /** {@inheritDoc} */ - public boolean needsInput() { - return false; - } - - /** {@inheritDoc} */ - public void onPause() { - mOnPauseCount++; - } - - /** {@inheritDoc} */ - public void onResume() { - mOnResumeCount++; - } - - /** {@inheritDoc} */ - public void cleanUp() { - mCleanupCount++; - } - - public int getOnPauseCount() { - return mOnPauseCount; - } - - public int getOnResumeCount() { - return mOnResumeCount; - } - - public int getCleanupCount() { - return mCleanupCount; - } - } - - /** - * Allows us to inject the lock and unlock views to simulate their behavior - * and detect their creation. - */ - private static class TestableLockPatternKeyguardView extends LockPatternKeyguardView { - private List<MockKeyguardScreen> mInjectedLockScreens; - private List<MockKeyguardScreen> mInjectedUnlockScreens; - - - - private TestableLockPatternKeyguardView(Context context, KeyguardViewCallback callback, - KeyguardUpdateMonitor updateMonitor, - LockPatternUtils lockPatternUtils, KeyguardWindowController controller) { - super(context, callback, updateMonitor, lockPatternUtils, controller); - } - - @Override - View createLockScreen() { - final MockKeyguardScreen newView = new MockKeyguardScreen(getContext()); - if (mInjectedLockScreens == null) mInjectedLockScreens = Lists.newArrayList(); - mInjectedLockScreens.add(newView); - return newView; - } - - @Override - View createUnlockScreenFor(UnlockMode unlockMode) { - final MockKeyguardScreen newView = new MockKeyguardScreen(getContext()); - if (mInjectedUnlockScreens == null) mInjectedUnlockScreens = Lists.newArrayList(); - mInjectedUnlockScreens.add(newView); - return newView; - } - - public List<MockKeyguardScreen> getInjectedLockScreens() { - return mInjectedLockScreens; - } - - public List<MockKeyguardScreen> getInjectedUnlockScreens() { - return mInjectedUnlockScreens; - } - } - - private static class MockKeyguardCallback implements KeyguardViewCallback { - - private int mPokeWakelockCount = 0; - private int mKeyguardDoneCount = 0; - - public void pokeWakelock() { - mPokeWakelockCount++; - } - - public void pokeWakelock(int millis) { - mPokeWakelockCount++; - } - - public void keyguardDone(boolean authenticated) { - mKeyguardDoneCount++; - } - - public void keyguardDoneDrawing() { - - } - - public int getPokeWakelockCount() { - return mPokeWakelockCount; - } - - public int getKeyguardDoneCount() { - return mKeyguardDoneCount; - } - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - mUpdateMonitor = new MockUpdateMonitor(getContext()); - mLockPatternUtils = new MockLockPatternUtils(getContext()); - mKeyguardViewCallback = new MockKeyguardCallback(); - - mLPKV = new TestableLockPatternKeyguardView(getContext(), mKeyguardViewCallback, - mUpdateMonitor, mLockPatternUtils, new KeyguardWindowController() { - public void setNeedsInput(boolean needsInput) { - } - }); - } - - public void testStateAfterCreatedWhileScreenOff() { - - assertEquals(1, mLPKV.getInjectedLockScreens().size()); - assertEquals(1, mLPKV.getInjectedUnlockScreens().size()); - - MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0); - MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0); - - assertEquals(0, lockScreen.getOnPauseCount()); - assertEquals(0, lockScreen.getOnResumeCount()); - assertEquals(0, lockScreen.getCleanupCount()); - - assertEquals(0, unlockScreen.getOnPauseCount()); - assertEquals(0, unlockScreen.getOnResumeCount()); - assertEquals(0, unlockScreen.getCleanupCount()); - - assertEquals(0, mKeyguardViewCallback.getPokeWakelockCount()); - assertEquals(0, mKeyguardViewCallback.getKeyguardDoneCount()); - } - - public void testWokenByNonMenuKey() { - mLPKV.wakeWhenReadyTq(0); - - // should have poked the wakelock to turn on the screen - assertEquals(1, mKeyguardViewCallback.getPokeWakelockCount()); - - // shouldn't be any additional views created - assertEquals(1, mLPKV.getInjectedLockScreens().size()); - assertEquals(1, mLPKV.getInjectedUnlockScreens().size()); - MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0); - MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0); - - // lock screen should be only visible one - assertEquals(View.VISIBLE, lockScreen.getVisibility()); - assertEquals(View.GONE, unlockScreen.getVisibility()); - - // on resume not called until screen turns on - assertEquals(0, lockScreen.getOnPauseCount()); - assertEquals(0, lockScreen.getOnResumeCount()); - assertEquals(0, lockScreen.getCleanupCount()); - - assertEquals(0, unlockScreen.getOnPauseCount()); - assertEquals(0, unlockScreen.getOnResumeCount()); - assertEquals(0, unlockScreen.getCleanupCount()); - - // simulate screen turning on - mLPKV.onScreenTurnedOn(); - - assertEquals(0, lockScreen.getOnPauseCount()); - assertEquals(1, lockScreen.getOnResumeCount()); - assertEquals(0, lockScreen.getCleanupCount()); - - assertEquals(0, unlockScreen.getOnPauseCount()); - assertEquals(0, unlockScreen.getOnResumeCount()); - assertEquals(0, unlockScreen.getCleanupCount()); - } - - public void testWokenByMenuKeyWhenPatternSet() { - assertEquals(true, mLockPatternUtils.isLockPatternEnabled()); - - mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU); - - // should have poked the wakelock to turn on the screen - assertEquals(1, mKeyguardViewCallback.getPokeWakelockCount()); - - // shouldn't be any additional views created - assertEquals(1, mLPKV.getInjectedLockScreens().size()); - assertEquals(1, mLPKV.getInjectedUnlockScreens().size()); - MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0); - MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0); - - // unlock screen should be only visible one - assertEquals(View.GONE, lockScreen.getVisibility()); - assertEquals(View.VISIBLE, unlockScreen.getVisibility()); - } - - public void testScreenRequestsRecreation() { - mLPKV.wakeWhenReadyTq(0); - mLPKV.onScreenTurnedOn(); - - assertEquals(1, mLPKV.getInjectedLockScreens().size()); - assertEquals(1, mLPKV.getInjectedUnlockScreens().size()); - MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0); - - assertEquals(0, lockScreen.getOnPauseCount()); - assertEquals(1, lockScreen.getOnResumeCount()); - - // simulate screen asking to be recreated - mLPKV.mKeyguardScreenCallback.recreateMe(new Configuration()); - - // should have been recreated - assertEquals(2, mLPKV.getInjectedLockScreens().size()); - assertEquals(2, mLPKV.getInjectedUnlockScreens().size()); - - // both old screens should have been cleaned up - assertEquals(1, mLPKV.getInjectedLockScreens().get(0).getCleanupCount()); - assertEquals(1, mLPKV.getInjectedUnlockScreens().get(0).getCleanupCount()); - - // old lock screen should have been paused - assertEquals(1, mLPKV.getInjectedLockScreens().get(0).getOnPauseCount()); - assertEquals(0, mLPKV.getInjectedUnlockScreens().get(0).getOnPauseCount()); - - // new lock screen should have been resumed - assertEquals(1, mLPKV.getInjectedLockScreens().get(1).getOnResumeCount()); - assertEquals(0, mLPKV.getInjectedUnlockScreens().get(1).getOnResumeCount()); - } - - public void testMenuDoesntGoToUnlockScreenOnWakeWhenPukLocked() { - // PUK locked - mUpdateMonitor.simState = IccCardConstants.State.PUK_REQUIRED; - - // wake by menu - mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU); - - assertEquals(1, mLPKV.getInjectedLockScreens().size()); - assertEquals(1, mLPKV.getInjectedUnlockScreens().size()); - MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0); - MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0); - - // lock screen should be only visible one - assertEquals(View.VISIBLE, lockScreen.getVisibility()); - assertEquals(View.GONE, unlockScreen.getVisibility()); - } - - public void testMenuGoesToLockScreenWhenDeviceNotSecure() { - mLockPatternUtils.setLockPatternEnabled(false); - - // wake by menu - mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU); - - assertEquals(1, mLPKV.getInjectedLockScreens().size()); - assertEquals(1, mLPKV.getInjectedUnlockScreens().size()); - MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0); - MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0); - - // lock screen should be only visible one - assertEquals(View.VISIBLE, lockScreen.getVisibility()); - assertEquals(View.GONE, unlockScreen.getVisibility()); - } -} |