diff options
Diffstat (limited to 'policy')
52 files changed, 2553 insertions, 9094 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..a2ac8fe 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -102,6 +102,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private boolean mIsWaitingForEcmExit = false; private boolean mHasTelephony; private boolean mHasVibrator; + private final boolean mShowSilentToggle; /** * @param context everything needs a context :( @@ -132,6 +133,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mAirplaneModeObserver); Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = vibrator != null && vibrator.hasVibrator(); + + mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean( + com.android.internal.R.bool.config_useFixedVolume); } /** @@ -260,8 +264,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) { @@ -309,7 +313,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } // last: silent mode - if (SHOW_SILENT_TOGGLE) { + if (mShowSilentToggle) { mItems.add(mSilentModeAction); } @@ -390,7 +394,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mAirplaneModeOn.updateState(mAirplaneState); mAdapter.notifyDataSetChanged(); mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - if (SHOW_SILENT_TOGGLE) { + if (mShowSilentToggle) { IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); mContext.registerReceiver(mRingerModeReceiver, filter); } @@ -407,7 +411,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { - if (SHOW_SILENT_TOGGLE) { + if (mShowSilentToggle) { try { mContext.unregisterReceiver(mRingerModeReceiver); } catch (IllegalArgumentException ie) { diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java new file mode 100644 index 0000000..3cf7e82 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java @@ -0,0 +1,126 @@ +/* + * + * 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.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.os.UserHandle; +import android.util.Log; +import android.util.SparseArray; +import android.view.KeyEvent; + +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** + * Stores a mapping of global keys. + * <p> + * A global key will NOT go to the foreground application and instead only ever be sent via targeted + * broadcast to the specified component. The action of the intent will be + * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with + * {@link Intent#EXTRA_KEY_EVENT}. + */ +final class GlobalKeyManager { + + private static final String TAG = "GlobalKeyManager"; + + private static final String TAG_GLOBAL_KEYS = "global_keys"; + private static final String ATTR_VERSION = "version"; + private static final String TAG_KEY = "key"; + private static final String ATTR_KEY_CODE = "keyCode"; + private static final String ATTR_COMPONENT = "component"; + + private static final int GLOBAL_KEY_FILE_VERSION = 1; + + private SparseArray<ComponentName> mKeyMapping; + + public GlobalKeyManager(Context context) { + mKeyMapping = new SparseArray<ComponentName>(); + loadGlobalKeys(context); + } + + /** + * Broadcasts an intent if the keycode is part of the global key mapping. + * + * @param context context used to broadcast the event + * @param keyCode keyCode which triggered this function + * @param event keyEvent which trigged this function + * @return {@code true} if this was handled + */ + boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) { + if (mKeyMapping.size() > 0) { + ComponentName component = mKeyMapping.get(keyCode); + if (component != null) { + Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) + .setComponent(component) + .putExtra(Intent.EXTRA_KEY_EVENT, event); + context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null); + return true; + } + } + return false; + } + + /** + * Returns {@code true} if the key will be handled globally. + */ + boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) { + return mKeyMapping.get(keyCode) != null; + } + + private void loadGlobalKeys(Context context) { + XmlResourceParser parser = null; + try { + parser = context.getResources().getXml(com.android.internal.R.xml.global_keys); + XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS); + int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0); + if (GLOBAL_KEY_FILE_VERSION == version) { + while (true) { + XmlUtils.nextElement(parser); + String element = parser.getName(); + if (element == null) { + break; + } + if (TAG_KEY.equals(element)) { + String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE); + String componentName = parser.getAttributeValue(null, ATTR_COMPONENT); + int keyCode = KeyEvent.keyCodeFromString(keyCodeName); + if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { + mKeyMapping.put(keyCode, ComponentName.unflattenFromString( + componentName)); + } + } + } + } + } catch (Resources.NotFoundException e) { + Log.w(TAG, "global keys file not found", e); + } catch (XmlPullParserException e) { + Log.w(TAG, "XML parser exception reading global keys file", e); + } catch (IOException e) { + Log.w(TAG, "I/O exception reading global keys file", e); + } finally { + if (parser != null) { + parser.close(); + } + } + } +} diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 41d67bc..6b28e8e 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; @@ -37,6 +33,7 @@ import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; import com.android.internal.widget.ActionBarContainer; import com.android.internal.widget.ActionBarContextView; +import com.android.internal.widget.ActionBarOverlayLayout; import com.android.internal.widget.ActionBarView; import android.app.KeyguardManager; @@ -383,6 +380,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { st.createdPanelView = cb.onCreatePanelView(st.featureId); } + final boolean isActionBarMenu = + (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR); + + if (isActionBarMenu && mActionBar != null) { + // Enforce ordering guarantees around events so that the action bar never + // dispatches menu-related events before the panel is prepared. + mActionBar.setMenuPrepared(); + } + if (st.createdPanelView == null) { // Init the panel state's menu--return false if init failed if (st.menu == null || st.refreshMenuContent) { @@ -392,7 +398,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - if (mActionBar != null) { + if (isActionBarMenu && mActionBar != null) { if (mActionMenuPresenterCallback == null) { mActionMenuPresenterCallback = new ActionMenuPresenterCallback(); } @@ -408,7 +414,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Ditch the menu created above st.setMenu(null); - if (mActionBar != null) { + if (isActionBarMenu && mActionBar != null) { // Don't show it in the action bar either mActionBar.setMenu(null, mActionMenuPresenterCallback); } @@ -433,7 +439,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { - if (mActionBar != null) { + if (isActionBarMenu && mActionBar != null) { // The app didn't want to show the menu for now but it still exists. // Clear it out of the action bar. mActionBar.setMenu(null, mActionMenuPresenterCallback); @@ -992,6 +998,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final Callback cb = getCallback(); if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) { if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) { + // If we have a menu invalidation pending, do it now. + if (mInvalidatePanelMenuPosted && + (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) { + mDecor.removeCallbacks(mInvalidatePanelMenuRunnable); + mInvalidatePanelMenuRunnable.run(); + } + final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); // If we don't have a menu or we're waiting for a full content refresh, @@ -2266,8 +2279,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 +2652,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)) { @@ -2790,11 +2805,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { com.android.internal.R.attr.dialogTitleDecorLayout, res, true); layoutResource = res.resourceId; } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) { - if ((features & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0) { - layoutResource = com.android.internal.R.layout.screen_action_bar_overlay; - } else { - layoutResource = com.android.internal.R.layout.screen_action_bar; - } + layoutResource = com.android.internal.R.layout.screen_action_bar; } else { layoutResource = com.android.internal.R.layout.screen_title; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 0f4262a..b0cd11ae 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -17,6 +17,8 @@ package com.android.internal.policy.impl; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.AppOpsManager; +import android.app.IUiModeManager; import android.app.ProgressDialog; import android.app.SearchManager; import android.app.UiModeManager; @@ -30,6 +32,7 @@ import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; @@ -58,15 +61,8 @@ 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.service.dreams.DreamService; +import android.service.dreams.IDreamManager; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -82,78 +78,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 @@ -171,6 +127,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; + // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. + // No longer recommended for desk docks; still useful in car docks. + static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true; + static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false; + static final int LONG_PRESS_POWER_NOTHING = 0; static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; static final int LONG_PRESS_POWER_SHUT_OFF = 2; @@ -179,8 +140,11 @@ 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 LONG_PRESS_HOME_ASSIST = 2; + + static final int DOUBLE_TAP_HOME_NOTHING = 0; + static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -228,13 +192,14 @@ 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; WindowManagerFuncs mWindowManagerFuncs; PowerManager mPowerManager; IStatusBarService mStatusBarService; + boolean mPreloadedRecentApps; final Object mServiceAquireLock = new Object(); Vibrator mVibrator; // Vibrator for giving feedback of orientation changes SearchManager mSearchManager; @@ -294,12 +259,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSystemReady; boolean mSystemBooted; boolean mHdmiPlugged; + int mUiMode; int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; int mLidOpenRotation; int mCarDockRotation; int mDeskDockRotation; - int mHdmiRotation; - boolean mHdmiRotationLock; + int mUndockedHdmiRotation; + int mDemoHdmiRotation; + boolean mDemoHdmiRotationLock; int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; int mUserRotation = Surface.ROTATION_0; @@ -354,10 +321,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 +377,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(); @@ -429,7 +404,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mShowingDream; boolean mDreamingLockscreen; boolean mHomePressed; - boolean mHomeLongPressed; + boolean mHomeConsumed; + boolean mHomeDoubleTapPending; Intent mHomeIntent; Intent mCarDockIntent; Intent mDeskDockIntent; @@ -456,8 +432,16 @@ 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; + private int mLongPressOnHomeBehavior; + + // What we do when the user double-taps on home + private int mDoubleTapOnHomeBehavior; // Screenshot trigger states // Time to volume and power must be pressed within this interval of each other. @@ -477,6 +461,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager.WakeLock mBroadcastWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock; + // Maps global key codes to the components that will handle them. + private GlobalKeyManager mGlobalKeyManager; + // Fallback actions by key code. private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions = new SparseArray<KeyCharacterMap.FallbackAction>(); @@ -555,8 +542,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 +673,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mVolumeDownKeyConsumedByScreenshotChord = true; cancelPendingPowerKeyAction(); - mHandler.postDelayed(mScreenshotChordLongPress, getScreenshotChordLongPressDelay()); + mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay()); } } } @@ -696,13 +683,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 +726,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - private final Runnable mScreenshotChordLongPress = new Runnable() { + private final Runnable mScreenshotRunnable = new Runnable() { + @Override public void run() { takeScreenshot(); } @@ -765,41 +752,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void handleLongPressOnHome() { - // We can't initialize this in init() since the configuration hasn't been loaded yet. - if (mLongPressOnHomeBehavior < 0) { - mLongPressOnHomeBehavior - = mContext.getResources().getInteger(R.integer.config_longPressOnHomeBehavior); - if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING || - mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) { - mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING; - } - } - if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { + mHomeConsumed = true; performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); - // 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_SYSTEM_UI) { + toggleRecentApps(); + } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_ASSIST) { + launchAssistAction(); + } } + } - 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) { - statusbar.toggleRecentApps(); - } - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException when showing recent apps", e); - // re-acquire status bar service next time it is needed. - mStatusBarService = null; - } + private void handleDoubleTapOnHome() { + if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) { + mHomeConsumed = true; + toggleRecentApps(); } } + private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() { + @Override + public void run() { + if (mHomeDoubleTapPending) { + mHomeDoubleTapPending = false; + launchHomeFromHotKey(); + } + } + }; + /** * Create (if necessary) and show or dismiss the recent apps dialog according * according to the requested behavior. @@ -847,6 +828,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void init(Context context, IWindowManager windowManager, WindowManagerFuncs windowManagerFuncs) { mContext = context; @@ -858,7 +840,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) { } @@ -866,6 +848,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mSettingsObserver.observe(); mShortcutManager = new ShortcutManager(context, mHandler); mShortcutManager.observe(); + mUiMode = context.getResources().getInteger( + com.android.internal.R.integer.config_defaultUiModeType); mHomeIntent = new Intent(Intent.ACTION_MAIN, null); mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK @@ -889,6 +873,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_carDockRotation); mDeskDockRotation = readRotation( com.android.internal.R.integer.config_deskDockRotation); + mUndockedHdmiRotation = readRotation( + com.android.internal.R.integer.config_undockedHdmiRotation); mCarDockEnablesAccelerometer = mContext.getResources().getBoolean( com.android.internal.R.bool.config_carDockEnablesAccelerometer); mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean( @@ -899,6 +885,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_lidNavigationAccessibility); mLidControlsSleep = mContext.getResources().getBoolean( com.android.internal.R.bool.config_lidControlsSleep); + readConfigurationDependentBehaviors(); + // register for dock events IntentFilter filter = new IntentFilter(); filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); @@ -938,6 +926,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenshotChordEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableScreenshotChord); + mGlobalKeyManager = new GlobalKeyManager(mContext); + // Controls rotation and the like. initializeHdmiState(); @@ -949,7 +939,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** + * Read values from config.xml that may be overridden depending on + * the configuration of the device. + * eg. Disable long press on home goes to recents on sw600dp. + */ + private void readConfigurationDependentBehaviors() { + mLongPressOnHomeBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnHomeBehavior); + if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING || + mLongPressOnHomeBehavior > LONG_PRESS_HOME_ASSIST) { + mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING; + } + + mDoubleTapOnHomeBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_doubleTapOnHomeBehavior); + if (mDoubleTapOnHomeBehavior < DOUBLE_TAP_HOME_NOTHING || + mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) { + mDoubleTapOnHomeBehavior = LONG_PRESS_HOME_NOTHING; + } + } + + @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; @@ -1053,11 +1068,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { // For demo purposes, allow the rotation of the HDMI display to be controlled. // By default, HDMI locks rotation to landscape. if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { - mHdmiRotation = mPortraitRotation; + mDemoHdmiRotation = mPortraitRotation; } else { - mHdmiRotation = mLandscapeRotation; + mDemoHdmiRotation = mLandscapeRotation; + } + mDemoHdmiRotationLock = 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; } - mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", true); } public void updateSettings() { @@ -1189,9 +1214,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 +1241,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; @@ -1312,6 +1340,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int navigationPresence) { mHaveBuiltInKeyboard = (keyboardPresence & PRESENCE_INTERNAL) != 0; + readConfigurationDependentBehaviors(); readLidState(); applyLidSwitchState(); @@ -1719,31 +1748,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,12 +1798,73 @@ 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 : com.android.internal.R.anim.lock_screen_behind_enter); } - + + private static void awakenDreams() { + IDreamManager dreamManager = getDreamManager(); + if (dreamManager != null) { + try { + dreamManager.awaken(); + } catch (RemoteException e) { + // fine, stay asleep then + } + } + } + + static IDreamManager getDreamManager() { + return IDreamManager.Stub.asInterface( + ServiceManager.checkService(DreamService.DREAM_SERVICE)); + } + static ITelephony getTelephonyService() { return ITelephony.Stub.asInterface( ServiceManager.checkService(Context.TELEPHONY_SERVICE)); @@ -1835,48 +1934,44 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If we have released the home key, and didn't do anything else // while it was pressed, then it is time to go home! if (!down) { - final boolean homeWasLongPressed = mHomeLongPressed; + cancelPreloadRecentApps(); + mHomePressed = false; - mHomeLongPressed = false; - if (!homeWasLongPressed) { - if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) { - try { - IStatusBarService statusbar = getStatusBarService(); - if (statusbar != null) { - statusbar.cancelPreloadRecentApps(); - } - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException when showing recent apps", e); - // re-acquire status bar service next time it is needed. - mStatusBarService = null; - } - } + if (mHomeConsumed) { + mHomeConsumed = false; + return -1; + } - mHomePressed = false; - if (!canceled) { - // If an incoming call is ringing, HOME is totally disabled. - // (The user is already on the InCallScreen at this point, - // and his ONLY options are to answer or reject the call.) - boolean incomingRinging = false; - try { - ITelephony telephonyService = getTelephonyService(); - if (telephonyService != null) { - incomingRinging = telephonyService.isRinging(); - } - } catch (RemoteException ex) { - Log.w(TAG, "RemoteException from getPhoneInterface()", ex); - } + if (canceled) { + Log.i(TAG, "Ignoring HOME; event canceled."); + return -1; + } - if (incomingRinging) { - Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); - } else { - launchHomeFromHotKey(); - } - } else { - Log.i(TAG, "Ignoring HOME; event canceled."); + // If an incoming call is ringing, HOME is totally disabled. + // (The user is already on the InCallScreen at this point, + // and his ONLY options are to answer or reject the call.) + try { + ITelephony telephonyService = getTelephonyService(); + if (telephonyService != null && telephonyService.isRinging()) { + Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); + return -1; } + } catch (RemoteException ex) { + Log.w(TAG, "RemoteException from getPhoneInterface()", ex); + } + + // Delay handling home if a double-tap is possible. + if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) { + mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case + mHomeDoubleTapPending = true; + mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable, + ViewConfiguration.getDoubleTapTimeout()); return -1; } + + // Go home! + launchHomeFromHotKey(); + return -1; } // If a system window has focus, then it doesn't make sense @@ -1897,25 +1992,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - if (down) { - if (!mHomePressed && mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) { - try { - IStatusBarService statusbar = getStatusBarService(); - if (statusbar != null) { - statusbar.preloadRecentApps(); - } - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException when preloading recent apps", e); - // re-acquire status bar service next time it is needed. - mStatusBarService = null; - } + + // Remember that home is pressed and handle special actions. + if (repeatCount == 0) { + mHomePressed = true; + if (mHomeDoubleTapPending) { + mHomeDoubleTapPending = false; + mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); + handleDoubleTapOnHome(); + } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI + || mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) { + preloadRecentApps(); } - if (repeatCount == 0) { - mHomePressed = true; - } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { - if (!keyguardOn) { - handleLongPressOnHome(); - } + } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { + if (!keyguardOn) { + handleLongPressOnHome(); } } return -1; @@ -1961,8 +2052,12 @@ 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) { + if (down && repeatCount == 0) { + preloadRecentApps(); + } else if (!down) { + toggleRecentApps(); + } } return -1; } else if (keyCode == KeyEvent.KEYCODE_ASSIST) { @@ -1985,6 +2080,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 @@ -2091,6 +2191,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } + if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { + return -1; + } + // Let the application handle the key. return 0; } @@ -2198,7 +2302,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 @@ -2218,6 +2322,51 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mSearchManager; } + private void preloadRecentApps() { + mPreloadedRecentApps = true; + try { + IStatusBarService statusbar = getStatusBarService(); + if (statusbar != null) { + statusbar.preloadRecentApps(); + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when preloading recent apps", e); + // re-acquire status bar service next time it is needed. + mStatusBarService = null; + } + } + + private void cancelPreloadRecentApps() { + if (mPreloadedRecentApps) { + mPreloadedRecentApps = false; + try { + IStatusBarService statusbar = getStatusBarService(); + if (statusbar != null) { + statusbar.cancelPreloadRecentApps(); + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when showing recent apps", e); + // re-acquire status bar service next time it is needed. + mStatusBarService = null; + } + } + } + + private void toggleRecentApps() { + mPreloadedRecentApps = false; // preloading no longer needs to be canceled + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); + try { + IStatusBarService statusbar = getStatusBarService(); + if (statusbar != null) { + statusbar.toggleRecentApps(); + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when showing recent apps", e); + // re-acquire status bar service next time it is needed. + mStatusBarService = null; + } + } + /** * A home key -> launch home action was detected. Take the appropriate action * given the situation with the keyguard. @@ -2370,7 +2519,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 +2538,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 +2643,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 +2664,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 +2693,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 +2702,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 +2715,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 +2761,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 +2771,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 +2783,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 +2800,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 +2852,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 +2865,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 +2896,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 +2907,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 +3009,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 +3026,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 +3041,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 +3086,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 +3116,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 +3127,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 +3162,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 +3172,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. @@ -3009,7 +3277,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDismissKeyguard = mWinDismissingKeyguard == win ? DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; mWinDismissingKeyguard = win; - mForceStatusBarFromKeyguard = false; + mForceStatusBarFromKeyguard = + mShowingLockscreen && mKeyguardMediator.isSecure(); } if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { mAllowLockscreenWhenOn = true; @@ -3341,8 +3610,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); } @@ -3417,6 +3686,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + // If the key would be handled globally, just return the result, don't worry about special + // key processing. + if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { + return result; + } + // Handle special keys. switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: @@ -3741,13 +4016,23 @@ 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); + } else { + try { + IUiModeManager uiModeService = IUiModeManager.Stub.asInterface( + ServiceManager.getService(Context.UI_MODE_SERVICE)); + mUiMode = uiModeService.getCurrentModeType(); + } catch (RemoteException e) { + } } updateRotation(true); - updateOrientationListenerLp(); + synchronized (mLock) { + updateOrientationListenerLp(); + } } }; @@ -3995,13 +4280,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { // enable 180 degree rotation while docked. preferredRotation = mDeskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation; - } else if (mHdmiPlugged && mHdmiRotationLock) { - // Ignore sensor when plugged into HDMI. + } else if (mHdmiPlugged && mDemoHdmiRotationLock) { + // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled. // Note that the dock orientation overrides the HDMI orientation. - preferredRotation = mHdmiRotation; + preferredRotation = mDemoHdmiRotation; + } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED + && mUndockedHdmiRotation >= 0) { + // Ignore sensor when plugged into HDMI and an undocked orientation has + // been specified in the configuration (only for legacy devices without + // full multi-display support). + // Note that the dock orientation overrides the HDMI orientation. + preferredRotation = mUndockedHdmiRotation; + } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + // Application just wants to remain locked in the last rotation. + preferredRotation = lastRotation; } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER - || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) + || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE + || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT + || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER)) || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE @@ -4017,7 +4315,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (sensorRotation != Surface.ROTATION_180 || mAllowAllRotations == 1 - || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR) { + || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR + || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) { preferredRotation = sensorRotation; } else { preferredRotation = lastRotation; @@ -4065,6 +4364,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mSeascapeRotation; case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: + case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: // Return either landscape rotation. if (isLandscapeOrSeascape(preferredRotation)) { return preferredRotation; @@ -4075,6 +4375,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mLandscapeRotation; case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: + case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: // Return either portrait rotation. if (isAnyPortrait(preferredRotation)) { return preferredRotation; @@ -4126,6 +4427,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { return rotation == mPortraitRotation || rotation == mUpsideDownRotation; } + public int getUserRotationMode() { + return Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ? + WindowManagerPolicy.USER_ROTATION_FREE : + WindowManagerPolicy.USER_ROTATION_LOCKED; + } // User rotation: to be used when all else fails in assigning an orientation to the device public void setUserRotationMode(int mode, int rot) { @@ -4358,8 +4665,70 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** + * Return an Intent to launch the currently active dock app as home. Returns + * null if the standard home should be launched, which is the case if any of the following is + * true: + * <ul> + * <li>The device is not in either car mode or desk mode + * <li>The device is in car mode but ENABLE_CAR_DOCK_HOME_CAPTURE is false + * <li>The device is in desk mode but ENABLE_DESK_DOCK_HOME_CAPTURE is false + * <li>The device is in car mode but there's no CAR_DOCK app with METADATA_DOCK_HOME + * <li>The device is in desk mode but there's no DESK_DOCK app with METADATA_DOCK_HOME + * </ul> + * @return + */ + Intent createHomeDockIntent() { + Intent intent = null; + + // What home does is based on the mode, not the dock state. That + // is, when in car mode you should be taken to car home regardless + // of whether we are actually in a car dock. + if (mUiMode == Configuration.UI_MODE_TYPE_CAR) { + if (ENABLE_CAR_DOCK_HOME_CAPTURE) { + intent = mCarDockIntent; + } + } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) { + if (ENABLE_DESK_DOCK_HOME_CAPTURE) { + intent = mDeskDockIntent; + } + } + + if (intent == null) { + return null; + } + + ActivityInfo ai = null; + ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser( + intent, + PackageManager.MATCH_DEFAULT_ONLY, + UserHandle.USER_CURRENT); + if (info != null) { + ai = info.activityInfo; + } + if (ai != null + && ai.metaData != null + && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) { + intent = new Intent(intent); + intent.setClassName(ai.packageName, ai.name); + return intent; + } + + return null; + } + void startDockOrHome() { - // We don't have dock home anymore. Home is home. If you lived here, you'd be home by now. + awakenDreams(); + + Intent dock = createHomeDockIntent(); + if (dock != null) { + try { + mContext.startActivityAsUser(dock, UserHandle.CURRENT); + return; + } catch (ActivityNotFoundException e) { + } + } + mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT); } @@ -4386,9 +4755,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { ActivityManagerNative.getDefault().stopAppSwitches(); sendCloseSystemWindows(); + Intent dock = createHomeDockIntent(); + if (dock != null) { + int result = ActivityManagerNative.getDefault() + .startActivityAsUser(null, null, dock, + dock.resolveTypeIfNeeded(mContext.getContentResolver()), + null, null, 0, + ActivityManager.START_FLAG_ONLY_IF_NEEDED, + null, null, null, UserHandle.USER_CURRENT); + if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) { + return false; + } + } } 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 +4841,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 +4933,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 +4953,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); @@ -4596,7 +4995,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu); } - pw.print(prefix); pw.print("mDockMode="); pw.print(mDockMode); + pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode); + pw.print(" mDockMode="); pw.print(mDockMode); pw.print(" mCarDockRotation="); pw.print(mCarDockRotation); pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation); pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode); @@ -4617,6 +5017,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); @@ -4713,7 +5129,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation); pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation); pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation); - pw.print(prefix); pw.print("mHdmiRotation="); pw.print(mHdmiRotation); - pw.print(" mHdmiRotationLock="); pw.println(mHdmiRotationLock); + pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation); + pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock); + pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation); } } 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/ClockView.java b/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java index 6c701c7..34bf6e7 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java @@ -42,7 +42,7 @@ import com.android.internal.R; public class ClockView extends RelativeLayout { private static final String ANDROID_CLOCK_FONT_FILE = "/system/fonts/AndroidClock.ttf"; private final static String M12 = "h:mm"; - private final static String M24 = "kk:mm"; + private final static String M24 = "HH:mm"; private Calendar mCalendar; private String mFormat; diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java index cd7324c..c68bab5 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.os.PowerManager; import android.os.SystemClock; +import android.os.UserHandle; import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.view.View; @@ -104,7 +105,8 @@ public class EmergencyButton extends Button { Intent intent = new Intent(ACTION_EMERGENCY_DIAL); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - getContext().startActivity(intent); + getContext().startActivityAsUser(intent, + new UserHandle(mLockPatternUtils.getCurrentUser())); } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java new file mode 100644 index 0000000..cfe1ef4 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.policy.impl.keyguard; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.LinearLayout; + +import com.android.internal.R; + +public class EmergencyCarrierArea extends LinearLayout { + + private CarrierText mCarrierText; + private EmergencyButton mEmergencyButton; + + public EmergencyCarrierArea(Context context) { + super(context); + } + + public EmergencyCarrierArea(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mCarrierText = (CarrierText) findViewById(R.id.carrier_text); + mEmergencyButton = (EmergencyButton) findViewById(R.id.emergency_call_button); + + // The emergency button overlaps the carrier text, only noticeable when highlighted. + // So temporarily hide the carrier text while the emergency button is pressed. + mEmergencyButton.setOnTouchListener(new OnTouchListener(){ + @Override + public boolean onTouch(View v, MotionEvent event) { + switch(event.getAction()) { + case MotionEvent.ACTION_DOWN: + mCarrierText.animate().alpha(0); + break; + case MotionEvent.ACTION_UP: + mCarrierText.animate().alpha(1); + break; + } + return false; + }}); + } +} 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/KeyguardCircleFramedDrawable.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java index 79b66f4..fe32099 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java @@ -100,6 +100,11 @@ class KeyguardCircleFramedDrawable extends Drawable { mFramePath = new Path(); } + public void reset() { + mScale = 1f; + mPressed = false; + } + @Override public void draw(Canvas canvas) { // clear background @@ -157,4 +162,14 @@ class KeyguardCircleFramedDrawable extends Drawable { @Override public void setColorFilter(ColorFilter cf) { } + + public boolean verifyParams(float iconSize, int frameColor, float stroke, + int frameShadowColor, float shadowRadius, int highlightColor) { + return mSize == iconSize + && mFrameColor == frameColor + && mStrokeWidth == stroke + && mFrameShadowColor == frameShadowColor + && mShadowRadius == shadowRadius + && mHighlightColor == highlightColor; + } } 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..7315aad 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java @@ -18,17 +18,22 @@ package com.android.internal.policy.impl.keyguard; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.util.Log; +import android.view.IRotationWatcher; +import android.view.IWindowManager; import android.view.View; import android.widget.ImageButton; import android.widget.LinearLayout; import com.android.internal.R; - import com.android.internal.widget.LockPatternUtils; +import java.lang.Math; + public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView { private static final String TAG = "FULKeyguardFaceUnlockView"; @@ -45,6 +50,30 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu private boolean mIsShowing = false; private final Object mIsShowingLock = new Object(); + private int mLastRotation; + private boolean mWatchingRotation; + private final IWindowManager mWindowManager = + IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + + private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() { + public void onRotationChanged(int rotation) { + if (DEBUG) Log.d(TAG, "onRotationChanged(): " + mLastRotation + "->" + rotation); + + // If the difference between the new rotation value and the previous rotation value is + // equal to 2, the rotation change was 180 degrees. This stops the biometric unlock + // and starts it in the new position. This is not performed for 90 degree rotations + // since a 90 degree rotation is a configuration change, which takes care of this for + // us. + if (Math.abs(rotation - mLastRotation) == 2) { + if (mBiometricUnlock != null) { + mBiometricUnlock.stop(); + maybeStartBiometricUnlock(); + } + } + mLastRotation = rotation; + } + }; + public KeyguardFaceUnlockView(Context context) { this(context, null); } @@ -91,6 +120,14 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu mBiometricUnlock.stop(); } KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback); + if (mWatchingRotation) { + try { + mWindowManager.removeRotationWatcher(mRotationWatcher); + mWatchingRotation = false; + } catch (RemoteException e) { + Log.e(TAG, "Remote exception when removing rotation watcher"); + } + } } @Override @@ -100,14 +137,35 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu mBiometricUnlock.stop(); } KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback); + if (mWatchingRotation) { + try { + mWindowManager.removeRotationWatcher(mRotationWatcher); + mWatchingRotation = false; + } catch (RemoteException e) { + Log.e(TAG, "Remote exception when removing rotation watcher"); + } + } } @Override public void onResume(int reason) { if (DEBUG) Log.d(TAG, "onResume()"); mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible(); - maybeStartBiometricUnlock(); + if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) { + maybeStartBiometricUnlock(); + } KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback); + + // Registers a callback which handles stopping the biometric unlock and restarting it in + // the new position for a 180 degree rotation change. + if (!mWatchingRotation) { + try { + mLastRotation = mWindowManager.watchRotation(mRotationWatcher); + mWatchingRotation = true; + } catch (RemoteException e) { + Log.e(TAG, "Remote exception when adding rotation watcher"); + } + } } @Override @@ -172,9 +230,15 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu return; } - // TODO: Some of these conditions are handled in KeyguardSecurityModel and may not be - // necessary here. + // Although these same conditions are handled in KeyguardSecurityModel, they are still + // necessary here. When a tablet is rotated 90 degrees, a configuration change is + // triggered and everything is torn down and reconstructed. That means + // KeyguardSecurityModel gets a chance to take care of the logic and doesn't even + // reconstruct KeyguardFaceUnlockView if the biometric unlock should be suppressed. + // However, for a 180 degree rotation, no configuration change is triggered, so only + // the logic here is capable of suppressing Face Unlock. if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE + && monitor.isAlternateUnlockEnabled() && !monitor.getMaxBiometricUnlockAttemptsReached() && !backupIsTimedOut) { mBiometricUnlock.start(); @@ -197,7 +261,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(); @@ -207,6 +271,14 @@ public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecu } @Override + public void onUserSwitchComplete(int userId) { + if (DEBUG) Log.d(TAG, "onUserSwitchComplete(" + userId + ")"); + if (mBiometricUnlock != null) { + maybeStartBiometricUnlock(); + } + } + + @Override public void onKeyguardVisibilityChanged(boolean showing) { if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); boolean wasShowing = false; 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..c3077c7 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -30,10 +30,12 @@ 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; import android.graphics.Rect; +import android.media.RemoteControlClient; import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; @@ -54,6 +56,7 @@ import android.widget.RemoteViews.OnClickHandler; import com.android.internal.R; import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.internal.policy.impl.keyguard.KeyguardUpdateMonitor.DisplayClientState; import com.android.internal.widget.LockPatternUtils; import java.io.File; @@ -61,9 +64,16 @@ import java.util.List; public class KeyguardHostView extends KeyguardViewBase { private static final String TAG = "KeyguardHostView"; + // Transport control states. + static final int TRANSPORT_GONE = 0; + static final int TRANSPORT_INVISIBLE = 1; + static final int TRANSPORT_VISIBLE = 2; + + private int mTransportState = TRANSPORT_GONE; // Use this to debug all of keyguard public static boolean DEBUG = KeyguardViewMediator.DEBUG; + public static boolean DEBUGXPORT = true; // debug music transport control // Found in KeyguardAppWidgetPickActivity.java static final int APPWIDGET_HOST_ID = 0x4B455947; @@ -101,14 +111,14 @@ public class KeyguardHostView extends KeyguardViewBase { private boolean mSafeModeEnabled; private boolean mUserSetupCompleted; - // User for whom this host view was created - private int mUserId; - /*package*/ interface TransportCallback { - void onListenerDetached(); - void onListenerAttached(); - void onPlayStateChanged(); - } + // 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; + + protected int mClientGeneration; /*package*/ interface UserSwitcherCallback { void hideSecurityView(int duration); @@ -128,29 +138,56 @@ public class KeyguardHostView extends KeyguardViewBase { public KeyguardHostView(Context context, AttributeSet attrs) { super(context, attrs); - mLockPatternUtils = new LockPatternUtils(context); - mUserId = mLockPatternUtils.getCurrentUser(); - mAppWidgetHost = new AppWidgetHost( - context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); - mAppWidgetHost.setUserId(mUserId); - cleanupAppWidgetIds(); - mAppWidgetManager = AppWidgetManager.getInstance(mContext); - mSecurityModel = new KeyguardSecurityModel(context); + if (DEBUG) Log.e(TAG, "KeyguardHostView()"); - mViewStateManager = new KeyguardViewStateManager(this); + 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(); 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(); + + // These need to be created with the user context... + 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; + } + + mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler, + Looper.myLooper()); + + cleanupAppWidgetIds(); + + mAppWidgetManager = AppWidgetManager.getInstance(userContext); + + mSecurityModel = new KeyguardSecurityModel(context); + + mViewStateManager = new KeyguardViewStateManager(this); + mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; + // Ensure we have the current state *before* we call showAppropriateWidgetPage() + getInitialTransportState(); + if (mSafeModeEnabled) { Log.v(TAG, "Keyguard widgets disabled by safe mode"); } @@ -162,6 +199,16 @@ public class KeyguardHostView extends KeyguardViewBase { } } + private void getInitialTransportState() { + DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext) + .getCachedDisplayClientState(); + mTransportState = (dcs.clearing ? TRANSPORT_GONE : + (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE)); + + if (DEBUG) Log.v(TAG, "Initial transport state: " + + mTransportState + ", pbstate=" + dcs.playbackState); + } + private void cleanupAppWidgetIds() { // Since this method may delete a widget (which we can't do until boot completed) we // may have to defer it until after boot complete. @@ -169,19 +216,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,8 +258,59 @@ public class KeyguardHostView extends KeyguardViewBase { mCleanupAppWidgetsOnBootCompleted = false; } } + @Override + public void onUserSwitchComplete(int userId) { + if (mKeyguardMultiUserSelectorView != null) { + mKeyguardMultiUserSelectorView.finalizeActiveUserView(true); + } + } + @Override + void onMusicClientIdChanged( + int clientGeneration, boolean clearing, android.app.PendingIntent intent) { + // Set transport state to invisible until we know music is playing (below) + if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) { + Log.v(TAG, (clearing ? "hide" : "show") + " transport, gen:" + clientGeneration); + } + mClientGeneration = clientGeneration; + final int newState = (clearing ? TRANSPORT_GONE + : (mTransportState == TRANSPORT_VISIBLE ? + TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE)); + if (newState != mTransportState) { + mTransportState = newState; + if (DEBUGXPORT) Log.v(TAG, "update widget: transport state changed"); + KeyguardHostView.this.post(mSwitchPageRunnable); + } + } + @Override + public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { + if (DEBUGXPORT) Log.v(TAG, "music state changed: " + playbackState); + if (mTransportState != TRANSPORT_GONE) { + final int newState = (isMusicPlaying(playbackState) ? + TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE); + if (newState != mTransportState) { + mTransportState = newState; + if (DEBUGXPORT) Log.v(TAG, "update widget: play state changed"); + KeyguardHostView.this.post(mSwitchPageRunnable); + } + } + } }; + private static final boolean isMusicPlaying(int playbackState) { + // This should agree with the list in AudioService.isPlaystateActive() + switch (playbackState) { + case RemoteControlClient.PLAYSTATE_PLAYING: + case RemoteControlClient.PLAYSTATE_BUFFERING: + case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: + case RemoteControlClient.PLAYSTATE_REWINDING: + case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: + case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: + return true; + default: + return false; + } + } + private SlidingChallengeLayout mSlidingChallengeLayout; @Override @@ -233,10 +333,15 @@ public class KeyguardHostView extends KeyguardViewBase { } private int getWidgetPosition(int id) { - final int children = mAppWidgetContainer.getChildCount(); + final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer; + final int children = appWidgetContainer.getChildCount(); for (int i = 0; i < children; i++) { - if (mAppWidgetContainer.getWidgetPageAt(i).getContent().getId() == id) { + final View content = appWidgetContainer.getWidgetPageAt(i).getContent(); + if (content != null && content.getId() == id) { return i; + } else if (content == null) { + // Attempt to track down bug #8886916 + Log.w(TAG, "*** Null content at " + "i=" + i + ",id=" + id + ",N=" + children); } } return -1; @@ -270,9 +375,7 @@ public class KeyguardHostView extends KeyguardViewBase { mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view); mViewStateManager.setSecurityViewContainer(mSecurityViewContainer); - if (!(mContext instanceof Activity)) { - setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK); - } + setBackButtonEnabled(false); addDefaultWidgets(); @@ -289,6 +392,13 @@ public class KeyguardHostView extends KeyguardViewBase { updateSecurityViews(); } + private void setBackButtonEnabled(boolean enabled) { + if (mContext instanceof Activity) return; // always enabled in activity mode + setSystemUiVisibility(enabled ? + getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK : + getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK); + } + private boolean shouldEnableAddWidget() { return numWidgets() < MAX_WIDGETS && mUserSetupCompleted; } @@ -342,21 +452,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 +505,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(); @@ -865,6 +977,10 @@ public class KeyguardHostView extends KeyguardViewBase { // Discard current runnable if we're switching back to the selector view setOnDismissAction(null); } + if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) { + // we're showing account as a backup, provide a way to get back to primary + setBackButtonEnabled(true); + } mCurrentSecuritySelection = securityMode; } @@ -1001,12 +1117,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); } @@ -1073,10 +1190,8 @@ public class KeyguardHostView extends KeyguardViewBase { } private void addDefaultWidgets() { - LayoutInflater inflater = LayoutInflater.from(mContext); - inflater.inflate(R.layout.keyguard_transport_control_view, this, true); - if (!mSafeModeEnabled && !widgetsDisabledByDpm()) { + LayoutInflater inflater = LayoutInflater.from(mContext); View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false); mAppWidgetContainer.addWidget(addWidget, 0); View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view); @@ -1102,66 +1217,19 @@ public class KeyguardHostView extends KeyguardViewBase { } enableUserSelectorIfNecessary(); - initializeTransportControl(); } - private boolean removeTransportFromWidgetPager() { - int page = getWidgetPosition(R.id.keyguard_transport_control); - if (page != -1) { - mAppWidgetContainer.removeWidget(mTransportControl); - - // XXX keep view attached so we still get show/hide events from AudioManager - KeyguardHostView.this.addView(mTransportControl); - mTransportControl.setVisibility(View.GONE); - mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE); - return true; - } - return false; - } - - private void addTransportToWidgetPager() { - if (getWidgetPosition(R.id.keyguard_transport_control) == -1) { - KeyguardHostView.this.removeView(mTransportControl); - // insert to left of camera if it exists, otherwise after right-most widget - int lastWidget = mAppWidgetContainer.getChildCount() - 1; - int position = 0; // handle no widget case - if (lastWidget >= 0) { - position = mAppWidgetContainer.isCameraPage(lastWidget) ? - lastWidget : lastWidget + 1; - } - mAppWidgetContainer.addWidget(mTransportControl, position); - mTransportControl.setVisibility(View.VISIBLE); - } - } - - private void initializeTransportControl() { - mTransportControl = - (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control); - mTransportControl.setVisibility(View.GONE); - - // This code manages showing/hiding the transport control. We keep it around and only - // add it to the hierarchy if it needs to be present. - if (mTransportControl != null) { - mTransportControl.setKeyguardCallback(new TransportCallback() { - @Override - public void onListenerDetached() { - if (removeTransportFromWidgetPager()) { - mTransportControl.post(mSwitchPageRunnable); - } - } - - @Override - public void onListenerAttached() { - // Transport will be added when playstate changes... - mTransportControl.post(mSwitchPageRunnable); - } - - @Override - public void onPlayStateChanged() { - mTransportControl.post(mSwitchPageRunnable); - } - }); + /** + * Create KeyguardTransportControlView on demand. + * @return + */ + private KeyguardTransportControlView getOrCreateTransportControl() { + if (mTransportControl == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + mTransportControl = (KeyguardTransportControlView) + inflater.inflate(R.layout.keyguard_transport_control_view, this, false); } + return mTransportControl; } private int getInsertPageIndex() { @@ -1330,25 +1398,28 @@ public class KeyguardHostView extends KeyguardViewBase { @Override public Parcelable onSaveInstanceState() { - if (DEBUG) Log.d(TAG, "onSaveInstanceState"); + if (DEBUG) Log.d(TAG, "onSaveInstanceState, tstate=" + mTransportState); Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); - ss.transportState = mViewStateManager.getTransportState(); + // If the transport is showing, force it to show it on restore. + final boolean showing = mTransportControl != null + && mAppWidgetContainer.getWidgetPageIndex(mTransportControl) >= 0; + ss.transportState = showing ? TRANSPORT_VISIBLE : mTransportState; ss.appWidgetToShow = mAppWidgetToShow; return ss; } @Override public void onRestoreInstanceState(Parcelable state) { - if (DEBUG) Log.d(TAG, "onRestoreInstanceState"); if (!(state instanceof SavedState)) { super.onRestoreInstanceState(state); return; } SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); - mViewStateManager.setTransportState(ss.transportState); + mTransportState = (ss.transportState); mAppWidgetToShow = ss.appWidgetToShow; + if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState); post(mSwitchPageRunnable); } @@ -1368,19 +1439,54 @@ public class KeyguardHostView extends KeyguardViewBase { } private void showAppropriateWidgetPage() { - int state = mViewStateManager.getTransportState(); - boolean isMusicPlaying = mTransportControl.isMusicPlaying() - || state == KeyguardViewStateManager.TRANSPORT_VISIBLE; - if (isMusicPlaying) { - mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE); - addTransportToWidgetPager(); - } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) { - mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE); - } - int pageToShow = getAppropriateWidgetPage(isMusicPlaying); + int state = mTransportState; + ensureTransportPresentOrRemoved(state); + int pageToShow = getAppropriateWidgetPage(state); mAppWidgetContainer.setCurrentPage(pageToShow); } + /** + * Examines the current state and adds the transport to the widget pager when the state changes. + * + * Showing the initial transport and keeping it around is a bit tricky because the signals + * coming from music players aren't always clear. Here's how the states are handled: + * + * {@link TRANSPORT_GONE} means we have no reason to show the transport - remove it if present. + * + * {@link TRANSPORT_INVISIBLE} means we have potential to show the transport because a music + * player is registered but not currently playing music (or we don't know the state yet). The + * code adds it conditionally on play state. + * + * {@link #TRANSPORT_VISIBLE} means a music player is active and transport should be showing. + * + * Once the transport is showing, we always show it until keyguard is dismissed. This state is + * maintained by onSave/RestoreInstanceState(). This state is cleared in + * {@link KeyguardViewManager#hide} when keyguard is dismissed, which causes the transport to be + * gone when keyguard is restarted until we get an update with the current state. + * + * @param state + */ + private void ensureTransportPresentOrRemoved(int state) { + final boolean showing = getWidgetPosition(R.id.keyguard_transport_control) != -1; + final boolean visible = state == TRANSPORT_VISIBLE; + final boolean shouldBeVisible = state == TRANSPORT_INVISIBLE && isMusicPlaying(state); + if (!showing && (visible || shouldBeVisible)) { + if (DEBUGXPORT) Log.v(TAG, "add transport"); + // insert to left of camera if it exists, otherwise after right-most widget + int lastWidget = mAppWidgetContainer.getChildCount() - 1; + int position = 0; // handle no widget case + if (lastWidget >= 0) { + position = mAppWidgetContainer.isCameraPage(lastWidget) ? + lastWidget : lastWidget + 1; + } + mAppWidgetContainer.addWidget(getOrCreateTransportControl(), position); + } else if (showing && state == TRANSPORT_GONE) { + if (DEBUGXPORT) Log.v(TAG, "remove transport"); + mAppWidgetContainer.removeWidget(getOrCreateTransportControl()); + mTransportControl = null; + } + } + private CameraWidgetFrame findCameraPage() { for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) { if (mAppWidgetContainer.isCameraPage(i)) { @@ -1394,7 +1500,7 @@ public class KeyguardHostView extends KeyguardViewBase { return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control); } - private int getAppropriateWidgetPage(boolean isMusicPlaying) { + private int getAppropriateWidgetPage(int musicTransportState) { // assumes at least one widget (besides camera + add) if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) { final int childCount = mAppWidgetContainer.getChildCount(); @@ -1407,9 +1513,9 @@ public class KeyguardHostView extends KeyguardViewBase { mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID; } // if music playing, show transport - if (isMusicPlaying) { + if (musicTransportState == TRANSPORT_VISIBLE) { if (DEBUG) Log.d(TAG, "Music playing, show transport"); - return mAppWidgetContainer.getWidgetPageIndex(mTransportControl); + return mAppWidgetContainer.getWidgetPageIndex(getOrCreateTransportControl()); } // else show the right-most widget (except for camera) @@ -1452,10 +1558,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 +1586,7 @@ public class KeyguardHostView extends KeyguardViewBase { } } }; - multiUser.setCallback(callback); + mKeyguardMultiUserSelectorView.setCallback(callback); } else { Throwable t = new Throwable(); t.fillInStackTrace(); @@ -1496,7 +1601,13 @@ public class KeyguardHostView extends KeyguardViewBase { @Override public void cleanUp() { - + // Make sure we let go of all widgets and their package contexts promptly. If we don't do + // this, and the associated application is uninstalled, it can cause a soft reboot. + int count = mAppWidgetContainer.getChildCount(); + for (int i = 0; i < count; i++) { + KeyguardWidgetFrame frame = mAppWidgetContainer.getWidgetPageAt(i); + frame.removeAllViews(); + } } /** @@ -1516,8 +1627,6 @@ public class KeyguardHostView extends KeyguardViewBase { return !configDisabled || isTestHarness || fileOverride; } - - public void goToUserSwitcher() { mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector)); } @@ -1537,6 +1646,12 @@ public class KeyguardHostView extends KeyguardViewBase { } public boolean handleBackKey() { + if (mCurrentSecuritySelection == SecurityMode.Account) { + // go back to primary screen and re-disable back + setBackButtonEnabled(false); + showPrimarySecurityScreen(false /*turningOff*/); + return true; + } if (mCurrentSecuritySelection != SecurityMode.None) { mCallback.dismiss(false); return true; @@ -1553,7 +1668,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..9b58803 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java @@ -23,28 +23,48 @@ import android.content.ContentResolver; import android.content.Context; import android.os.BatteryManager; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Slog; import android.view.View; import android.widget.TextView; import libcore.util.MutableInt; +import java.lang.ref.WeakReference; + import com.android.internal.R; +import com.android.internal.widget.ILockSettings; +import com.android.internal.widget.LockPatternUtils; /*** * 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; static final int SECURITY_MESSAGE_DURATION = 5000; protected static final int FADE_DURATION = 750; + private static final String TAG = "KeyguardMessageArea"; + // are we showing battery information? boolean mShowingBatteryInfo = false; @@ -70,6 +90,9 @@ class KeyguardMessageArea extends TextView { CharSequence mMessage; boolean mShowingMessage; + private CharSequence mSeparator; + private LockPatternUtils mLockPatternUtils; + Runnable mClearMessageRunnable = new Runnable() { @Override public void run() { @@ -144,8 +167,6 @@ class KeyguardMessageArea extends TextView { } }; - private CharSequence mSeparator; - public KeyguardMessageArea(Context context) { this(context, null); } @@ -153,6 +174,8 @@ class KeyguardMessageArea extends TextView { public KeyguardMessageArea(Context context, AttributeSet attrs) { super(context, attrs); + mLockPatternUtils = new LockPatternUtils(context); + // This is required to ensure marquee works setSelected(true); @@ -174,7 +197,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)); } /** @@ -214,11 +239,12 @@ class KeyguardMessageArea extends TextView { String getOwnerInfo() { ContentResolver res = getContext().getContentResolver(); - final boolean ownerInfoEnabled = Settings.Secure.getIntForUser(res, - Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1, UserHandle.USER_CURRENT) != 0; - return ownerInfoEnabled && !mShowingMessage ? - Settings.Secure.getStringForUser(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO, - UserHandle.USER_CURRENT) : null; + String info = null; + final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(); + if (ownerInfoEnabled && !mShowingMessage) { + info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser()); + } + return info; } private CharSequence getChargeInfo(MutableInt icon) { @@ -271,4 +297,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..387e0ce 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) { @@ -123,20 +124,32 @@ class KeyguardMultiUserAvatar extends FrameLayout { mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar); mUserName = (TextView) findViewById(R.id.keyguard_user_name); - Bitmap icon = null; - try { - icon = BitmapFactory.decodeFile(rewriteIconPath(user.iconPath)); - } catch (Exception e) { - if (DEBUG) Log.d(TAG, "failed to open profile icon " + user.iconPath, e); - } + mFramed = (KeyguardCircleFramedDrawable) + KeyguardViewMediator.getAvatarCache().get(user.id); + + // If we can't find it or the params don't match, create the drawable again + if (mFramed == null + || !mFramed.verifyParams(mIconSize, mFrameColor, mStroke, mFrameShadowColor, + mShadowRadius, mHighlightColor)) { + Bitmap icon = null; + try { + icon = BitmapFactory.decodeFile(rewriteIconPath(user.iconPath)); + } catch (Exception e) { + if (DEBUG) Log.d(TAG, "failed to open profile icon " + user.iconPath, e); + } - if (icon == null) { - icon = BitmapFactory.decodeResource(mContext.getResources(), - com.android.internal.R.drawable.ic_contact_picture); + if (icon == null) { + icon = BitmapFactory.decodeResource(mContext.getResources(), + com.android.internal.R.drawable.ic_contact_picture); + } + + mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke, + mFrameShadowColor, mShadowRadius, mHighlightColor); + KeyguardViewMediator.getAvatarCache().put(user.id, mFramed); } - mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke, - mFrameShadowColor, mShadowRadius, mHighlightColor); + mFramed.reset(); + mUserImage.setImageDrawable(mFramed); mUserName.setText(mUserInfo.name); setOnClickListener(mUserSelector); @@ -212,13 +225,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/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java index ffa88d5..5e3b7da 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java @@ -74,7 +74,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick private int mCurrentPlayState; private AudioManager mAudioManager; private IRemoteControlDisplayWeak mIRCD; - private boolean mMusicClientPresent = true; /** * The metadata which should be populated into the view once we've been attached @@ -110,12 +109,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick break; case MSG_SET_GENERATION_ID: - if (msg.arg2 != 0) { - // This means nobody is currently registered. Hide the view. - onListenerDetached(); - } else { - onListenerAttached(); - } if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2); mClientGeneration = msg.arg1; mClientIntent = (PendingIntent) msg.obj; @@ -124,7 +117,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick } } }; - private KeyguardHostView.TransportCallback mTransportCallback; /** * This class is required to have weak linkage to the current TransportControlView @@ -140,7 +132,8 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick mLocalHandler = new WeakReference<Handler>(handler); } - public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) { + public void setPlaybackState(int generationId, int state, long stateChangeTimeMs, + long currentPosMs, float speed) { Handler handler = mLocalHandler.get(); if (handler != null) { handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget(); @@ -154,7 +147,7 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick } } - public void setTransportControlFlags(int generationId, int flags) { + public void setTransportControlInfo(int generationId, int flags, int posCapabilities) { Handler handler = mLocalHandler.get(); if (handler != null) { handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags) @@ -195,26 +188,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick mIRCD = new IRemoteControlDisplayWeak(mHandler); } - protected void onListenerDetached() { - mMusicClientPresent = false; - if (DEBUG) Log.v(TAG, "onListenerDetached()"); - if (mTransportCallback != null) { - mTransportCallback.onListenerDetached(); - } else { - Log.w(TAG, "onListenerDetached: no callback"); - } - } - - private void onListenerAttached() { - mMusicClientPresent = true; - if (DEBUG) Log.v(TAG, "onListenerAttached()"); - if (mTransportCallback != null) { - mTransportCallback.onListenerAttached(); - } else { - Log.w(TAG, "onListenerAttached(): no callback"); - } - } - private void updateTransportControls(int transportControlFlags) { mTransportControlFlags = transportControlFlags; } @@ -250,6 +223,15 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick } @Override + protected void onSizeChanged (int w, int h, int oldw, int oldh) { + if (mAttached) { + int dim = Math.min(512, Math.max(w, h)); + if (DEBUG) Log.v(TAG, "TCV uses bitmap size=" + dim); + mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim); + } + } + + @Override public void onDetachedFromWindow() { if (DEBUG) Log.v(TAG, "onDetachFromWindow()"); super.onDetachedFromWindow(); @@ -333,11 +315,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick updatePlayPauseState(mCurrentPlayState); } - public boolean isMusicPlaying() { - return mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING - || mCurrentPlayState == RemoteControlClient.PLAYSTATE_BUFFERING; - } - private static void setVisibilityBasedOnFlag(View view, int flags, int flag) { if ((flags & flag) != 0) { view.setVisibility(View.VISIBLE); @@ -381,7 +358,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick mBtnPlay.setImageResource(imageResId); mBtnPlay.setContentDescription(getResources().getString(imageDescId)); mCurrentPlayState = state; - mTransportCallback.onPlayStateChanged(); } static class SavedState extends BaseSavedState { @@ -414,28 +390,6 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick }; } - @Override - public Parcelable onSaveInstanceState() { - Parcelable superState = super.onSaveInstanceState(); - SavedState ss = new SavedState(superState); - ss.clientPresent = mMusicClientPresent; - return ss; - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - if (!(state instanceof SavedState)) { - super.onRestoreInstanceState(state); - return; - } - SavedState ss = (SavedState) state; - super.onRestoreInstanceState(ss.getSuperState()); - if (ss.clientPresent) { - if (DEBUG) Log.v(TAG, "Reattaching client because it was attached"); - onListenerAttached(); - } - } - public void onClick(View v) { int keyCode = -1; if (v == mBtnPrev) { @@ -513,8 +467,4 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick return false; } } - - public void setKeyguardCallback(KeyguardHostView.TransportCallback transportCallback) { - mTransportCallback = transportCallback; - } } 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..5a64586 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java @@ -18,12 +18,15 @@ package com.android.internal.policy.impl.keyguard; import android.app.ActivityManagerNative; import android.app.IUserSwitchObserver; +import android.app.PendingIntent; 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 android.graphics.Bitmap; + import static android.os.BatteryManager.BATTERY_STATUS_FULL; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN; @@ -32,7 +35,9 @@ 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.media.IRemoteControlDisplay; import android.os.BatteryManager; +import android.os.Bundle; import android.os.Handler; import android.os.IRemoteCallback; import android.os.Message; @@ -79,10 +84,14 @@ 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 final int MSG_SET_CURRENT_CLIENT_ID = 315; + protected static final int MSG_SET_PLAYBACK_STATE = 316; + protected static final int MSG_USER_INFO_CHANGED = 317; private static KeyguardUpdateMonitor sInstance; @@ -116,6 +125,8 @@ public class KeyguardUpdateMonitor { mCallbacks = Lists.newArrayList(); private ContentObserver mDeviceProvisionedObserver; + private boolean mSwitchingUser; + private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -147,8 +158,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); @@ -159,11 +173,70 @@ public class KeyguardUpdateMonitor { case MSG_BOOT_COMPLETED: handleBootCompleted(); break; - + case MSG_SET_CURRENT_CLIENT_ID: + handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj); + break; + case MSG_SET_PLAYBACK_STATE: + handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj); + break; + case MSG_USER_INFO_CHANGED: + handleUserInfoChanged(msg.arg1); + break; } } }; + private AudioManager mAudioManager; + + static class DisplayClientState { + public int clientGeneration; + public boolean clearing; + public PendingIntent intent; + public int playbackState; + public long playbackEventTime; + } + + private DisplayClientState mDisplayClientState = new DisplayClientState(); + + /** + * This currently implements the bare minimum required to enable showing and hiding + * KeyguardTransportControl. There's a lot of client state to maintain which is why + * KeyguardTransportControl maintains an independent connection while it's showing. + */ + private final IRemoteControlDisplay.Stub mRemoteControlDisplay = + new IRemoteControlDisplay.Stub() { + + public void setPlaybackState(int generationId, int state, long stateChangeTimeMs, + long currentPosMs, float speed) { + Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE, + generationId, state, stateChangeTimeMs); + mHandler.sendMessage(msg); + } + + public void setMetadata(int generationId, Bundle metadata) { + + } + + public void setTransportControlInfo(int generationId, int flags, int posCapabilities) { + + } + + public void setArtwork(int generationId, Bitmap bitmap) { + + } + + public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) { + + } + + public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent, + boolean clearing) throws RemoteException { + Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID, + clientGeneration, (clearing ? 1 : 0), mediaIntent); + mHandler.sendMessage(msg); + } + }; + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { @@ -211,6 +284,17 @@ public class KeyguardUpdateMonitor { } }; + private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() { + + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED, + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0)); + } + } + }; + /** * When we receive a * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, @@ -320,6 +404,47 @@ public class KeyguardUpdateMonitor { return sInstance; } + protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) { + mDisplayClientState.clientGeneration = clientGeneration; + mDisplayClientState.clearing = clearing; + mDisplayClientState.intent = p; + if (DEBUG) + Log.v(TAG, "handleSetGenerationId(g=" + clientGeneration + ", clear=" + clearing + ")"); + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onMusicClientIdChanged(clientGeneration, clearing, p); + } + } + } + + protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) { + if (DEBUG) + Log.v(TAG, "handleSetPlaybackState(gen=" + generationId + + ", state=" + playbackState + ", t=" + eventTime + ")"); + mDisplayClientState.playbackState = playbackState; + mDisplayClientState.playbackEventTime = eventTime; + if (generationId == mDisplayClientState.clientGeneration) { + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onMusicPlaybackStateChanged(playbackState, eventTime); + } + } + } else { + Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current"); + } + } + + private void handleUserInfoChanged(int userId) { + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onUserInfoChanged(userId); + } + } + } + private KeyguardUpdateMonitor(Context context) { mContext = context; @@ -354,16 +479,24 @@ public class KeyguardUpdateMonitor { bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED); context.registerReceiver(mBroadcastReceiver, bootCompleteFilter); + final IntentFilter userInfoFilter = new IntentFilter(Intent.ACTION_USER_INFO_CHANGED); + context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, userInfoFilter, + null, null); + try { ActivityManagerNative.getDefault().registerUserSwitchObserver( 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)); + mSwitchingUser = true; } @Override public void onUserSwitchComplete(int newUserId) throws RemoteException { + mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE, + newUserId)); + mSwitchingUser = false; } }); } catch (RemoteException e) { @@ -418,16 +551,15 @@ 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); try { reply.sendResult(null); } catch (RemoteException e) { @@ -435,10 +567,24 @@ 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() { mBootCompleted = true; + mAudioManager = new AudioManager(mContext); + mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -448,7 +594,7 @@ public class KeyguardUpdateMonitor { } /** - * We need to store this state in the KeyguardUpdateMonitor since this class will not be + * We need to store this state in the KeyguardUpdateMonitor since this class will not be * destroyed. */ public boolean hasBootCompleted() { @@ -456,7 +602,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++) { @@ -617,6 +763,10 @@ public class KeyguardUpdateMonitor { return mKeyguardIsVisible; } + public boolean isSwitchingUser() { + return mSwitchingUser; + } + private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) { final boolean nowPluggedIn = current.isPluggedIn(); final boolean wasPluggedIn = old.isPluggedIn(); @@ -717,6 +867,12 @@ public class KeyguardUpdateMonitor { callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); callback.onClockVisibilityChanged(); callback.onSimStateChanged(mSimState); + callback.onMusicClientIdChanged( + mDisplayClientState.clientGeneration, + mDisplayClientState.clearing, + mDisplayClientState.intent); + callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState, + mDisplayClientState.playbackEventTime); } public void sendKeyguardVisibilityChanged(boolean showing) { @@ -820,4 +976,8 @@ public class KeyguardUpdateMonitor { || simState == IccCardConstants.State.PUK_REQUIRED || simState == IccCardConstants.State.PERM_DISABLED); } + + public DisplayClientState getCachedDisplayClientState() { + return mDisplayClientState; + } } 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..41816db 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java @@ -15,6 +15,7 @@ */ package com.android.internal.policy.impl.keyguard; +import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.media.AudioManager; @@ -85,9 +86,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. @@ -101,10 +107,28 @@ class KeyguardUpdateMonitorCallback { void onUserRemoved(int userId) { } /** + * Called when the user's info changed. + */ + void onUserInfoChanged(int userId) { } + + /** * Called when boot completed. * * Note, this callback will only be received if boot complete occurs after registering with * KeyguardUpdateMonitor. */ void onBootCompleted() { } + + /** + * Called when audio client attaches or detaches from AudioManager. + */ + void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { } + + /** + * Called when the audio playback state changes. + * @param playbackState + * @param eventTime + */ + public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { } + } 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..30c95fb 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 @@ -206,6 +200,9 @@ public class KeyguardViewManager { stretch, stretch, type, flags, PixelFormat.TRANSLUCENT); lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; + lp.screenOrientation = enableScreenRotation ? + ActivityInfo.SCREEN_ORIENTATION_USER : ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + if (ActivityManager.isHighEndGfx()) { lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; lp.privateFlags |= @@ -244,6 +241,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..885cb45 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; @@ -253,6 +254,11 @@ public class KeyguardViewMediator { private final float mLockSoundVolume; /** + * Cache of avatar drawables, for use by KeyguardMultiUserAvatar. + */ + private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache(); + + /** * The callback used by the keyguard view to tell the {@link KeyguardViewMediator} * various things. */ @@ -310,21 +316,34 @@ 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. - KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false); + // When we switch users we want to bring the new user to the biometric unlock even + // if the current user has gone to the backup. + KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); } } @Override + public void onUserSwitchComplete(int userId) { + mSwitchingUser = false; + } + + @Override public void onUserRemoved(int userId) { mLockPatternUtils.removeUser(userId); + sMultiUserAvatarCache.clear(userId); + } + + @Override + public void onUserInfoChanged(int userId) { + sMultiUserAvatarCache.clear(userId); } @Override @@ -908,7 +927,7 @@ public class KeyguardViewMediator { * @see #handleReset() */ private void resetStateLocked(Bundle options) { - if (DEBUG) Log.d(TAG, "resetStateLocked"); + if (DEBUG) Log.e(TAG, "resetStateLocked"); Message msg = mHandler.obtainMessage(RESET, options); mHandler.sendMessage(msg); } @@ -1361,6 +1380,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 +1440,10 @@ public class KeyguardViewMediator { private boolean isAssistantAvailable() { return mSearchManager != null - && mSearchManager.getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; + && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; + } + + public static MultiUserAvatarCache getAvatarCache() { + return sMultiUserAvatarCache; } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java index 0a166e1..4410063 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java @@ -15,7 +15,6 @@ */ package com.android.internal.policy.impl.keyguard; -import android.appwidget.AppWidgetManager; import android.os.Handler; import android.os.Looper; import android.view.View; @@ -35,13 +34,6 @@ public class KeyguardViewStateManager implements private static final int SCREEN_ON_RING_HINT_DELAY = 300; Handler mMainQueue = new Handler(Looper.myLooper()); - // transport control states - static final int TRANSPORT_GONE = 0; - static final int TRANSPORT_INVISIBLE = 1; - static final int TRANSPORT_VISIBLE = 2; - - private int mTransportState = TRANSPORT_GONE; - int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE; // Paged view state @@ -310,14 +302,6 @@ public class KeyguardViewStateManager implements } } - public void setTransportState(int state) { - mTransportState = state; - } - - public int getTransportState() { - return mTransportState; - } - // ChallengeLayout.OnBouncerStateChangedListener @Override public void onBouncerStateChanged(boolean bouncerActive) { 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..770fafc 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); @@ -158,6 +169,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit KeyguardWidgetFrame newWidgetPage = getWidgetPageAt(newPageIndex); if (newWidgetPage != null) { newWidgetPage.onActive(true); + newWidgetPage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); newWidgetPage.requestAccessibilityFocus(); } if (mParent != null && AccessibilityManager.getInstance(mContext).isEnabled()) { @@ -583,13 +595,12 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit animateOutlinesAndSidePages(false); } - public void showInitialPageHints() { - mShowingInitialHints = true; + void updateChildrenContentAlpha(float sidePageAlpha) { int count = getChildCount(); for (int i = 0; i < count; i++) { KeyguardWidgetFrame child = getWidgetPageAt(i); if (i != mCurrentPage) { - child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); + child.setBackgroundAlpha(sidePageAlpha); child.setContentAlpha(0f); } else { child.setBackgroundAlpha(0f); @@ -598,9 +609,15 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit } } + public void showInitialPageHints() { + mShowingInitialHints = true; + updateChildrenContentAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); + } + @Override void setCurrentPage(int currentPage) { super.setCurrentPage(currentPage); + updateChildrenContentAlpha(0.0f); updateWidgetFramesImportantForAccessibility(); } @@ -857,4 +874,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/MultiUserAvatarCache.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java new file mode 100644 index 0000000..7969c7d --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.policy.impl.keyguard; + +import android.graphics.drawable.Drawable; + +import java.util.HashMap; + +public class MultiUserAvatarCache { + + private final HashMap<Integer, Drawable> mCache; + + public MultiUserAvatarCache() { + mCache = new HashMap<Integer, Drawable>(); + } + + public void clear(int userId) { + mCache.remove(userId); + } + + public Drawable get(int userId) { + return mCache.get(userId); + } + + public void put(int userId, Drawable image) { + mCache.put(userId, image); + } +} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java index 539ec1a..10562e8 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java @@ -86,7 +86,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private static final int MIN_SNAP_VELOCITY = 1500; private static final int MIN_FLING_VELOCITY = 250; - // We are disabling touch interaction of the widget region for factory ROM. + // We are disabling touch interaction of the widget region for factory ROM. private static final boolean DISABLE_TOUCH_INTERACTION = false; private static final boolean DISABLE_TOUCH_SIDE_PAGES = true; private static final boolean DISABLE_FLING_TO_DELETE = false; @@ -756,6 +756,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override public void onChildViewRemoved(View parent, View child) { mForceScreenScrolled = true; + invalidate(); + invalidateCachedOffsets(); } protected void invalidateCachedOffsets() { @@ -1348,6 +1350,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mTouchState == TOUCH_STATE_SCROLLING) { // Scroll to follow the motion event final int pointerIndex = ev.findPointerIndex(mActivePointerId); + + if (pointerIndex == -1) return true; + final float x = ev.getX(pointerIndex); final float deltaX = mLastMotionX + mLastMotionXRemainder - x; 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()); - } -} |