diff options
Diffstat (limited to 'policy')
56 files changed, 1248 insertions, 18954 deletions
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/KeyguardServiceWrapper.java new file mode 100644 index 0000000..e649125 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/KeyguardServiceWrapper.java @@ -0,0 +1,211 @@ +/* + * 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; + +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.policy.IKeyguardShowCallback; +import com.android.internal.policy.IKeyguardExitCallback; +import com.android.internal.policy.IKeyguardService; + +/** + * A wrapper class for KeyguardService. It implements IKeyguardService to ensure the interface + * remains consistent. + * + */ +public class KeyguardServiceWrapper implements IKeyguardService { + private IKeyguardService mService; + private String TAG = "KeyguardServiceWrapper"; + + public KeyguardServiceWrapper(IKeyguardService service) { + mService = service; + } + + public boolean isShowing() { + try { + return mService.isShowing(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + return false; + } + + public boolean isSecure() { + try { + return mService.isSecure(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + return false; // TODO cache state + } + + public boolean isShowingAndNotHidden() { + try { + return mService.isShowingAndNotHidden(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + return false; // TODO cache state + } + + public boolean isInputRestricted() { + try { + return mService.isInputRestricted(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + return false; // TODO cache state + } + + public boolean isDismissable() { + try { + return mService.isDismissable(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + return true; // TODO cache state + } + + public void verifyUnlock(IKeyguardExitCallback callback) { + try { + mService.verifyUnlock(callback); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void keyguardDone(boolean authenticated, boolean wakeup) { + try { + mService.keyguardDone(authenticated, wakeup); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void setHidden(boolean isHidden) { + try { + mService.setHidden(isHidden); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void dismiss() { + try { + mService.dismiss(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void onWakeKeyWhenKeyguardShowing(int keyCode) { + try { + mService.onWakeKeyWhenKeyguardShowing(keyCode); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void onWakeMotionWhenKeyguardShowing() { + try { + mService.onWakeMotionWhenKeyguardShowing(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void onDreamingStarted() { + try { + mService.onDreamingStarted(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void onDreamingStopped() { + try { + mService.onDreamingStopped(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void onScreenTurnedOff(int reason) { + try { + mService.onScreenTurnedOff(reason); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void onScreenTurnedOn(IKeyguardShowCallback result) { + try { + mService.onScreenTurnedOn(result); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void setKeyguardEnabled(boolean enabled) { + try { + mService.setKeyguardEnabled(enabled); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void onSystemReady() { + try { + mService.onSystemReady(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void doKeyguardTimeout(Bundle options) { + try { + mService.doKeyguardTimeout(options); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void setCurrentUser(int userId) { + try { + mService.setCurrentUser(userId); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + public void showAssistant() { + try { + mService.showAssistant(); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + + @Override + public IBinder asBinder() { + return mService.asBinder(); + } + +}
\ No newline at end of file diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 6b28e8e..085134d 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -139,6 +139,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ActionMenuPresenterCallback mActionMenuPresenterCallback; private PanelMenuPresenterCallback mPanelMenuPresenterCallback; + static final int FLAG_RESOURCE_SET_ICON = 1 << 0; + static final int FLAG_RESOURCE_SET_LOGO = 1 << 1; + int mResourcesSetFlags; + int mIconRes; + int mLogoRes; + private DrawableFeatureState[] mDrawables; private PanelFeatureState[] mPanels; @@ -1393,6 +1399,46 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override + public void setIcon(int resId) { + mIconRes = resId; + mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON; + if (mActionBar != null) { + mActionBar.setIcon(resId); + } + } + + @Override + public void setDefaultIcon(int resId) { + if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0) { + return; + } + mIconRes = resId; + if (mActionBar != null && !mActionBar.hasIcon()) { + mActionBar.setIcon(resId); + } + } + + @Override + public void setLogo(int resId) { + mLogoRes = resId; + mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO; + if (mActionBar != null) { + mActionBar.setLogo(resId); + } + } + + @Override + public void setDefaultLogo(int resId) { + if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0) { + return; + } + mLogoRes = resId; + if (mActionBar != null && !mActionBar.hasLogo()) { + mActionBar.setLogo(resId); + } + } + /** * Request that key events come to this activity. Use this if your activity * has no views with focus, but the activity still wants a chance to process @@ -2946,6 +2992,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { "incompatible window decor! Ignoring request."); } + if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 || + (mIconRes != 0 && !mActionBar.hasIcon())) { + mActionBar.setIcon(mIconRes); + } + if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 || + (mLogoRes != 0 && !mActionBar.hasLogo())) { + mActionBar.setLogo(mLogoRes); + } + // Post the panel invalidate for later; avoid application onCreateOptionsMenu // being called in the middle of onCreate or similar. mDecor.post(new Runnable() { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index b0cd11ae..6272ab2 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -94,8 +94,7 @@ 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.policy.impl.keyguard.KeyguardServiceDelegate; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.telephony.ITelephony; import com.android.internal.widget.PointerLocationView; @@ -104,6 +103,7 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.util.HashSet; import static android.view.WindowManager.LayoutParams.*; import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; @@ -114,7 +114,7 @@ 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 * PhoneWindowManager. This is used to protect some internal state, and - * can be acquired with either thw Lw and Li lock held, so has the restrictions + * can be acquired with either the Lw and Li lock held, so has the restrictions * of both of those when held. */ public class PhoneWindowManager implements WindowManagerPolicy { @@ -164,6 +164,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SYSTEM_UI_CHANGING_LAYOUT = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; + /** + * Keyguard stuff + */ + private WindowState mKeyguardScrim; + /* Table of Application Launch keys. Maps from key codes to intent categories. * * These are special keys that are used to launch particular kinds of applications, @@ -209,13 +214,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback of virtual key press. long[] mVirtualKeyVibePattern; - + // Vibrator pattern for a short vibration. long[] mKeyboardTapVibePattern; // Vibrator pattern for haptic feedback during boot when safe mode is disabled. long[] mSafeModeDisabledVibePattern; - + // Vibrator pattern for haptic feedback during boot when safe mode is enabled. long[] mSafeModeEnabledVibePattern; @@ -236,7 +241,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int[] mNavigationBarWidthForRotation = new int[4]; WindowState mKeyguard = null; - KeyguardViewMediator mKeyguardMediator; + KeyguardServiceDelegate mKeyguardDelegate; GlobalActions mGlobalActions; volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread boolean mPendingPowerKeyUpCanceled; @@ -284,7 +289,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean mHasSoftInput = false; - + int mPointerLocationMode = 0; // guarded by mLock // The last window we were told about in focusChanged. @@ -381,7 +386,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpContentFrame = new Rect(); static final Rect mTmpVisibleFrame = new Rect(); static final Rect mTmpNavigationFrame = new Rect(); - + WindowState mTopFullscreenOpaqueWindowState; boolean mTopIsFullscreen; boolean mForceStatusBar; @@ -456,6 +461,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mPowerKeyTriggered; private long mPowerKeyTime; + /* The number of steps between min and max brightness */ + private static final int BRIGHTNESS_STEPS = 10; + SettingsObserver mSettingsObserver; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; @@ -540,20 +548,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(false); } } - + class MyOrientationListener extends WindowOrientationListener { MyOrientationListener(Context context, Handler handler) { super(context, handler); } - + @Override public void onProposedRotationChanged(int rotation) { - if (localLOGV) Log.v(TAG, "onProposedRotationChanged, rotation=" + rotation); + if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation); updateRotation(false); } } MyOrientationListener mOrientationListener; + private static final int HIDEYBAR_NONE = 0; + private static final int HIDEYBAR_SHOWING = 1; + private static final int HIDEYBAR_HIDING = 2; + private int mStatusHideybar; + private int mNavigationHideybar; + + private InputChannel mSystemGestureInputChannel; + private SystemGestures mSystemGestures; + IStatusBarService getStatusBarService() { synchronized (mServiceAquireLock) { if (mStatusBarService == null) { @@ -617,7 +634,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } //Could have been invoked due to screen turning on or off or //change of the currently visible window's orientation - if (localLOGV) Log.v(TAG, "Screen status="+mScreenOnEarly+ + if (localLOGV) Slog.v(TAG, "Screen status="+mScreenOnEarly+ ", current orientation="+mCurrentAppOrientation+ ", SensorEnabled="+mOrientationSensorEnabled); boolean disable = true; @@ -627,7 +644,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //enable listener if not already enabled if (!mOrientationSensorEnabled) { mOrientationListener.enable(); - if(localLOGV) Log.v(TAG, "Enabling listeners"); + if(localLOGV) Slog.v(TAG, "Enabling listeners"); mOrientationSensorEnabled = true; } } @@ -635,7 +652,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { //check if sensors need to be disabled if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); - if(localLOGV) Log.v(TAG, "Disabling listeners"); + if(localLOGV) Slog.v(TAG, "Disabling listeners"); mOrientationSensorEnabled = false; } } @@ -679,7 +696,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private long getScreenshotChordLongPressDelay() { - if (mKeyguardMediator.isShowing()) { + if (mKeyguardDelegate.isShowing()) { // Double the time it takes to take a screenshot from the keyguard return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER * ViewConfiguration.getGlobalActionKeyTimeout()); @@ -742,7 +759,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (keyguardShowing) { // since it took two seconds of long press to bring this up, // poke the wake lock so they have some time to see the dialog. - mKeyguardMediator.userActivity(); + mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } } @@ -835,10 +852,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManager = windowManager; mWindowManagerFuncs = windowManagerFuncs; mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); - if (!mHeadless) { - // don't create KeyguardViewMediator if headless - mKeyguardMediator = new KeyguardViewMediator(context, null); - } mHandler = new PolicyHandler(); mOrientationListener = new MyOrientationListener(mContext, mHandler); try { @@ -911,6 +924,37 @@ public class PhoneWindowManager implements WindowManagerPolicy { filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); context.registerReceiver(mMultiuserReceiver, filter); + // monitor for system gestures + mSystemGestureInputChannel = mWindowManagerFuncs.monitorInput("SystemGestures"); + mSystemGestures = new SystemGestures(mSystemGestureInputChannel, + mHandler.getLooper(), context, + new SystemGestures.Callbacks() { + @Override + public void onSwipeFromTop() { + if (mStatusBar != null) { + requestHideybars(mStatusBar); + } + } + @Override + public void onSwipeFromBottom() { + if (mNavigationBar != null && mNavigationBarOnBottom) { + requestHideybars(mNavigationBar); + } + } + @Override + public void onSwipeFromRight() { + if (mNavigationBar != null && !mNavigationBarOnBottom) { + requestHideybars(mNavigationBar); + } + } + @Override + public void onDebug() { + if (OverlayTesting.ENABLED) { + OverlayTesting.toggleForceOverlay(mFocusedWindow, mContext); + } + } + }); + mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); mLongPressVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_longPressVibePattern); @@ -1279,6 +1323,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_DISPLAY_OVERLAY: case TYPE_HIDDEN_NAV_CONSUMER: case TYPE_KEYGUARD: + case TYPE_KEYGUARD_SCRIM: case TYPE_KEYGUARD_DIALOG: case TYPE_MAGNIFICATION_OVERLAY: case TYPE_NAVIGATION_BAR: @@ -1303,11 +1348,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { != PackageManager.PERMISSION_GRANTED; } + @Override public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) { switch (attrs.type) { case TYPE_SYSTEM_OVERLAY: case TYPE_SECURE_SYSTEM_OVERLAY: - case TYPE_TOAST: // These types of windows can't receive input events. attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; @@ -1331,11 +1376,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private boolean isBuiltInKeyboardVisible() { - return mHaveBuiltInKeyboard && !isHidden(mLidKeyboardAccessibility); - } - /** {@inheritDoc} */ + @Override public void adjustConfigurationLw(Configuration config, int keyboardPresence, int navigationPresence) { mHaveBuiltInKeyboard = (keyboardPresence & PRESENCE_INTERNAL) != 0; @@ -1361,6 +1403,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public int windowTypeToLayerLw(int type) { if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { return 2; @@ -1396,54 +1439,57 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_INPUT_METHOD_DIALOG: // on-screen keyboards and other such input method user interfaces go here. return 11; + case TYPE_KEYGUARD_SCRIM: + // the safety window that shows behind keyguard while keyguard is starting + return 12; case TYPE_KEYGUARD: // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - return 12; - case TYPE_KEYGUARD_DIALOG: return 13; - case TYPE_STATUS_BAR_SUB_PANEL: + case TYPE_KEYGUARD_DIALOG: return 14; - case TYPE_STATUS_BAR: + case TYPE_STATUS_BAR_SUB_PANEL: return 15; - case TYPE_STATUS_BAR_PANEL: + case TYPE_STATUS_BAR: return 16; + case TYPE_STATUS_BAR_PANEL: + return 17; case TYPE_VOLUME_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 17; + return 18; case TYPE_SYSTEM_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 18; + return 19; case TYPE_NAVIGATION_BAR: // the navigation bar, if available, shows atop most things - return 19; + return 20; case TYPE_NAVIGATION_BAR_PANEL: // some panels (e.g. search) need to show on top of the navigation bar - return 20; + return 21; case TYPE_SYSTEM_ERROR: // system-level error dialogs - return 21; + return 22; case TYPE_MAGNIFICATION_OVERLAY: // used to highlight the magnified portion of a display - return 22; + return 23; case TYPE_DISPLAY_OVERLAY: // used to simulate secondary display devices - return 23; + return 24; case TYPE_DRAG: // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - return 24; - case TYPE_SECURE_SYSTEM_OVERLAY: return 25; - case TYPE_BOOT_PROGRESS: + case TYPE_SECURE_SYSTEM_OVERLAY: return 26; + case TYPE_BOOT_PROGRESS: + return 27; case TYPE_POINTER: // the (mouse) pointer layer - return 27; - case TYPE_HIDDEN_NAV_CONSUMER: return 28; + case TYPE_HIDDEN_NAV_CONSUMER: + return 29; } Log.e(TAG, "Unknown window type: " + type); return 2; @@ -1534,6 +1580,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_DREAM: case TYPE_UNIVERSE_BACKGROUND: case TYPE_KEYGUARD: + case TYPE_KEYGUARD_SCRIM: return false; default: return true; @@ -1544,7 +1591,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public View addStartingWindow(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, - int icon, int windowFlags) { + int icon, int logo, int windowFlags) { if (!SHOW_STARTING_ANIMATIONS) { return null; } @@ -1601,6 +1648,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW); } + win.setDefaultIcon(icon); + win.setDefaultLogo(logo); + win.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); @@ -1707,7 +1757,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } mNavigationBar = win; - if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar); + if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); break; case TYPE_NAVIGATION_BAR_PANEL: mContext.enforceCallingOrSelfPermission( @@ -1730,6 +1780,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mKeyguard = win; break; + case TYPE_KEYGUARD_SCRIM: + if (mKeyguardScrim != null) { + return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; + } + mKeyguardScrim = win; + break; + } return WindowManagerGlobal.ADD_OKAY; } @@ -1739,8 +1796,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mStatusBar == win) { mStatusBar = null; } else if (mKeyguard == win) { + Log.v(TAG, "Removing keyguard window (Did it crash?)"); mKeyguard = null; - } else if (mNavigationBar == win) { + mKeyguardDelegate.showScrim(); + } else if (mKeyguardScrim == win) { + Log.v(TAG, "Removing keyguard scrim"); + mKeyguardScrim = null; + } if (mNavigationBar == win) { mNavigationBar = null; } } @@ -1980,6 +2042,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (attrs != null) { final int type = attrs.type; if (type == WindowManager.LayoutParams.TYPE_KEYGUARD + || type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { // the "app" is keyguard, so give it the key return 0; @@ -2085,6 +2148,43 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.post(mScreenshotRunnable); } return -1; + } else if (keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP + || keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN) { + if (down) { + int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1; + + // Disable autobrightness if it's on + int auto = Settings.System.getIntForUser( + mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, + UserHandle.USER_CURRENT_OR_SELF); + if (auto != 0) { + Settings.System.putIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, + UserHandle.USER_CURRENT_OR_SELF); + } + + int min = mPowerManager.getMinimumScreenBrightnessSetting(); + int max = mPowerManager.getMaximumScreenBrightnessSetting(); + int step = (max - min + BRIGHTNESS_STEPS - 1) / BRIGHTNESS_STEPS * direction; + int brightness = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS, + mPowerManager.getDefaultScreenBrightnessSetting(), + UserHandle.USER_CURRENT_OR_SELF); + brightness += step; + // Make sure we don't go beyond the limits. + brightness = Math.min(max, brightness); + brightness = Math.max(min, brightness); + + Settings.System.putIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS, brightness, + UserHandle.USER_CURRENT_OR_SELF); + Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF); + } + return -1; } // Shortcuts are invoked through Search+key, so intercept those here @@ -2102,7 +2202,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { - mContext.startActivity(shortcutIntent); + mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " @@ -2128,7 +2228,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { - mContext.startActivity(shortcutIntent); + mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " @@ -2146,7 +2246,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { - mContext.startActivity(intent); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping application launch key because " + "the activity to which it is registered was not found: " @@ -2293,7 +2393,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (searchManager != null) { searchManager.stopSearch(); } - mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); } catch (ActivityNotFoundException e) { Slog.w(TAG, "No activity to handle assist long press action.", e); } @@ -2308,7 +2408,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); try { - mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); } catch (ActivityNotFoundException e) { Slog.w(TAG, "No activity to handle assist action.", e); } @@ -2372,12 +2472,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) { + if (mKeyguardDelegate != null && mKeyguardDelegate.isShowingAndNotHidden()) { // don't launch home if keyguard showing - } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { + } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock // before launching home - mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { + mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() { public void onKeyguardExitResult(boolean success) { if (success) { try { @@ -2400,13 +2500,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - /** - * A delayed callback use to determine when it is okay to re-allow applications - * to use certain system UI flags. This is used to prevent applications from - * spamming system UI changes that prevent the navigation bar from being shown. - */ - final Runnable mAllowSystemUiDelay = new Runnable() { - @Override public void run() { + private final Runnable mClearHideNavigationFlag = new Runnable() { + @Override + public void run() { + synchronized (mWindowManagerFuncs.getWindowManagerLock()) { + // Clear flags. + mForceClearedSystemUiFlags &= + ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + } + mWindowManagerFuncs.reevaluateStatusBarVisibility(); } }; @@ -2430,7 +2532,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { // When the user taps down, we re-show the nav bar. boolean changed = false; - synchronized (mLock) { + synchronized (mWindowManagerFuncs.getWindowManagerLock()) { // Any user activity always causes us to show the // navigation controls, if they had been hidden. // We also clear the low profile and only content @@ -2452,16 +2554,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mForceClearedSystemUiFlags != newVal) { mForceClearedSystemUiFlags = newVal; changed = true; - mHandler.postDelayed(new Runnable() { - @Override public void run() { - synchronized (mLock) { - // Clear flags. - mForceClearedSystemUiFlags &= - ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; - } - mWindowManagerFuncs.reevaluateStatusBarVisibility(); - } - }, 1000); + mHandler.postDelayed(mClearHideNavigationFlag, 1000); } } if (changed) { @@ -2485,6 +2578,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public int adjustSystemUiVisibilityLw(int visibility) { + if (mStatusBar != null && mStatusHideybar == HIDEYBAR_SHOWING && + 0 == (visibility & View.STATUS_BAR_OVERLAY)) { + mStatusHideybar = HIDEYBAR_HIDING; + mStatusBar.hideLw(true); + } + if (mNavigationBar != null && mNavigationHideybar == HIDEYBAR_SHOWING && + 0 == (visibility & View.NAVIGATION_BAR_OVERLAY)) { + mNavigationHideybar = HIDEYBAR_HIDING; + mNavigationBar.hideLw(true); + } // Reset any bits in mForceClearingStatusBarVisibility that // are now clear. mResettingSystemUiFlags &= visibility; @@ -2586,8 +2689,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom; mRestrictedScreenLeft = mUnrestrictedScreenLeft; mRestrictedScreenTop = mUnrestrictedScreenTop; - mRestrictedScreenWidth = mUnrestrictedScreenWidth; - mRestrictedScreenHeight = mUnrestrictedScreenHeight; + mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth; + mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight; mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft = mCurLeft = mUnrestrictedScreenLeft; mDockTop = mContentTop = mStableTop = mStableFullscreenTop @@ -2613,12 +2716,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { // For purposes of putting out fake window up to steal focus, we will // drive nav being hidden only by whether it is requested. boolean navVisible = (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; + boolean overlayAllowed = (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_ALLOW_OVERLAY) != 0; // When the navigation bar isn't visible, we put up a fake // input window to catch all touch events. This way we can // detect when the user presses anywhere to bring back the nav // bar and ensure the application doesn't see the event. - if (navVisible) { + if (navVisible || overlayAllowed) { if (mHideNavFakeWindow != null) { mHideNavFakeWindow.dismiss(); mHideNavFakeWindow = null; @@ -2635,7 +2739,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // then take that into account. navVisible |= !mCanHideNavigationBar; + boolean updateSysUiVisibility = false; if (mNavigationBar != null) { + boolean navBarHideyShowing = mNavigationHideybar == HIDEYBAR_SHOWING; // Force the navigation bar to its appropriate place and // size. We need to do this directly, instead of relying on // it to bubble up from the nav bar, because this needs to @@ -2647,7 +2753,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { - mNavigationBarHeightForRotation[displayRotation]; mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom); mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top; - if (navVisible) { + if (navBarHideyShowing) { + mNavigationBar.showLw(true); + } else if (navVisible) { mNavigationBar.showLw(true); mDockBottom = mTmpNavigationFrame.top; mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop; @@ -2668,7 +2776,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { - mNavigationBarWidthForRotation[displayRotation]; mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight); mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left; - if (navVisible) { + if (navBarHideyShowing) { + mNavigationBar.showLw(true); + } else if (navVisible) { mNavigationBar.showLw(true); mDockRight = mTmpNavigationFrame.left; mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft; @@ -2694,9 +2804,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { // And compute the final frame. mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame); - if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); + if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); + if (mNavigationHideybar == HIDEYBAR_HIDING && !mNavigationBar.isVisibleLw()) { + // Finished animating out, clean up and reset alpha + mNavigationHideybar = HIDEYBAR_NONE; + updateSysUiVisibility = true; + } } - if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", + if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", mDockLeft, mDockTop, mDockRight, mDockBottom)); // decide where the status bar goes ahead of time @@ -2720,9 +2835,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // For layout, the status bar is always at the top with our fixed height. mStableTop = mUnrestrictedScreenTop + mStatusBarHeight; + boolean statusBarOverlay = (mLastSystemUiFlags & View.STATUS_BAR_OVERLAY) != 0; + // If the status bar is hidden, we don't want to cause // windows behind it to scroll. - if (mStatusBar.isVisibleLw()) { + if (mStatusBar.isVisibleLw() && !statusBarOverlay) { // Status bar may go away, so the screen area it occupies // is available to apps but just covering them when the // status bar is visible. @@ -2733,24 +2850,34 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContentLeft = mCurLeft = mDockLeft; mContentRight = mCurRight = mDockRight; - if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " + + if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format( "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]", mDockLeft, mDockTop, mDockRight, mDockBottom, mContentLeft, mContentTop, mContentRight, mContentBottom, mCurLeft, mCurTop, mCurRight, mCurBottom)); } - if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()) { + if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw() && !statusBarOverlay) { // If the status bar is currently requested to be visible, // and not in the process of animating on or off, then // we can tell the app that it is covered by it. mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight; } + + if (mStatusHideybar == HIDEYBAR_HIDING && !mStatusBar.isVisibleLw()) { + // Finished animating out, clean up and reset alpha + mStatusHideybar = HIDEYBAR_NONE; + updateSysUiVisibility = true; + } + } + if (updateSysUiVisibility) { + updateSystemUiVisibilityLw(); } } } /** {@inheritDoc} */ + @Override public int getSystemDecorRectLw(Rect systemRect) { systemRect.left = mSystemLeft; systemRect.top = mSystemTop; @@ -2761,6 +2888,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } + @Override + public void getContentRectLw(Rect r) { + r.set(mContentLeft, mContentTop, mContentRight, mContentBottom); + } + 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) { @@ -2840,9 +2972,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean needsToOffsetInputMethodTarget = isDefaultDisplay && (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null); if (needsToOffsetInputMethodTarget) { - if (DEBUG_LAYOUT) { - Slog.i(TAG, "Offset ime target window by the last ime window state"); - } + if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state"); offsetInputMethodWindowLw(mLastInputMethodWindow); } @@ -2886,8 +3016,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { 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() + if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): 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 @@ -2917,11 +3046,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { ? mRestrictedScreenTop+mRestrictedScreenHeight : mUnrestrictedScreenTop + mUnrestrictedScreenHeight; - if (DEBUG_LAYOUT) { - Log.v(TAG, String.format( + if (DEBUG_LAYOUT) Slog.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) { @@ -3003,8 +3130,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) { - if (DEBUG_LAYOUT) - Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN"); + if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + + "): IN_SCREEN"); // A window that has requested to fill the entire screen just // gets everything, period. if (attrs.type == TYPE_STATUS_BAR_PANEL @@ -3018,11 +3145,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.bottom = df.bottom = of.bottom = cf.bottom = hasNavBar ? mRestrictedScreenTop+mRestrictedScreenHeight : mUnrestrictedScreenTop + mUnrestrictedScreenHeight; - if (DEBUG_LAYOUT) { - Log.v(TAG, String.format( + if (DEBUG_LAYOUT) Slog.v(TAG, String.format( "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)", pf.left, pf.top, pf.right, pf.bottom)); - } } else if (attrs.type == TYPE_NAVIGATION_BAR || attrs.type == TYPE_NAVIGATION_BAR_PANEL) { // The navigation bar has Real Ultimate Power. @@ -3032,11 +3157,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { + mUnrestrictedScreenWidth; pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; - if (DEBUG_LAYOUT) { - Log.v(TAG, String.format( + if (DEBUG_LAYOUT) Slog.v(TAG, String.format( "Laying out navigation bar window: (%d,%d - %d,%d)", pf.left, pf.top, pf.right, pf.bottom)); - } } else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY || attrs.type == TYPE_BOOT_PROGRESS) && ((fl & FLAG_FULLSCREEN) != 0)) { @@ -3112,14 +3235,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { vf.set(cf); } } else if (attached != null) { - if (DEBUG_LAYOUT) - Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached); + if (DEBUG_LAYOUT) Slog.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, of, cf, vf); } else { - if (DEBUG_LAYOUT) - Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window"); + if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + + "): normal window"); // Otherwise, a normal window must be placed inside the content // of all screen decorations. if (attrs.type == TYPE_STATUS_BAR_PANEL) { @@ -3167,7 +3290,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { = vf.right = vf.bottom = 10000; } - if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle() + if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) + " attach=" + attached + " type=" + attrs.type + String.format(" flags=0x%08x", fl) @@ -3197,7 +3320,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mCurBottom > top) { mCurBottom = top; } - if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom=" + if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom=" + mDockBottom + " mContentBottom=" + mContentBottom + " mCurBottom=" + mCurBottom); } @@ -3264,21 +3387,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { && attrs.x == 0 && attrs.y == 0 && attrs.width == WindowManager.LayoutParams.MATCH_PARENT && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) { - if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); + if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { - if (DEBUG_LAYOUT) Log.v(TAG, "Setting mHideLockScreen to true by win " + win); + if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win); mHideLockScreen = true; mForceStatusBarFromKeyguard = false; } if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0 && mDismissKeyguard == DISMISS_KEYGUARD_NONE) { - if (DEBUG_LAYOUT) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); + if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win); mDismissKeyguard = mWinDismissingKeyguard == win ? DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; mWinDismissingKeyguard = win; - mForceStatusBarFromKeyguard = - mShowingLockscreen && mKeyguardMediator.isSecure(); + mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure(); } if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { mAllowLockscreenWhenOn = true; @@ -3306,17 +3428,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (mStatusBar != null) { - if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar + if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar + " forcefkg=" + mForceStatusBarFromKeyguard + " top=" + mTopFullscreenOpaqueWindowState); if (mForceStatusBar || mForceStatusBarFromKeyguard) { - if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced"); + if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced"); if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } else if (mTopFullscreenOpaqueWindowState != null) { if (localLOGV) { - Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() + Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); - Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() + Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() + " lp.flags=0x" + Integer.toHexString(lp.flags)); } topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0 @@ -3325,8 +3447,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the // case though. - if (topIsFullscreen) { - if (DEBUG_LAYOUT) Log.v(TAG, "** HIDING status bar"); + if (mStatusHideybar == HIDEYBAR_SHOWING) { + if (mStatusBar.showLw(true)) { + changes |= FINISH_LAYOUT_REDO_LAYOUT; + } + } else if (topIsFullscreen) { + if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar"); if (mStatusBar.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT; @@ -3343,11 +3469,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBarService = null; } }}); - } else if (DEBUG_LAYOUT) { - Log.v(TAG, "Preventing status bar from hiding by policy"); + } else { + if (DEBUG_LAYOUT) Slog.v(TAG, "Policy preventing status bar from hiding"); } } else { - if (DEBUG_LAYOUT) Log.v(TAG, "** SHOWING status bar: top is not fullscreen"); + if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen"); if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; } } @@ -3358,19 +3484,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Hide the key guard if a visible window explicitly specifies that it wants to be // displayed when the screen is locked. if (mKeyguard != null) { - if (localLOGV) Log.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard=" + if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard=" + mHideLockScreen); - if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardMediator.isSecure()) { + if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardDelegate.isSecure()) { if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - if (mKeyguardMediator.isShowing()) { + if (mKeyguardDelegate.isShowing()) { mHandler.post(new Runnable() { @Override public void run() { - mKeyguardMediator.keyguardDone(false, false); + mKeyguardDelegate.keyguardDone(false, false); } }); } @@ -3380,7 +3506,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - mKeyguardMediator.setHidden(true); + mKeyguardDelegate.setHidden(true); } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) { // This is the case of keyguard isSecure() and not mHideLockScreen. if (mDismissKeyguard == DISMISS_KEYGUARD_START) { @@ -3390,11 +3516,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - mKeyguardMediator.setHidden(false); + mKeyguardDelegate.setHidden(false); mHandler.post(new Runnable() { @Override public void run() { - mKeyguardMediator.dismiss(); + mKeyguardDelegate.dismiss(); } }); } @@ -3405,7 +3531,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - mKeyguardMediator.setHidden(false); + mKeyguardDelegate.setHidden(false); } } @@ -3456,7 +3582,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (lidOpen) { if (keyguardIsShowingTq()) { - mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(KeyEvent.KEYCODE_POWER); + mKeyguardDelegate.onWakeKeyWhenKeyguardShowingTq(KeyEvent.KEYCODE_POWER); } else { mPowerManager.wakeUp(SystemClock.uptimeMillis()); } @@ -3541,7 +3667,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { keycode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER, - 0); + 0, + mContext.getBasePackageName()); } catch (RemoteException e) { Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e); } finally { @@ -3636,10 +3763,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the same as if it were open and in front. // This will prevent any keys other than the power button from waking the screen // when the keyguard is hidden by another activity. - final boolean keyguardActive = (mKeyguardMediator == null ? false : + final boolean keyguardActive = (mKeyguardDelegate == null ? false : (isScreenOn ? - mKeyguardMediator.isShowingAndNotHidden() : - mKeyguardMediator.isShowing())); + mKeyguardDelegate.isShowingAndNotHidden() : + mKeyguardDelegate.isShowing())); if (keyCode == KeyEvent.KEYCODE_POWER) { policyFlags |= WindowManagerPolicy.FLAG_WAKE; @@ -3678,7 +3805,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) { if (keyguardActive) { // If the keyguard is showing, let it wake the device when ready. - mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode); + mKeyguardDelegate.onWakeKeyWhenKeyguardShowingTq(keyCode); } else { // Otherwise, wake the device ourselves. result |= ACTION_WAKE_UP; @@ -3948,9 +4075,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean isWakeMotion = (policyFlags & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; if (isWakeMotion) { - if (mKeyguardMediator != null && mKeyguardMediator.isShowing()) { + if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { // If the keyguard is showing, let it decide what to do with the wake motion. - mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq(); + mKeyguardDelegate.onWakeMotionWhenKeyguardShowing(); } else { // Otherwise, wake the device ourselves. result |= ACTION_WAKE_UP; @@ -4040,12 +4167,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) { - if (mKeyguardMediator != null) { - mKeyguardMediator.onDreamingStarted(); + if (mKeyguardDelegate != null) { + mKeyguardDelegate.onDreamingStarted(); } } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) { - if (mKeyguardMediator != null) { - mKeyguardMediator.onDreamingStopped(); + if (mKeyguardDelegate != null) { + mKeyguardDelegate.onDreamingStopped(); } } } @@ -4064,7 +4191,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // force a re-application of focused window sysui visibility. // the window may never have been shown for this user // e.g. the keyguard when going through the new-user setup flow - synchronized(mLock) { + synchronized (mWindowManagerFuncs.getWindowManagerLock()) { mLastSystemUiFlags = 0; updateSystemUiVisibilityLw(); } @@ -4072,6 +4199,38 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; + private void requestHideybars(WindowState swipeTarget) { + synchronized (mWindowManagerFuncs.getWindowManagerLock()) { + boolean sb = checkShowHideybar("status", mStatusHideybar, mStatusBar); + boolean nb = checkShowHideybar("navigation", mNavigationHideybar, mNavigationBar); + if (sb || nb) { + WindowState hideyTarget = sb ? mStatusBar : mNavigationBar; + if (sb ^ nb && hideyTarget != swipeTarget) { + if (DEBUG) Slog.d(TAG, "Not showing hideybar, wrong swipe target"); + return; + } + mStatusHideybar = sb ? HIDEYBAR_SHOWING : mStatusHideybar; + mNavigationHideybar = nb ? HIDEYBAR_SHOWING : mNavigationHideybar; + updateSystemUiVisibilityLw(); + } + } + } + + private boolean checkShowHideybar(String tag, int hideybar, WindowState win) { + if (hideybar == HIDEYBAR_SHOWING) { + if (DEBUG) Slog.d(TAG, "Not showing " + tag + " hideybar, already shown"); + return false; + } else if (win == null) { + if (DEBUG) Slog.d(TAG, "Not showing " + tag + " hideybar, bar doesn't exist"); + return false; + } else if (win.isDisplayedLw()) { + if (DEBUG) Slog.d(TAG, "Not showing " + tag + " hideybar, bar already visible"); + return false; + } else { + return true; + } + } + @Override public void screenTurnedOff(int why) { EventLog.writeEvent(70000, 0); @@ -4079,8 +4238,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOnEarly = false; mScreenOnFully = false; } - if (mKeyguardMediator != null) { - mKeyguardMediator.onScreenTurnedOff(why); + if (mKeyguardDelegate != null) { + mKeyguardDelegate.onScreenTurnedOff(why); } synchronized (mLock) { updateOrientationListenerLp(); @@ -4107,9 +4266,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void waitForKeyguard(final ScreenOnListener screenOnListener) { - if (mKeyguardMediator != null) { + if (mKeyguardDelegate != null) { if (screenOnListener != null) { - mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() { + mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() { @Override public void onShown(IBinder windowToken) { waitForKeyguardWindowDrawn(windowToken, screenOnListener); @@ -4117,10 +4276,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { }); return; } else { - mKeyguardMediator.onScreenTurnedOn(null); + mKeyguardDelegate.onScreenTurnedOn(null); } } else { - Slog.i(TAG, "No keyguard mediator!"); + Slog.i(TAG, "No keyguard interface!"); } finishScreenTurningOn(screenOnListener); } @@ -4175,21 +4334,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void enableKeyguard(boolean enabled) { - if (mKeyguardMediator != null) { - mKeyguardMediator.setKeyguardEnabled(enabled); + if (mKeyguardDelegate != null) { + mKeyguardDelegate.setKeyguardEnabled(enabled); } } /** {@inheritDoc} */ public void exitKeyguardSecurely(OnKeyguardExitResult callback) { - if (mKeyguardMediator != null) { - mKeyguardMediator.verifyUnlock(callback); + if (mKeyguardDelegate != null) { + mKeyguardDelegate.verifyUnlock(callback); } } private boolean keyguardIsShowingTq() { - if (mKeyguardMediator == null) return false; - return mKeyguardMediator.isShowingAndNotHidden(); + if (mKeyguardDelegate == null) return false; + return mKeyguardDelegate.isShowingAndNotHidden(); } @@ -4200,26 +4359,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public boolean isKeyguardSecure() { - if (mKeyguardMediator == null) return false; - return mKeyguardMediator.isSecure(); + if (mKeyguardDelegate == null) return false; + return mKeyguardDelegate.isSecure(); } /** {@inheritDoc} */ public boolean inKeyguardRestrictedKeyInputMode() { - if (mKeyguardMediator == null) return false; - return mKeyguardMediator.isInputRestricted(); + if (mKeyguardDelegate == null) return false; + return mKeyguardDelegate.isInputRestricted(); } public void dismissKeyguardLw() { - if (mKeyguardMediator.isShowing()) { + if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { mHandler.post(new Runnable() { public void run() { - if (mKeyguardMediator.isDismissable()) { + if (mKeyguardDelegate.isDismissable()) { // Can we just finish the keyguard straight away? - mKeyguardMediator.keyguardDone(false, true); + mKeyguardDelegate.keyguardDone(false, true); } else { // ask the keyguard to prompt the user to authenticate if necessary - mKeyguardMediator.dismiss(); + mKeyguardDelegate.dismiss(); } } }); @@ -4462,7 +4621,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ? HapticFeedbackConstants.SAFE_MODE_ENABLED : HapticFeedbackConstants.SAFE_MODE_DISABLED, true); } - + static long[] getLongIntArray(Resources r, int resid) { int[] ar = r.getIntArray(resid); if (ar == null) { @@ -4474,17 +4633,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { } return out; } - + /** {@inheritDoc} */ + @Override public void systemReady() { - if (mKeyguardMediator != null) { - // tell the keyguard - mKeyguardMediator.onSystemReady(); + if (!mHeadless) { + mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null); + mKeyguardDelegate.onSystemReady(); } synchronized (mLock) { updateOrientationListenerLp(); mSystemReady = true; mHandler.post(new Runnable() { + @Override public void run() { updateSettings(); } @@ -4591,8 +4752,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void run() { synchronized (this) { if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard"); - if (mKeyguardMediator != null) { - mKeyguardMediator.doKeyguardTimeout(options); + if (mKeyguardDelegate != null) { + mKeyguardDelegate.doKeyguardTimeout(options); } mLockScreenTimerActive = false; options = null; @@ -4620,7 +4781,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void updateLockScreenTimeout() { synchronized (mScreenLockTimeout) { boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && - mKeyguardMediator != null && mKeyguardMediator.isSecure()); + mKeyguardDelegate != null && mKeyguardDelegate.isSecure()); if (mLockScreenTimerActive != enable) { if (enable) { if (localLOGV) Log.v(TAG, "setting lockscreen timer"); @@ -4635,6 +4796,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void enableScreenAfterBoot() { readLidState(); applyLidSwitchState(); @@ -4676,7 +4838,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * <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 + * @return A dock intent. */ Intent createHomeDockIntent() { Intent intent = null; @@ -4731,7 +4893,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT); } - + /** * goes to the home screen * @return whether it did anything @@ -4783,7 +4945,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } return true; } - + + @Override public void setCurrentOrientationLw(int newOrientation) { synchronized (mLock) { if (newOrientation != mCurrentAppOrientation) { @@ -4807,18 +4970,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { ringTone.setStreamType(AudioManager.STREAM_MUSIC); ringTone.play(); } + private boolean isGlobalAccessibilityGestureEnabled() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1; } + @Override public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { if (!mVibrator.hasVibrator()) { return false; } final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0; - if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) { + if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotHidden())) { return false; } long[] pattern = null; @@ -4866,9 +5031,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void keepScreenOnStoppedLw() { - if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) { + if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotHidden()) { long curTime = SystemClock.uptimeMillis(); - mPowerManager.userActivity(curTime, false); + mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } } @@ -4887,14 +5052,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { // will quickly lose focus once it correctly gets hidden. return 0; } + int tmpVisibility = mFocusedWindow.getSystemUiVisibility() & ~mResettingSystemUiFlags & ~mForceClearedSystemUiFlags; if (mForcingShowNavBar && mFocusedWindow.getSurfaceLayer() < mForcingShowNavBarLayer) { tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS; } - final int visibility = tmpVisibility; - int diff = visibility ^ mLastSystemUiFlags; + final int visibility = updateHideybarsLw(tmpVisibility); + final int diff = visibility ^ mLastSystemUiFlags; final boolean needsMenu = mFocusedWindow.getNeedsMenuLw(mTopFullscreenOpaqueWindowState); if (diff == 0 && mLastFocusNeedsMenu == needsMenu && mFocusedApp == mFocusedWindow.getAppToken()) { @@ -4904,6 +5070,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mLastFocusNeedsMenu = needsMenu; mFocusedApp = mFocusedWindow.getAppToken(); mHandler.post(new Runnable() { + @Override public void run() { try { IStatusBarService statusbar = getStatusBarService(); @@ -4920,8 +5087,120 @@ public class PhoneWindowManager implements WindowManagerPolicy { return diff; } + private int updateHideybarsLw(int tmpVisibility) { + if (OverlayTesting.ENABLED) { + tmpVisibility = OverlayTesting.applyForced(mFocusedWindow, tmpVisibility); + } + boolean statusBarHasFocus = + mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR; + if (statusBarHasFocus) { + // prevent status bar interaction from clearing certain flags + int flags = View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_ALLOW_OVERLAY; + tmpVisibility = (tmpVisibility & ~flags) | (mLastSystemUiFlags & flags); + } + boolean overlayAllowed = (tmpVisibility & View.SYSTEM_UI_FLAG_ALLOW_OVERLAY) != 0; + if (mStatusHideybar == HIDEYBAR_SHOWING) { + // status hideybar requested + boolean hideStatusBarWM = + (mFocusedWindow.getAttrs().flags + & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; + boolean hideStatusBarSysui = + (tmpVisibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0; + + boolean statusHideyAllowed = + hideStatusBarWM + || (hideStatusBarSysui && overlayAllowed) + || statusBarHasFocus; + + if (mStatusBar == null || !statusHideyAllowed) { + mStatusHideybar = HIDEYBAR_NONE; + if (mStatusBar != null && hideStatusBarSysui) { + // clear the clearable flags instead + int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS; + if (newVal != mResettingSystemUiFlags) { + mResettingSystemUiFlags = newVal; + mWindowManagerFuncs.reevaluateStatusBarVisibility(); + } + } + } else { + // show status hideybar + tmpVisibility |= View.STATUS_BAR_OVERLAY; + if ((mLastSystemUiFlags & View.STATUS_BAR_OVERLAY) == 0) { + tmpVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; + mStatusBar.showLw(true); + } + } + } + if (mNavigationHideybar == HIDEYBAR_SHOWING) { + // navigation hideybar requested + boolean hideNavigationBarSysui = + (tmpVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; + boolean navigationHideyAllowed = + hideNavigationBarSysui && overlayAllowed && mNavigationBar != null; + if (!navigationHideyAllowed) { + mNavigationHideybar = HIDEYBAR_NONE; + } else { + // show navigation hideybar + tmpVisibility |= View.NAVIGATION_BAR_OVERLAY; + if ((mLastSystemUiFlags & View.NAVIGATION_BAR_OVERLAY) == 0) { + tmpVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; + mNavigationBar.showLw(true); + } + } + } + return tmpVisibility; + } + + // TODO temporary helper that allows testing overlay bars on existing apps + private static final class OverlayTesting { + static final boolean ENABLED = true; + private static final HashSet<String> sForced = new HashSet<String>(); + + private static String parseActivity(WindowState win) { + if (win != null && win.getAppToken() != null) { + String str = win.getAppToken().toString(); + int end = str.lastIndexOf(' '); + if (end > 0) { + int start = str.lastIndexOf(' ', end - 1); + if (start > -1) { + return str.substring(start + 1, end); + } + } + } + return null; + } + + public static int applyForced(WindowState focused, int vis) { + if (sForced.contains(parseActivity(focused))) { + vis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_ALLOW_OVERLAY; + } + return vis; + } + + public static void toggleForceOverlay(WindowState focused, Context context) { + String activity = parseActivity(focused); + if (activity != null) { + String action; + if (sForced.contains(activity)) { + sForced.remove(activity); + action = "Force overlay disabled"; + } else { + sForced.add(activity); + action = "Force overlay enabled"; + } + android.widget.Toast.makeText(context, + action + " for " + activity, android.widget.Toast.LENGTH_SHORT).show(); + } + } + } + // Use this instead of checking config_showNavigationBar so that it can be consistently // overridden by qemu.hw.mainkeys in the emulator. + @Override public boolean hasNavigationBar() { return mHasNavigationBar; } @@ -4934,8 +5213,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void setCurrentUserLw(int newUserId) { - if (mKeyguardMediator != null) { - mKeyguardMediator.setCurrentUser(newUserId); + if (mKeyguardDelegate != null) { + mKeyguardDelegate.setCurrentUser(newUserId); } if (mStatusBarService != null) { try { @@ -4949,7 +5228,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void showAssistant() { - mKeyguardMediator.showAssistant(); + mKeyguardDelegate.showAssistant(); } @Override diff --git a/policy/src/com/android/internal/policy/impl/SystemGestures.java b/policy/src/com/android/internal/policy/impl/SystemGestures.java new file mode 100644 index 0000000..c9731a5 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/SystemGestures.java @@ -0,0 +1,208 @@ +/* + * 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; + +import android.content.Context; +import android.os.Looper; +import android.util.Slog; +import android.view.InputChannel; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.InputEventReceiver; +import android.view.MotionEvent; + +/* + * Listens for system-wide input gestures, firing callbacks when detected. + * @hide + */ +public class SystemGestures extends InputEventReceiver { + private static final String TAG = "SystemGestures"; + private static final boolean DEBUG = false; + private static final long SWIPE_TIMEOUT_MS = 500; + private static final int MAX_TRACKED_POINTERS = 32; // max per input system + private static final int UNTRACKED_POINTER = -1; + + private static final int SWIPE_NONE = 0; + private static final int SWIPE_FROM_TOP = 1; + private static final int SWIPE_FROM_BOTTOM = 2; + private static final int SWIPE_FROM_RIGHT = 3; + + private final int mSwipeStartThreshold; + private final int mSwipeEndThreshold; + private final Callbacks mCallbacks; + private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS]; + private final float[] mDownX = new float[MAX_TRACKED_POINTERS]; + private final float[] mDownY = new float[MAX_TRACKED_POINTERS]; + private final long[] mDownTime = new long[MAX_TRACKED_POINTERS]; + + int screenHeight; + int screenWidth; + private int mDownPointers; + private boolean mSwipeFireable; + private boolean mDebugFireable; + + public SystemGestures(InputChannel inputChannel, Looper looper, + Context context, Callbacks callbacks) { + super(inputChannel, looper); + mCallbacks = checkNull("callbacks", callbacks); + mSwipeStartThreshold = checkNull("context", context).getResources() + .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); + mSwipeEndThreshold = mSwipeStartThreshold * 2; + } + + private static <T> T checkNull(String name, T arg) { + if (arg == null) { + throw new IllegalArgumentException(name + " must not be null"); + } + return arg; + } + + @Override + public void onInputEvent(InputEvent event) { + if (event instanceof MotionEvent && event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { + onPointerMotionEvent((MotionEvent) event); + } + finishInputEvent(event, false /*handled*/); + } + + private void onPointerMotionEvent(MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + mSwipeFireable = true; + mDebugFireable = true; + mDownPointers = 0; + captureDown(event, 0); + break; + case MotionEvent.ACTION_POINTER_DOWN: + captureDown(event, event.getActionIndex()); + if (mDebugFireable) { + mDebugFireable = event.getPointerCount() < 5; + if (!mDebugFireable) { + if (DEBUG) Slog.d(TAG, "Firing debug"); + mCallbacks.onDebug(); + } + } + break; + case MotionEvent.ACTION_MOVE: + if (mSwipeFireable) { + final int swipe = detectSwipe(event); + mSwipeFireable = swipe == SWIPE_NONE; + if (swipe == SWIPE_FROM_TOP) { + if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop"); + mCallbacks.onSwipeFromTop(); + } else if (swipe == SWIPE_FROM_BOTTOM) { + if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom"); + mCallbacks.onSwipeFromBottom(); + } else if (swipe == SWIPE_FROM_RIGHT) { + if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight"); + mCallbacks.onSwipeFromRight(); + } + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mSwipeFireable = false; + mDebugFireable = false; + break; + default: + if (DEBUG) Slog.d(TAG, "Ignoring " + event); + } + } + + private void captureDown(MotionEvent event, int pointerIndex) { + final int pointerId = event.getPointerId(pointerIndex); + final int i = findIndex(pointerId); + if (DEBUG) Slog.d(TAG, "pointer " + pointerId + + " down pointerIndex=" + pointerIndex + " trackingIndex=" + i); + if (i != UNTRACKED_POINTER) { + mDownX[i] = event.getX(pointerIndex); + mDownY[i] = event.getY(pointerIndex); + mDownTime[i] = event.getEventTime(); + if (DEBUG) Slog.d(TAG, "pointer " + pointerId + + " down x=" + mDownX[i] + " y=" + mDownY[i]); + } + } + + private int findIndex(int pointerId) { + for (int i = 0; i < mDownPointers; i++) { + if (mDownPointerId[i] == pointerId) { + return i; + } + } + if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) { + return UNTRACKED_POINTER; + } + mDownPointerId[mDownPointers++] = pointerId; + return mDownPointers - 1; + } + + private int detectSwipe(MotionEvent move) { + final int historySize = move.getHistorySize(); + final int pointerCount = move.getPointerCount(); + for (int p = 0; p < pointerCount; p++) { + final int pointerId = move.getPointerId(p); + final int i = findIndex(pointerId); + if (i != UNTRACKED_POINTER) { + for (int h = 0; h < historySize; h++) { + final long time = move.getHistoricalEventTime(h); + final float x = move.getHistoricalX(p, h); + final float y = move.getHistoricalY(p, h); + final int swipe = detectSwipe(i, time, x, y); + if (swipe != SWIPE_NONE) { + return swipe; + } + } + final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p)); + if (swipe != SWIPE_NONE) { + return swipe; + } + } + } + return SWIPE_NONE; + } + + private int detectSwipe(int i, long time, float x, float y) { + final float fromX = mDownX[i]; + final float fromY = mDownY[i]; + final long elapsed = time - mDownTime[i]; + if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i] + + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed); + if (fromY <= mSwipeStartThreshold + && y > fromY + mSwipeEndThreshold + && elapsed < SWIPE_TIMEOUT_MS) { + return SWIPE_FROM_TOP; + } + if (fromY >= screenHeight - mSwipeStartThreshold + && y < fromY - mSwipeEndThreshold + && elapsed < SWIPE_TIMEOUT_MS) { + return SWIPE_FROM_BOTTOM; + } + if (fromX >= screenWidth - mSwipeStartThreshold + && x < fromX - mSwipeEndThreshold + && elapsed < SWIPE_TIMEOUT_MS) { + return SWIPE_FROM_RIGHT; + } + return SWIPE_NONE; + } + + interface Callbacks { + void onSwipeFromTop(); + void onSwipeFromBottom(); + void onSwipeFromRight(); + void onDebug(); + } +} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/BiometricSensorUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard/BiometricSensorUnlock.java deleted file mode 100644 index e65a716..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/BiometricSensorUnlock.java +++ /dev/null @@ -1,68 +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; - -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(); - - /** - * Stops and removes the biometric unlock and shows the backup unlock - */ - public void stopAndShowBackup(); - - /** - * 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/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java deleted file mode 100644 index 762711d..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java +++ /dev/null @@ -1,458 +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; - -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.Color; -import android.graphics.Point; -import android.graphics.Rect; -import android.os.Handler; -import android.os.SystemClock; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.ImageView.ScaleType; - -import com.android.internal.R; -import com.android.internal.policy.impl.keyguard.KeyguardActivityLauncher.CameraWidgetInfo; - -public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener { - private static final String TAG = CameraWidgetFrame.class.getSimpleName(); - private static final boolean DEBUG = KeyguardHostView.DEBUG; - private static final int WIDGET_ANIMATION_DURATION = 250; // ms - private static final int WIDGET_WAIT_DURATION = 650; // ms - private static final int RECOVERY_DELAY = 1000; // ms - - interface Callbacks { - void onLaunchingCamera(); - void onCameraLaunchedSuccessfully(); - void onCameraLaunchedUnsuccessfully(); - } - - private final Handler mHandler = new Handler(); - private final KeyguardActivityLauncher mActivityLauncher; - private final Callbacks mCallbacks; - private final CameraWidgetInfo mWidgetInfo; - private final WindowManager mWindowManager; - private final Point mRenderedSize = new Point(); - private final int[] mTmpLoc = new int[2]; - private final Rect mTmpRect = new Rect(); - - private long mLaunchCameraStart; - private boolean mActive; - private boolean mTransitioning; - private boolean mDown; - - private FixedSizeFrameLayout mPreview; - private View mFullscreenPreview; - - private final Runnable mTransitionToCameraRunnable = new Runnable() { - @Override - public void run() { - transitionToCamera(); - }}; - - private final Runnable mTransitionToCameraEndAction = new Runnable() { - @Override - public void run() { - if (!mTransitioning) - return; - Handler worker = getWorkerHandler() != null ? getWorkerHandler() : mHandler; - mLaunchCameraStart = SystemClock.uptimeMillis(); - if (DEBUG) Log.d(TAG, "Launching camera at " + mLaunchCameraStart); - mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable); - }}; - - private final Runnable mPostTransitionToCameraEndAction = new Runnable() { - @Override - public void run() { - mHandler.post(mTransitionToCameraEndAction); - }}; - - private final Runnable mRecoverRunnable = new Runnable() { - @Override - public void run() { - recover(); - }}; - - private final Runnable mRenderRunnable = new Runnable() { - @Override - public void run() { - render(); - }}; - - private final Runnable mSecureCameraActivityStartedRunnable = new Runnable() { - @Override - public void run() { - onSecureCameraActivityStarted(); - } - }; - - private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { - private boolean mShowing; - void onKeyguardVisibilityChanged(boolean showing) { - if (mShowing == showing) - return; - mShowing = showing; - CameraWidgetFrame.this.onKeyguardVisibilityChanged(mShowing); - }; - }; - - private static final class FixedSizeFrameLayout extends FrameLayout { - int width; - int height; - - FixedSizeFrameLayout(Context context) { - super(context); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - measureChildren( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); - setMeasuredDimension(width, height); - } - } - - private CameraWidgetFrame(Context context, Callbacks callbacks, - KeyguardActivityLauncher activityLauncher, - CameraWidgetInfo widgetInfo, View previewWidget) { - super(context); - mCallbacks = callbacks; - mActivityLauncher = activityLauncher; - mWidgetInfo = widgetInfo; - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - KeyguardUpdateMonitor.getInstance(context).registerCallback(mCallback); - - mPreview = new FixedSizeFrameLayout(context); - mPreview.addView(previewWidget); - addView(mPreview); - - View clickBlocker = new View(context); - clickBlocker.setBackgroundColor(Color.TRANSPARENT); - clickBlocker.setOnClickListener(this); - addView(clickBlocker); - - setContentDescription(context.getString(R.string.keyguard_accessibility_camera)); - if (DEBUG) Log.d(TAG, "new CameraWidgetFrame instance " + instanceId()); - } - - public static CameraWidgetFrame create(Context context, Callbacks callbacks, - KeyguardActivityLauncher launcher) { - if (context == null || callbacks == null || launcher == null) - return null; - - CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo(); - if (widgetInfo == null) - return null; - View previewWidget = getPreviewWidget(context, widgetInfo); - if (previewWidget == null) - return null; - - return new CameraWidgetFrame(context, callbacks, launcher, widgetInfo, previewWidget); - } - - private static View getPreviewWidget(Context context, CameraWidgetInfo widgetInfo) { - return widgetInfo.layoutId > 0 ? - inflateWidgetView(context, widgetInfo) : - inflateGenericWidgetView(context); - } - - private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) { - if (DEBUG) Log.d(TAG, "inflateWidgetView: " + widgetInfo.contextPackage); - View widgetView = null; - Exception exception = null; - try { - Context cameraContext = context.createPackageContext( - widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED); - LayoutInflater cameraInflater = (LayoutInflater) - cameraContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - cameraInflater = cameraInflater.cloneInContext(cameraContext); - widgetView = cameraInflater.inflate(widgetInfo.layoutId, null, false); - } catch (NameNotFoundException e) { - exception = e; - } catch (RuntimeException e) { - exception = e; - } - if (exception != null) { - Log.w(TAG, "Error creating camera widget view", exception); - } - return widgetView; - } - - private static View inflateGenericWidgetView(Context context) { - if (DEBUG) Log.d(TAG, "inflateGenericWidgetView"); - ImageView iv = new ImageView(context); - iv.setImageResource(com.android.internal.R.drawable.ic_lockscreen_camera); - iv.setScaleType(ScaleType.CENTER); - iv.setBackgroundColor(Color.argb(127, 0, 0, 0)); - return iv; - } - - private void render() { - final View root = getRootView(); - final int width = root.getWidth(); - final int height = root.getHeight(); - if (mRenderedSize.x == width && mRenderedSize.y == height) { - if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s", width, height)); - return; - } - if (width == 0 || height == 0) { - return; - } - - mPreview.width = width; - mPreview.height = height; - mPreview.requestLayout(); - - final int thisWidth = getWidth() - getPaddingLeft() - getPaddingRight(); - final int thisHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - - final float pvScaleX = (float) thisWidth / width; - final float pvScaleY = (float) thisHeight / height; - final float pvScale = Math.min(pvScaleX, pvScaleY); - - final int pvWidth = (int) (pvScale * width); - final int pvHeight = (int) (pvScale * height); - - final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0; - final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0; - - mPreview.setPivotX(0); - mPreview.setPivotY(0); - mPreview.setScaleX(pvScale); - mPreview.setScaleY(pvScale); - mPreview.setTranslationX(pvTransX); - mPreview.setTranslationY(pvTransY); - - mRenderedSize.set(width, height); - if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s instance=%s", - width, height, instanceId())); - } - - private void transitionToCamera() { - if (mTransitioning || mDown) return; - - mTransitioning = true; - - enableWindowExitAnimation(false); - - mPreview.getLocationInWindow(mTmpLoc); - final float pvHeight = mPreview.getHeight() * mPreview.getScaleY(); - final float pvCenter = mTmpLoc[1] + pvHeight / 2f; - - final ViewGroup root = (ViewGroup) getRootView(); - if (mFullscreenPreview == null) { - mFullscreenPreview = getPreviewWidget(mContext, mWidgetInfo); - mFullscreenPreview.setClickable(false); - root.addView(mFullscreenPreview); - } - - root.getWindowVisibleDisplayFrame(mTmpRect); - final float fsHeight = mTmpRect.height(); - final float fsCenter = mTmpRect.top + fsHeight / 2; - - final float fsScaleY = pvHeight / fsHeight; - final float fsTransY = pvCenter - fsCenter; - final float fsScaleX = mPreview.getScaleX(); - - mPreview.setVisibility(View.GONE); - mFullscreenPreview.setVisibility(View.VISIBLE); - mFullscreenPreview.setTranslationY(fsTransY); - mFullscreenPreview.setScaleX(fsScaleX); - mFullscreenPreview.setScaleY(fsScaleY); - mFullscreenPreview - .animate() - .scaleX(1) - .scaleY(1) - .translationX(0) - .translationY(0) - .setDuration(WIDGET_ANIMATION_DURATION) - .withEndAction(mPostTransitionToCameraEndAction) - .start(); - mCallbacks.onLaunchingCamera(); - } - - private void recover() { - if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis()); - mCallbacks.onCameraLaunchedUnsuccessfully(); - reset(); - } - - @Override - public void setOnLongClickListener(OnLongClickListener l) { - // ignore - } - - @Override - public void onClick(View v) { - if (DEBUG) Log.d(TAG, "clicked"); - if (mTransitioning) return; - if (mActive) { - cancelTransitionToCamera(); - transitionToCamera(); - } - } - - @Override - protected void onDetachedFromWindow() { - if (DEBUG) Log.d(TAG, "onDetachedFromWindow: instance " + instanceId() - + " at " + SystemClock.uptimeMillis()); - super.onDetachedFromWindow(); - KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback); - cancelTransitionToCamera(); - mHandler.removeCallbacks(mRecoverRunnable); - } - - @Override - public void onActive(boolean isActive) { - mActive = isActive; - if (mActive) { - rescheduleTransitionToCamera(); - } else { - reset(); - } - } - - @Override - public boolean onUserInteraction(MotionEvent event) { - if (mTransitioning) { - if (DEBUG) Log.d(TAG, "onUserInteraction eaten: mTransitioning"); - return true; - } - - getLocationOnScreen(mTmpLoc); - int rawBottom = mTmpLoc[1] + getHeight(); - if (event.getRawY() > rawBottom) { - if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget"); - return true; - } - - int action = event.getAction(); - mDown = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE; - if (mActive) { - rescheduleTransitionToCamera(); - } - if (DEBUG) Log.d(TAG, "onUserInteraction observed, not eaten"); - return false; - } - - @Override - protected void onFocusLost() { - if (DEBUG) Log.d(TAG, "onFocusLost at " + SystemClock.uptimeMillis()); - cancelTransitionToCamera(); - super.onFocusLost(); - } - - public void onScreenTurnedOff() { - if (DEBUG) Log.d(TAG, "onScreenTurnedOff"); - reset(); - } - - private void rescheduleTransitionToCamera() { - if (DEBUG) Log.d(TAG, "rescheduleTransitionToCamera at " + SystemClock.uptimeMillis()); - mHandler.removeCallbacks(mTransitionToCameraRunnable); - mHandler.postDelayed(mTransitionToCameraRunnable, WIDGET_WAIT_DURATION); - } - - private void cancelTransitionToCamera() { - if (DEBUG) Log.d(TAG, "cancelTransitionToCamera at " + SystemClock.uptimeMillis()); - mHandler.removeCallbacks(mTransitionToCameraRunnable); - } - - private void onCameraLaunched() { - mCallbacks.onCameraLaunchedSuccessfully(); - reset(); - } - - private void reset() { - if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis()); - mLaunchCameraStart = 0; - mTransitioning = false; - mDown = false; - cancelTransitionToCamera(); - mHandler.removeCallbacks(mRecoverRunnable); - mPreview.setVisibility(View.VISIBLE); - if (mFullscreenPreview != null) { - mFullscreenPreview.animate().cancel(); - mFullscreenPreview.setVisibility(View.GONE); - } - enableWindowExitAnimation(true); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s", - w, h, oldw, oldh, SystemClock.uptimeMillis())); - mHandler.post(mRenderRunnable); - super.onSizeChanged(w, h, oldw, oldh); - } - - @Override - public void onBouncerShowing(boolean showing) { - if (showing) { - mTransitioning = false; - mHandler.post(mRecoverRunnable); - } - } - - private void enableWindowExitAnimation(boolean isEnabled) { - View root = getRootView(); - ViewGroup.LayoutParams lp = root.getLayoutParams(); - if (!(lp instanceof WindowManager.LayoutParams)) - return; - WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp; - int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0; - if (newWindowAnimations != wlp.windowAnimations) { - if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations - + " at " + SystemClock.uptimeMillis()); - wlp.windowAnimations = newWindowAnimations; - mWindowManager.updateViewLayout(root, wlp); - } - } - - private void onKeyguardVisibilityChanged(boolean showing) { - if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged " + showing - + " at " + SystemClock.uptimeMillis()); - if (mTransitioning && !showing) { - mTransitioning = false; - mHandler.removeCallbacks(mRecoverRunnable); - if (mLaunchCameraStart > 0) { - long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart; - if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime)); - mLaunchCameraStart = 0; - onCameraLaunched(); - } - } - } - - private void onSecureCameraActivityStarted() { - if (DEBUG) Log.d(TAG, "onSecureCameraActivityStarted at " + SystemClock.uptimeMillis()); - mHandler.postDelayed(mRecoverRunnable, RECOVERY_DELAY); - } - - private String instanceId() { - return Integer.toHexString(hashCode()); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java deleted file mode 100644 index a38e86d..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java +++ /dev/null @@ -1,258 +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; - -import android.content.Context; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.widget.TextView; - -import com.android.internal.R; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.IccCardConstants.State; -import com.android.internal.widget.LockPatternUtils; - -public class CarrierText extends TextView { - private static CharSequence mSeparator; - - private LockPatternUtils mLockPatternUtils; - - private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { - private CharSequence mPlmn; - private CharSequence mSpn; - private State mSimState; - - @Override - public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - mPlmn = plmn; - mSpn = spn; - updateCarrierText(mSimState, mPlmn, mSpn); - } - - @Override - public void onSimStateChanged(IccCardConstants.State simState) { - mSimState = simState; - updateCarrierText(mSimState, mPlmn, mSpn); - } - }; - /** - * The status of this lock screen. Primarily used for widgets on LockScreen. - */ - private static enum StatusMode { - Normal, // Normal case (sim card present, it's not locked) - NetworkLocked, // SIM card is 'network locked'. - SimMissing, // SIM card is missing. - SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access - SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times - SimLocked, // SIM card is currently locked - SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure - SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM. - } - - public CarrierText(Context context) { - this(context, null); - } - - public CarrierText(Context context, AttributeSet attrs) { - super(context, attrs); - mLockPatternUtils = new LockPatternUtils(mContext); - } - - protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) { - CharSequence text = getCarrierTextForSimState(simState, plmn, spn); - if (KeyguardViewManager.USE_UPPER_CASE) { - setText(text != null ? text.toString().toUpperCase() : null); - } else { - setText(text); - } - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mSeparator = getResources().getString(R.string.kg_text_message_separator); - setSelected(true); // Allow marquee to work. - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback); - } - - /** - * Top-level function for creating carrier text. Makes text based on simState, PLMN - * and SPN as well as device capabilities, such as being emergency call capable. - * - * @param simState - * @param plmn - * @param spn - * @return - */ - private CharSequence getCarrierTextForSimState(IccCardConstants.State simState, - CharSequence plmn, CharSequence spn) { - CharSequence carrierText = null; - StatusMode status = getStatusForIccState(simState); - switch (status) { - case Normal: - carrierText = concatenate(plmn, spn); - break; - - case SimNotReady: - carrierText = null; // nothing to display yet. - break; - - case NetworkLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - mContext.getText(R.string.lockscreen_network_locked_message), plmn); - 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), - plmn); - break; - - case SimPermDisabled: - carrierText = getContext().getText( - R.string.lockscreen_permanent_disabled_sim_message_short); - break; - - case SimMissingLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_missing_sim_message_short), - plmn); - break; - - case SimLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_sim_locked_message), - plmn); - break; - - case SimPukLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.lockscreen_sim_puk_locked_message), - plmn); - break; - } - - return carrierText; - } - - /* - * Add emergencyCallMessage to carrier string only if phone supports emergency calls. - */ - private CharSequence makeCarrierStringOnEmergencyCapable( - CharSequence simMessage, CharSequence emergencyCallMessage) { - if (mLockPatternUtils.isEmergencyCallCapable()) { - return concatenate(simMessage, emergencyCallMessage); - } - return simMessage; - } - - /** - * Determine the current status of the lock screen given the SIM state and other stuff. - */ - private 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 = - !KeyguardUpdateMonitor.getInstance(mContext).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.SimNotReady; - 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 static CharSequence concatenate(CharSequence plmn, CharSequence spn) { - final boolean plmnValid = !TextUtils.isEmpty(plmn); - final boolean spnValid = !TextUtils.isEmpty(spn); - if (plmnValid && spnValid) { - return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString(); - } else if (plmnValid) { - return plmn; - } else if (spnValid) { - return spn; - } else { - return ""; - } - } - - private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState, - String plmn, String spn) { - int carrierHelpTextId = 0; - StatusMode status = getStatusForIccState(simState); - switch (status) { - case NetworkLocked: - carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled; - break; - - case SimMissing: - carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long; - break; - - case SimPermDisabled: - carrierHelpTextId = R.string.lockscreen_permanent_disabled_sim_instructions; - break; - - case SimMissingLocked: - carrierHelpTextId = R.string.lockscreen_missing_sim_instructions; - break; - - case Normal: - case SimLocked: - case SimPukLocked: - break; - } - - return mContext.getText(carrierHelpTextId); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/ChallengeLayout.java deleted file mode 100644 index 8ece559..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/ChallengeLayout.java +++ /dev/null @@ -1,97 +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; - -/** - * Interface implemented by ViewGroup-derived layouts that implement - * special logic for presenting security challenges to the user. - */ -public interface ChallengeLayout { - /** - * @return true if the security challenge area of this layout is currently visible - */ - boolean isChallengeShowing(); - - /** - * @return true if the challenge area significantly overlaps other content - */ - boolean isChallengeOverlapping(); - - /** - * Show or hide the challenge layout. - * - * If you want to show the challenge layout in bouncer mode where applicable, - * use {@link #showBouncer()} instead. - * - * @param b true to show, false to hide - */ - void showChallenge(boolean b); - - /** - * Show the bouncer challenge. This may block access to other child views. - */ - void showBouncer(); - - /** - * Hide the bouncer challenge if it is currently showing. - * This may restore previously blocked access to other child views. - */ - void hideBouncer(); - - /** - * Returns true if the challenge is currently in bouncer mode, - * potentially blocking access to other child views. - */ - boolean isBouncing(); - - /** - * Returns the duration of the bounce animation. - */ - int getBouncerAnimationDuration(); - - /** - * Set a listener that will respond to changes in bouncer state. - * - * @param listener listener to register - */ - void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener); - - /** - * Listener interface that reports changes in bouncer state. - * The bouncer is - */ - public interface OnBouncerStateChangedListener { - /** - * Called when the bouncer state changes. - * The bouncer is activated when the user must pass a security challenge - * to proceed with the requested action. - * - * <p>This differs from simply showing or hiding the security challenge - * as the bouncer will prevent interaction with other elements of the UI. - * If the user attempts to escape from the bouncer, it will be dismissed, - * this method will be called with false as the parameter, and the action - * should be canceled. If the security component reports a successful - * authentication and the containing code calls hideBouncer() as a result, - * this method will also be called with a false parameter. It is up to the - * caller of hideBouncer to be ready for this.</p> - * - * @param bouncerActive true if the bouncer is now active, - * false if the bouncer was dismissed. - */ - public void onBouncerStateChanged(boolean bouncerActive); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java b/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java deleted file mode 100644 index 4825e23..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java +++ /dev/null @@ -1,82 +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; - -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; - -public class CheckLongPressHelper { - private View mView; - private boolean mHasPerformedLongPress; - private CheckForLongPress mPendingCheckForLongPress; - private float mDownX, mDownY; - private int mLongPressTimeout; - private int mScaledTouchSlop; - - class CheckForLongPress implements Runnable { - public void run() { - if ((mView.getParent() != null) && mView.hasWindowFocus() - && !mHasPerformedLongPress) { - if (mView.performLongClick()) { - mView.setPressed(false); - mHasPerformedLongPress = true; - } - } - } - } - - public CheckLongPressHelper(View v) { - mScaledTouchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); - mLongPressTimeout = ViewConfiguration.getLongPressTimeout(); - mView = v; - } - - public void postCheckForLongPress(MotionEvent ev) { - mDownX = ev.getX(); - mDownY = ev.getY(); - mHasPerformedLongPress = false; - - if (mPendingCheckForLongPress == null) { - mPendingCheckForLongPress = new CheckForLongPress(); - } - mView.postDelayed(mPendingCheckForLongPress, mLongPressTimeout); - } - - public void onMove(MotionEvent ev) { - float x = ev.getX(); - float y = ev.getY(); - boolean xMoved = Math.abs(mDownX - x) > mScaledTouchSlop; - boolean yMoved = Math.abs(mDownY - y) > mScaledTouchSlop; - - if (xMoved || yMoved) { - cancelLongPress(); - } - } - - public void cancelLongPress() { - mHasPerformedLongPress = false; - if (mPendingCheckForLongPress != null) { - mView.removeCallbacks(mPendingCheckForLongPress); - mPendingCheckForLongPress = null; - } - } - - public boolean hasPerformedLongPress() { - return mHasPerformedLongPress; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java b/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java deleted file mode 100644 index 34bf6e7..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java +++ /dev/null @@ -1,224 +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; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.database.ContentObserver; -import android.graphics.Typeface; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; -import android.text.format.DateFormat; -import android.util.AttributeSet; -import android.view.View; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import java.lang.ref.WeakReference; -import java.text.DateFormatSymbols; -import java.util.Calendar; -import com.android.internal.R; - -/** - * Displays the time - */ -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 = "HH:mm"; - - private Calendar mCalendar; - private String mFormat; - private TextView mTimeView; - private AmPm mAmPm; - private ContentObserver mFormatChangeObserver; - private int mAttached = 0; // for debugging - tells us whether attach/detach is unbalanced - - /* called by system on minute ticks */ - private final Handler mHandler = new Handler(); - private BroadcastReceiver mIntentReceiver; - - private static class TimeChangedReceiver extends BroadcastReceiver { - private WeakReference<ClockView> mClock; - private Context mContext; - - public TimeChangedReceiver(ClockView clock) { - mClock = new WeakReference<ClockView>(clock); - mContext = clock.getContext(); - } - - @Override - public void onReceive(Context context, Intent intent) { - // Post a runnable to avoid blocking the broadcast. - final boolean timezoneChanged = - intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED); - final ClockView clock = mClock.get(); - if (clock != null) { - clock.mHandler.post(new Runnable() { - public void run() { - if (timezoneChanged) { - clock.mCalendar = Calendar.getInstance(); - } - clock.updateTime(); - } - }); - } else { - try { - mContext.unregisterReceiver(this); - } catch (RuntimeException e) { - // Shouldn't happen - } - } - } - }; - - static class AmPm { - private TextView mAmPmTextView; - private String mAmString, mPmString; - - AmPm(View parent, Typeface tf) { - // No longer used, uncomment if we decide to use AM/PM indicator again - // mAmPmTextView = (TextView) parent.findViewById(R.id.am_pm); - if (mAmPmTextView != null && tf != null) { - mAmPmTextView.setTypeface(tf); - } - - String[] ampm = new DateFormatSymbols().getAmPmStrings(); - mAmString = ampm[0]; - mPmString = ampm[1]; - } - - void setShowAmPm(boolean show) { - if (mAmPmTextView != null) { - mAmPmTextView.setVisibility(show ? View.VISIBLE : View.GONE); - } - } - - void setIsMorning(boolean isMorning) { - if (mAmPmTextView != null) { - mAmPmTextView.setText(isMorning ? mAmString : mPmString); - } - } - } - - private static class FormatChangeObserver extends ContentObserver { - private WeakReference<ClockView> mClock; - private Context mContext; - public FormatChangeObserver(ClockView clock) { - super(new Handler()); - mClock = new WeakReference<ClockView>(clock); - mContext = clock.getContext(); - } - @Override - public void onChange(boolean selfChange) { - ClockView digitalClock = mClock.get(); - if (digitalClock != null) { - digitalClock.setDateFormat(); - digitalClock.updateTime(); - } else { - try { - mContext.getContentResolver().unregisterContentObserver(this); - } catch (RuntimeException e) { - // Shouldn't happen - } - } - } - } - - public ClockView(Context context) { - this(context, null); - } - - public ClockView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mTimeView = (TextView) findViewById(R.id.clock_text); - mTimeView.setTypeface(Typeface.createFromFile(ANDROID_CLOCK_FONT_FILE)); - mAmPm = new AmPm(this, null); - mCalendar = Calendar.getInstance(); - setDateFormat(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - mAttached++; - - /* monitor time ticks, time changed, timezone */ - if (mIntentReceiver == null) { - mIntentReceiver = new TimeChangedReceiver(this); - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_TIME_TICK); - filter.addAction(Intent.ACTION_TIME_CHANGED); - filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.OWNER, filter, null, null ); - } - - /* monitor 12/24-hour display preference */ - if (mFormatChangeObserver == null) { - mFormatChangeObserver = new FormatChangeObserver(this); - mContext.getContentResolver().registerContentObserver( - Settings.System.CONTENT_URI, true, mFormatChangeObserver); - } - - updateTime(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - mAttached--; - - if (mIntentReceiver != null) { - mContext.unregisterReceiver(mIntentReceiver); - } - if (mFormatChangeObserver != null) { - mContext.getContentResolver().unregisterContentObserver( - mFormatChangeObserver); - } - - mFormatChangeObserver = null; - mIntentReceiver = null; - } - - void updateTime(Calendar c) { - mCalendar = c; - updateTime(); - } - - public void updateTime() { - mCalendar.setTimeInMillis(System.currentTimeMillis()); - - CharSequence newTime = DateFormat.format(mFormat, mCalendar); - mTimeView.setText(newTime); - mAmPm.setIsMorning(mCalendar.get(Calendar.AM_PM) == 0); - } - - private void setDateFormat() { - mFormat = android.text.format.DateFormat.is24HourFormat(getContext()) ? M24 : M12; - mAmPm.setShowAmPm(mFormat.equals(M12)); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java deleted file mode 100644 index c68bab5..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java +++ /dev/null @@ -1,132 +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; - -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; -import android.widget.Button; - -import com.android.internal.telephony.IccCardConstants.State; -import com.android.internal.widget.LockPatternUtils; - -/** - * This class implements a smart emergency button that updates itself based - * on telephony state. When the phone is idle, it is an emergency call button. - * When there's a call in progress, it presents an appropriate message and - * allows the user to return to the call. - */ -public class EmergencyButton extends Button { - - private static final int EMERGENCY_CALL_TIMEOUT = 10000; // screen timeout after starting e.d. - private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; - - KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onSimStateChanged(State simState) { - int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState(); - updateEmergencyCallButton(simState, phoneState); - } - - void onPhoneStateChanged(int phoneState) { - State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState(); - updateEmergencyCallButton(simState, phoneState); - }; - }; - private LockPatternUtils mLockPatternUtils; - private PowerManager mPowerManager; - - public EmergencyButton(Context context) { - this(context, null); - } - - public EmergencyButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mLockPatternUtils = new LockPatternUtils(mContext); - mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - setOnClickListener(new OnClickListener() { - public void onClick(View v) { - takeEmergencyCallAction(); - } - }); - int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState(); - State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState(); - updateEmergencyCallButton(simState, phoneState); - } - - /** - * Shows the emergency dialer or returns the user to the existing call. - */ - public void takeEmergencyCallAction() { - // TODO: implement a shorter timeout once new PowerManager API is ready. - // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT) - mPowerManager.userActivity(SystemClock.uptimeMillis(), true); - 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().startActivityAsUser(intent, - new UserHandle(mLockPatternUtils.getCurrentUser())); - } - } - - private void updateEmergencyCallButton(State simState, int phoneState) { - boolean enabled = false; - if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) { - enabled = true; // always show "return to call" if phone is off-hook - } else if (mLockPatternUtils.isEmergencyCallCapable()) { - boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimLocked(); - if (simLocked) { - // Some countries can't handle emergency calls while SIM is locked. - enabled = mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked(); - } else { - // True if we need to show a secure screen (pin/pattern/SIM pin/SIM puk); - // hides emergency button on "Slide" screen if device is not secure. - enabled = mLockPatternUtils.isSecure(); - } - } - mLockPatternUtils.updateEmergencyCallButtonState(this, phoneState, enabled, - KeyguardViewManager.USE_UPPER_CASE, false); - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java deleted file mode 100644 index cfe1ef4..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 deleted file mode 100644 index e58eb5b..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java +++ /dev/null @@ -1,462 +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; - -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.PowerManager; -import android.os.RemoteException; -import android.os.UserHandle; -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; - - // 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_SERVICE_CONNECTED = 0; - private final int MSG_SERVICE_DISCONNECTED = 1; - private final int MSG_UNLOCK = 2; - private final int MSG_CANCEL = 3; - private final int MSG_REPORT_FAILED_ATTEMPT = 4; - private final int MSG_POKE_WAKELOCK = 5; - - // 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; - - // 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; - - KeyguardSecurityCallback 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) { - mContext = context; - mLockPatternUtils = new LockPatternUtils(context); - mHandler = new Handler(this); - } - - public void setKeyguardCallback(KeyguardSecurityCallback keyguardScreenCallback) { - mKeyguardScreenCallback = keyguardScreenCallback; - } - - /** - * 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; - } - - /** - * Dismisses face unlock and goes to the backup lock - */ - public void stopAndShowBackup() { - if (DEBUG) Log.d(TAG, "stopAndShowBackup()"); - mHandler.sendEmptyMessage(MSG_CANCEL); - } - - /** - * 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"); - } - - if (!mBoundToService) { - Log.d(TAG, "Binding to Face Unlock service for user=" - + mLockPatternUtils.getCurrentUser()); - mContext.bindServiceAsUser(new Intent(IFaceLockInterface.class.getName()), - mConnection, - Context.BIND_AUTO_CREATE, - new UserHandle(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 from non-UI thread"); - } - - // Clearing any old service connected messages. - mHandler.removeMessages(MSG_SERVICE_CONNECTED); - - 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. - */ - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_SERVICE_CONNECTED: - handleServiceConnected(); - break; - case MSG_SERVICE_DISCONNECTED: - handleServiceDisconnected(); - break; - case MSG_UNLOCK: - handleUnlock(msg.arg1); - break; - case MSG_CANCEL: - handleCancel(); - break; - case MSG_REPORT_FAILED_ATTEMPT: - handleReportFailedAttempt(); - break; - case MSG_POKE_WAKELOCK: - handlePokeWakelock(msg.arg1); - break; - default: - Log.e(TAG, "Unhandled message"); - return false; - } - return true; - } - - /** - * 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.userActivity(0); - - 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. - */ - void handleUnlock(int authenticatedUserId) { - if (DEBUG) Log.d(TAG, "handleUnlock()"); - stop(); - int currentUserId = mLockPatternUtils.getCurrentUser(); - if (authenticatedUserId == currentUserId) { - if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId); - mKeyguardScreenCallback.reportSuccessfulUnlockAttempt(); - mKeyguardScreenCallback.dismiss(true); - } else { - Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId + - ") because the current user is " + currentUserId); - } - } - - /** - * Stops the Face Unlock service and goes to the backup lock. - */ - void handleCancel() { - if (DEBUG) Log.d(TAG, "handleCancel()"); - // We are going to the backup method, so we don't want to see Face Unlock again until the - // next time the user visits keyguard. - KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false); - - mKeyguardScreenCallback.showBackupSecurity(); - stop(); - mKeyguardScreenCallback.userActivity(BACKUP_LOCK_TIMEOUT); - } - - /** - * Increments the number of failed Face Unlock attempts. - */ - void handleReportFailedAttempt() { - if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()"); - // We are going to the backup method, so we don't want to see Face Unlock again until the - // next time the user visits keyguard. - KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false); - - mKeyguardScreenCallback.reportFailedUnlockAttempt(); - } - - /** - * If the screen is on, pokes the wakelock to keep the screen alive and active for a specific - * amount of time. - */ - void handlePokeWakelock(int millis) { - PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - if (powerManager.isScreenOn()) { - mKeyguardScreenCallback.userActivity(millis); - } - } - - /** - * Implements service connection methods. - */ - private ServiceConnection mConnection = new ServiceConnection() { - /** - * Called when the Face Unlock service connects after calling bind(). - */ - 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. - */ - 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. - */ - public void unlock() { - if (DEBUG) Log.d(TAG, "unlock()"); - Message message = mHandler.obtainMessage(MSG_UNLOCK, UserHandle.getCallingUserId(), -1); - mHandler.sendMessage(message); - } - - /** - * Called when Face Unlock wants to go to the backup. - */ - 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. - */ - public void reportFailedAttempt() { - if (DEBUG) Log.d(TAG, "reportFailedAttempt()"); - mHandler.sendEmptyMessage(MSG_REPORT_FAILED_ATTEMPT); - } - - /** - * 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/KeyguardAbsKeyInputView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java deleted file mode 100644 index cc520dc..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java +++ /dev/null @@ -1,263 +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; - -import android.content.Context; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.CountDownTimer; -import android.os.SystemClock; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.AttributeSet; -import android.view.HapticFeedbackConstants; -import android.view.KeyEvent; -import android.view.View; -import android.view.inputmethod.EditorInfo; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; - -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; - -/** - * Base class for PIN and password unlock screens. - */ -public abstract class KeyguardAbsKeyInputView extends LinearLayout - implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { - protected KeyguardSecurityCallback mCallback; - protected TextView mPasswordEntry; - protected LockPatternUtils mLockPatternUtils; - protected SecurityMessageDisplay mSecurityMessageDisplay; - protected View mEcaView; - private Drawable mBouncerFrame; - protected boolean mEnableHaptics; - - // 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. - protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; - - public KeyguardAbsKeyInputView(Context context) { - this(context, null); - } - - public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mCallback = callback; - } - - public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled(); - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - if (hasWindowFocus) { - reset(); - } - } - - public void reset() { - // start fresh - mPasswordEntry.setText(""); - mPasswordEntry.requestFocus(); - - // if the user is currently locked out, enforce it. - long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); - if (deadline != 0) { - handleAttemptLockout(deadline); - } else { - resetState(); - } - } - - protected abstract int getPasswordTextViewId(); - protected abstract void resetState(); - - @Override - protected void onFinishInflate() { - mLockPatternUtils = new LockPatternUtils(mContext); - - mPasswordEntry = (TextView) findViewById(getPasswordTextViewId()); - mPasswordEntry.setOnEditorActionListener(this); - mPasswordEntry.addTextChangedListener(this); - - // Set selected property on so the view can send accessibility events. - mPasswordEntry.setSelected(true); - - // Poke the wakelock any time the text is selected or modified - mPasswordEntry.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.userActivity(0); // TODO: customize timeout for text? - } - }); - - 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 (mCallback != null) { - mCallback.userActivity(0); - } - } - }); - mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); - mEcaView = findViewById(R.id.keyguard_selector_fade_container); - View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame); - if (bouncerFrameView != null) { - mBouncerFrame = bouncerFrameView.getBackground(); - } - } - - @Override - protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { - // send focus to the password field - return mPasswordEntry.requestFocus(direction, previouslyFocusedRect); - } - - /* - * Override this if you have a different string for "wrong password" - * - * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this - */ - protected int getWrongPasswordStringId() { - return R.string.kg_wrong_password; - } - - protected void verifyPasswordAndUnlock() { - String entry = mPasswordEntry.getText().toString(); - if (mLockPatternUtils.checkPassword(entry)) { - mCallback.reportSuccessfulUnlockAttempt(); - mCallback.dismiss(true); - } 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 == (mCallback.getFailedAttempts() - % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { - long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); - handleAttemptLockout(deadline); - } - mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true); - } - mPasswordEntry.setText(""); - } - - // Prevent user from using the PIN/Password entry until scheduled deadline. - protected void handleAttemptLockout(long elapsedRealtimeDeadline) { - mPasswordEntry.setEnabled(false); - long elapsedRealtime = SystemClock.elapsedRealtime(); - new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { - - @Override - public void onTick(long millisUntilFinished) { - int secondsRemaining = (int) (millisUntilFinished / 1000); - mSecurityMessageDisplay.setMessage( - R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining); - } - - @Override - public void onFinish() { - mSecurityMessageDisplay.setMessage("", false); - resetState(); - } - }.start(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - mCallback.userActivity(0); - return false; - } - - @Override - 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; - } - - @Override - public boolean needsInput() { - return false; - } - - @Override - public void onPause() { - - } - - @Override - public void onResume(int reason) { - reset(); - } - - @Override - public KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - if (mCallback != null) { - mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS); - } - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - } - - // Cause a VIRTUAL_KEY vibration - public void doHapticKeyClick() { - if (mEnableHaptics) { - performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING - | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } - } - - @Override - public void showBouncer(int duration) { - KeyguardSecurityViewHelper. - showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); - } - - @Override - public void hideBouncer(int duration) { - KeyguardSecurityViewHelper. - hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); - } -} - diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAccountView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAccountView.java deleted file mode 100644 index e0e7128..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAccountView.java +++ /dev/null @@ -1,333 +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; - -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.Dialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.UserHandle; -import android.text.Editable; -import android.text.InputFilter; -import android.text.LoginFilter; -import android.text.TextWatcher; -import android.util.AttributeSet; -import android.view.KeyEvent; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; - -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.R; - -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 KeyguardAccountView extends LinearLayout implements KeyguardSecurityView, - View.OnClickListener, TextWatcher { - private static final int AWAKE_POKE_MILLIS = 30000; - private static final String LOCK_PATTERN_PACKAGE = "com.android.settings"; - private static final String LOCK_PATTERN_CLASS = LOCK_PATTERN_PACKAGE + ".ChooseLockGeneric"; - - private KeyguardSecurityCallback mCallback; - private LockPatternUtils mLockPatternUtils; - private EditText mLogin; - private EditText mPassword; - private Button mOk; - public boolean mEnableFallback; - private SecurityMessageDisplay mSecurityMessageDisplay; - - /** - * Shown while making asynchronous check of password. - */ - private ProgressDialog mCheckingDialog; - - public KeyguardAccountView(Context context) { - this(context, null, 0); - } - - public KeyguardAccountView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardAccountView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mLockPatternUtils = new LockPatternUtils(getContext()); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - 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); - - mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); - reset(); - } - - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mCallback = callback; - } - - public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - } - - public KeyguardSecurityCallback getCallback() { - return mCallback; - } - - - 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) { - if (mCallback != null) { - mCallback.userActivity(AWAKE_POKE_MILLIS); - } - } - - @Override - protected boolean onRequestFocusInDescendants(int direction, - Rect previouslyFocusedRect) { - // send focus to the login field - return mLogin.requestFocus(direction, previouslyFocusedRect); - } - - public boolean needsInput() { - return true; - } - - public void reset() { - // start fresh - mLogin.setText(""); - mPassword.setText(""); - mLogin.requestFocus(); - boolean permLocked = mLockPatternUtils.isPermanentlyLocked(); - mSecurityMessageDisplay.setMessage(permLocked ? R.string.kg_login_too_many_attempts : - R.string.kg_login_instructions, permLocked ? true : false); - } - - /** {@inheritDoc} */ - public void cleanUp() { - if (mCheckingDialog != null) { - mCheckingDialog.hide(); - } - mCallback = null; - mLockPatternUtils = null; - } - - public void onClick(View v) { - mCallback.userActivity(0); - 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.startActivityAsUser(intent, - new UserHandle(mLockPatternUtils.getCurrentUser())); - mCallback.reportSuccessfulUnlockAttempt(); - - // dismiss keyguard - mCallback.dismiss(true); - } else { - mSecurityMessageDisplay.setMessage(R.string.kg_login_invalid_input, true); - 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.dismiss(false); - } else { - // TODO: 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).getAccountsByTypeAsUser("com.google", - new UserHandle(mLockPatternUtils.getCurrentUser())); - - // 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.userActivity(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).confirmCredentialsAsUser(account, options, null /* activity */, - new AccountManagerCallback<Bundle>() { - public void run(AccountManagerFuture<Bundle> future) { - try { - mCallback.userActivity(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 */, new UserHandle(mLockPatternUtils.getCurrentUser())); - } - - private Dialog getProgressDialog() { - if (mCheckingDialog == null) { - mCheckingDialog = new ProgressDialog(mContext); - mCheckingDialog.setMessage( - mContext.getString(R.string.kg_login_checking_password)); - mCheckingDialog.setIndeterminate(true); - mCheckingDialog.setCancelable(false); - mCheckingDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - return mCheckingDialog; - } - - @Override - public void onPause() { - - } - - @Override - public void onResume(int reason) { - reset(); - } - - @Override - public void showUsabilityHint() { - } - - @Override - public void showBouncer(int duration) { - } - - @Override - public void hideBouncer(int duration) { - } -} - diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java deleted file mode 100644 index 6539db3..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardActivityLauncher.java +++ /dev/null @@ -1,273 +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; - -import android.app.ActivityManagerNative; -import android.app.ActivityOptions; -import android.app.IActivityManager.WaitResult; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProviderInfo; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Bundle; -import android.os.Handler; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.provider.MediaStore; -import android.util.Log; -import android.view.WindowManager; - -import com.android.internal.policy.impl.keyguard.KeyguardHostView.OnDismissAction; -import com.android.internal.widget.LockPatternUtils; - -import java.util.List; - -public abstract class KeyguardActivityLauncher { - private static final String TAG = KeyguardActivityLauncher.class.getSimpleName(); - private static final boolean DEBUG = KeyguardHostView.DEBUG; - private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout"; - private static final Intent SECURE_CAMERA_INTENT = - new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) - .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - private static final Intent INSECURE_CAMERA_INTENT = - new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); - - abstract Context getContext(); - - abstract KeyguardSecurityCallback getCallback(); - - abstract LockPatternUtils getLockPatternUtils(); - - public static class CameraWidgetInfo { - public String contextPackage; - public int layoutId; - } - - public CameraWidgetInfo getCameraWidgetInfo() { - CameraWidgetInfo info = new CameraWidgetInfo(); - Intent intent = getCameraIntent(); - PackageManager packageManager = getContext().getPackageManager(); - final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( - intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser()); - if (appList.size() == 0) { - if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Nothing found"); - return null; - } - ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, - PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA, - getLockPatternUtils().getCurrentUser()); - if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): resolved: " + resolved); - if (wouldLaunchResolverActivity(resolved, appList)) { - if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Would launch resolver"); - return info; - } - if (resolved == null || resolved.activityInfo == null) { - return null; - } - if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) { - if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no metadata found"); - return info; - } - int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT); - if (layoutId == 0) { - if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no layout specified"); - return info; - } - info.contextPackage = resolved.activityInfo.packageName; - info.layoutId = layoutId; - return info; - } - - public void launchCamera(Handler worker, Runnable onSecureCameraStarted) { - LockPatternUtils lockPatternUtils = getLockPatternUtils(); - if (lockPatternUtils.isSecure()) { - // Launch the secure version of the camera - if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) { - // TODO: Show disambiguation dialog instead. - // For now, we'll treat this like launching any other app from secure keyguard. - // When they do, user sees the system's ResolverActivity which lets them choose - // which secure camera to use. - launchActivity(SECURE_CAMERA_INTENT, false, false, null, null); - } else { - launchActivity(SECURE_CAMERA_INTENT, true, false, worker, onSecureCameraStarted); - } - } else { - // Launch the normal camera - launchActivity(INSECURE_CAMERA_INTENT, false, false, null, null); - } - } - - public void launchWidgetPicker(int appWidgetId) { - Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK); - - pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false); - pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER, - AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD); - - Bundle options = new Bundle(); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, - AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD); - pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options); - pickIntent.addFlags( - Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_SINGLE_TOP - | Intent.FLAG_ACTIVITY_CLEAR_TOP - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - - launchActivity(pickIntent, false, false, null, null); - } - - /** - * Launches the said intent for the current foreground user. - * - * @param intent - * @param showsWhileLocked true if the activity can be run on top of keyguard. - * See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED} - * @param useDefaultAnimations true if default transitions should be used, else suppressed. - * @param worker if supplied along with onStarted, used to launch the blocking activity call. - * @param onStarted if supplied along with worker, called after activity is started. - */ - public void launchActivity(final Intent intent, - boolean showsWhileLocked, - boolean useDefaultAnimations, - final Handler worker, - final Runnable onStarted) { - - final Context context = getContext(); - final Bundle animation = useDefaultAnimations ? null - : ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle(); - launchActivityWithAnimation(intent, showsWhileLocked, animation, worker, onStarted); - } - - public void launchActivityWithAnimation(final Intent intent, - boolean showsWhileLocked, - final Bundle animation, - final Handler worker, - final Runnable onStarted) { - - LockPatternUtils lockPatternUtils = getLockPatternUtils(); - intent.addFlags( - Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_SINGLE_TOP - | Intent.FLAG_ACTIVITY_CLEAR_TOP); - boolean isSecure = lockPatternUtils.isSecure(); - if (!isSecure || showsWhileLocked) { - if (!isSecure) { - dismissKeyguardOnNextActivity(); - } - try { - if (DEBUG) Log.d(TAG, String.format("Starting activity for intent %s at %s", - intent, SystemClock.uptimeMillis())); - startActivityForCurrentUser(intent, animation, worker, onStarted); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "Activity not found for intent + " + intent.getAction()); - } - } else { - // Create a runnable to start the activity and ask the user to enter their - // credentials. - KeyguardSecurityCallback callback = getCallback(); - callback.setOnDismissAction(new OnDismissAction() { - @Override - public boolean onDismiss() { - dismissKeyguardOnNextActivity(); - startActivityForCurrentUser(intent, animation, worker, onStarted); - return true; - } - }); - callback.dismiss(false); - } - } - - private void dismissKeyguardOnNextActivity() { - try { - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); - } catch (RemoteException e) { - Log.w(TAG, "can't dismiss keyguard on launch"); - } - } - - private void startActivityForCurrentUser(final Intent intent, final Bundle options, - Handler worker, final Runnable onStarted) { - final UserHandle user = new UserHandle(UserHandle.USER_CURRENT); - if (worker == null || onStarted == null) { - getContext().startActivityAsUser(intent, options, user); - return; - } - // if worker + onStarted are supplied, run blocking activity launch call in the background - worker.post(new Runnable(){ - @Override - public void run() { - try { - WaitResult result = ActivityManagerNative.getDefault().startActivityAndWait( - null /*caller*/, - null /*caller pkg*/, - intent, - intent.resolveTypeIfNeeded(getContext().getContentResolver()), - null /*resultTo*/, - null /*resultWho*/, - 0 /*requestCode*/, - Intent.FLAG_ACTIVITY_NEW_TASK, - null /*profileFile*/, - null /*profileFd*/, - options, - user.getIdentifier()); - if (DEBUG) Log.d(TAG, String.format("waitResult[%s,%s,%s,%s] at %s", - result.result, result.thisTime, result.totalTime, result.who, - SystemClock.uptimeMillis())); - } catch (RemoteException e) { - Log.w(TAG, "Error starting activity", e); - return; - } - try { - onStarted.run(); - } catch (Throwable t) { - Log.w(TAG, "Error running onStarted callback", t); - } - }}); - } - - private Intent getCameraIntent() { - return getLockPatternUtils().isSecure() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT; - } - - private boolean wouldLaunchResolverActivity(Intent intent) { - PackageManager packageManager = getContext().getPackageManager(); - ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, - PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser()); - List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( - intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser()); - return wouldLaunchResolverActivity(resolved, appList); - } - - private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) { - // If the list contains the above resolved activity, then it can't be - // ResolverActivity itself. - for (int i = 0; i < appList.size(); i++) { - ResolveInfo tmp = appList.get(i); - if (tmp.activityInfo.name.equals(resolved.activityInfo.name) - && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) { - return false; - } - } - return true; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java deleted file mode 100644 index fe32099..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java +++ /dev/null @@ -1,175 +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; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; - -import android.util.Log; - -class KeyguardCircleFramedDrawable extends Drawable { - - private final Bitmap mBitmap; - private final int mSize; - private final Paint mPaint; - private final float mShadowRadius; - private final float mStrokeWidth; - private final int mFrameColor; - private final int mHighlightColor; - private final int mFrameShadowColor; - - private float mScale; - private Path mFramePath; - private Rect mSrcRect; - private RectF mDstRect; - private RectF mFrameRect; - private boolean mPressed; - - public KeyguardCircleFramedDrawable(Bitmap bitmap, int size, - int frameColor, float strokeWidth, - int frameShadowColor, float shadowRadius, - int highlightColor) { - super(); - mSize = size; - mShadowRadius = shadowRadius; - mFrameColor = frameColor; - mFrameShadowColor = frameShadowColor; - mStrokeWidth = strokeWidth; - mHighlightColor = highlightColor; - - mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(mBitmap); - - final int width = bitmap.getWidth(); - final int height = bitmap.getHeight(); - final int square = Math.min(width, height); - - final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square); - final RectF circleRect = new RectF(0f, 0f, mSize, mSize); - circleRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f); - circleRect.inset(mShadowRadius, mShadowRadius); - - final Path fillPath = new Path(); - fillPath.addArc(circleRect, 0f, 360f); - - canvas.drawColor(0, PorterDuff.Mode.CLEAR); - - // opaque circle matte - mPaint = new Paint(); - mPaint.setAntiAlias(true); - mPaint.setColor(Color.BLACK); - mPaint.setStyle(Paint.Style.FILL); - canvas.drawPath(fillPath, mPaint); - - // mask in the icon where the bitmap is opaque - mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); - canvas.drawBitmap(bitmap, cropRect, circleRect, mPaint); - - // prepare paint for frame drawing - mPaint.setXfermode(null); - - mScale = 1f; - - mSrcRect = new Rect(0, 0, mSize, mSize); - mDstRect = new RectF(0, 0, mSize, mSize); - mFrameRect = new RectF(mDstRect); - mFramePath = new Path(); - } - - public void reset() { - mScale = 1f; - mPressed = false; - } - - @Override - public void draw(Canvas canvas) { - // clear background - final float outside = Math.min(canvas.getWidth(), canvas.getHeight()); - final float inside = mScale * outside; - final float pad = (outside - inside) / 2f; - - mDstRect.set(pad, pad, outside - pad, outside - pad); - canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null); - - mFrameRect.set(mDstRect); - mFrameRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f); - mFrameRect.inset(mShadowRadius, mShadowRadius); - - mFramePath.reset(); - mFramePath.addArc(mFrameRect, 0f, 360f); - - // white frame - if (mPressed) { - mPaint.setStyle(Paint.Style.FILL); - mPaint.setColor(Color.argb((int) (0.33f * 255), - Color.red(mHighlightColor), - Color.green(mHighlightColor), - Color.blue(mHighlightColor))); - canvas.drawPath(mFramePath, mPaint); - } - mPaint.setStrokeWidth(mStrokeWidth); - mPaint.setStyle(Paint.Style.STROKE); - mPaint.setColor(mPressed ? mHighlightColor : mFrameColor); - mPaint.setShadowLayer(mShadowRadius, 0f, 0f, mFrameShadowColor); - canvas.drawPath(mFramePath, mPaint); - } - - public void setScale(float scale) { - mScale = scale; - } - - public float getScale() { - return mScale; - } - - public void setPressed(boolean pressed) { - mPressed = pressed; - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - @Override - public void setAlpha(int alpha) { - } - - @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 deleted file mode 100644 index 7315aad..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java +++ /dev/null @@ -1,317 +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; - -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"; - private static final boolean DEBUG = false; - private KeyguardSecurityCallback mKeyguardSecurityCallback; - private LockPatternUtils mLockPatternUtils; - private BiometricSensorUnlock mBiometricUnlock; - private View mFaceUnlockAreaView; - private ImageButton mCancelButton; - private SecurityMessageDisplay mSecurityMessageDisplay; - private View mEcaView; - private Drawable mBouncerFrame; - - 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); - } - - public KeyguardFaceUnlockView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - initializeBiometricUnlockView(); - - mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); - mEcaView = findViewById(R.id.keyguard_selector_fade_container); - View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame); - if (bouncerFrameView != null) { - mBouncerFrame = bouncerFrameView.getBackground(); - } - } - - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mKeyguardSecurityCallback = callback; - // TODO: formalize this in the interface or factor it out - ((FaceUnlock)mBiometricUnlock).setKeyguardCallback(callback); - } - - @Override - public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - } - - @Override - public void reset() { - - } - - @Override - public void onDetachedFromWindow() { - if (DEBUG) Log.d(TAG, "onDetachedFromWindow()"); - if (mBiometricUnlock != null) { - 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 onPause() { - if (DEBUG) Log.d(TAG, "onPause()"); - if (mBiometricUnlock != null) { - 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(); - 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 - public boolean needsInput() { - return false; - } - - @Override - public KeyguardSecurityCallback getCallback() { - return mKeyguardSecurityCallback; - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - mBiometricUnlock.initializeView(mFaceUnlockAreaView); - } - - private void initializeBiometricUnlockView() { - if (DEBUG) Log.d(TAG, "initializeBiometricUnlockView()"); - mFaceUnlockAreaView = findViewById(R.id.face_unlock_area_view); - if (mFaceUnlockAreaView != null) { - mBiometricUnlock = new FaceUnlock(mContext); - - mCancelButton = (ImageButton) findViewById(R.id.face_unlock_cancel_button); - mCancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mBiometricUnlock.stopAndShowBackup(); - } - }); - } else { - Log.w(TAG, "Couldn't find biometric unlock view"); - } - } - - /** - * Starts the biometric unlock if it should be started based on a number of factors. If it - * should not be started, it either goes to the back up, or remains showing to prepare for - * it being started later. - */ - private void maybeStartBiometricUnlock() { - if (DEBUG) Log.d(TAG, "maybeStartBiometricUnlock()"); - if (mBiometricUnlock != null) { - KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); - final boolean backupIsTimedOut = ( - monitor.getFailedUnlockAttempts() >= - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT); - PowerManager powerManager = (PowerManager) mContext.getSystemService( - Context.POWER_SERVICE); - - boolean isShowing; - synchronized(mIsShowingLock) { - isShowing = mIsShowing; - } - - // Don't start it if the screen is off or if it's not showing, but keep this view up - // because we want it here and ready for when the screen turns on or when it does start - // showing. - if (!powerManager.isScreenOn() || !isShowing) { - mBiometricUnlock.stop(); // It shouldn't be running but calling this can't hurt. - return; - } - - // 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(); - } else { - mBiometricUnlock.stopAndShowBackup(); - } - } - } - - KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { - // We need to stop the biometric unlock when a phone call comes in - @Override - public void onPhoneStateChanged(int phoneState) { - if (DEBUG) Log.d(TAG, "onPhoneStateChanged(" + phoneState + ")"); - if (phoneState == TelephonyManager.CALL_STATE_RINGING) { - if (mBiometricUnlock != null) { - mBiometricUnlock.stopAndShowBackup(); - } - } - } - - @Override - public void onUserSwitching(int userId) { - if (DEBUG) Log.d(TAG, "onUserSwitched(" + userId + ")"); - if (mBiometricUnlock != null) { - mBiometricUnlock.stop(); - } - // No longer required; static value set by KeyguardViewMediator - // mLockPatternUtils.setCurrentUser(userId); - } - - @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; - synchronized(mIsShowingLock) { - wasShowing = mIsShowing; - mIsShowing = showing; - } - PowerManager powerManager = (PowerManager) mContext.getSystemService( - Context.POWER_SERVICE); - if (mBiometricUnlock != null) { - if (!showing && wasShowing) { - mBiometricUnlock.stop(); - } else if (showing && powerManager.isScreenOn() && !wasShowing) { - maybeStartBiometricUnlock(); - } - } - } - }; - - @Override - public void showUsabilityHint() { - } - - @Override - public void showBouncer(int duration) { - KeyguardSecurityViewHelper. - showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); - } - - @Override - public void hideBouncer(int duration) { - KeyguardSecurityViewHelper. - hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardGlowStripView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardGlowStripView.java deleted file mode 100644 index e1c95f0..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardGlowStripView.java +++ /dev/null @@ -1,139 +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; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; -import android.widget.LinearLayout; - -import com.android.internal.R; - -/** - * A layout which animates a strip of horizontal, pulsing dots on request. This is used - * to indicate the presence of pages to the left / right. - */ -public class KeyguardGlowStripView extends LinearLayout { - private static final int DURATION = 500; - - private static final float SLIDING_WINDOW_SIZE = 0.4f; - private int mDotStripTop; - private int mHorizontalDotGap; - - private int mDotSize; - private int mNumDots; - private Drawable mDotDrawable; - private boolean mLeftToRight = true; - - private float mAnimationProgress = 0f; - private boolean mDrawDots = false; - private ValueAnimator mAnimator; - private Interpolator mDotAlphaInterpolator = new DecelerateInterpolator(0.5f); - - public KeyguardGlowStripView(Context context) { - this(context, null, 0); - } - - public KeyguardGlowStripView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardGlowStripView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyguardGlowStripView); - mDotSize = a.getDimensionPixelSize(R.styleable.KeyguardGlowStripView_dotSize, mDotSize); - mNumDots = a.getInt(R.styleable.KeyguardGlowStripView_numDots, mNumDots); - mDotDrawable = a.getDrawable(R.styleable.KeyguardGlowStripView_glowDot); - mLeftToRight = a.getBoolean(R.styleable.KeyguardGlowStripView_leftToRight, mLeftToRight); - } - - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - int availableWidth = w - getPaddingLeft() - getPaddingRight(); - mHorizontalDotGap = (availableWidth - mDotSize * mNumDots) / (mNumDots - 1); - mDotStripTop = getPaddingTop(); - invalidate(); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - - if (!mDrawDots) return; - - int xOffset = getPaddingLeft(); - mDotDrawable.setBounds(0, 0, mDotSize, mDotSize); - - for (int i = 0; i < mNumDots; i++) { - // We fudge the relative position to provide a fade in of the first dot and a fade - // out of the final dot. - float relativeDotPosition = SLIDING_WINDOW_SIZE / 2 + ((1.0f * i) / (mNumDots - 1)) * - (1 - SLIDING_WINDOW_SIZE); - float distance = Math.abs(relativeDotPosition - mAnimationProgress); - float alpha = Math.max(0, 1 - distance / (SLIDING_WINDOW_SIZE / 2)); - - alpha = mDotAlphaInterpolator.getInterpolation(alpha); - - canvas.save(); - canvas.translate(xOffset, mDotStripTop); - mDotDrawable.setAlpha((int) (alpha * 255)); - mDotDrawable.draw(canvas); - canvas.restore(); - xOffset += mDotSize + mHorizontalDotGap; - } - } - - public void makeEmGo() { - if (mAnimator != null) { - mAnimator.cancel(); - } - float from = mLeftToRight ? 0f : 1f; - float to = mLeftToRight ? 1f : 0f; - mAnimator = ValueAnimator.ofFloat(from, to); - mAnimator.setDuration(DURATION); - mAnimator.setInterpolator(new LinearInterpolator()); - mAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mDrawDots = false; - // make sure we draw one frame at the end with everything gone. - invalidate(); - } - - @Override - public void onAnimationStart(Animator animation) { - mDrawDots = true; - } - }); - mAnimator.addUpdateListener(new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mAnimationProgress = (Float) animation.getAnimatedValue(); - invalidate(); - } - }); - mAnimator.start(); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java deleted file mode 100644 index c3077c7..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ /dev/null @@ -1,1684 +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; - -import android.app.Activity; -import android.app.ActivityManager; -import android.app.ActivityOptions; -import android.app.AlertDialog; -import android.app.SearchManager; -import android.app.admin.DevicePolicyManager; -import android.appwidget.AppWidgetHost; -import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProviderInfo; -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; -import android.os.SystemClock; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.Settings; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.view.animation.AnimationUtils; -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; -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; - - private final int MAX_WIDGETS = 5; - - private AppWidgetHost mAppWidgetHost; - private AppWidgetManager mAppWidgetManager; - private KeyguardWidgetPager mAppWidgetContainer; - private KeyguardSecurityViewFlipper mSecurityViewContainer; - private KeyguardSelectorView mKeyguardSelectorView; - private KeyguardTransportControlView mTransportControl; - private boolean mIsVerifyUnlockOnly; - private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView - private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; - private int mAppWidgetToShow; - - private boolean mCheckAppWidgetConsistencyOnBootCompleted = false; - private boolean mCleanupAppWidgetsOnBootCompleted = false; - - protected OnDismissAction mDismissAction; - - protected int mFailedAttempts; - private LockPatternUtils mLockPatternUtils; - - private KeyguardSecurityModel mSecurityModel; - private KeyguardViewStateManager mViewStateManager; - - private Rect mTempRect = new Rect(); - - private int mDisabledFeatures; - - private boolean mCameraDisabled; - - private boolean mSafeModeEnabled; - - private boolean mUserSetupCompleted; - - // 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); - void showSecurityView(); - void showUnlockHint(); - void userActivity(); - } - - /*package*/ interface OnDismissAction { - /* returns true if the dismiss should be deferred */ - boolean onDismiss(); - } - - public KeyguardHostView(Context context) { - this(context, null); - } - - public KeyguardHostView(Context context, AttributeSet attrs) { - super(context, attrs); - - if (DEBUG) Log.e(TAG, "KeyguardHostView()"); - - 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); - 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"); - } - if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) { - Log.v(TAG, "Keyguard widgets disabled by DPM"); - } - if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) { - Log.v(TAG, "Keyguard secure camera disabled by DPM"); - } - } - - 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. - if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) { - mCleanupAppWidgetsOnBootCompleted = true; - return; - } - 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); - } - } - } - } - - private static boolean contains(int[] array, int target) { - for (int value : array) { - if (value == target) { - return true; - } - } - return false; - } - - private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks = - new KeyguardUpdateMonitorCallback() { - @Override - public void onBootCompleted() { - if (mCheckAppWidgetConsistencyOnBootCompleted) { - checkAppWidgetConsistency(); - mSwitchPageRunnable.run(); - mCheckAppWidgetConsistencyOnBootCompleted = false; - } - if (mCleanupAppWidgetsOnBootCompleted) { - cleanupAppWidgetIds(); - 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 - public boolean onTouchEvent(MotionEvent ev) { - boolean result = super.onTouchEvent(ev); - mTempRect.set(0, 0, 0, 0); - offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect); - ev.offsetLocation(mTempRect.left, mTempRect.top); - result = mSecurityViewContainer.dispatchTouchEvent(ev) || result; - ev.offsetLocation(-mTempRect.left, -mTempRect.top); - return result; - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - if (mViewMediatorCallback != null) { - mViewMediatorCallback.keyguardDoneDrawing(); - } - } - - private int getWidgetPosition(int id) { - final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer; - final int children = appWidgetContainer.getChildCount(); - for (int i = 0; i < children; i++) { - 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; - } - - @Override - protected void onFinishInflate() { - // Grab instances of and make any necessary changes to the main layouts. Create - // view state manager and wire up necessary listeners / callbacks. - View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target); - mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container); - mAppWidgetContainer.setVisibility(VISIBLE); - mAppWidgetContainer.setCallbacks(mWidgetCallbacks); - mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget); - mAppWidgetContainer.setMinScale(0.5f); - - mSlidingChallengeLayout = (SlidingChallengeLayout) findViewById(R.id.sliding_layout); - if (mSlidingChallengeLayout != null) { - mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager); - } - mAppWidgetContainer.setViewStateManager(mViewStateManager); - mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils); - - ChallengeLayout challenge = mSlidingChallengeLayout != null ? mSlidingChallengeLayout : - (ChallengeLayout) findViewById(R.id.multi_pane_challenge); - challenge.setOnBouncerStateChangedListener(mViewStateManager); - mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration()); - mViewStateManager.setPagedView(mAppWidgetContainer); - mViewStateManager.setChallengeLayout(challenge); - mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper); - mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view); - mViewStateManager.setSecurityViewContainer(mSecurityViewContainer); - - setBackButtonEnabled(false); - - addDefaultWidgets(); - - addWidgetsFromSettings(); - if (!shouldEnableAddWidget()) { - mAppWidgetContainer.setAddWidgetEnabled(false); - } - checkAppWidgetConsistency(); - mSwitchPageRunnable.run(); - // This needs to be called after the pages are all added. - mViewStateManager.showUsabilityHints(); - - showPrimarySecurityScreen(false); - 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; - } - - private int getDisabledFeatures(DevicePolicyManager dpm) { - int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; - if (dpm != null) { - final int currentUser = mLockPatternUtils.getCurrentUser(); - disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser); - } - return disabledFeatures; - } - - private boolean widgetsDisabledByDpm() { - return (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0; - } - - private boolean cameraDisabledByDpm() { - return mCameraDisabled - || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0; - } - - private void updateSecurityViews() { - int children = mSecurityViewContainer.getChildCount(); - for (int i = 0; i < children; i++) { - updateSecurityView(mSecurityViewContainer.getChildAt(i)); - } - } - - private void updateSecurityView(View view) { - if (view instanceof KeyguardSecurityView) { - KeyguardSecurityView ksv = (KeyguardSecurityView) view; - ksv.setKeyguardCallback(mCallback); - ksv.setLockPatternUtils(mLockPatternUtils); - if (mViewStateManager.isBouncing()) { - ksv.showBouncer(0); - } else { - ksv.hideBouncer(0); - } - } else { - Log.w(TAG, "View " + view + " is not a KeyguardSecurityView"); - } - } - - void setLockPatternUtils(LockPatternUtils utils) { - mSecurityModel.setLockPatternUtils(utils); - mLockPatternUtils = utils; - updateSecurityViews(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mAppWidgetHost.startListening(); - KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mAppWidgetHost.stopListening(); - KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks); - } - - void addWidget(AppWidgetHostView view, int pageIndex) { - mAppWidgetContainer.addWidget(view, pageIndex); - } - - private KeyguardWidgetPager.Callbacks mWidgetCallbacks - = new KeyguardWidgetPager.Callbacks() { - @Override - public void userActivity() { - KeyguardHostView.this.userActivity(); - } - - @Override - public void onUserActivityTimeoutChanged() { - KeyguardHostView.this.onUserActivityTimeoutChanged(); - } - - @Override - public void onAddView(View v) { - if (!shouldEnableAddWidget()) { - mAppWidgetContainer.setAddWidgetEnabled(false); - } - } - - @Override - public void onRemoveView(View v, boolean deletePermanently) { - if (deletePermanently) { - final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); - if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && - appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) { - mAppWidgetHost.deleteAppWidgetId(appWidgetId); - } - } - } - - @Override - public void onRemoveViewAnimationCompleted() { - if (shouldEnableAddWidget()) { - mAppWidgetContainer.setAddWidgetEnabled(true); - } - } - }; - - public void initializeSwitchingUserState(boolean switching) { - if (!switching && mKeyguardMultiUserSelectorView != null) { - mKeyguardMultiUserSelectorView.finalizeActiveUserView(false); - } - } - - public void userActivity() { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.userActivity(); - } - } - - public void onUserActivityTimeoutChanged() { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.onUserActivityTimeoutChanged(); - } - } - - @Override - public long getUserActivityTimeout() { - // Currently only considering user activity timeouts needed by widgets. - // Could also take into account longer timeouts for certain security views. - if (mAppWidgetContainer != null) { - return mAppWidgetContainer.getUserActivityTimeout(); - } - return -1; - } - - private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { - - public void userActivity(long timeout) { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.userActivity(timeout); - } - } - - public void dismiss(boolean authenticated) { - showNextSecurityScreenOrFinish(authenticated); - } - - public boolean isVerifyUnlockOnly() { - return mIsVerifyUnlockOnly; - } - - public void reportSuccessfulUnlockAttempt() { - KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts(); - mLockPatternUtils.reportSuccessfulPasswordAttempt(); - } - - public void reportFailedUnlockAttempt() { - if (mCurrentSecuritySelection == SecurityMode.Biometric) { - KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt(); - } else { - KeyguardHostView.this.reportFailedUnlockAttempt(); - } - } - - public int getFailedAttempts() { - return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(); - } - - @Override - public void showBackupSecurity() { - KeyguardHostView.this.showBackupSecurityScreen(); - } - - @Override - public void setOnDismissAction(OnDismissAction action) { - KeyguardHostView.this.setOnDismissAction(action); - } - - }; - - private void showDialog(String title, String message) { - final AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(title) - .setMessage(message) - .setNeutralButton(com.android.internal.R.string.ok, null) - .create(); - if (!(mContext instanceof Activity)) { - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - dialog.show(); - } - - private void showTimeoutDialog() { - int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; - int messageId = 0; - - switch (mSecurityModel.getSecurityMode()) { - case Pattern: - messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message; - break; - case PIN: - messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message; - break; - case Password: - messageId = R.string.kg_too_many_failed_password_attempts_dialog_message; - break; - } - - if (messageId != 0) { - final String message = mContext.getString(messageId, - KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(), - 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.kg_failed_attempts_almost_at_wipe, - attempts, remaining); - showDialog(null, message); - } - - private void showWipeDialog(int attempts) { - String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts); - 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.kg_failed_attempts_almost_at_login, - count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds); - showDialog(null, message); - } - - private void reportFailedUnlockAttempt() { - final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); - final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time - - if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); - - SecurityMode mode = mSecurityModel.getSecurityMode(); - final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern; - - final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager() - .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser()); - - 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 - - boolean showTimeout = false; - 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 { - 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); - showSecurityScreen(SecurityMode.Account); - // don't show timeout dialog because we show account unlock screen next - showTimeout = false; - } - } - } - monitor.reportFailedUnlockAttempt(); - mLockPatternUtils.reportFailedPasswordAttempt(); - if (showTimeout) { - showTimeoutDialog(); - } - } - - /** - * Shows the primary security screen for the user. This will be either the multi-selector - * or the user's security method. - * @param turningOff true if the device is being turned off - */ - void showPrimarySecurityScreen(boolean turningOff) { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); - if (!turningOff && - KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) { - // If we're not turning off, then allow biometric alternate. - // We'll reload it when the device comes back on. - securityMode = mSecurityModel.getAlternateFor(securityMode); - } - showSecurityScreen(securityMode); - } - - /** - * Shows the backup security screen for the current security mode. This could be used for - * password recovery screens but is currently only used for pattern unlock to show the - * account unlock screen and biometric unlock to show the user's normal unlock. - */ - private void showBackupSecurityScreen() { - if (DEBUG) Log.d(TAG, "showBackupSecurity()"); - SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection); - showSecurityScreen(backup); - } - - public boolean showNextSecurityScreenIfPresent() { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - // Allow an alternate, such as biometric unlock - securityMode = mSecurityModel.getAlternateFor(securityMode); - if (SecurityMode.None == securityMode) { - return false; - } else { - showSecurityScreen(securityMode); // switch to the alternate security view - return true; - } - } - - private void showNextSecurityScreenOrFinish(boolean authenticated) { - if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); - boolean finish = false; - if (SecurityMode.None == mCurrentSecuritySelection) { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - // Allow an alternate, such as biometric unlock - securityMode = mSecurityModel.getAlternateFor(securityMode); - if (SecurityMode.None == securityMode) { - finish = true; // no security required - } else { - showSecurityScreen(securityMode); // switch to the alternate security view - } - } else if (authenticated) { - switch (mCurrentSecuritySelection) { - case Pattern: - case Password: - case PIN: - case Account: - case Biometric: - finish = true; - break; - - case SimPin: - case SimPuk: - // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - if (securityMode != SecurityMode.None) { - showSecurityScreen(securityMode); - } else { - finish = true; - } - break; - - default: - Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe"); - showPrimarySecurityScreen(false); - break; - } - } else { - showPrimarySecurityScreen(false); - } - if (finish) { - // If the alternate unlock was suppressed, it can now be safely - // enabled because the user has left keyguard. - KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); - - // If there's a pending runnable because the user interacted with a widget - // and we're leaving keyguard, then run it. - boolean deferKeyguardDone = false; - if (mDismissAction != null) { - deferKeyguardDone = mDismissAction.onDismiss(); - mDismissAction = null; - } - if (mViewMediatorCallback != null) { - if (deferKeyguardDone) { - mViewMediatorCallback.keyguardDonePending(); - } else { - mViewMediatorCallback.keyguardDone(true); - } - } - } else { - mViewStateManager.showBouncer(true); - } - } - - private OnClickHandler mOnClickHandler = new OnClickHandler() { - @Override - public boolean onClickHandler(final View view, - final android.app.PendingIntent pendingIntent, - final Intent fillInIntent) { - if (pendingIntent.isActivity()) { - setOnDismissAction(new OnDismissAction() { - public boolean onDismiss() { - try { - // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? - Context context = view.getContext(); - ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, - 0, 0, - view.getMeasuredWidth(), view.getMeasuredHeight()); - context.startIntentSender( - pendingIntent.getIntentSender(), fillInIntent, - Intent.FLAG_ACTIVITY_NEW_TASK, - Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle()); - } catch (IntentSender.SendIntentException e) { - android.util.Log.e(TAG, "Cannot send pending intent: ", e); - } catch (Exception e) { - android.util.Log.e(TAG, "Cannot send pending intent due to " + - "unknown exception: ", e); - } - return false; - } - }); - - if (mViewStateManager.isChallengeShowing()) { - mViewStateManager.showBouncer(true); - } else { - mCallback.dismiss(false); - } - return true; - } else { - return super.onClickHandler(view, pendingIntent, fillInIntent); - } - }; - }; - - // Used to ignore callbacks from methods that are no longer current (e.g. face unlock). - // This avoids unwanted asynchronous events from messing with the state. - private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { - - @Override - public void userActivity(long timeout) { - } - - @Override - public void showBackupSecurity() { - } - - @Override - public void setOnDismissAction(OnDismissAction action) { - } - - @Override - public void reportSuccessfulUnlockAttempt() { - } - - @Override - public void reportFailedUnlockAttempt() { - } - - @Override - public boolean isVerifyUnlockOnly() { - return false; - } - - @Override - public int getFailedAttempts() { - return 0; - } - - @Override - public void dismiss(boolean securityVerified) { - } - }; - - protected boolean mShowSecurityWhenReturn; - - @Override - public void reset() { - mIsVerifyUnlockOnly = false; - mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_status_view)); - } - - /** - * Sets an action to perform when keyguard is dismissed. - * @param action - */ - protected void setOnDismissAction(OnDismissAction action) { - mDismissAction = action; - } - - private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { - final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); - KeyguardSecurityView view = null; - final int children = mSecurityViewContainer.getChildCount(); - for (int child = 0; child < children; child++) { - if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) { - view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child)); - break; - } - } - int layoutId = getLayoutIdFor(securityMode); - if (view == null && layoutId != 0) { - final LayoutInflater inflater = LayoutInflater.from(mContext); - if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); - View v = inflater.inflate(layoutId, mSecurityViewContainer, false); - mSecurityViewContainer.addView(v); - updateSecurityView(v); - view = (KeyguardSecurityView)v; - } - - if (view instanceof KeyguardSelectorView) { - KeyguardSelectorView selectorView = (KeyguardSelectorView) view; - View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container); - selectorView.setCarrierArea(carrierText); - } - - return view; - } - - /** - * Switches to the given security view unless it's already being shown, in which case - * this is a no-op. - * - * @param securityMode - */ - private void showSecurityScreen(SecurityMode securityMode) { - if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); - - if (securityMode == mCurrentSecuritySelection) return; - - KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); - KeyguardSecurityView newView = getSecurityView(securityMode); - - // Enter full screen mode if we're in SIM or Account screen - boolean fullScreenEnabled = getResources().getBoolean( - com.android.internal.R.bool.kg_sim_puk_account_full_screen); - boolean isSimOrAccount = securityMode == SecurityMode.SimPin - || securityMode == SecurityMode.SimPuk - || securityMode == SecurityMode.Account; - mAppWidgetContainer.setVisibility( - isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE); - - if (mSlidingChallengeLayout != null) { - mSlidingChallengeLayout.setChallengeInteractive(!fullScreenEnabled); - } - - // Emulate Activity life cycle - if (oldView != null) { - oldView.onPause(); - oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view - } - newView.onResume(KeyguardSecurityView.VIEW_REVEALED); - newView.setKeyguardCallback(mCallback); - - final boolean needsInput = newView.needsInput(); - if (mViewMediatorCallback != null) { - mViewMediatorCallback.setNeedsInput(needsInput); - } - - // Find and show this child. - final int childCount = mSecurityViewContainer.getChildCount(); - - mSecurityViewContainer.setInAnimation( - AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in)); - mSecurityViewContainer.setOutAnimation( - AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out)); - final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); - for (int i = 0; i < childCount; i++) { - if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) { - mSecurityViewContainer.setDisplayedChild(i); - break; - } - } - - if (securityMode == SecurityMode.None) { - // 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; - } - - @Override - public void onScreenTurnedOn() { - if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); - showPrimarySecurityScreen(false); - getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON); - - // This is a an attempt to fix bug 7137389 where the device comes back on but the entire - // layout is blank but forcing a layout causes it to reappear (e.g. with with - // hierarchyviewer). - requestLayout(); - - if (mViewStateManager != null) { - mViewStateManager.showUsabilityHints(); - } - requestFocus(); - } - - @Override - public void onScreenTurnedOff() { - if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s", - Integer.toHexString(hashCode()), SystemClock.uptimeMillis())); - // Once the screen turns off, we no longer consider this to be first boot and we want the - // biometric unlock to start next time keyguard is shown. - KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); - // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen - // turns off we reset that behavior - clearAppWidgetToShow(); - checkAppWidgetConsistency(); - showPrimarySecurityScreen(true); - getSecurityView(mCurrentSecuritySelection).onPause(); - CameraWidgetFrame cameraPage = findCameraPage(); - if (cameraPage != null) { - cameraPage.onScreenTurnedOff(); - } - clearFocus(); - } - - public void clearAppWidgetToShow() { - mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID; - } - - @Override - public void show() { - if (DEBUG) Log.d(TAG, "show()"); - showPrimarySecurityScreen(false); - } - - private boolean isSecure() { - SecurityMode mode = mSecurityModel.getSecurityMode(); - switch (mode) { - case Pattern: - return mLockPatternUtils.isLockPatternEnabled(); - case Password: - case PIN: - return mLockPatternUtils.isLockPasswordEnabled(); - case SimPin: - case SimPuk: - case Account: - return true; - case None: - return false; - default: - throw new IllegalStateException("Unknown security mode " + mode); - } - } - - @Override - public void wakeWhenReadyTq(int keyCode) { - if (DEBUG) Log.d(TAG, "onWakeKey"); - if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) { - if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU"); - showSecurityScreen(SecurityMode.None); - } else { - if (DEBUG) Log.d(TAG, "poking wake lock immediately"); - } - if (mViewMediatorCallback != null) { - mViewMediatorCallback.wakeUp(); - } - } - - @Override - public void verifyUnlock() { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - if (securityMode == KeyguardSecurityModel.SecurityMode.None) { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.keyguardDone(true); - } - } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern - && securityMode != KeyguardSecurityModel.SecurityMode.PIN - && securityMode != KeyguardSecurityModel.SecurityMode.Password) { - // can only verify unlock when in pattern/password mode - if (mViewMediatorCallback != null) { - mViewMediatorCallback.keyguardDone(false); - } - } else { - // otherwise, go to the unlock screen, see if they can verify it - mIsVerifyUnlockOnly = true; - showSecurityScreen(securityMode); - } - } - - private int getSecurityViewIdForMode(SecurityMode securityMode) { - switch (securityMode) { - case None: return R.id.keyguard_selector_view; - case Pattern: return R.id.keyguard_pattern_view; - case PIN: return R.id.keyguard_pin_view; - case Password: return R.id.keyguard_password_view; - case Biometric: return R.id.keyguard_face_unlock_view; - case Account: return R.id.keyguard_account_view; - case SimPin: return R.id.keyguard_sim_pin_view; - case SimPuk: return R.id.keyguard_sim_puk_view; - } - return 0; - } - - private int getLayoutIdFor(SecurityMode securityMode) { - switch (securityMode) { - case None: return R.layout.keyguard_selector_view; - case Pattern: return R.layout.keyguard_pattern_view; - case PIN: return R.layout.keyguard_pin_view; - case Password: return R.layout.keyguard_password_view; - case Biometric: return R.layout.keyguard_face_unlock_view; - case Account: return R.layout.keyguard_account_view; - case SimPin: return R.layout.keyguard_sim_pin_view; - case SimPuk: return R.layout.keyguard_sim_puk_view; - default: - return 0; - } - } - - private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) { - AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId); - if (appWidgetInfo != null) { - 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 for user" - + mUserId + ", deleting"); - mAppWidgetHost.deleteAppWidgetId(appId); - mLockPatternUtils.removeAppWidget(appId); - } - return false; - } - } - - private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks = - new CameraWidgetFrame.Callbacks() { - @Override - public void onLaunchingCamera() { - setSliderHandleAlpha(0); - } - - @Override - public void onCameraLaunchedSuccessfully() { - if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) { - mAppWidgetContainer.scrollLeft(); - } - setSliderHandleAlpha(1); - mShowSecurityWhenReturn = true; - } - - @Override - public void onCameraLaunchedUnsuccessfully() { - setSliderHandleAlpha(1); - } - - private void setSliderHandleAlpha(float alpha) { - SlidingChallengeLayout slider = - (SlidingChallengeLayout) findViewById(R.id.sliding_layout); - if (slider != null) { - slider.setHandleAlpha(alpha); - } - } - }; - - private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { - @Override - Context getContext() { - return mContext; - } - - @Override - KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - LockPatternUtils getLockPatternUtils() { - return mLockPatternUtils; - } - }; - - private int numWidgets() { - final int childCount = mAppWidgetContainer.getChildCount(); - int widgetCount = 0; - for (int i = 0; i < childCount; i++) { - if (mAppWidgetContainer.isWidgetPage(i)) { - widgetCount++; - } - } - return widgetCount; - } - - private void addDefaultWidgets() { - 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); - addWidgetButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - // Pass in an invalid widget id... the picker will allocate an ID for us - mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID); - } - }); - } - - // We currently disable cameras in safe mode because we support loading 3rd party - // cameras we can't trust. TODO: plumb safe mode into camera creation code and only - // inflate system-provided camera? - if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted - && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) { - View cameraWidget = - CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher); - if (cameraWidget != null) { - mAppWidgetContainer.addWidget(cameraWidget); - } - } - - enableUserSelectorIfNecessary(); - } - - /** - * 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() { - View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget); - int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget); - if (insertionIndex < 0) { - insertionIndex = 0; // no add widget page found - } else { - insertionIndex++; // place after add widget - } - return insertionIndex; - } - - private void addDefaultStatusWidget(int index) { - LayoutInflater inflater = LayoutInflater.from(mContext); - View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true); - mAppWidgetContainer.addWidget(statusWidget, index); - } - - private void addWidgetsFromSettings() { - if (mSafeModeEnabled || widgetsDisabledByDpm()) { - return; - } - - int insertionIndex = getInsertPageIndex(); - - // Add user-selected widget - final int[] widgets = mLockPatternUtils.getAppWidgets(); - - if (widgets == null) { - Log.d(TAG, "Problem reading widgets"); - } else { - for (int i = widgets.length -1; i >= 0; i--) { - if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) { - addDefaultStatusWidget(insertionIndex); - } else { - // We add the widgets from left to right, starting after the first page after - // the add page. We count down, since the order will be persisted from right - // to left, starting after camera. - addWidget(widgets[i], insertionIndex, true); - } - } - } - } - - private int allocateIdForDefaultAppWidget() { - int appWidgetId; - Resources res = getContext().getResources(); - ComponentName defaultAppWidget = new ComponentName( - res.getString(R.string.widget_default_package_name), - res.getString(R.string.widget_default_class_name)); - - // Note: we don't support configuring the widget - appWidgetId = mAppWidgetHost.allocateAppWidgetId(); - - try { - mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget); - - } catch (IllegalArgumentException e) { - Log.e(TAG, "Error when trying to bind default AppWidget: " + e); - mAppWidgetHost.deleteAppWidgetId(appWidgetId); - appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; - } - return appWidgetId; - } - public void checkAppWidgetConsistency() { - // Since this method may bind a widget (which we can't do until boot completed) we - // may have to defer it until after boot complete. - if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) { - mCheckAppWidgetConsistencyOnBootCompleted = true; - return; - } - final int childCount = mAppWidgetContainer.getChildCount(); - boolean widgetPageExists = false; - for (int i = 0; i < childCount; i++) { - if (mAppWidgetContainer.isWidgetPage(i)) { - widgetPageExists = true; - break; - } - } - if (!widgetPageExists) { - final int insertPageIndex = getInsertPageIndex(); - - final boolean userAddedWidgetsEnabled = !widgetsDisabledByDpm(); - boolean addedDefaultAppWidget = false; - - if (!mSafeModeEnabled) { - if (userAddedWidgetsEnabled) { - int appWidgetId = allocateIdForDefaultAppWidget(); - if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { - addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true); - } - } else { - // note: even if widgetsDisabledByDpm() returns true, we still bind/create - // the default appwidget if possible - int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId(); - if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { - appWidgetId = allocateIdForDefaultAppWidget(); - if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { - mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId); - } - } - if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { - addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false); - if (!addedDefaultAppWidget) { - mAppWidgetHost.deleteAppWidgetId(appWidgetId); - mLockPatternUtils.writeFallbackAppWidgetId( - AppWidgetManager.INVALID_APPWIDGET_ID); - } - } - } - } - - // Use the built-in status/clock view if we can't inflate the default widget - if (!addedDefaultAppWidget) { - addDefaultStatusWidget(insertPageIndex); - } - - // trigger DB updates only if user-added widgets are enabled - if (!mSafeModeEnabled && userAddedWidgetsEnabled) { - mAppWidgetContainer.onAddView( - mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex); - } - } - } - - Runnable mSwitchPageRunnable = new Runnable() { - @Override - public void run() { - showAppropriateWidgetPage(); - } - }; - - static class SavedState extends BaseSavedState { - int transportState; - int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID; - - SavedState(Parcelable superState) { - super(superState); - } - - private SavedState(Parcel in) { - super(in); - this.transportState = in.readInt(); - this.appWidgetToShow = in.readInt(); - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(this.transportState); - out.writeInt(this.appWidgetToShow); - } - - public static final Parcelable.Creator<SavedState> CREATOR - = new Parcelable.Creator<SavedState>() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } - - @Override - public Parcelable onSaveInstanceState() { - if (DEBUG) Log.d(TAG, "onSaveInstanceState, tstate=" + mTransportState); - Parcelable superState = super.onSaveInstanceState(); - SavedState ss = new SavedState(superState); - // 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 (!(state instanceof SavedState)) { - super.onRestoreInstanceState(state); - return; - } - SavedState ss = (SavedState) state; - super.onRestoreInstanceState(ss.getSuperState()); - mTransportState = (ss.transportState); - mAppWidgetToShow = ss.appWidgetToShow; - if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState); - post(mSwitchPageRunnable); - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - super.onWindowFocusChanged(hasWindowFocus); - if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused")); - if (hasWindowFocus && mShowSecurityWhenReturn) { - SlidingChallengeLayout slider = - (SlidingChallengeLayout) findViewById(R.id.sliding_layout); - if (slider != null) { - slider.setHandleAlpha(1); - slider.showChallenge(true); - } - mShowSecurityWhenReturn = false; - } - } - - private void showAppropriateWidgetPage() { - 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)) { - return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i); - } - } - return null; - } - - boolean isMusicPage(int pageIndex) { - return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control); - } - - private int getAppropriateWidgetPage(int musicTransportState) { - // assumes at least one widget (besides camera + add) - if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) { - final int childCount = mAppWidgetContainer.getChildCount(); - for (int i = 0; i < childCount; i++) { - if (mAppWidgetContainer.getWidgetPageAt(i).getContentAppWidgetId() - == mAppWidgetToShow) { - return i; - } - } - mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID; - } - // if music playing, show transport - if (musicTransportState == TRANSPORT_VISIBLE) { - if (DEBUG) Log.d(TAG, "Music playing, show transport"); - return mAppWidgetContainer.getWidgetPageIndex(getOrCreateTransportControl()); - } - - // else show the right-most widget (except for camera) - int rightMost = mAppWidgetContainer.getChildCount() - 1; - if (mAppWidgetContainer.isCameraPage(rightMost)) { - rightMost--; - } - if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost); - return rightMost; - } - - private void enableUserSelectorIfNecessary() { - if (!UserManager.supportsMultipleUsers()) { - return; // device doesn't support multi-user mode - } - final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - if (um == null) { - Throwable t = new Throwable(); - t.fillInStackTrace(); - Log.e(TAG, "user service is null.", t); - return; - } - - // if there are multiple users, we need to enable to multi-user switcher - final List<UserInfo> users = um.getUsers(true); - if (users == null) { - Throwable t = new Throwable(); - t.fillInStackTrace(); - Log.e(TAG, "list of users is null.", t); - return; - } - - final View multiUserView = findViewById(R.id.keyguard_user_selector); - if (multiUserView == null) { - Throwable t = new Throwable(); - t.fillInStackTrace(); - Log.e(TAG, "can't find user_selector in layout.", t); - return; - } - - if (users.size() > 1) { - if (multiUserView instanceof KeyguardMultiUserSelectorView) { - mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView; - mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE); - mKeyguardMultiUserSelectorView.addUsers(users); - UserSwitcherCallback callback = new UserSwitcherCallback() { - @Override - public void hideSecurityView(int duration) { - mSecurityViewContainer.animate().alpha(0).setDuration(duration); - } - - @Override - public void showSecurityView() { - mSecurityViewContainer.setAlpha(1.0f); - } - - @Override - public void showUnlockHint() { - if (mKeyguardSelectorView != null) { - mKeyguardSelectorView.showUsabilityHint(); - } - } - - @Override - public void userActivity() { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.userActivity(); - } - } - }; - mKeyguardMultiUserSelectorView.setCallback(callback); - } else { - Throwable t = new Throwable(); - t.fillInStackTrace(); - if (multiUserView == null) { - Log.e(TAG, "could not find the user_selector.", t); - } else { - Log.e(TAG, "user_selector is the wrong type.", t); - } - } - } - } - - @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(); - } - } - - /** - * In general, we enable unlocking the insecure keyguard 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 static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; - private boolean shouldEnableMenuKey() { - final Resources res = getResources(); - final boolean configDisabled = res.getBoolean( - com.android.internal.R.bool.config_disableMenuKeyInLockScreen); - final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); - final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); - return !configDisabled || isTestHarness || fileOverride; - } - - public void goToUserSwitcher() { - mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector)); - } - - public void goToWidget(int appWidgetId) { - mAppWidgetToShow = appWidgetId; - mSwitchPageRunnable.run(); - } - - public boolean handleMenuKey() { - // The following enables the MENU key to work for testing automation - if (shouldEnableMenuKey()) { - showNextSecurityScreenOrFinish(false); - return true; - } - return false; - } - - 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; - } - return false; - } - - /** - * Dismisses the keyguard by going to the next screen or making it gone. - */ - public void dismiss() { - showNextSecurityScreenOrFinish(false); - } - - public void showAssistant() { - final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); - - if (intent == null) return; - - final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, - R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit, - getHandler(), null); - - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - mActivityLauncher.launchActivityWithAnimation( - intent, false, opts.toBundle(), null, null); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardLinearLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardLinearLayout.java deleted file mode 100644 index 0fc54cd..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardLinearLayout.java +++ /dev/null @@ -1,46 +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; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.LinearLayout; - -/** - * A layout that arranges its children into a special type of grid. - */ -public class KeyguardLinearLayout extends LinearLayout { - int mTopChild = 0; - - public KeyguardLinearLayout(Context context) { - this(context, null, 0); - } - - public KeyguardLinearLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardLinearLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public void setTopChild(View child) { - int top = indexOfChild(child); - mTopChild = top; - invalidate(); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java deleted file mode 100644 index 9b58803..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java +++ /dev/null @@ -1,321 +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; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -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; - - // is the bouncer up? - boolean mShowingBouncer = false; - - // last known plugged in state - boolean mCharging = false; - - // last known battery level - int mBatteryLevel = 100; - - KeyguardUpdateMonitor mUpdateMonitor; - - // Timeout before we reset the message to show charging/owner info - long mTimeout = SECURITY_MESSAGE_DURATION; - - // Shadowed text values - protected boolean mBatteryCharged; - protected boolean mBatteryIsLow; - - private Handler mHandler; - - CharSequence mMessage; - boolean mShowingMessage; - private CharSequence mSeparator; - private LockPatternUtils mLockPatternUtils; - - Runnable mClearMessageRunnable = new Runnable() { - @Override - public void run() { - mMessage = null; - mShowingMessage = false; - if (mShowingBouncer) { - hideMessage(FADE_DURATION, true); - } else { - update(); - } - } - }; - - public static class Helper implements SecurityMessageDisplay { - KeyguardMessageArea mMessageArea; - Helper(View v) { - mMessageArea = (KeyguardMessageArea) v.findViewById(R.id.keyguard_message_area); - if (mMessageArea == null) { - throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass()); - } - } - - public void setMessage(CharSequence msg, boolean important) { - if (!TextUtils.isEmpty(msg) && important) { - mMessageArea.mMessage = msg; - mMessageArea.securityMessageChanged(); - } - } - - public void setMessage(int resId, boolean important) { - if (resId != 0 && important) { - mMessageArea.mMessage = mMessageArea.getContext().getResources().getText(resId); - mMessageArea.securityMessageChanged(); - } - } - - public void setMessage(int resId, boolean important, Object... formatArgs) { - if (resId != 0 && important) { - mMessageArea.mMessage = mMessageArea.getContext().getString(resId, formatArgs); - mMessageArea.securityMessageChanged(); - } - } - - @Override - public void showBouncer(int duration) { - mMessageArea.hideMessage(duration, false); - mMessageArea.mShowingBouncer = true; - } - - @Override - public void hideBouncer(int duration) { - mMessageArea.showMessage(duration); - mMessageArea.mShowingBouncer = false; - } - - @Override - public void setTimeout(int timeoutMs) { - mMessageArea.mTimeout = timeoutMs; - } - } - - private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { - mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow(); - mCharging = status.status == BatteryManager.BATTERY_STATUS_CHARGING - || status.status == BatteryManager.BATTERY_STATUS_FULL; - mBatteryLevel = status.level; - mBatteryCharged = status.isCharged(); - mBatteryIsLow = status.isBatteryLow(); - update(); - } - }; - - public KeyguardMessageArea(Context context) { - this(context, null); - } - - public KeyguardMessageArea(Context context, AttributeSet attrs) { - super(context, attrs); - - mLockPatternUtils = new LockPatternUtils(context); - - // This is required to ensure marquee works - setSelected(true); - - // Registering this callback immediately updates the battery state, among other things. - mUpdateMonitor = KeyguardUpdateMonitor.getInstance(getContext()); - mUpdateMonitor.registerCallback(mInfoCallback); - mHandler = new Handler(Looper.myLooper()); - - mSeparator = getResources().getString(R.string.kg_text_message_separator); - - update(); - } - - public void securityMessageChanged() { - setAlpha(1f); - mShowingMessage = true; - update(); - mHandler.removeCallbacks(mClearMessageRunnable); - if (mTimeout > 0) { - mHandler.postDelayed(mClearMessageRunnable, mTimeout); - } - mHandler.removeCallbacksAndMessages(ANNOUNCE_TOKEN); - mHandler.postAtTime(new AnnounceRunnable(this, getText()), ANNOUNCE_TOKEN, - (SystemClock.uptimeMillis() + ANNOUNCEMENT_DELAY)); - } - - /** - * 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 update() { - MutableInt icon = new MutableInt(0); - CharSequence status = concat(getChargeInfo(icon), getOwnerInfo(), getCurrentMessage()); - setCompoundDrawablesWithIntrinsicBounds(icon.value, 0, 0, 0); - setText(status); - } - - private CharSequence concat(CharSequence... args) { - StringBuilder b = new StringBuilder(); - if (!TextUtils.isEmpty(args[0])) { - b.append(args[0]); - } - for (int i = 1; i < args.length; i++) { - CharSequence text = args[i]; - if (!TextUtils.isEmpty(text)) { - if (b.length() > 0) { - b.append(mSeparator); - } - b.append(text); - } - } - return b.toString(); - } - - CharSequence getCurrentMessage() { - return mShowingMessage ? mMessage : null; - } - - String getOwnerInfo() { - ContentResolver res = getContext().getContentResolver(); - String info = null; - final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(); - if (ownerInfoEnabled && !mShowingMessage) { - info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser()); - } - return info; - } - - private CharSequence getChargeInfo(MutableInt icon) { - CharSequence string = null; - if (mShowingBatteryInfo && !mShowingMessage) { - // Battery status - if (mCharging) { - // Charging, charged or waiting to charge. - string = getContext().getString(mBatteryCharged - ? com.android.internal.R.string.lockscreen_charged - : com.android.internal.R.string.lockscreen_plugged_in, mBatteryLevel); - icon.value = CHARGING_ICON; - } else if (mBatteryIsLow) { - // Battery is low - string = getContext().getString( - com.android.internal.R.string.lockscreen_low_battery); - icon.value = BATTERY_LOW_ICON; - } - } - return string; - } - - private void hideMessage(int duration, boolean thenUpdate) { - if (duration > 0) { - Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f); - anim.setDuration(duration); - if (thenUpdate) { - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - update(); - } - }); - } - anim.start(); - } else { - setAlpha(0f); - if (thenUpdate) { - update(); - } - } - } - - private void showMessage(int duration) { - if (duration > 0) { - Animator anim = ObjectAnimator.ofFloat(this, "alpha", 1f); - anim.setDuration(duration); - anim.start(); - } else { - 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 deleted file mode 100644 index 387e0ce..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java +++ /dev/null @@ -1,247 +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; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.pm.UserInfo; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.internal.R; - -class KeyguardMultiUserAvatar extends FrameLayout { - private static final String TAG = KeyguardMultiUserAvatar.class.getSimpleName(); - private static final boolean DEBUG = KeyguardHostView.DEBUG; - - private ImageView mUserImage; - private TextView mUserName; - private UserInfo mUserInfo; - private static final float ACTIVE_ALPHA = 1.0f; - private static final float INACTIVE_ALPHA = 1.0f; - private static final float ACTIVE_SCALE = 1.5f; - private static final float ACTIVE_TEXT_ALPHA = 0f; - private static final float INACTIVE_TEXT_ALPHA = 0.5f; - private static final int SWITCH_ANIMATION_DURATION = 150; - - private final float mActiveAlpha; - private final float mActiveScale; - private final float mActiveTextAlpha; - private final float mInactiveAlpha; - private final float mInactiveTextAlpha; - private final float mShadowRadius; - private final float mStroke; - private final float mIconSize; - private final int mFrameColor; - private final int mFrameShadowColor; - private final int mTextColor; - private final int mHighlightColor; - - private boolean mTouched; - - private boolean mActive; - 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) { - KeyguardMultiUserAvatar icon = (KeyguardMultiUserAvatar) - LayoutInflater.from(context).inflate(resId, userSelector, false); - - icon.init(info, userSelector); - return icon; - } - - public KeyguardMultiUserAvatar(Context context) { - this(context, null, 0); - } - - public KeyguardMultiUserAvatar(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - Resources res = mContext.getResources(); - mTextColor = res.getColor(R.color.keyguard_avatar_nick_color); - mIconSize = res.getDimension(R.dimen.keyguard_avatar_size); - mStroke = res.getDimension(R.dimen.keyguard_avatar_frame_stroke_width); - mShadowRadius = res.getDimension(R.dimen.keyguard_avatar_frame_shadow_radius); - mFrameColor = res.getColor(R.color.keyguard_avatar_frame_color); - mFrameShadowColor = res.getColor(R.color.keyguard_avatar_frame_shadow_color); - mHighlightColor = res.getColor(R.color.keyguard_avatar_frame_pressed_color); - mActiveTextAlpha = ACTIVE_TEXT_ALPHA; - mInactiveTextAlpha = INACTIVE_TEXT_ALPHA; - mActiveScale = ACTIVE_SCALE; - mActiveAlpha = ACTIVE_ALPHA; - mInactiveAlpha = INACTIVE_ALPHA; - - mTouched = false; - - setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - - protected String rewriteIconPath(String path) { - if (!this.getClass().getName().contains("internal")) { - return path.replace("system", "data"); - } - return path; - } - - public void init(UserInfo user, KeyguardMultiUserSelectorView userSelector) { - mUserInfo = user; - mUserSelector = userSelector; - - mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar); - mUserName = (TextView) findViewById(R.id.keyguard_user_name); - - 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); - } - - mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke, - mFrameShadowColor, mShadowRadius, mHighlightColor); - KeyguardViewMediator.getAvatarCache().put(user.id, mFramed); - } - - mFramed.reset(); - - mUserImage.setImageDrawable(mFramed); - mUserName.setText(mUserInfo.name); - setOnClickListener(mUserSelector); - mInit = false; - } - - public void setActive(boolean active, boolean animate, final Runnable onComplete) { - if (mActive != active || mInit) { - mActive = active; - - if (active) { - KeyguardLinearLayout parent = (KeyguardLinearLayout) getParent(); - parent.setTopChild(this); - // TODO: Create an appropriate asset when string changes are possible. - setContentDescription(mUserName.getText() - + ". " + mContext.getString(R.string.user_switched, "")); - } else { - setContentDescription(mUserName.getText()); - } - } - updateVisualsForActive(mActive, animate, SWITCH_ANIMATION_DURATION, onComplete); - } - - void updateVisualsForActive(boolean active, boolean animate, int duration, - final Runnable onComplete) { - final float finalAlpha = active ? mActiveAlpha : mInactiveAlpha; - final float initAlpha = active ? mInactiveAlpha : mActiveAlpha; - final float finalScale = active ? 1f : 1f / mActiveScale; - final float initScale = mFramed.getScale(); - final int finalTextAlpha = active ? (int) (mActiveTextAlpha * 255) : - (int) (mInactiveTextAlpha * 255); - final int initTextAlpha = active ? (int) (mInactiveTextAlpha * 255) : - (int) (mActiveTextAlpha * 255); - int textColor = mTextColor; - mUserName.setTextColor(textColor); - - if (animate && mTouched) { - ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); - va.addUpdateListener(new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float r = animation.getAnimatedFraction(); - float scale = (1 - r) * initScale + r * finalScale; - float alpha = (1 - r) * initAlpha + r * finalAlpha; - int textAlpha = (int) ((1 - r) * initTextAlpha + r * finalTextAlpha); - mFramed.setScale(scale); - mUserImage.setAlpha(alpha); - mUserName.setTextColor(Color.argb(textAlpha, 255, 255, 255)); - mUserImage.invalidate(); - } - }); - va.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onComplete != null) { - onComplete.run(); - } - } - }); - va.setDuration(duration); - va.start(); - } else { - mFramed.setScale(finalScale); - mUserImage.setAlpha(finalAlpha); - mUserName.setTextColor(Color.argb(finalTextAlpha, 255, 255, 255)); - if (onComplete != null) { - post(onComplete); - } - } - - mTouched = true; - } - - @Override - public void setPressed(boolean pressed) { - 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 deleted file mode 100644 index f9ea5bb..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java +++ /dev/null @@ -1,172 +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; - -import android.app.ActivityManagerNative; -import android.content.Context; -import android.content.pm.UserInfo; -import android.os.RemoteException; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import com.android.internal.R; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; - -public class KeyguardMultiUserSelectorView extends FrameLayout implements View.OnClickListener { - private static final String TAG = "KeyguardMultiUserSelectorView"; - - private ViewGroup mUsersGrid; - private KeyguardMultiUserAvatar mActiveUserAvatar; - private KeyguardHostView.UserSwitcherCallback mCallback; - private static final int FADE_OUT_ANIMATION_DURATION = 100; - - public KeyguardMultiUserSelectorView(Context context) { - this(context, null, 0); - } - - public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - protected void onFinishInflate () { - mUsersGrid = (ViewGroup) findViewById(R.id.keyguard_users_grid); - mUsersGrid.removeAllViews(); - setClipChildren(false); - setClipToPadding(false); - - } - - public void setCallback(KeyguardHostView.UserSwitcherCallback callback) { - mCallback = callback; - } - - public void addUsers(Collection<UserInfo> userList) { - UserInfo activeUser; - try { - activeUser = ActivityManagerNative.getDefault().getCurrentUser(); - } catch (RemoteException re) { - activeUser = null; - } - - ArrayList<UserInfo> users = new ArrayList<UserInfo>(userList); - Collections.sort(users, mOrderAddedComparator); - - for (UserInfo user: users) { - KeyguardMultiUserAvatar uv = createAndAddUser(user); - if (user.id == activeUser.id) { - mActiveUserAvatar = uv; - } - 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) { - return (lhs.serialNumber - rhs.serialNumber); - } - }; - - private KeyguardMultiUserAvatar createAndAddUser(UserInfo user) { - KeyguardMultiUserAvatar uv = KeyguardMultiUserAvatar.fromXml( - R.layout.keyguard_multi_user_avatar, mContext, this, user); - mUsersGrid.addView(uv); - return uv; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - if(event.getActionMasked() != MotionEvent.ACTION_CANCEL && mCallback != null) { - mCallback.userActivity(); - } - return false; - } - - private void setAllClickable(boolean clickable) - { - for(int i = 0; i < mUsersGrid.getChildCount(); i++) { - View v = mUsersGrid.getChildAt(i); - v.setClickable(clickable); - v.setPressed(false); - } - } - - @Override - public void onClick(View v) { - if (!(v instanceof KeyguardMultiUserAvatar)) return; - final KeyguardMultiUserAvatar avatar = (KeyguardMultiUserAvatar) v; - if (avatar.isClickable()) { // catch race conditions - if (mActiveUserAvatar == avatar) { - // If they click the currently active user, show the unlock hint - mCallback.showUnlockHint(); - return; - } else { - // 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; - 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/KeyguardPINView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java deleted file mode 100644 index fa80352..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java +++ /dev/null @@ -1,120 +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; - -import android.content.Context; -import android.text.Editable; -import android.text.InputType; -import android.text.TextWatcher; -import android.text.method.DigitsKeyListener; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView.OnEditorActionListener; - -import com.android.internal.R; - -/** - * Displays a PIN pad for unlocking. - */ -public class KeyguardPINView extends KeyguardAbsKeyInputView - implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { - - public KeyguardPINView(Context context) { - this(context, null); - } - - public KeyguardPINView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - protected void resetState() { - if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) { - mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true); - } else { - mSecurityMessageDisplay.setMessage(R.string.kg_pin_instructions, false); - } - mPasswordEntry.setEnabled(true); - } - - @Override - protected int getPasswordTextViewId() { - return R.id.pinEntry; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - final View ok = findViewById(R.id.key_enter); - if (ok != null) { - ok.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - doHapticKeyClick(); - if (mPasswordEntry.isEnabled()) { - verifyPasswordAndUnlock(); - } - } - }); - ok.setOnHoverListener(new LiftToActivateListener(getContext())); - } - - // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts, - // not a separate view - View pinDelete = findViewById(R.id.delete_button); - if (pinDelete != null) { - pinDelete.setVisibility(View.VISIBLE); - pinDelete.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - // check for time-based lockouts - if (mPasswordEntry.isEnabled()) { - CharSequence str = mPasswordEntry.getText(); - if (str.length() > 0) { - mPasswordEntry.setText(str.subSequence(0, str.length()-1)); - } - } - doHapticKeyClick(); - } - }); - pinDelete.setOnLongClickListener(new View.OnLongClickListener() { - public boolean onLongClick(View v) { - // check for time-based lockouts - if (mPasswordEntry.isEnabled()) { - mPasswordEntry.setText(""); - } - doHapticKeyClick(); - return true; - } - }); - } - - mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); - mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER - | InputType.TYPE_NUMBER_VARIATION_PASSWORD); - - mPasswordEntry.requestFocus(); - } - - @Override - public void showUsabilityHint() { - } - - @Override - public int getWrongPasswordStringId() { - return R.string.kg_wrong_pin; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java deleted file mode 100644 index d52c993..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java +++ /dev/null @@ -1,208 +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; - -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.content.res.Configuration; -import android.text.Editable; -import android.text.InputType; -import android.text.TextWatcher; -import android.text.method.DigitsKeyListener; -import android.text.method.TextKeyListener; -import android.util.AttributeSet; -import android.view.View; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; -import android.widget.TextView.OnEditorActionListener; - -import com.android.internal.R; -import com.android.internal.widget.PasswordEntryKeyboardHelper; -import com.android.internal.widget.PasswordEntryKeyboardView; - -import java.util.List; -/** - * Displays an alphanumeric (latin-1) key entry for the user to enter - * an unlock password - */ - -public class KeyguardPasswordView extends KeyguardAbsKeyInputView - implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { - - private final boolean mShowImeAtScreenOn; - - InputMethodManager mImm; - - public KeyguardPasswordView(Context context) { - this(context, null); - } - - public KeyguardPasswordView(Context context, AttributeSet attrs) { - super(context, attrs); - mShowImeAtScreenOn = context.getResources(). - getBoolean(R.bool.kg_show_ime_at_screen_on); - } - - protected void resetState() { - mSecurityMessageDisplay.setMessage(R.string.kg_password_instructions, false); - mPasswordEntry.setEnabled(true); - } - - @Override - protected int getPasswordTextViewId() { - return R.id.passwordEntry; - } - - @Override - public boolean needsInput() { - return true; - } - - @Override - public void onResume(int reason) { - super.onResume(reason); - mPasswordEntry.requestFocus(); - if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) { - mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); - } - } - - @Override - public void onPause() { - super.onPause(); - mImm.hideSoftInputFromWindow(getWindowToken(), 0); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - boolean imeOrDeleteButtonVisible = false; - - mImm = (InputMethodManager) getContext().getSystemService( - Context.INPUT_METHOD_SERVICE); - - mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); - mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT - | InputType.TYPE_TEXT_VARIATION_PASSWORD); - - // Poke the wakelock any time the text is selected or modified - mPasswordEntry.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.userActivity(0); // TODO: customize timeout for text? - } - }); - - 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 (mCallback != null) { - mCallback.userActivity(0); - } - } - }); - - mPasswordEntry.requestFocus(); - - // If there's more than one IME, enable the IME switcher button - View switchImeButton = findViewById(R.id.switch_ime_button); - if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(mImm, false)) { - switchImeButton.setVisibility(View.VISIBLE); - imeOrDeleteButtonVisible = true; - switchImeButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.userActivity(0); // Leave the screen on a bit longer - mImm.showInputMethodPicker(); - } - }); - } - - // If no icon is visible, reset the start margin on the password field so the text is - // still centered. - if (!imeOrDeleteButtonVisible) { - android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams(); - if (params instanceof MarginLayoutParams) { - final MarginLayoutParams mlp = (MarginLayoutParams) params; - mlp.setMarginStart(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 - public void showUsabilityHint() { - } - - @Override - public int getWrongPasswordStringId() { - return R.string.kg_wrong_password; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java deleted file mode 100644 index e114b78..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java +++ /dev/null @@ -1,412 +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; - -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.content.Context; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.CountDownTimer; -import android.os.SystemClock; -import android.os.UserHandle; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; - -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.LockPatternView; -import com.android.internal.R; - -import java.io.IOException; -import java.util.List; - -public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView { - - private static final String TAG = "SecurityPatternView"; - private static final boolean DEBUG = false; - - // 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 LockPatternView mLockPatternView; - private Button mForgotPatternButton; - private KeyguardSecurityCallback mCallback; - private boolean mEnableFallback; - - /** - * Keeps track of the last time we poked the wake lock during dispatching of the touch event. - * Initialized to something guaranteed to make us poke the wakelock 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 Rect mTempRect = new Rect(); - private SecurityMessageDisplay mSecurityMessageDisplay; - private View mEcaView; - private Drawable mBouncerFrame; - - enum FooterMode { - Normal, - ForgotLockPattern, - VerifyUnlocked - } - - public KeyguardPatternView(Context context) { - this(context, null); - } - - public KeyguardPatternView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mCallback = callback; - } - - public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mLockPatternUtils = mLockPatternUtils == null - ? new LockPatternUtils(mContext) : mLockPatternUtils; - - mLockPatternView = (LockPatternView) findViewById(R.id.lockPatternView); - 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()); - - mForgotPatternButton = (Button) findViewById(R.id.forgot_password_button); - // note: some configurations don't have an emergency call area - if (mForgotPatternButton != null) { - mForgotPatternButton.setText(R.string.kg_forgot_pattern_button_text); - mForgotPatternButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.showBackupSecurity(); - } - }); - } - - setFocusableInTouchMode(true); - - maybeEnableFallback(mContext); - mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); - mEcaView = findViewById(R.id.keyguard_selector_fade_container); - View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame); - if (bouncerFrameView != null) { - mBouncerFrame = bouncerFrameView.getBackground(); - } - } - - private void updateFooter(FooterMode mode) { - if (mForgotPatternButton == null) return; // no ECA? no footer - - switch (mode) { - case Normal: - if (DEBUG) Log.d(TAG, "mode normal"); - mForgotPatternButton.setVisibility(View.GONE); - break; - case ForgotLockPattern: - if (DEBUG) Log.d(TAG, "mode ForgotLockPattern"); - mForgotPatternButton.setVisibility(View.VISIBLE); - break; - case VerifyUnlocked: - if (DEBUG) Log.d(TAG, "mode VerifyUnlocked"); - mForgotPatternButton.setVisibility(View.GONE); - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - boolean result = super.onTouchEvent(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 long elapsed = SystemClock.elapsedRealtime() - mLastPokeTime; - if (result && (elapsed > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) { - mLastPokeTime = SystemClock.elapsedRealtime(); - } - mTempRect.set(0, 0, 0, 0); - offsetRectIntoDescendantCoords(mLockPatternView, mTempRect); - ev.offsetLocation(mTempRect.left, mTempRect.top); - result = mLockPatternView.dispatchTouchEvent(ev) || result; - ev.offsetLocation(-mTempRect.left, -mTempRect.top); - return result; - } - - public void reset() { - // reset lock pattern - mLockPatternView.enableInput(); - mLockPatternView.setEnabled(true); - mLockPatternView.clearPattern(); - - // if the user is currently locked out, enforce it. - long deadline = mLockPatternUtils.getLockoutAttemptDeadline(); - if (deadline != 0) { - handleAttemptLockout(deadline); - } else { - displayDefaultSecurityMessage(); - } - - // 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); - } - - } - - private void displayDefaultSecurityMessage() { - if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) { - mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true); - } else { - mSecurityMessageDisplay.setMessage(R.string.kg_pattern_instructions, false); - } - } - - @Override - public void showUsabilityHint() { - } - - /** TODO: hook this up */ - public void cleanUp() { - if (DEBUG) Log.v(TAG, "Cleanup() called on " + this); - mLockPatternUtils = 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 - reset(); - } - } - - private class UnlockPatternListener implements LockPatternView.OnPatternListener { - - public void onPatternStart() { - mLockPatternView.removeCallbacks(mCancelPatternRunnable); - } - - public void onPatternCleared() { - } - - public void onPatternCellAdded(List<LockPatternView.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.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS); - } else { - // Give just a little extra time if they hit one of the first few dots - mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS); - } - } - - public void onPatternDetected(List<LockPatternView.Cell> pattern) { - if (mLockPatternUtils.checkPattern(pattern)) { - mCallback.reportSuccessfulUnlockAttempt(); - mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct); - mTotalFailedPatternAttempts = 0; - mCallback.dismiss(true); - } else { - if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { - mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS); - } - mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); - if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { - mTotalFailedPatternAttempts++; - mFailedPatternAttemptsSinceLastTimeout++; - mCallback.reportFailedUnlockAttempt(); - } - if (mFailedPatternAttemptsSinceLastTimeout - >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { - long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); - handleAttemptLockout(deadline); - } else { - mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true); - mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS); - } - } - } - } - - 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(); - } - - 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.getAccountsByTypeAsUser("com.google", - new UserHandle(mLockPatternUtils.getCurrentUser())); - } - - 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) { - return; - } - - // lookup the confirmCredentials intent for the current account - mAccountManager.confirmCredentialsAsUser(mAccounts[mAccountIndex], null, null, this, - null, new UserHandle(mLockPatternUtils.getCurrentUser())); - } - - 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 handleAttemptLockout(long elapsedRealtimeDeadline) { - mLockPatternView.clearPattern(); - mLockPatternView.setEnabled(false); - final long elapsedRealtime = SystemClock.elapsedRealtime(); - if (mEnableFallback) { - updateFooter(FooterMode.ForgotLockPattern); - } - - mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { - - @Override - public void onTick(long millisUntilFinished) { - final int secondsRemaining = (int) (millisUntilFinished / 1000); - mSecurityMessageDisplay.setMessage( - R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining); - } - - @Override - public void onFinish() { - mLockPatternView.setEnabled(true); - displayDefaultSecurityMessage(); - // TODO mUnlockIcon.setVisibility(View.VISIBLE); - mFailedPatternAttemptsSinceLastTimeout = 0; - if (mEnableFallback) { - updateFooter(FooterMode.ForgotLockPattern); - } else { - updateFooter(FooterMode.Normal); - } - } - - }.start(); - } - - @Override - public boolean needsInput() { - return false; - } - - @Override - public void onPause() { - if (mCountdownTimer != null) { - mCountdownTimer.cancel(); - mCountdownTimer = null; - } - } - - @Override - public void onResume(int reason) { - reset(); - } - - @Override - public KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - public void showBouncer(int duration) { - KeyguardSecurityViewHelper. - showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); - } - - @Override - public void hideBouncer(int duration) { - KeyguardSecurityViewHelper. - hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityCallback.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityCallback.java deleted file mode 100644 index 7e6c108..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityCallback.java +++ /dev/null @@ -1,68 +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; - -import com.android.internal.policy.impl.keyguard.KeyguardHostView.OnDismissAction; - -public interface KeyguardSecurityCallback { - - /** - * Dismiss the given security screen. - * @param securityVerified true if the user correctly entered credentials for the given screen. - */ - void dismiss(boolean securityVerified); - - /** - * Manually report user activity to keep the device awake. If timeout is 0, - * uses user-defined timeout. - * @param timeout - */ - void userActivity(long timeout); - - /** - * Checks if keyguard is in "verify credentials" mode. - * @return true if user has been asked to verify security. - */ - boolean isVerifyUnlockOnly(); - - /** - * Call when user correctly enters their credentials - */ - void reportSuccessfulUnlockAttempt(); - - /** - * Call when the user incorrectly enters their credentials - */ - void reportFailedUnlockAttempt(); - - /** - * Gets the number of attempts thus far as reported by {@link #reportFailedUnlockAttempt()} - * @return number of failed attempts - */ - int getFailedAttempts(); - - /** - * Shows the backup security for the current method. If none available, this call is a no-op. - */ - void showBackupSecurity(); - - /** - * Sets an action to perform after the user successfully enters their credentials. - * @param action - */ - void setOnDismissAction(OnDismissAction action); - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java deleted file mode 100644 index 375a96a..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.android.internal.policy.impl.keyguard; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; - -import com.android.internal.R; - -public class KeyguardSecurityContainer extends FrameLayout { - public KeyguardSecurityContainer(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardSecurityContainer(Context context) { - this(null, null, 0); - } - - public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - KeyguardSecurityViewFlipper getFlipper() { - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - if (child instanceof KeyguardSecurityViewFlipper) { - return (KeyguardSecurityViewFlipper) child; - } - } - return null; - } - - public void showBouncer(int duration) { - KeyguardSecurityViewFlipper flipper = getFlipper(); - if (flipper != null) { - flipper.showBouncer(duration); - } - } - - public void hideBouncer(int duration) { - KeyguardSecurityViewFlipper flipper = getFlipper(); - if (flipper != null) { - flipper.hideBouncer(duration); - } - } -} - diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java deleted file mode 100644 index 7a69586..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java +++ /dev/null @@ -1,147 +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; - -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.telephony.TelephonyManager; - -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.widget.LockPatternUtils; - -public class KeyguardSecurityModel { - /** - * The different types of security available for {@link Mode#UnlockScreen}. - * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() - */ - enum SecurityMode { - Invalid, // NULL state - None, // No security enabled - Pattern, // Unlock by drawing a pattern. - Password, // Unlock by entering an alphanumeric password - PIN, // Strictly numeric password - Biometric, // Unlock with a biometric key (e.g. finger print or face unlock) - Account, // Unlock by entering an account's login and password. - SimPin, // Unlock by entering a sim pin. - SimPuk // Unlock by entering a sim puk - } - - private Context mContext; - private LockPatternUtils mLockPatternUtils; - - KeyguardSecurityModel(Context context) { - mContext = context; - mLockPatternUtils = new LockPatternUtils(context); - } - - void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - } - - /** - * Returns true if biometric unlock is installed and selected. If this returns false there is - * no need to even construct the biometric unlock. - */ - boolean isBiometricUnlockEnabled() { - return mLockPatternUtils.usingBiometricWeak() - && mLockPatternUtils.isBiometricWeakInstalled(); - } - - /** - * Returns true if a condition is currently suppressing the biometric unlock. If this returns - * true there is no need to even construct the biometric unlock. - */ - private boolean isBiometricUnlockSuppressed() { - KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); - final boolean backupIsTimedOut = monitor.getFailedUnlockAttempts() >= - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; - return monitor.getMaxBiometricUnlockAttemptsReached() || backupIsTimedOut - || !monitor.isAlternateUnlockEnabled() - || monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE; - } - - SecurityMode getSecurityMode() { - KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); - final IccCardConstants.State simState = updateMonitor.getSimState(); - SecurityMode mode = SecurityMode.None; - if (simState == IccCardConstants.State.PIN_REQUIRED) { - mode = SecurityMode.SimPin; - } else if (simState == IccCardConstants.State.PUK_REQUIRED - && mLockPatternUtils.isPukUnlockScreenEnable()) { - mode = SecurityMode.SimPuk; - } else { - final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality(); - switch (security) { - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: - mode = mLockPatternUtils.isLockPasswordEnabled() ? - SecurityMode.PIN : SecurityMode.None; - break; - case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: - case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: - mode = mLockPatternUtils.isLockPasswordEnabled() ? - SecurityMode.Password : SecurityMode.None; - break; - - case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: - case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: - if (mLockPatternUtils.isLockPatternEnabled()) { - mode = mLockPatternUtils.isPermanentlyLocked() ? - SecurityMode.Account : SecurityMode.Pattern; - } - break; - - default: - throw new IllegalStateException("Unknown unlock mode:" + mode); - } - } - return mode; - } - - /** - * Some unlock methods can have an alternate, such as biometric unlocks (e.g. face unlock). - * This function decides if an alternate unlock is available and returns it. Otherwise, - * returns @param mode. - * - * @param mode the mode we want the alternate for - * @return alternate or the given mode - */ - SecurityMode getAlternateFor(SecurityMode mode) { - if (isBiometricUnlockEnabled() && !isBiometricUnlockSuppressed() - && (mode == SecurityMode.Password - || mode == SecurityMode.PIN - || mode == SecurityMode.Pattern)) { - return SecurityMode.Biometric; - } - return mode; // no alternate, return what was given - } - - /** - * Some unlock methods can have a backup which gives the user another way to get into - * the device. This is currently only supported for Biometric and Pattern unlock. - * - * @return backup method or current security mode - */ - SecurityMode getBackupSecurityMode(SecurityMode mode) { - switch(mode) { - case Biometric: - return getSecurityMode(); - case Pattern: - return SecurityMode.Account; - } - return mode; // no backup, return current security mode - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityView.java deleted file mode 100644 index a3ac39c..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityView.java +++ /dev/null @@ -1,87 +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; - -import com.android.internal.widget.LockPatternUtils; - -public interface KeyguardSecurityView { - static public final int SCREEN_ON = 1; - static public final int VIEW_REVEALED = 2; - - /** - * Interface back to keyguard to tell it when security - * @param callback - */ - void setKeyguardCallback(KeyguardSecurityCallback callback); - - /** - * Set {@link LockPatternUtils} object. Useful for providing a mock interface. - * @param utils - */ - void setLockPatternUtils(LockPatternUtils utils); - - /** - * Reset the view and prepare to take input. This should do things like clearing the - * password or pattern and clear error messages. - */ - void reset(); - - /** - * Emulate activity life cycle within the view. When called, the view should clean up - * and prepare to be removed. - */ - void onPause(); - - /** - * Emulate activity life cycle within this view. When called, the view should prepare itself - * to be shown. - * @param reason the root cause of the event. - */ - void onResume(int reason); - - /** - * Inquire whether this view requires IME (keyboard) interaction. - * - * @return true if IME interaction is required. - */ - boolean needsInput(); - - /** - * Get {@link KeyguardSecurityCallback} for the given object - * @return KeyguardSecurityCallback - */ - KeyguardSecurityCallback getCallback(); - - /** - * Instruct the view to show usability hints, if any. - * - */ - void showUsabilityHint(); - - /** - * Place the security view into bouncer mode. - * Animate transisiton if duration is non-zero. - * @param duration millisends for the transisiton animation. - */ - void showBouncer(int duration); - - /** - * Place the security view into non-bouncer mode. - * Animate transisiton if duration is non-zero. - * @param duration millisends for the transisiton animation. - */ - void hideBouncer(int duration); -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java deleted file mode 100644 index aa31b00..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java +++ /dev/null @@ -1,279 +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; - -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewDebug; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ViewFlipper; - -/** - * Subclass of the current view flipper that allows us to overload dispatchTouchEvent() so - * we can emulate {@link WindowManager.LayoutParams#FLAG_SLIPPERY} within a view hierarchy. - * - */ -public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView { - private static final String TAG = "KeyguardSecurityViewFlipper"; - private static final boolean DEBUG = false; - - private Rect mTempRect = new Rect(); - - public KeyguardSecurityViewFlipper(Context context) { - this(context, null); - } - - public KeyguardSecurityViewFlipper(Context context, AttributeSet attr) { - super(context, attr); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - boolean result = super.onTouchEvent(ev); - mTempRect.set(0, 0, 0, 0); - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - if (child.getVisibility() == View.VISIBLE) { - offsetRectIntoDescendantCoords(child, mTempRect); - ev.offsetLocation(mTempRect.left, mTempRect.top); - result = child.dispatchTouchEvent(ev) || result; - ev.offsetLocation(-mTempRect.left, -mTempRect.top); - } - } - return result; - } - - KeyguardSecurityView getSecurityView() { - View child = getChildAt(getDisplayedChild()); - if (child instanceof KeyguardSecurityView) { - return (KeyguardSecurityView) child; - } - return null; - } - - @Override - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.setKeyguardCallback(callback); - } - } - - @Override - public void setLockPatternUtils(LockPatternUtils utils) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.setLockPatternUtils(utils); - } - } - - @Override - public void reset() { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.reset(); - } - } - - @Override - public void onPause() { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.onPause(); - } - } - - @Override - public void onResume(int reason) { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.onResume(reason); - } - } - - @Override - public boolean needsInput() { - KeyguardSecurityView ksv = getSecurityView(); - return (ksv != null) ? ksv.needsInput() : false; - } - - @Override - public KeyguardSecurityCallback getCallback() { - KeyguardSecurityView ksv = getSecurityView(); - return (ksv != null) ? ksv.getCallback() : null; - } - - @Override - public void showUsabilityHint() { - KeyguardSecurityView ksv = getSecurityView(); - if (ksv != null) { - ksv.showUsabilityHint(); - } - } - - @Override - public void showBouncer(int duration) { - KeyguardSecurityView active = getSecurityView(); - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - if (child instanceof KeyguardSecurityView) { - KeyguardSecurityView ksv = (KeyguardSecurityView) child; - ksv.showBouncer(ksv == active ? duration : 0); - } - } - } - - @Override - public void hideBouncer(int duration) { - KeyguardSecurityView active = getSecurityView(); - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - if (child instanceof KeyguardSecurityView) { - KeyguardSecurityView ksv = (KeyguardSecurityView) child; - ksv.hideBouncer(ksv == active ? duration : 0); - } - } - } - - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams; - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : new LayoutParams(p); - } - - @Override - public LayoutParams generateLayoutParams(AttributeSet attrs) { - return new LayoutParams(getContext(), attrs); - } - - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - final int widthMode = MeasureSpec.getMode(widthSpec); - final int heightMode = MeasureSpec.getMode(heightSpec); - if (DEBUG && widthMode != MeasureSpec.AT_MOST) { - Log.w(TAG, "onMeasure: widthSpec " + MeasureSpec.toString(widthSpec) + - " should be AT_MOST"); - } - if (DEBUG && heightMode != MeasureSpec.AT_MOST) { - Log.w(TAG, "onMeasure: heightSpec " + MeasureSpec.toString(heightSpec) + - " should be AT_MOST"); - } - - final int widthSize = MeasureSpec.getSize(widthSpec); - final int heightSize = MeasureSpec.getSize(heightSpec); - int maxWidth = widthSize; - int maxHeight = heightSize; - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - if (lp.maxWidth > 0 && lp.maxWidth < maxWidth) { - maxWidth = lp.maxWidth; - } - if (lp.maxHeight > 0 && lp.maxHeight < maxHeight) { - maxHeight = lp.maxHeight; - } - } - - final int wPadding = getPaddingLeft() + getPaddingRight(); - final int hPadding = getPaddingTop() + getPaddingBottom(); - maxWidth -= wPadding; - maxHeight -= hPadding; - - int width = widthMode == MeasureSpec.EXACTLY ? widthSize : 0; - int height = heightMode == MeasureSpec.EXACTLY ? heightSize : 0; - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - final int childWidthSpec = makeChildMeasureSpec(maxWidth, lp.width); - final int childHeightSpec = makeChildMeasureSpec(maxHeight, lp.height); - - child.measure(childWidthSpec, childHeightSpec); - - width = Math.max(width, Math.min(child.getMeasuredWidth(), widthSize - wPadding)); - height = Math.max(height, Math.min(child.getMeasuredHeight(), heightSize - hPadding)); - } - setMeasuredDimension(width + wPadding, height + hPadding); - } - - private int makeChildMeasureSpec(int maxSize, int childDimen) { - final int mode; - final int size; - switch (childDimen) { - case LayoutParams.WRAP_CONTENT: - mode = MeasureSpec.AT_MOST; - size = maxSize; - break; - case LayoutParams.MATCH_PARENT: - mode = MeasureSpec.EXACTLY; - size = maxSize; - break; - default: - mode = MeasureSpec.EXACTLY; - size = Math.min(maxSize, childDimen); - break; - } - return MeasureSpec.makeMeasureSpec(size, mode); - } - - public static class LayoutParams extends FrameLayout.LayoutParams { - @ViewDebug.ExportedProperty(category = "layout") - public int maxWidth; - - @ViewDebug.ExportedProperty(category = "layout") - public int maxHeight; - - public LayoutParams(ViewGroup.LayoutParams other) { - super(other); - } - - public LayoutParams(LayoutParams other) { - super(other); - - maxWidth = other.maxWidth; - maxHeight = other.maxHeight; - } - - public LayoutParams(Context c, AttributeSet attrs) { - super(c, attrs); - - final TypedArray a = c.obtainStyledAttributes(attrs, - R.styleable.KeyguardSecurityViewFlipper_Layout, 0, 0); - maxWidth = a.getDimensionPixelSize( - R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxWidth, 0); - maxHeight = a.getDimensionPixelSize( - R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxHeight, 0); - a.recycle(); - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewHelper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewHelper.java deleted file mode 100644 index 3d59f8d..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewHelper.java +++ /dev/null @@ -1,94 +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; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.graphics.drawable.Drawable; -import android.view.View; - -/** - * Some common functions that are useful for KeyguardSecurityViews. - */ -public class KeyguardSecurityViewHelper { - - public static void showBouncer(SecurityMessageDisplay securityMessageDisplay, - final View ecaView, Drawable bouncerFrame, int duration) { - if (securityMessageDisplay != null) { - securityMessageDisplay.showBouncer(duration); - } - if (ecaView != null) { - if (duration > 0) { - Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 0f); - anim.setDuration(duration); - anim.addListener(new AnimatorListenerAdapter() { - private boolean mCanceled; - @Override - public void onAnimationCancel(Animator animation) { - // Fail safe and show the emergency button in onAnimationEnd() - mCanceled = true; - ecaView.setAlpha(1f); - } - @Override - public void onAnimationEnd(Animator animation) { - ecaView.setVisibility(mCanceled ? View.VISIBLE : View.INVISIBLE); - } - }); - anim.start(); - } else { - ecaView.setAlpha(0f); - ecaView.setVisibility(View.INVISIBLE); - } - } - if (bouncerFrame != null) { - if (duration > 0) { - Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 0, 255); - anim.setDuration(duration); - anim.start(); - } else { - bouncerFrame.setAlpha(255); - } - } - } - - public static void hideBouncer(SecurityMessageDisplay securityMessageDisplay, - View ecaView, Drawable bouncerFrame, int duration) { - if (securityMessageDisplay != null) { - securityMessageDisplay.hideBouncer(duration); - } - if (ecaView != null) { - ecaView.setVisibility(View.VISIBLE); - if (duration > 0) { - Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 1f); - anim.setDuration(duration); - anim.start(); - } else { - ecaView.setAlpha(1f); - } - } - if (bouncerFrame != null) { - if (duration > 0) { - Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 255, 0); - anim.setDuration(duration); - anim.start(); - } else { - bouncerFrame.setAlpha(0); - } - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java deleted file mode 100644 index 6859042..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java +++ /dev/null @@ -1,288 +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; - -import android.animation.ObjectAnimator; -import android.app.SearchManager; -import android.app.admin.DevicePolicyManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.os.UserHandle; -import android.provider.Settings; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; -import android.view.View; -import android.widget.LinearLayout; - -import com.android.internal.telephony.IccCardConstants.State; -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.multiwaveview.GlowPadView; -import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener; -import com.android.internal.R; - -public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView { - private static final boolean DEBUG = KeyguardHostView.DEBUG; - private static final String TAG = "SecuritySelectorView"; - private static final String ASSIST_ICON_METADATA_NAME = - "com.android.systemui.action_assist_icon"; - - private KeyguardSecurityCallback mCallback; - private GlowPadView mGlowPadView; - private ObjectAnimator mAnim; - private View mFadeView; - private boolean mIsBouncing; - private boolean mCameraDisabled; - private boolean mSearchDisabled; - private LockPatternUtils mLockPatternUtils; - private SecurityMessageDisplay mSecurityMessageDisplay; - private Drawable mBouncerFrame; - - OnTriggerListener mOnTriggerListener = new OnTriggerListener() { - - 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, true, UserHandle.USER_CURRENT); - if (assistIntent != null) { - mActivityLauncher.launchActivity(assistIntent, false, true, null, null); - } else { - Log.w(TAG, "Failed to get intent for assist activity"); - } - mCallback.userActivity(0); - break; - - case com.android.internal.R.drawable.ic_lockscreen_camera: - mActivityLauncher.launchCamera(null, null); - mCallback.userActivity(0); - break; - - case com.android.internal.R.drawable.ic_lockscreen_unlock_phantom: - case com.android.internal.R.drawable.ic_lockscreen_unlock: - mCallback.userActivity(0); - mCallback.dismiss(false); - break; - } - } - - public void onReleased(View v, int handle) { - if (!mIsBouncing) { - doTransition(mFadeView, 1.0f); - } - } - - public void onGrabbed(View v, int handle) { - mCallback.userActivity(0); - doTransition(mFadeView, 0.0f); - } - - public void onGrabbedStateChange(View v, int handle) { - - } - - public void onFinishFinalAnimation() { - - } - - }; - - KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onDevicePolicyManagerStateChanged() { - updateTargets(); - } - - @Override - public void onSimStateChanged(State simState) { - updateTargets(); - } - }; - - private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { - - @Override - KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - LockPatternUtils getLockPatternUtils() { - return mLockPatternUtils; - } - - @Override - Context getContext() { - return mContext; - }}; - - public KeyguardSelectorView(Context context) { - this(context, null); - } - - public KeyguardSelectorView(Context context, AttributeSet attrs) { - super(context, attrs); - mLockPatternUtils = new LockPatternUtils(getContext()); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view); - mGlowPadView.setOnTriggerListener(mOnTriggerListener); - updateTargets(); - - mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); - View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame); - mBouncerFrame = bouncerFrameView.getBackground(); - } - - public void setCarrierArea(View carrierArea) { - mFadeView = carrierArea; - } - - public boolean isTargetPresent(int resId) { - return mGlowPadView.getTargetPosition(resId) != -1; - } - - @Override - public void showUsabilityHint() { - mGlowPadView.ping(); - } - - private void updateTargets() { - int currentUserHandle = mLockPatternUtils.getCurrentUser(); - DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager(); - int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUserHandle); - boolean secureCameraDisabled = mLockPatternUtils.isSecure() - && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0; - boolean cameraDisabledByAdmin = dpm.getCameraDisabled(null, currentUserHandle) - || secureCameraDisabled; - final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext()); - boolean disabledBySimState = monitor.isSimLocked(); - boolean cameraTargetPresent = - isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_camera); - boolean searchTargetPresent = - isTargetPresent(com.android.internal.R.drawable.ic_action_assist_generic); - - if (cameraDisabledByAdmin) { - Log.v(TAG, "Camera disabled by Device Policy"); - } else if (disabledBySimState) { - Log.v(TAG, "Camera disabled by Sim State"); - } - boolean currentUserSetup = 0 != Settings.Secure.getIntForUser( - mContext.getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, - 0 /*default */, - currentUserHandle); - boolean searchActionAvailable = - ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; - mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent - || !currentUserSetup; - mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent - || !currentUserSetup; - updateResources(); - } - - public void updateResources() { - // Update the search icon with drawable from the search .apk - if (!mSearchDisabled) { - Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .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 - // 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); - } - } - } - - mGlowPadView.setEnableTarget(com.android.internal.R.drawable - .ic_lockscreen_camera, !mCameraDisabled); - mGlowPadView.setEnableTarget(com.android.internal.R.drawable - .ic_action_assist_generic, !mSearchDisabled); - } - - void doTransition(View view, float to) { - if (mAnim != null) { - mAnim.cancel(); - } - mAnim = ObjectAnimator.ofFloat(view, "alpha", to); - mAnim.start(); - } - - public void setKeyguardCallback(KeyguardSecurityCallback callback) { - mCallback = callback; - } - - public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - } - - @Override - public void reset() { - mGlowPadView.reset(false); - } - - @Override - public boolean needsInput() { - return false; - } - - @Override - public void onPause() { - KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mInfoCallback); - } - - @Override - public void onResume(int reason) { - KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mInfoCallback); - } - - @Override - public KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - public void showBouncer(int duration) { - mIsBouncing = true; - KeyguardSecurityViewHelper. - showBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration); - } - - @Override - public void hideBouncer(int duration) { - mIsBouncing = false; - KeyguardSecurityViewHelper. - hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java new file mode 100644 index 0000000..2bb94be --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java @@ -0,0 +1,318 @@ +package com.android.internal.policy.impl.keyguard; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.ActivityInfo; +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; +import android.util.Slog; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.WindowManagerPolicy.OnKeyguardExitResult; + +import com.android.internal.policy.IKeyguardExitCallback; +import com.android.internal.policy.IKeyguardShowCallback; +import com.android.internal.policy.IKeyguardService; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.policy.impl.KeyguardServiceWrapper; + +/** + * A local class that keeps a cache of keyguard state that can be restored in the event + * keyguard crashes. It currently also allows runtime-selectable + * local or remote instances of keyguard. + */ +public class KeyguardServiceDelegate { + private static final String KEYGUARD_PACKAGE = "com.android.keyguard"; + private static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService"; + private static final String TAG = "KeyguardServiceDelegate"; + private static final boolean DEBUG = true; + protected KeyguardServiceWrapper mKeyguardService; + private View mScrim; // shown if keyguard crashes + private KeyguardState mKeyguardState = new KeyguardState(); + + /* package */ static final class KeyguardState { + boolean showing; + boolean showingAndNotHidden; + boolean inputRestricted; + boolean hidden; + boolean secure; + boolean dreaming; + boolean systemIsReady; + public boolean enabled; + public boolean dismissable; + public int offReason; + public int currentUser; + public boolean screenIsOn; + }; + + public interface ShowListener { + public void onShown(IBinder windowToken); + } + + // A delegate class to map a particular invocation with a ShowListener object. + private final class KeyguardShowDelegate extends IKeyguardShowCallback.Stub { + private ShowListener mShowListener; + + KeyguardShowDelegate(ShowListener showListener) { + mShowListener = showListener; + } + + @Override + public void onShown(IBinder windowToken) throws RemoteException { + if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****"); + if (mShowListener != null) { + mShowListener.onShown(windowToken); + } + hideScrim(); + } + }; + + // A delegate class to map a particular invocation with an OnKeyguardExitResult object. + private final class KeyguardExitDelegate extends IKeyguardExitCallback.Stub { + private OnKeyguardExitResult mOnKeyguardExitResult; + + KeyguardExitDelegate(OnKeyguardExitResult onKeyguardExitResult) { + mOnKeyguardExitResult = onKeyguardExitResult; + } + + @Override + public void onKeyguardExitResult(boolean success) throws RemoteException { + if (DEBUG) Log.v(TAG, "**** onKeyguardExitResult(" + success +") CALLED ****"); + if (mOnKeyguardExitResult != null) { + mOnKeyguardExitResult.onKeyguardExitResult(success); + } + } + }; + + public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) { + Intent intent = new Intent(); + intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS); + mScrim = createScrim(context); + if (!context.bindServiceAsUser(intent, mKeyguardConnection, + Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { + if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS); + } else { + if (DEBUG) Log.v(TAG, "*** Keyguard started"); + } + } + + private final ServiceConnection mKeyguardConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)"); + mKeyguardService = new KeyguardServiceWrapper( + IKeyguardService.Stub.asInterface(service)); + if (mKeyguardState.systemIsReady) { + // If the system is ready, it means keyguard crashed and restarted. + mKeyguardService.onSystemReady(); + // This is used to hide the scrim once keyguard displays. + mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null)); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)"); + mKeyguardService = null; + } + + }; + + public boolean isShowing() { + if (mKeyguardService != null) { + mKeyguardState.showing = mKeyguardService.isShowing(); + } + return mKeyguardState.showing; + } + + public boolean isShowingAndNotHidden() { + if (mKeyguardService != null) { + mKeyguardState.showingAndNotHidden = mKeyguardService.isShowingAndNotHidden(); + } + return mKeyguardState.showingAndNotHidden; + } + + public boolean isInputRestricted() { + if (mKeyguardService != null) { + mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted(); + } + return mKeyguardState.inputRestricted; + } + + public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) { + if (mKeyguardService != null) { + mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult)); + } + } + + public void keyguardDone(boolean authenticated, boolean wakeup) { + if (mKeyguardService != null) { + mKeyguardService.keyguardDone(authenticated, wakeup); + } + } + + public void setHidden(boolean isHidden) { + if (mKeyguardService != null) { + mKeyguardService.setHidden(isHidden); + } + mKeyguardState.hidden = isHidden; + } + + public void dismiss() { + if (mKeyguardService != null) { + mKeyguardService.dismiss(); + } + } + + public boolean isSecure() { + if (mKeyguardService != null) { + mKeyguardState.secure = mKeyguardService.isSecure(); + } + return mKeyguardState.secure; + } + + public void onWakeKeyWhenKeyguardShowingTq(int keycodePower) { + if (mKeyguardService != null) { + mKeyguardService.onWakeKeyWhenKeyguardShowing(keycodePower); + } + } + + public void onWakeMotionWhenKeyguardShowing() { + if (mKeyguardService != null) { + mKeyguardService.onWakeMotionWhenKeyguardShowing(); + } + } + + public void onDreamingStarted() { + if (mKeyguardService != null) { + mKeyguardService.onDreamingStarted(); + } + mKeyguardState.dreaming = true; + } + + public void onDreamingStopped() { + if (mKeyguardService != null) { + mKeyguardService.onDreamingStopped(); + } + mKeyguardState.dreaming = false; + } + + public void onScreenTurnedOn(final ShowListener showListener) { + if (mKeyguardService != null) { + if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + showListener + ")"); + mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(showListener)); + } else { + // try again when we establish a connection + Slog.w(TAG, "onScreenTurnedOn(): no keyguard service!"); + // This shouldn't happen, but if it does, invoke the listener immediately + // to avoid a dark screen... + showListener.onShown(null); + } + mKeyguardState.screenIsOn = true; + } + + public void onScreenTurnedOff(int why) { + if (mKeyguardService != null) { + mKeyguardService.onScreenTurnedOff(why); + } + mKeyguardState.offReason = why; + mKeyguardState.screenIsOn = false; + } + + public void setKeyguardEnabled(boolean enabled) { + if (mKeyguardService != null) { + mKeyguardService.setKeyguardEnabled(enabled); + } + mKeyguardState.enabled = enabled; + } + + public boolean isDismissable() { + if (mKeyguardService != null) { + mKeyguardState.dismissable = mKeyguardService.isDismissable(); + } + return mKeyguardState.dismissable; + } + + public void onSystemReady() { + if (mKeyguardService != null) { + mKeyguardService.onSystemReady(); + } else { + if (DEBUG) Log.v(TAG, "onSystemReady() called before keyguard service was ready"); + mKeyguardState.systemIsReady = true; + } + } + + public void doKeyguardTimeout(Bundle options) { + if (mKeyguardService != null) { + mKeyguardService.doKeyguardTimeout(options); + } + } + + public void showAssistant() { + if (mKeyguardService != null) { + mKeyguardService.showAssistant(); + } + } + + public void setCurrentUser(int newUserId) { + if (mKeyguardService != null) { + mKeyguardService.setCurrentUser(newUserId); + } + mKeyguardState.currentUser = newUserId; + } + + private static final View createScrim(Context context) { + View view = new View(context); + + int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR + | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN + | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER + ; + + final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; + final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM; + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + stretch, stretch, type, flags, PixelFormat.TRANSLUCENT); + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + lp.setTitle("KeyguardScrim"); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + wm.addView(view, lp); + view.setVisibility(View.GONE); + // Disable pretty much everything in statusbar until keyguard comes back and we know + // the state of the world. + view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME + | View.STATUS_BAR_DISABLE_BACK + | View.STATUS_BAR_DISABLE_RECENT + | View.STATUS_BAR_DISABLE_EXPAND + | View.STATUS_BAR_DISABLE_SEARCH); + return view; + } + + public void showScrim() { + mScrim.post(new Runnable() { + @Override + public void run() { + mScrim.setVisibility(View.VISIBLE); + } + }); + } + + public void hideScrim() { + mScrim.post(new Runnable() { + @Override + public void run() { + mScrim.setVisibility(View.GONE); + } + }); + } + +} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java deleted file mode 100644 index ab364ee..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java +++ /dev/null @@ -1,213 +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; - -import com.android.internal.telephony.ITelephony; - -import android.content.Context; -import android.app.Activity; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.text.Editable; -import android.text.InputType; -import android.text.TextWatcher; -import android.text.method.DigitsKeyListener; -import android.util.AttributeSet; -import android.view.View; -import android.view.WindowManager; -import android.widget.TextView.OnEditorActionListener; - -import com.android.internal.R; - -/** - * Displays a PIN pad for unlocking. - */ -public class KeyguardSimPinView extends KeyguardAbsKeyInputView - implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { - - private ProgressDialog mSimUnlockProgressDialog = null; - private volatile boolean mSimCheckInProgress; - - public KeyguardSimPinView(Context context) { - this(context, null); - } - - public KeyguardSimPinView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void resetState() { - mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true); - mPasswordEntry.setEnabled(true); - } - - @Override - protected int getPasswordTextViewId() { - return R.id.pinEntry; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - final View ok = findViewById(R.id.key_enter); - if (ok != null) { - ok.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - doHapticKeyClick(); - verifyPasswordAndUnlock(); - } - }); - } - - // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts, - // not a separate view - View pinDelete = findViewById(R.id.delete_button); - if (pinDelete != null) { - pinDelete.setVisibility(View.VISIBLE); - pinDelete.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - CharSequence str = mPasswordEntry.getText(); - if (str.length() > 0) { - mPasswordEntry.setText(str.subSequence(0, str.length()-1)); - } - doHapticKeyClick(); - } - }); - pinDelete.setOnLongClickListener(new View.OnLongClickListener() { - public boolean onLongClick(View v) { - mPasswordEntry.setText(""); - doHapticKeyClick(); - return true; - } - }); - } - - mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); - mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER - | InputType.TYPE_NUMBER_VARIATION_PASSWORD); - - mPasswordEntry.requestFocus(); - } - - @Override - public void showUsabilityHint() { - } - - @Override - public void onPause() { - // dismiss the dialog. - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.dismiss(); - mSimUnlockProgressDialog = null; - } - } - - /** - * 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 onSimCheckResponse(boolean success); - - @Override - public void run() { - try { - final boolean result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPin(mPin); - post(new Runnable() { - public void run() { - onSimCheckResponse(result); - } - }); - } catch (RemoteException e) { - post(new Runnable() { - public void run() { - onSimCheckResponse(false); - } - }); - } - } - } - - private Dialog getSimUnlockProgressDialog() { - if (mSimUnlockProgressDialog == null) { - mSimUnlockProgressDialog = new ProgressDialog(mContext); - mSimUnlockProgressDialog.setMessage( - mContext.getString(R.string.kg_sim_unlock_progress_dialog_message)); - mSimUnlockProgressDialog.setIndeterminate(true); - mSimUnlockProgressDialog.setCancelable(false); - if (!(mContext instanceof Activity)) { - mSimUnlockProgressDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - } - return mSimUnlockProgressDialog; - } - - @Override - protected void verifyPasswordAndUnlock() { - String entry = mPasswordEntry.getText().toString(); - - if (entry.length() < 4) { - // otherwise, display a message to the user, and don't submit. - mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true); - mPasswordEntry.setText(""); - mCallback.userActivity(0); - return; - } - - getSimUnlockProgressDialog().show(); - - if (!mSimCheckInProgress) { - mSimCheckInProgress = true; // there should be only one - new CheckSimPin(mPasswordEntry.getText().toString()) { - void onSimCheckResponse(final boolean success) { - 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. - KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(); - mCallback.dismiss(true); - } else { - mSecurityMessageDisplay.setMessage - (R.string.kg_password_wrong_pin_code, true); - mPasswordEntry.setText(""); - } - mCallback.userActivity(0); - mSimCheckInProgress = false; - } - }); - } - }.start(); - } - } -} - diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java deleted file mode 100644 index e5b4b73..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java +++ /dev/null @@ -1,282 +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; - -import android.app.Activity; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.text.Editable; -import android.text.InputType; -import android.text.TextWatcher; -import android.text.method.DigitsKeyListener; -import android.util.AttributeSet; -import android.view.View; -import android.view.WindowManager; -import android.widget.TextView.OnEditorActionListener; - -import com.android.internal.telephony.ITelephony; - -import com.android.internal.R; - -/** - * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier. - */ -public class KeyguardSimPukView extends KeyguardAbsKeyInputView - implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { - - private ProgressDialog mSimUnlockProgressDialog = null; - private volatile boolean mCheckInProgress; - private String mPukText; - private String mPinText; - private StateMachine mStateMachine = new StateMachine(); - - private class StateMachine { - final int ENTER_PUK = 0; - final int ENTER_PIN = 1; - final int CONFIRM_PIN = 2; - final int DONE = 3; - private int state = ENTER_PUK; - - public void next() { - int msg = 0; - if (state == ENTER_PUK) { - if (checkPuk()) { - state = ENTER_PIN; - msg = R.string.kg_puk_enter_pin_hint; - } else { - msg = R.string.kg_invalid_sim_puk_hint; - } - } else if (state == ENTER_PIN) { - if (checkPin()) { - state = CONFIRM_PIN; - msg = R.string.kg_enter_confirm_pin_hint; - } else { - msg = R.string.kg_invalid_sim_pin_hint; - } - } else if (state == CONFIRM_PIN) { - if (confirmPin()) { - state = DONE; - msg = - com.android.internal.R.string.lockscreen_sim_unlock_progress_dialog_message; - updateSim(); - } else { - state = ENTER_PIN; // try again? - msg = R.string.kg_invalid_confirm_pin_hint; - } - } - mPasswordEntry.setText(null); - if (msg != 0) { - mSecurityMessageDisplay.setMessage(msg, true); - } - } - - void reset() { - mPinText=""; - mPukText=""; - state = ENTER_PUK; - mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true); - mPasswordEntry.requestFocus(); - } - } - - public KeyguardSimPukView(Context context) { - this(context, null); - } - - public KeyguardSimPukView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void resetState() { - mStateMachine.reset(); - mPasswordEntry.setEnabled(true); - } - - @Override - protected int getPasswordTextViewId() { - return R.id.pinEntry; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - final View ok = findViewById(R.id.key_enter); - if (ok != null) { - ok.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - doHapticKeyClick(); - verifyPasswordAndUnlock(); - } - }); - } - - // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts, - // not a separate view - View pinDelete = findViewById(R.id.delete_button); - if (pinDelete != null) { - pinDelete.setVisibility(View.VISIBLE); - pinDelete.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - CharSequence str = mPasswordEntry.getText(); - if (str.length() > 0) { - mPasswordEntry.setText(str.subSequence(0, str.length()-1)); - } - doHapticKeyClick(); - } - }); - pinDelete.setOnLongClickListener(new View.OnLongClickListener() { - public boolean onLongClick(View v) { - mPasswordEntry.setText(""); - doHapticKeyClick(); - return true; - } - }); - } - - mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); - mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER - | InputType.TYPE_NUMBER_VARIATION_PASSWORD); - - mPasswordEntry.requestFocus(); - - mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default - } - - @Override - public void showUsabilityHint() { - } - - @Override - public void onPause() { - // dismiss the dialog. - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.dismiss(); - mSimUnlockProgressDialog = null; - } - } - - /** - * 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); - } - }); - } - } - } - - private Dialog getSimUnlockProgressDialog() { - if (mSimUnlockProgressDialog == null) { - mSimUnlockProgressDialog = new ProgressDialog(mContext); - mSimUnlockProgressDialog.setMessage( - mContext.getString(R.string.kg_sim_unlock_progress_dialog_message)); - mSimUnlockProgressDialog.setIndeterminate(true); - mSimUnlockProgressDialog.setCancelable(false); - if (!(mContext instanceof Activity)) { - mSimUnlockProgressDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - } - } - return mSimUnlockProgressDialog; - } - - private boolean checkPuk() { - // make sure the puk is at least 8 digits long. - if (mPasswordEntry.getText().length() >= 8) { - mPukText = mPasswordEntry.getText().toString(); - return true; - } - return false; - } - - private boolean checkPin() { - // make sure the PIN is between 4 and 8 digits - int length = mPasswordEntry.getText().length(); - if (length >= 4 && length <= 8) { - mPinText = mPasswordEntry.getText().toString(); - return true; - } - return false; - } - - public boolean confirmPin() { - return mPinText.equals(mPasswordEntry.getText().toString()); - } - - private void updateSim() { - getSimUnlockProgressDialog().show(); - - if (!mCheckInProgress) { - mCheckInProgress = true; - new CheckSimPuk(mPukText, mPinText) { - void onSimLockChangedResponse(final boolean success) { - post(new Runnable() { - public void run() { - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - if (success) { - mCallback.dismiss(true); - } else { - mStateMachine.reset(); - mSecurityMessageDisplay.setMessage(R.string.kg_invalid_puk, true); - } - mCheckInProgress = false; - } - }); - } - }.start(); - } - } - - @Override - protected void verifyPasswordAndUnlock() { - mStateMachine.next(); - } -} - - diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java deleted file mode 100644 index d938cec..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java +++ /dev/null @@ -1,156 +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; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Typeface; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Slog; -import android.view.View; -import android.widget.GridLayout; -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; - 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 = com.android.internal.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 SimpleDateFormat mDateFormat; - private LockPatternUtils mLockPatternUtils; - - private TextView mDateView; - private TextView mAlarmStatusView; - private ClockView mClockView; - - private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onTimeChanged() { - refresh(); - } - - @Override - void onKeyguardVisibilityChanged(boolean showing) { - if (showing) { - if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing); - refresh(); - } - }; - }; - - public KeyguardStatusView(Context context) { - this(context, null, 0); - } - - public KeyguardStatusView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - Resources res = getContext().getResources(); - 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); - mLockPatternUtils = new LockPatternUtils(getContext()); - - // Use custom font in mDateView - mDateView.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD); - - // Required to get Marquee to work. - final View marqueeViews[] = { mDateView, mAlarmStatusView }; - for (int i = 0; i < marqueeViews.length; i++) { - View v = marqueeViews[i]; - if (v == null) { - throw new RuntimeException("Can't find widget at index " + i); - } - v.setSelected(true); - } - refresh(); - } - - protected void refresh() { - mClockView.updateTime(); - refreshDate(); - refreshAlarmStatus(); // might as well - } - - void refreshAlarmStatus() { - // Update Alarm status - String nextAlarm = mLockPatternUtils.getNextAlarm(); - if (!TextUtils.isEmpty(nextAlarm)) { - maybeSetUpperCaseText(mAlarmStatusView, nextAlarm); - mAlarmStatusView.setCompoundDrawablesWithIntrinsicBounds(ALARM_ICON, 0, 0, 0); - mAlarmStatusView.setVisibility(View.VISIBLE); - } else { - mAlarmStatusView.setVisibility(View.GONE); - } - } - - void refreshDate() { - maybeSetUpperCaseText(mDateView, mDateFormat.format(new Date())); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback); - } - - public int getAppWidgetId() { - return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET; - } - - private void maybeSetUpperCaseText(TextView textView, CharSequence text) { - 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 deleted file mode 100644 index 5e3b7da..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java +++ /dev/null @@ -1,470 +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; - -import android.app.PendingIntent; -import android.app.PendingIntent.CanceledException; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.media.AudioManager; -import android.media.IRemoteControlDisplay; -import android.media.MediaMetadataRetriever; -import android.media.RemoteControlClient; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.RemoteException; -import android.os.SystemClock; -import android.text.Spannable; -import android.text.TextUtils; -import android.text.style.ForegroundColorSpan; -import android.util.AttributeSet; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.internal.R; - -import java.lang.ref.WeakReference; -/** - * This is the widget responsible for showing music controls in keyguard. - */ -public class KeyguardTransportControlView extends FrameLayout implements OnClickListener { - - private static final int MSG_UPDATE_STATE = 100; - private static final int MSG_SET_METADATA = 101; - private static final int MSG_SET_TRANSPORT_CONTROLS = 102; - private static final int MSG_SET_ARTWORK = 103; - private static final int MSG_SET_GENERATION_ID = 104; - private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s - protected static final boolean DEBUG = false; - protected static final String TAG = "TransportControlView"; - - private ImageView mAlbumArt; - private TextView mTrackTitle; - private ImageView mBtnPrev; - private ImageView mBtnPlay; - private ImageView mBtnNext; - private int mClientGeneration; - private Metadata mMetadata = new Metadata(); - private boolean mAttached; - private PendingIntent mClientIntent; - private int mTransportControlFlags; - private int mCurrentPlayState; - private AudioManager mAudioManager; - private IRemoteControlDisplayWeak mIRCD; - - /** - * The metadata which should be populated into the view once we've been attached - */ - private Bundle mPopulateMetadataWhenAttached = null; - - // This handler is required to ensure messages from IRCD are handled in sequence and on - // the UI thread. - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_STATE: - if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2); - break; - - case MSG_SET_METADATA: - if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj); - break; - - case MSG_SET_TRANSPORT_CONTROLS: - if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2); - break; - - case MSG_SET_ARTWORK: - if (mClientGeneration == msg.arg1) { - if (mMetadata.bitmap != null) { - mMetadata.bitmap.recycle(); - } - mMetadata.bitmap = (Bitmap) msg.obj; - mAlbumArt.setImageBitmap(mMetadata.bitmap); - } - break; - - case MSG_SET_GENERATION_ID: - if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2); - mClientGeneration = msg.arg1; - mClientIntent = (PendingIntent) msg.obj; - break; - - } - } - }; - - /** - * This class is required to have weak linkage to the current TransportControlView - * because the remote process can hold a strong reference to this binder object and - * we can't predict when it will be GC'd in the remote process. Without this code, it - * would allow a heavyweight object to be held on this side of the binder when there's - * no requirement to run a GC on the other side. - */ - private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub { - private WeakReference<Handler> mLocalHandler; - - IRemoteControlDisplayWeak(Handler handler) { - mLocalHandler = new WeakReference<Handler>(handler); - } - - 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(); - } - } - - public void setMetadata(int generationId, Bundle metadata) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); - } - } - - public void setTransportControlInfo(int generationId, int flags, int posCapabilities) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags) - .sendToTarget(); - } - } - - public void setArtwork(int generationId, Bitmap bitmap) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget(); - } - } - - public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); - handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget(); - } - } - - public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent, - boolean clearing) throws RemoteException { - Handler handler = mLocalHandler.get(); - if (handler != null) { - handler.obtainMessage(MSG_SET_GENERATION_ID, - clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget(); - } - } - }; - - public KeyguardTransportControlView(Context context, AttributeSet attrs) { - super(context, attrs); - if (DEBUG) Log.v(TAG, "Create TCV " + this); - mAudioManager = new AudioManager(mContext); - mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback - mIRCD = new IRemoteControlDisplayWeak(mHandler); - } - - private void updateTransportControls(int transportControlFlags) { - mTransportControlFlags = transportControlFlags; - } - - @Override - public void onFinishInflate() { - super.onFinishInflate(); - mTrackTitle = (TextView) findViewById(R.id.title); - mTrackTitle.setSelected(true); // enable marquee - mAlbumArt = (ImageView) findViewById(R.id.albumart); - mBtnPrev = (ImageView) findViewById(R.id.btn_prev); - mBtnPlay = (ImageView) findViewById(R.id.btn_play); - mBtnNext = (ImageView) findViewById(R.id.btn_next); - final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext }; - for (View view : buttons) { - view.setOnClickListener(this); - } - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - if (DEBUG) Log.v(TAG, "onAttachToWindow()"); - if (mPopulateMetadataWhenAttached != null) { - updateMetadata(mPopulateMetadataWhenAttached); - mPopulateMetadataWhenAttached = null; - } - if (!mAttached) { - if (DEBUG) Log.v(TAG, "Registering TCV " + this); - mAudioManager.registerRemoteControlDisplay(mIRCD); - } - mAttached = true; - } - - @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(); - if (mAttached) { - if (DEBUG) Log.v(TAG, "Unregistering TCV " + this); - mAudioManager.unregisterRemoteControlDisplay(mIRCD); - } - mAttached = false; - } - - class Metadata { - private String artist; - private String trackTitle; - private String albumTitle; - private Bitmap bitmap; - - public String toString() { - return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + albumTitle + "]"; - } - } - - private String getMdString(Bundle data, int id) { - return data.getString(Integer.toString(id)); - } - - private void updateMetadata(Bundle data) { - if (mAttached) { - mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST); - mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE); - mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM); - populateMetadata(); - } else { - mPopulateMetadataWhenAttached = data; - } - } - - /** - * Populates the given metadata into the view - */ - private void populateMetadata() { - StringBuilder sb = new StringBuilder(); - int trackTitleLength = 0; - if (!TextUtils.isEmpty(mMetadata.trackTitle)) { - sb.append(mMetadata.trackTitle); - trackTitleLength = mMetadata.trackTitle.length(); - } - if (!TextUtils.isEmpty(mMetadata.artist)) { - if (sb.length() != 0) { - sb.append(" - "); - } - sb.append(mMetadata.artist); - } - if (!TextUtils.isEmpty(mMetadata.albumTitle)) { - if (sb.length() != 0) { - sb.append(" - "); - } - sb.append(mMetadata.albumTitle); - } - mTrackTitle.setText(sb.toString(), TextView.BufferType.SPANNABLE); - Spannable str = (Spannable) mTrackTitle.getText(); - if (trackTitleLength != 0) { - str.setSpan(new ForegroundColorSpan(0xffffffff), 0, trackTitleLength, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - trackTitleLength++; - } - if (sb.length() > trackTitleLength) { - str.setSpan(new ForegroundColorSpan(0x7fffffff), trackTitleLength, sb.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - mAlbumArt.setImageBitmap(mMetadata.bitmap); - final int flags = mTransportControlFlags; - setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS); - setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT); - setVisibilityBasedOnFlag(mBtnPlay, flags, - RemoteControlClient.FLAG_KEY_MEDIA_PLAY - | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE - | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE - | RemoteControlClient.FLAG_KEY_MEDIA_STOP); - - updatePlayPauseState(mCurrentPlayState); - } - - private static void setVisibilityBasedOnFlag(View view, int flags, int flag) { - if ((flags & flag) != 0) { - view.setVisibility(View.VISIBLE); - } else { - view.setVisibility(View.GONE); - } - } - - private void updatePlayPauseState(int state) { - if (DEBUG) Log.v(TAG, - "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state); - if (state == mCurrentPlayState) { - return; - } - final int imageResId; - final int imageDescId; - switch (state) { - case RemoteControlClient.PLAYSTATE_ERROR: - imageResId = com.android.internal.R.drawable.stat_sys_warning; - // TODO use more specific image description string for warning, but here the "play" - // message is still valid because this button triggers a play command. - imageDescId = com.android.internal.R.string.lockscreen_transport_play_description; - break; - - case RemoteControlClient.PLAYSTATE_PLAYING: - imageResId = com.android.internal.R.drawable.ic_media_pause; - imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description; - break; - - case RemoteControlClient.PLAYSTATE_BUFFERING: - imageResId = com.android.internal.R.drawable.ic_media_stop; - imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description; - break; - - case RemoteControlClient.PLAYSTATE_PAUSED: - default: - imageResId = com.android.internal.R.drawable.ic_media_play; - imageDescId = com.android.internal.R.string.lockscreen_transport_play_description; - break; - } - mBtnPlay.setImageResource(imageResId); - mBtnPlay.setContentDescription(getResources().getString(imageDescId)); - mCurrentPlayState = state; - } - - static class SavedState extends BaseSavedState { - boolean clientPresent; - - SavedState(Parcelable superState) { - super(superState); - } - - private SavedState(Parcel in) { - super(in); - this.clientPresent = in.readInt() != 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(this.clientPresent ? 1 : 0); - } - - public static final Parcelable.Creator<SavedState> CREATOR - = new Parcelable.Creator<SavedState>() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } - - public void onClick(View v) { - int keyCode = -1; - if (v == mBtnPrev) { - keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS; - } else if (v == mBtnNext) { - keyCode = KeyEvent.KEYCODE_MEDIA_NEXT; - } else if (v == mBtnPlay) { - keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; - - } - if (keyCode != -1) { - sendMediaButtonClick(keyCode); - } - } - - private void sendMediaButtonClick(int keyCode) { - if (mClientIntent == null) { - // Shouldn't be possible because this view should be hidden in this case. - Log.e(TAG, "sendMediaButtonClick(): No client is currently registered"); - return; - } - // use the registered PendingIntent that will be processed by the registered - // media button event receiver, which is the component of mClientIntent - KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); - intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - try { - mClientIntent.send(getContext(), 0, intent); - } catch (CanceledException e) { - Log.e(TAG, "Error sending intent for media button down: "+e); - e.printStackTrace(); - } - - keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode); - intent = new Intent(Intent.ACTION_MEDIA_BUTTON); - intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - try { - mClientIntent.send(getContext(), 0, intent); - } catch (CanceledException e) { - Log.e(TAG, "Error sending intent for media button up: "+e); - e.printStackTrace(); - } - } - - public boolean providesClock() { - return false; - } - - private boolean wasPlayingRecently(int state, long stateChangeTimeMs) { - switch (state) { - case RemoteControlClient.PLAYSTATE_PLAYING: - case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: - case RemoteControlClient.PLAYSTATE_REWINDING: - case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: - case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: - case RemoteControlClient.PLAYSTATE_BUFFERING: - // actively playing or about to play - return true; - case RemoteControlClient.PLAYSTATE_NONE: - return false; - case RemoteControlClient.PLAYSTATE_STOPPED: - case RemoteControlClient.PLAYSTATE_PAUSED: - case RemoteControlClient.PLAYSTATE_ERROR: - // we have stopped playing, check how long ago - if (DEBUG) { - if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) { - Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently"); - } else { - Log.v(TAG, "wasPlayingRecently: time > TIMEOUT"); - } - } - return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS); - default: - Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()"); - return false; - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java deleted file mode 100644 index 5a64586..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java +++ /dev/null @@ -1,983 +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; - -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; -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.media.IRemoteControlDisplay; -import android.os.BatteryManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.IRemoteCallback; -import android.os.Message; -import android.os.RemoteException; -import android.os.UserHandle; -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.lang.ref.WeakReference; -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 #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()} - * and {@link #clearFailedUnlockAttempts()}. 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; - private static final int MSG_DPM_STATE_CHANGED = 309; - 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; - - 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 mKeyguardIsVisible; - private boolean mBootCompleted; - - // Device provisioning state - private boolean mDeviceProvisioned; - - // Battery status - private BatteryStatus mBatteryStatus; - - // Password attempts - private int mFailedAttempts = 0; - private int mFailedBiometricUnlockAttempts = 0; - - private boolean mAlternateUnlockEnabled; - - private boolean mClockVisible; - - private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>> - mCallbacks = Lists.newArrayList(); - private ContentObserver mDeviceProvisionedObserver; - - private boolean mSwitchingUser; - - 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_SWITCHING: - handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj); - break; - case MSG_USER_SWITCH_COMPLETE: - handleUserSwitchComplete(msg.arg1); - break; - case MSG_USER_REMOVED: - handleUserRemoved(msg.arg1); - break; - case MSG_KEYGUARD_VISIBILITY_CHANGED: - handleKeyguardVisibilityChanged(msg.arg1); - break; - 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) { - 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_REMOVED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED, - intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); - } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_BOOT_COMPLETED)); - } - } - }; - - 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, - * 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 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra) - || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) { - // This is required because telephony doesn't return to "READY" after - // these state transitions. See bug 7197471. - state = IccCardConstants.State.READY; - } 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, power, or wireless). - * @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 static KeyguardUpdateMonitor getInstance(Context context) { - if (sInstance == null) { - sInstance = new KeyguardUpdateMonitor(context); - } - 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; - - mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); - // 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_REMOVED); - context.registerReceiver(mBroadcastReceiver, filter); - - final IntentFilter bootCompleteFilter = new IntentFilter(); - bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - 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_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) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private boolean isDeviceProvisionedInSettingsDb() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DEVICE_PROVISIONED, 0) != 0; - } - - private void watchForDeviceProvisioning() { - mDeviceProvisionedObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); - 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, mDeviceProvisionedObserver); - - // prevent a race condition between where we check the flag and where we register the - // observer by grabbing the value once again... - boolean provisioned = isDeviceProvisionedInSettingsDb(); - 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 = mCallbacks.size() - 1; i >= 0; i--) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.onDevicePolicyManagerStateChanged(); - } - } - } - - /** - * Handle {@link #MSG_USER_SWITCHING} - */ - 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.onUserSwitching(userId); - } - } - try { - reply.sendResult(null); - } catch (RemoteException e) { - } - } - - /** - * 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) { - cb.onBootCompleted(); - } - } - } - - /** - * We need to store this state in the KeyguardUpdateMonitor since this class will not be - * destroyed. - */ - public boolean hasBootCompleted() { - return mBootCompleted; - } - - /** - * Handle {@link #MSG_USER_REMOVED} - */ - protected void handleUserRemoved(int userId) { - for (int i = 0; i < mCallbacks.size(); i++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.onUserRemoved(userId); - } - } - } - - /** - * Handle {@link #MSG_DEVICE_PROVISIONED} - */ - protected void handleDeviceProvisioned() { - for (int i = 0; i < mCallbacks.size(); i++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.onDeviceProvisioned(); - } - } - if (mDeviceProvisionedObserver != null) { - // We don't need the observer anymore... - mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver); - mDeviceProvisionedObserver = 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++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.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++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.onRingerModeChanged(mode); - } - } - } - - /** - * Handle {@link #MSG_TIME_UPDATE} - */ - private void handleTimeUpdate() { - if (DEBUG) Log.d(TAG, "handleTimeUpdate"); - for (int i = 0; i < mCallbacks.size(); i++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.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++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.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++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.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++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.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++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.onClockVisibilityChanged(); - } - } - } - - /** - * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED} - */ - private void handleKeyguardVisibilityChanged(int showing) { - if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")"); - boolean isShowing = (showing == 1); - mKeyguardIsVisible = isShowing; - for (int i = 0; i < mCallbacks.size(); i++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.onKeyguardVisibilityChanged(isShowing); - } - } - } - - public boolean isKeyguardVisible() { - 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(); - 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 callback The callback to remove - */ - public void removeCallback(KeyguardUpdateMonitorCallback callback) { - if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback); - for (int i = mCallbacks.size() - 1; i >= 0; i--) { - if (mCallbacks.get(i).get() == callback) { - mCallbacks.remove(i); - } - } - } - - /** - * Register to receive notifications about general keyguard information - * (see {@link InfoCallback}. - * @param callback The callback to register - */ - public void registerCallback(KeyguardUpdateMonitorCallback callback) { - if (DEBUG) Log.v(TAG, "*** register callback for " + callback); - // Prevent adding duplicate callbacks - for (int i = 0; i < mCallbacks.size(); i++) { - if (mCallbacks.get(i).get() == callback) { - if (DEBUG) Log.e(TAG, "Object tried to add another callback", - new Exception("Called by")); - return; - } - } - mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback)); - removeCallback(null); // remove unused references - sendUpdates(callback); - } - - private void sendUpdates(KeyguardUpdateMonitorCallback 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); - callback.onMusicClientIdChanged( - mDisplayClientState.clientGeneration, - mDisplayClientState.clearing, - mDisplayClientState.intent); - callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState, - mDisplayClientState.playbackEventTime); - } - - public void sendKeyguardVisibilityChanged(boolean showing) { - if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")"); - Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED); - message.arg1 = showing ? 1 : 0; - message.sendToTarget(); - } - - 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 getFailedUnlockAttempts() { - return mFailedAttempts; - } - - public void clearFailedUnlockAttempts() { - mFailedAttempts = 0; - mFailedBiometricUnlockAttempts = 0; - } - - public void reportFailedUnlockAttempt() { - 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 isAlternateUnlockEnabled() { - return mAlternateUnlockEnabled; - } - - public void setAlternateUnlockEnabled(boolean enabled) { - mAlternateUnlockEnabled = enabled; - } - - public boolean isSimLocked() { - return isSimLocked(mSimState); - } - - public static boolean isSimLocked(IccCardConstants.State state) { - return state == IccCardConstants.State.PIN_REQUIRED - || state == IccCardConstants.State.PUK_REQUIRED - || state == IccCardConstants.State.PERM_DISABLED; - } - - public boolean isSimPinSecure() { - return isSimPinSecure(mSimState); - } - - public static boolean isSimPinSecure(IccCardConstants.State state) { - final IccCardConstants.State simState = state; - return (simState == IccCardConstants.State.PIN_REQUIRED - || 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 deleted file mode 100644 index 41816db..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java +++ /dev/null @@ -1,134 +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; - -import android.app.PendingIntent; -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 the visibility of the keyguard changes. - * @param showing Indicates if the keyguard is now visible. - */ - void onKeyguardVisibilityChanged(boolean showing) { } - - /** - * 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 change begins. - */ - void onUserSwitching(int userId) { } - - /** - * Called when the user change is complete. - */ - void onUserSwitchComplete(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) { } - - /** - * 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/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java deleted file mode 100644 index 6fcacd3..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java +++ /dev/null @@ -1,264 +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; - -import android.app.Activity; -import android.content.Context; -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.util.AttributeSet; -import android.util.Log; -import android.util.Slog; -import android.view.KeyEvent; -import android.widget.FrameLayout; - -/** - * Base class for keyguard view. {@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 AudioManager mAudioManager; - private TelephonyManager mTelephonyManager = null; - protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback; - - // 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 - private static final 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) { - this(context, null); - } - - public KeyguardViewBase(Context context, AttributeSet attrs) { - super(context, attrs); - resetBackground(); - } - - public void resetBackground() { - setBackground(mBackgroundDrawable); - } - - /** - * 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(); - - /** - * Gets the desired user activity timeout in milliseconds, or -1 if the - * default should be used. - */ - abstract public long getUserActivityTimeout(); - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (interceptMediaKey(event)) { - return true; - } - return super.dispatchKeyEvent(event); - } - - /** - * 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); - - if (!(mContext instanceof Activity)) { - setSystemUiVisibility(STATUS_BAR_DISABLE_BACK); - } - } - - public void setViewMediatorCallback( - KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) { - mViewMediatorCallback = viewMediatorCallback; - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java deleted file mode 100644 index 30c95fb..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java +++ /dev/null @@ -1,449 +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; - -import android.app.Activity; -import android.app.ActivityManager; -import android.appwidget.AppWidgetManager; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.IBinder; -import android.os.Parcelable; -import android.os.SystemProperties; -import android.util.Log; -import android.util.Slog; -import android.util.SparseArray; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewManager; -import android.view.WindowManager; -import android.widget.FrameLayout; - -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; - -/** - * Manages creating, showing, hiding and resetting the keyguard. Calls back - * via {@link KeyguardViewMediator.ViewMediatorCallback} 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 { - 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; - - private final Context mContext; - private final ViewManager mViewManager; - private final KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback; - - private WindowManager.LayoutParams mWindowLayoutParams; - private boolean mNeedsInput = false; - - private FrameLayout mKeyguardHost; - private KeyguardHostView mKeyguardView; - - private boolean mScreenOn = false; - private LockPatternUtils mLockPatternUtils; - - 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. - * @param lockPatternUtils - */ - public KeyguardViewManager(Context context, ViewManager viewManager, - KeyguardViewMediator.ViewMediatorCallback callback, - LockPatternUtils lockPatternUtils) { - mContext = context; - mViewManager = viewManager; - mViewMediatorCallback = callback; - mLockPatternUtils = lockPatternUtils; - } - - /** - * Show the keyguard. Will handle creating and attaching to the view manager - * lazily. - */ - public synchronized void show(Bundle options) { - if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView); - - boolean enableScreenRotation = shouldEnableScreenRotation(); - - maybeCreateKeyguardLocked(enableScreenRotation, false, options); - maybeEnableScreenRotation(enableScreenRotation); - - // Disable common aspects of the system/status/navigation bars that are not appropriate or - // useful on any keyguard screen 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. - final int visFlags = View.STATUS_BAR_DISABLE_HOME; - if (DEBUG) Log.v(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")"); - mKeyguardHost.setSystemUiVisibility(visFlags); - - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - mKeyguardHost.setVisibility(View.VISIBLE); - mKeyguardView.show(); - mKeyguardView.requestFocus(); - } - - private boolean shouldEnableScreenRotation() { - Resources res = mContext.getResources(); - return SystemProperties.getBoolean("lockscreen.rot_override",false) - || res.getBoolean(com.android.internal.R.bool.config_enableLockScreenRotation); - } - - class ViewManagerHost extends FrameLayout { - public ViewManagerHost(Context context) { - super(context); - setFitsSystemWindows(true); - } - - @Override - protected boolean fitSystemWindows(Rect insets) { - Log.v("TAG", "bug 7643792: fitSystemWindows(" + insets.toShortString() + ")"); - return super.fitSystemWindows(insets); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - 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 - public boolean dispatchKeyEvent(KeyEvent event) { - if (mKeyguardView != null) { - // Always process back and menu keys, regardless of focus - if (event.getAction() == KeyEvent.ACTION_DOWN) { - int keyCode = event.getKeyCode(); - if (keyCode == KeyEvent.KEYCODE_BACK && mKeyguardView.handleBackKey()) { - return true; - } else if (keyCode == KeyEvent.KEYCODE_MENU && mKeyguardView.handleMenuKey()) { - return true; - } - } - // Always process media keys, regardless of focus - if (mKeyguardView.dispatchKeyEvent(event)) { - return true; - } - } - return super.dispatchKeyEvent(event); - } - } - - SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>(); - - private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force, - Bundle options) { - final boolean isActivity = (mContext instanceof Activity); // for test activity - - if (mKeyguardHost != null) { - mKeyguardHost.saveHierarchyState(mStateContainer); - } - - if (mKeyguardHost == null) { - if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); - - mKeyguardHost = new ViewManagerHost(mContext); - - int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR - | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN - | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; - - if (!mNeedsInput) { - flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - } - if (ActivityManager.isHighEndGfx()) { - flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; - } - - final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; - final int type = isActivity ? WindowManager.LayoutParams.TYPE_APPLICATION - : WindowManager.LayoutParams.TYPE_KEYGUARD; - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - 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 |= - WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED; - } - lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY; - if (isActivity) { - lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; - } - lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; - lp.setTitle(isActivity ? "KeyguardMock" : "Keyguard"); - mWindowLayoutParams = lp; - mViewManager.addView(mKeyguardHost, lp); - } - - if (force || mKeyguardView == null) { - inflateKeyguardView(options); - mKeyguardView.requestFocus(); - } - updateUserActivityTimeoutInWindowLayoutParams(); - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - - mKeyguardHost.restoreHierarchyState(mStateContainer); - } - - private void inflateKeyguardView(Bundle options) { - View v = mKeyguardHost.findViewById(R.id.keyguard_host_view); - if (v != null) { - mKeyguardHost.removeView(v); - } - // TODO: Remove once b/7094175 is fixed - if (false) Slog.d(TAG, "inflateKeyguardView: b/7094175 mContext.config=" - + mContext.getResources().getConfiguration()); - final LayoutInflater inflater = LayoutInflater.from(mContext); - View view = inflater.inflate(R.layout.keyguard_host_view, mKeyguardHost, true); - 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 - // the view mediator callback. Make sure it knows the correct IME state. - if (mViewMediatorCallback != null) { - KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById( - R.id.keyguard_password_view); - - if (kpv != null) { - mViewMediatorCallback.setNeedsInput(kpv.needsInput()); - } - } - - if (options != null) { - int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET, - AppWidgetManager.INVALID_APPWIDGET_ID); - if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) { - mKeyguardView.goToWidget(widgetToShow); - } - } - } - - public void updateUserActivityTimeout() { - updateUserActivityTimeoutInWindowLayoutParams(); - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - } - - private void updateUserActivityTimeoutInWindowLayoutParams() { - // Use the user activity timeout requested by the keyguard view, if any. - if (mKeyguardView != null) { - long timeout = mKeyguardView.getUserActivityTimeout(); - if (timeout >= 0) { - mWindowLayoutParams.userActivityTimeout = timeout; - return; - } - } - - // Otherwise, use the default timeout. - mWindowLayoutParams.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS; - } - - private void maybeEnableScreenRotation(boolean enableScreenRotation) { - // TODO: move this outside - 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); - } - - 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; - } - - try { - mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); - } catch (java.lang.IllegalArgumentException e) { - // TODO: Ensure this method isn't called on views that are changing... - Log.w(TAG,"Can't update input method on " + mKeyguardHost + " window not attached"); - } - } - } - - /** - * Reset the state of the view. - */ - public synchronized void reset(Bundle options) { - if (DEBUG) Log.d(TAG, "reset()"); - // User might have switched, check if we need to go back to keyguard - // TODO: It's preferable to stay and show the correct lockscreen or unlock if none - maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, options); - } - - 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 (showListener != null) { - 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() { - @Override - public void run() { - if (mKeyguardHost.getVisibility() == View.VISIBLE) { - showListener.onShown(mKeyguardHost.getWindowToken()); - } else { - showListener.onShown(null); - } - } - }); - } else { - showListener.onShown(null); - } - } - } else if (showListener != null) { - showListener.onShown(null); - } - } - - public synchronized void verifyUnlock() { - if (DEBUG) Log.d(TAG, "verifyUnlock()"); - show(null); - 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; - } - 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); - - // We really only want to preserve keyguard state for configuration changes. Hence - // we should clear state of widgets (e.g. Music) when we hide keyguard so it can - // start with a fresh state when we return. - mStateContainer.clear(); - - // 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() { - @Override - public void run() { - synchronized (KeyguardViewManager.this) { - lastView.cleanUp(); - mKeyguardHost.removeView(lastView); - } - } - }, 500); - } - } - } - - /** - * Dismisses the keyguard by going to the next screen or making it gone. - */ - public synchronized void dismiss() { - if (mScreenOn) { - mKeyguardView.dismiss(); - } - } - - /** - * @return Whether the keyguard is showing - */ - public synchronized boolean isShowing() { - return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE); - } - - public void showAssistant() { - if (mKeyguardView != null) { - mKeyguardView.showAssistant(); - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java deleted file mode 100644 index 885cb45..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java +++ /dev/null @@ -1,1449 +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; - -import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; - -import android.app.Activity; -import android.app.ActivityManagerNative; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.SearchManager; -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.Bundle; -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.os.UserManager; -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; - -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.widget.LockPatternUtils; - - -/** - * 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 { - private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; - 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 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; - private static final int SHOW_ASSISTANT = 14; - - /** - * 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 ViewMediatorCallback#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 mSwitchingUser; - - 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; - - /** UserManager for querying number of users */ - private UserManager mUserManager; - - /** SearchManager for determining whether or not search assistant is available */ - private SearchManager mSearchManager; - - /** - * 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 #wakeWhenReady(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; - - /** - * 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 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 boolean mKeyguardDonePending = false; - - private SoundPool mLockSounds; - private int mLockSoundId; - private int mUnlockSoundId; - private int mLockSoundStreamId; - - /** - * The volume applied to the lock/unlock sounds. - */ - 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. - */ - public interface ViewMediatorCallback { - - /** - * Wake the device immediately. - */ - void wakeUp(); - - /** - * Reports user activity and requests that the screen stay on. - */ - void userActivity(); - - /** - * Reports user activity and requests that the screen stay on for at least - * the specified amount of time. - * @param millis The amount of time in millis. This value is currently ignored. - */ - void userActivity(long 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(); - - /** - * Tell ViewMediator that the current view needs IME input - * @param needsInput - */ - void setNeedsInput(boolean needsInput); - - /** - * Tell view mediator that the keyguard view's desired user activity timeout - * has changed and needs to be reapplied to the window. - */ - void onUserActivityTimeoutChanged(); - - /** - * Report that the keyguard is dismissable, pending the next keyguardDone call. - */ - void keyguardDonePending(); - } - - KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { - - @Override - 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(); - // 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 - 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() { - sendUserPresentBroadcast(); - } - - @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(null); - } - } - } - 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(null); - } - } - 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(null); - } - } - break; - case READY: - synchronized (this) { - if (isShowing()) { - resetStateLocked(null); - } - } - break; - } - } - - }; - - ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() { - public void wakeUp() { - KeyguardViewMediator.this.wakeUp(); - } - - public void userActivity() { - KeyguardViewMediator.this.userActivity(); - } - - public void userActivity(long holdMs) { - KeyguardViewMediator.this.userActivity(holdMs); - } - - public void keyguardDone(boolean authenticated) { - KeyguardViewMediator.this.keyguardDone(authenticated, true); - } - - public void keyguardDoneDrawing() { - mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING); - } - - @Override - public void setNeedsInput(boolean needsInput) { - mKeyguardViewManager.setNeedsInput(needsInput); - } - - @Override - public void onUserActivityTimeoutChanged() { - mKeyguardViewManager.updateUserActivityTimeout(); - } - - @Override - public void keyguardDonePending() { - mKeyguardDonePending = true; - } - }; - - public void wakeUp() { - mPM.wakeUp(SystemClock.uptimeMillis()); - } - - public void userActivity() { - userActivity(AWAKE_INTERVAL_DEFAULT_MS); - } - - public void userActivity(long holdMs) { - // We ignore the hold time. Eventually we should remove it. - // Instead, the keyguard window has an explicit user activity timeout set on it. - mPM.userActivity(SystemClock.uptimeMillis(), false); - } - - /** - * Construct a KeyguardViewMediator - * @param context - * @param lockPatternUtils optional mock interface for LockPatternUtils - */ - public KeyguardViewMediator(Context context, LockPatternUtils lockPatternUtils) { - mContext = context; - mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - 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 = KeyguardUpdateMonitor.getInstance(context); - - mLockPatternUtils = lockPatternUtils != null - ? lockPatternUtils : new LockPatternUtils(mContext); - mLockPatternUtils.setCurrentUser(UserHandle.USER_OWNER); - - WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); - - mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback, - mLockPatternUtils); - - 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) { - Log.w(TAG, "failed to load lock 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) { - Log.w(TAG, "failed to load unlock 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() { - mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); - synchronized (this) { - if (DEBUG) Log.d(TAG, "onSystemReady"); - mSystemReady = true; - mUpdateMonitor.registerCallback(mUpdateCallback); - - // Suppress biometric unlock right after boot until things have settled if it is the - // selected security method, otherwise unsuppress it. It must be unsuppressed if it is - // not the selected security method for the following reason: if the user starts - // without a screen lock selected, the biometric unlock would be suppressed the first - // time they try to use it. - // - // Note that the biometric unlock will still not show if it is not the selected method. - // Calling setAlternateUnlockEnabled(true) simply says don't suppress it if it is the - // selected method. - if (mLockPatternUtils.usingBiometricWeak() - && mLockPatternUtils.isBiometricWeakInstalled()) { - if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot"); - mUpdateMonitor.setAlternateUnlockEnabled(false); - } else { - mUpdateMonitor.setAlternateUnlockEnabled(true); - } - - doKeyguardLocked(); - } - // Most services aren't available until the system reaches the ready state, so we - // send it here when the device first boots. - maybeSendUserPresentBroadcast(); - } - - /** - * 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 + ")"); - - mKeyguardDonePending = false; - - // 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(null); - } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT - || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) { - doKeyguardLaterLocked(); - } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) { - // Do not enable the keyguard if the prox sensor forced the screen off. - } else { - doKeyguardLocked(); - } - } - } - - private void doKeyguardLaterLocked() { - // 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, mLockPatternUtils.getCurrentUser()); - - 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); - } - } - - private void cancelDoKeyguardLaterLocked() { - mDelayedShowingSequence++; - } - - /** - * Let's us know the screen was turned on. - */ - public void onScreenTurnedOn(KeyguardViewManager.ShowListener showListener) { - synchronized (this) { - mScreenOn = true; - cancelDoKeyguardLaterLocked(); - if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); - if (showListener != null) { - notifyScreenOnLocked(showListener); - } - } - maybeSendUserPresentBroadcast(); - } - - private void maybeSendUserPresentBroadcast() { - if (mSystemReady && mLockPatternUtils.isLockScreenDisabled() - && mUserManager.getUsers(true).size() == 1) { - // Lock screen is disabled because the user has set the preference to "None". - // In this case, send out ACTION_USER_PRESENT here instead of in - // handleKeyguardDone() - sendUserPresentBroadcast(); - } - } - - /** - * A dream started. We should lock after the usual screen-off lock timeout but only - * if there is a secure lock pattern. - */ - public void onDreamingStarted() { - synchronized (this) { - if (mScreenOn && mLockPatternUtils.isSecure()) { - doKeyguardLaterLocked(); - } - } - } - - /** - * A dream stopped. - */ - public void onDreamingStopped() { - synchronized (this) { - if (mScreenOn) { - cancelDoKeyguardLaterLocked(); - } - } - } - - /** - * 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(null); - } else { - showLocked(null); - - // 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); - mUpdateMonitor.sendKeyguardVisibilityChanged(!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(); - 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(Bundle options) { - mHandler.removeMessages(KEYGUARD_TIMEOUT); - Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT, options); - 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(); - } - - private void doKeyguardLocked() { - doKeyguardLocked(null); - } - - /** - * Enable the keyguard if the settings are appropriate. - */ - private void doKeyguardLocked(Bundle options) { - // 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 (mUserManager.getUsers(true).size() < 2 - && 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(options); - } - - /** - * Dismiss the keyguard through the security layers. - */ - public void dismiss() { - if (mShowing && !mHidden) { - mKeyguardViewManager.dismiss(); - } - } - - /** - * Send message to keyguard telling it to reset its state. - * @param options options about how to show the keyguard - * @see #handleReset() - */ - private void resetStateLocked(Bundle options) { - if (DEBUG) Log.e(TAG, "resetStateLocked"); - Message msg = mHandler.obtainMessage(RESET, options); - 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 wakeWhenReady(int keyCode) { - if (DBG_WAKE) Log.d(TAG, "wakeWhenReady(" + 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(Bundle options) { - if (DEBUG) Log.d(TAG, "showLocked"); - // ensure we stay awake until we are finished displaying the keyguard - mShowKeyguardWakeLock.acquire(); - Message msg = mHandler.obtainMessage(SHOW, options); - 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 mLockPatternUtils.isSecure() - || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure(); - } - - /** - * Update the newUserId. Call while holding WindowManagerService lock. - * NOTE: Should only be called by KeyguardViewMediator in response to the user id changing. - * - * @param newUserId The id of the incoming user. - */ - public void setCurrentUser(int newUserId) { - mLockPatternUtils.setCurrentUser(newUserId); - } - - 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 - */ - public void onWakeKeyWhenKeyguardShowingTq(int keyCode) { - if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")"); - - // 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 - wakeWhenReady(keyCode); - } - - /** - * 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. - */ - public void 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 - wakeWhenReady(KeyEvent.KEYCODE_UNKNOWN); - } - - public void keyguardDone(boolean authenticated, boolean wakeup) { - mKeyguardDonePending = false; - 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.clearFailedUnlockAttempts(); - } - - 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; - } - } - } - } - - /** - * 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(Looper.myLooper(), null, true /*async*/) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case SHOW: - handleShow((Bundle) msg.obj); - return ; - case HIDE: - handleHide(); - return ; - case RESET: - handleReset((Bundle) msg.obj); - 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, true); - return; - case SET_HIDDEN: - handleSetHidden(msg.arg1 != 0); - break; - case KEYGUARD_TIMEOUT: - synchronized (KeyguardViewMediator.this) { - doKeyguardLocked((Bundle) msg.obj); - } - break; - case SHOW_ASSISTANT: - handleShowAssistant(); - break; - } - } - }; - - /** - * @see #keyguardDone - * @see #KEYGUARD_DONE - */ - private void handleKeyguardDone(boolean wakeup) { - if (DEBUG) Log.d(TAG, "handleKeyguardDone"); - handleHide(); - if (wakeup) { - wakeUp(); - } - - sendUserPresentBroadcast(); - } - - private void sendUserPresentBroadcast() { - if (!(mContext instanceof Activity)) { - 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); - } - } - } - - 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(Bundle options) { - synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleShow"); - if (!mSystemReady) return; - - mKeyguardViewManager.show(options); - mShowing = true; - mKeyguardDonePending = false; - updateActivityLockScreenState(); - adjustStatusBarLocked(); - userActivity(); - 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; - mKeyguardDonePending = false; - updateActivityLockScreenState(); - adjustStatusBarLocked(); - } - } - - 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) { - // Permanently disable components not available when keyguard is enabled - // (like recents). Temporary enable/disable (e.g. the "back" button) are - // done in KeyguardHostView. - 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 (!isAssistantAvailable()) { - flags |= StatusBarManager.DISABLE_SEARCH; - } - } - - if (DEBUG) { - Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden - + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags)); - } - - if (!(mContext instanceof Activity)) { - mStatusBarManager.disable(flags); - } - } - } - - /** - * Handle message sent by {@link #wakeWhenReady(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"); - userActivity(); - } - - /** - * Now that the keyguard is ready and has poked the wake lock, we can - * release the handoff wakelock - */ - mWakeAndHandOff.release(); - } - } - - /** - * Handle message sent by {@link #resetStateLocked(Bundle)} - * @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); - } - } - - /** - * Handle message sent by {@link #verifyUnlock} - * @see #VERIFY_UNLOCK - */ - 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); - } - } - - public boolean isDismissable() { - return mKeyguardDonePending || !isSecure(); - } - - public void showAssistant() { - Message msg = mHandler.obtainMessage(SHOW_ASSISTANT); - mHandler.sendMessage(msg); - } - - public void handleShowAssistant() { - mKeyguardViewManager.showAssistant(); - } - - private boolean isAssistantAvailable() { - return mSearchManager != 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 deleted file mode 100644 index 4410063..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java +++ /dev/null @@ -1,317 +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; - -import android.os.Handler; -import android.os.Looper; -import android.view.View; - -public class KeyguardViewStateManager implements - SlidingChallengeLayout.OnChallengeScrolledListener, - ChallengeLayout.OnBouncerStateChangedListener { - - private KeyguardWidgetPager mKeyguardWidgetPager; - private ChallengeLayout mChallengeLayout; - private KeyguardHostView mKeyguardHostView; - private int[] mTmpPoint = new int[2]; - private int[] mTmpLoc = new int[2]; - - private KeyguardSecurityView mKeyguardSecurityContainer; - private static final int SCREEN_ON_HINT_DURATION = 1000; - private static final int SCREEN_ON_RING_HINT_DELAY = 300; - Handler mMainQueue = new Handler(Looper.myLooper()); - - int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE; - - // Paged view state - private int mPageListeningToSlider = -1; - private int mCurrentPage = -1; - private int mPageIndexOnPageBeginMoving = -1; - - int mChallengeTop = 0; - - public KeyguardViewStateManager(KeyguardHostView hostView) { - mKeyguardHostView = hostView; - } - - public void setPagedView(KeyguardWidgetPager pagedView) { - mKeyguardWidgetPager = pagedView; - updateEdgeSwiping(); - } - - public void setChallengeLayout(ChallengeLayout layout) { - mChallengeLayout = layout; - updateEdgeSwiping(); - } - - private void updateEdgeSwiping() { - if (mChallengeLayout != null && mKeyguardWidgetPager != null) { - if (mChallengeLayout.isChallengeOverlapping()) { - mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(true); - } else { - mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(false); - } - } - } - - public boolean isChallengeShowing() { - if (mChallengeLayout != null) { - return mChallengeLayout.isChallengeShowing(); - } - return false; - } - - public boolean isChallengeOverlapping() { - if (mChallengeLayout != null) { - return mChallengeLayout.isChallengeOverlapping(); - } - return false; - } - - public void setSecurityViewContainer(KeyguardSecurityView container) { - mKeyguardSecurityContainer = container; - } - - public void showBouncer(boolean show) { - mChallengeLayout.showBouncer(); - } - - public boolean isBouncing() { - return mChallengeLayout.isBouncing(); - } - - public void fadeOutSecurity(int duration) { - ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration); - } - - public void fadeInSecurity(int duration) { - ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration); - } - - public void onPageBeginMoving() { - if (mChallengeLayout.isChallengeOverlapping() && - mChallengeLayout instanceof SlidingChallengeLayout) { - SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout; - scl.fadeOutChallenge(); - mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage(); - } - // We use mAppWidgetToShow to show a particular widget after you add it-- - // once the user swipes a page we clear that behavior - if (mKeyguardHostView != null) { - mKeyguardHostView.clearAppWidgetToShow(); - mKeyguardHostView.setOnDismissAction(null); - } - if (mHideHintsRunnable != null) { - mMainQueue.removeCallbacks(mHideHintsRunnable); - mHideHintsRunnable = null; - } - } - - public void onPageEndMoving() { - mPageIndexOnPageBeginMoving = -1; - } - - public void onPageSwitching(View newPage, int newPageIndex) { - if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) { - boolean isCameraPage = newPage instanceof CameraWidgetFrame; - ((SlidingChallengeLayout) mChallengeLayout).setChallengeInteractive(!isCameraPage); - } - - // If the page we're settling to is the same as we started on, and the action of - // moving the page hid the security, we restore it immediately. - if (mPageIndexOnPageBeginMoving == mKeyguardWidgetPager.getNextPage() && - mChallengeLayout instanceof SlidingChallengeLayout) { - SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout; - scl.fadeInChallenge(); - mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(-1); - } - mPageIndexOnPageBeginMoving = -1; - } - - public void onPageSwitched(View newPage, int newPageIndex) { - // Reset the previous page size and ensure the current page is sized appropriately. - // We only modify the page state if it is not currently under control by the slider. - // This prevents conflicts. - - // If the page hasn't switched, don't bother with any of this - if (mCurrentPage == newPageIndex) return; - - if (mKeyguardWidgetPager != null && mChallengeLayout != null) { - KeyguardWidgetFrame prevPage = mKeyguardWidgetPager.getWidgetPageAt(mCurrentPage); - if (prevPage != null && mCurrentPage != mPageListeningToSlider && mCurrentPage - != mKeyguardWidgetPager.getWidgetToResetOnPageFadeOut()) { - prevPage.resetSize(); - } - - KeyguardWidgetFrame newCurPage = mKeyguardWidgetPager.getWidgetPageAt(newPageIndex); - boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping(); - if (challengeOverlapping && !newCurPage.isSmall() - && mPageListeningToSlider != newPageIndex) { - newCurPage.shrinkWidget(); - } - } - - mCurrentPage = newPageIndex; - } - - private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) { - mTmpPoint[0] = 0; - mTmpPoint[1] = top; - mapPoint((View) mChallengeLayout, frame, mTmpPoint); - return mTmpPoint[1]; - } - - /** - * Simple method to map a point from one view's coordinates to another's. Note: this method - * doesn't account for transforms, so if the views will be transformed, this should not be used. - * - * @param fromView The view to which the point is relative - * @param toView The view into which the point should be mapped - * @param pt The point - */ - private void mapPoint(View fromView, View toView, int pt[]) { - fromView.getLocationInWindow(mTmpLoc); - - int x = mTmpLoc[0]; - int y = mTmpLoc[1]; - - toView.getLocationInWindow(mTmpLoc); - int vX = mTmpLoc[0]; - int vY = mTmpLoc[1]; - - pt[0] += x - vX; - pt[1] += y - vY; - } - - private void userActivity() { - if (mKeyguardHostView != null) { - mKeyguardHostView.onUserActivityTimeoutChanged(); - mKeyguardHostView.userActivity(); - } - } - - @Override - public void onScrollStateChanged(int scrollState) { - if (mKeyguardWidgetPager == null || mChallengeLayout == null) return; - - boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping(); - - if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) { - KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider); - if (frame == null) return; - - if (!challengeOverlapping) { - if (!mKeyguardWidgetPager.isPageMoving()) { - frame.resetSize(); - userActivity(); - } else { - mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider); - } - } - if (frame.isSmall()) { - // This is to make sure that if the scroller animation gets cut off midway - // that the frame doesn't stay in a partial down position. - frame.setFrameHeight(frame.getSmallFrameHeight()); - } - if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) { - frame.hideFrame(this); - } - updateEdgeSwiping(); - - if (mChallengeLayout.isChallengeShowing()) { - mKeyguardSecurityContainer.onResume(KeyguardSecurityView.VIEW_REVEALED); - } else { - mKeyguardSecurityContainer.onPause(); - } - mPageListeningToSlider = -1; - } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) { - // Whether dragging or settling, if the last state was idle, we use this signal - // to update the current page who will receive events from the sliding challenge. - // We resize the frame as appropriate. - mPageListeningToSlider = mKeyguardWidgetPager.getNextPage(); - KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider); - if (frame == null) return; - - // Skip showing the frame and shrinking the widget if we are - if (!mChallengeLayout.isBouncing()) { - if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) { - frame.showFrame(this); - } - - // As soon as the security begins sliding, the widget becomes small (if it wasn't - // small to begin with). - if (!frame.isSmall()) { - // We need to fetch the final page, in case the pages are in motion. - mPageListeningToSlider = mKeyguardWidgetPager.getNextPage(); - frame.shrinkWidget(false); - } - } else { - if (!frame.isSmall()) { - // We need to fetch the final page, in case the pages are in motion. - mPageListeningToSlider = mKeyguardWidgetPager.getNextPage(); - } - } - - // View is on the move. Pause the security view until it completes. - mKeyguardSecurityContainer.onPause(); - } - mLastScrollState = scrollState; - } - - @Override - public void onScrollPositionChanged(float scrollPosition, int challengeTop) { - mChallengeTop = challengeTop; - KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider); - if (frame != null && mLastScrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) { - frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop)); - } - } - - private Runnable mHideHintsRunnable = new Runnable() { - @Override - public void run() { - if (mKeyguardWidgetPager != null) { - mKeyguardWidgetPager.hideOutlinesAndSidePages(); - } - } - }; - - public void showUsabilityHints() { - mMainQueue.postDelayed( new Runnable() { - @Override - public void run() { - mKeyguardSecurityContainer.showUsabilityHint(); - } - } , SCREEN_ON_RING_HINT_DELAY); - mKeyguardWidgetPager.showInitialPageHints(); - if (mHideHintsRunnable != null) { - mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION); - } - } - - // ChallengeLayout.OnBouncerStateChangedListener - @Override - public void onBouncerStateChanged(boolean bouncerActive) { - if (bouncerActive) { - mKeyguardWidgetPager.zoomOutToBouncer(); - } else { - mKeyguardWidgetPager.zoomInFromBouncer(); - if (mKeyguardHostView != null) { - mKeyguardHostView.setOnDismissAction(null); - } - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java deleted file mode 100644 index 257fd27..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java +++ /dev/null @@ -1,290 +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; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import com.android.internal.R; - -import java.util.ArrayList; - -public class KeyguardWidgetCarousel extends KeyguardWidgetPager { - - private float mAdjacentPagesAngle; - private static float MAX_SCROLL_PROGRESS = 1.3f; - private static float CAMERA_DISTANCE = 10000; - protected AnimatorSet mChildrenTransformsAnimator; - float[] mTmpTransform = new float[3]; - - public KeyguardWidgetCarousel(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardWidgetCarousel(Context context) { - this(context, null, 0); - } - - public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle); - } - - protected float getMaxScrollProgress() { - return MAX_SCROLL_PROGRESS; - } - - public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) { - View child = getChildAt(index); - if (child == null) return 0f; - - boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1; - float scrollProgress = getScrollProgress(screenCenter, child, index); - - if (isOverScrollChild(index, scrollProgress)) { - return 1.0f; - } else if ((showSidePages && inVisibleRange) || index == getNextPage()) { - scrollProgress = getBoundedScrollProgress(screenCenter, child, index); - float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS); - return alpha; - } else { - return 0f; - } - } - - public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) { - boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1; - if (inVisibleRange) { - return super.getOutlineAlphaForPage(screenCenter, index, showSidePages); - } else { - return 0f; - } - } - - private void updatePageAlphaValues(int screenCenter) { - if (mChildrenOutlineFadeAnimation != null) { - mChildrenOutlineFadeAnimation.cancel(); - mChildrenOutlineFadeAnimation = null; - } - boolean showSidePages = mShowingInitialHints || isPageMoving(); - if (!isReordering(false)) { - for (int i = 0; i < getChildCount(); i++) { - KeyguardWidgetFrame child = getWidgetPageAt(i); - if (child != null) { - float outlineAlpha = getOutlineAlphaForPage(screenCenter, i, showSidePages); - float contentAlpha = getAlphaForPage(screenCenter, i,showSidePages); - child.setBackgroundAlpha(outlineAlpha); - child.setContentAlpha(contentAlpha); - } - } - } - } - - public void showInitialPageHints() { - mShowingInitialHints = true; - int count = getChildCount(); - for (int i = 0; i < count; i++) { - boolean inVisibleRange = i >= getNextPage() - 1 && i <= getNextPage() + 1; - KeyguardWidgetFrame child = getWidgetPageAt(i); - if (inVisibleRange) { - child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); - child.setContentAlpha(1f); - } else { - child.setBackgroundAlpha(0f); - child.setContentAlpha(0f); - } - } - } - - @Override - protected void screenScrolled(int screenCenter) { - mScreenCenter = screenCenter; - updatePageAlphaValues(screenCenter); - if (isReordering(false)) return; - for (int i = 0; i < getChildCount(); i++) { - KeyguardWidgetFrame v = getWidgetPageAt(i); - float scrollProgress = getScrollProgress(screenCenter, v, i); - float boundedProgress = getBoundedScrollProgress(screenCenter, v, i); - if (v == mDragView || v == null) continue; - v.setCameraDistance(CAMERA_DISTANCE); - - if (isOverScrollChild(i, scrollProgress)) { - v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress); - v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0); - } else { - int width = v.getMeasuredWidth(); - float pivotX = (width / 2f) + boundedProgress * (width / 2f); - float pivotY = v.getMeasuredHeight() / 2; - float rotationY = - mAdjacentPagesAngle * boundedProgress; - v.setPivotX(pivotX); - v.setPivotY(pivotY); - v.setRotationY(rotationY); - v.setOverScrollAmount(0f, false); - } - float alpha = v.getAlpha(); - // If the view has 0 alpha, we set it to be invisible so as to prevent - // it from accepting touches - if (alpha == 0) { - v.setVisibility(INVISIBLE); - } else if (v.getVisibility() != VISIBLE) { - v.setVisibility(VISIBLE); - } - } - } - - void animatePagesToNeutral() { - if (mChildrenTransformsAnimator != null) { - mChildrenTransformsAnimator.cancel(); - mChildrenTransformsAnimator = null; - } - - int count = getChildCount(); - PropertyValuesHolder alpha; - PropertyValuesHolder outlineAlpha; - PropertyValuesHolder rotationY; - ArrayList<Animator> anims = new ArrayList<Animator>(); - - for (int i = 0; i < count; i++) { - KeyguardWidgetFrame child = getWidgetPageAt(i); - boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1); - if (!inVisibleRange) { - child.setRotationY(0f); - } - alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f); - outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", - KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); - rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f); - ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY); - child.setVisibility(VISIBLE); - if (!inVisibleRange) { - a.setInterpolator(mSlowFadeInterpolator); - } - anims.add(a); - } - - int duration = REORDERING_ZOOM_IN_OUT_DURATION; - mChildrenTransformsAnimator = new AnimatorSet(); - mChildrenTransformsAnimator.playTogether(anims); - - mChildrenTransformsAnimator.setDuration(duration); - mChildrenTransformsAnimator.start(); - } - - private void getTransformForPage(int screenCenter, int index, float[] transform) { - View child = getChildAt(index); - float boundedProgress = getBoundedScrollProgress(screenCenter, child, index); - float rotationY = - mAdjacentPagesAngle * boundedProgress; - int width = child.getMeasuredWidth(); - float pivotX = (width / 2f) + boundedProgress * (width / 2f); - float pivotY = child.getMeasuredHeight() / 2; - - transform[0] = pivotX; - transform[1] = pivotY; - transform[2] = rotationY; - } - - Interpolator mFastFadeInterpolator = new Interpolator() { - Interpolator mInternal = new DecelerateInterpolator(1.5f); - float mFactor = 2.5f; - @Override - public float getInterpolation(float input) { - return mInternal.getInterpolation(Math.min(mFactor * input, 1f)); - } - }; - - Interpolator mSlowFadeInterpolator = new Interpolator() { - Interpolator mInternal = new AccelerateInterpolator(1.5f); - float mFactor = 1.3f; - @Override - public float getInterpolation(float input) { - input -= (1 - 1 / mFactor); - input = mFactor * Math.max(input, 0f); - return mInternal.getInterpolation(input); - } - }; - - void animatePagesToCarousel() { - if (mChildrenTransformsAnimator != null) { - mChildrenTransformsAnimator.cancel(); - mChildrenTransformsAnimator = null; - } - - int count = getChildCount(); - PropertyValuesHolder alpha; - PropertyValuesHolder outlineAlpha; - PropertyValuesHolder rotationY; - PropertyValuesHolder pivotX; - PropertyValuesHolder pivotY; - ArrayList<Animator> anims = new ArrayList<Animator>(); - - for (int i = 0; i < count; i++) { - KeyguardWidgetFrame child = getWidgetPageAt(i); - float finalAlpha = getAlphaForPage(mScreenCenter, i, true); - float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i, true); - getTransformForPage(mScreenCenter, i, mTmpTransform); - - boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1); - - ObjectAnimator a; - alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha); - outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha); - pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]); - pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]); - rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]); - - if (inVisibleRange) { - // for the central pages we animate into a rotated state - a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, - pivotX, pivotY, rotationY); - } else { - a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha); - a.setInterpolator(mFastFadeInterpolator); - } - anims.add(a); - } - - int duration = REORDERING_ZOOM_IN_OUT_DURATION; - mChildrenTransformsAnimator = new AnimatorSet(); - mChildrenTransformsAnimator.playTogether(anims); - - mChildrenTransformsAnimator.setDuration(duration); - mChildrenTransformsAnimator.start(); - } - - protected void reorderStarting() { - mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION); - animatePagesToNeutral(); - } - - protected boolean zoomIn(final Runnable onCompleteRunnable) { - animatePagesToCarousel(); - return super.zoomIn(onCompleteRunnable); - } - - @Override - protected void onEndReordering() { - super.onEndReordering(); - mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION); - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java deleted file mode 100644 index babb9cb..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java +++ /dev/null @@ -1,529 +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; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetManager; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.Shader; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.widget.FrameLayout; - -import com.android.internal.R; - -public class KeyguardWidgetFrame extends FrameLayout { - private final static PorterDuffXfermode sAddBlendMode = - new PorterDuffXfermode(PorterDuff.Mode.ADD); - - static final float OUTLINE_ALPHA_MULTIPLIER = 0.6f; - static final int HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR = 0x99FF0000; - - // Temporarily disable this for the time being until we know why the gfx is messing up - static final boolean ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY = true; - - private int mGradientColor; - private LinearGradient mForegroundGradient; - private LinearGradient mLeftToRightGradient; - private LinearGradient mRightToLeftGradient; - private Paint mGradientPaint = new Paint(); - boolean mLeftToRight = true; - - private float mOverScrollAmount = 0f; - private final Rect mForegroundRect = new Rect(); - private int mForegroundAlpha = 0; - private CheckLongPressHelper mLongPressHelper; - private Animator mFrameFade; - private boolean mIsSmall = false; - private Handler mWorkerHandler; - - private float mBackgroundAlpha; - private float mContentAlpha; - private float mBackgroundAlphaMultiplier = 1.0f; - private Drawable mBackgroundDrawable; - private Rect mBackgroundRect = new Rect(); - - // These variables are all needed in order to size things properly before we're actually - // measured. - private int mSmallWidgetHeight; - private int mSmallFrameHeight; - private boolean mWidgetLockedSmall = false; - private int mMaxChallengeTop = -1; - private int mFrameStrokeAdjustment; - private boolean mPerformAppWidgetSizeUpdateOnBootComplete; - - // This will hold the width value before we've actually been measured - private int mFrameHeight; - - private boolean mIsHoveringOverDeleteDropTarget; - - // Multiple callers may try and adjust the alpha of the frame. When a caller shows - // the outlines, we give that caller control, and nobody else can fade them out. - // This prevents animation conflicts. - private Object mBgAlphaController; - - public KeyguardWidgetFrame(Context context) { - this(context, null, 0); - } - - public KeyguardWidgetFrame(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardWidgetFrame(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mLongPressHelper = new CheckLongPressHelper(this); - - Resources res = context.getResources(); - // TODO: this padding should really correspond to the padding embedded in the background - // drawable (ie. outlines). - float density = res.getDisplayMetrics().density; - int padding = (int) (res.getDisplayMetrics().density * 8); - setPadding(padding, padding, padding, padding); - - mFrameStrokeAdjustment = 2 + (int) (2 * density); - - // This will be overriden on phones based on the current security mode, however on tablets - // we need to specify a height. - mSmallWidgetHeight = - res.getDimensionPixelSize(com.android.internal.R.dimen.kg_small_widget_height); - mBackgroundDrawable = res.getDrawable(R.drawable.kg_widget_bg_padded); - mGradientColor = res.getColor(com.android.internal.R.color.kg_widget_pager_gradient); - mGradientPaint.setXfermode(sAddBlendMode); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - cancelLongPress(); - KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks); - - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks); - } - - private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks = - new KeyguardUpdateMonitorCallback() { - @Override - public void onBootCompleted() { - if (mPerformAppWidgetSizeUpdateOnBootComplete) { - performAppWidgetSizeCallbacksIfNecessary(); - mPerformAppWidgetSizeUpdateOnBootComplete = false; - } - } - }; - - void setIsHoveringOverDeleteDropTarget(boolean isHovering) { - if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) { - if (mIsHoveringOverDeleteDropTarget != isHovering) { - mIsHoveringOverDeleteDropTarget = isHovering; - invalidate(); - } - } - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - // Watch for longpress events at this level to make sure - // users can always pick up this widget - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - mLongPressHelper.postCheckForLongPress(ev); - break; - case MotionEvent.ACTION_MOVE: - mLongPressHelper.onMove(ev); - break; - case MotionEvent.ACTION_POINTER_DOWN: - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mLongPressHelper.cancelLongPress(); - break; - } - - // Otherwise continue letting touch events fall through to children - return false; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - // Watch for longpress events at this level to make sure - // users can always pick up this widget - switch (ev.getAction()) { - case MotionEvent.ACTION_MOVE: - mLongPressHelper.onMove(ev); - break; - case MotionEvent.ACTION_POINTER_DOWN: - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mLongPressHelper.cancelLongPress(); - break; - } - - // We return true here to ensure that we will get cancel / up signal - // even if none of our children have requested touch. - return true; - } - - @Override - public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { - super.requestDisallowInterceptTouchEvent(disallowIntercept); - cancelLongPress(); - } - - @Override - public void cancelLongPress() { - super.cancelLongPress(); - mLongPressHelper.cancelLongPress(); - } - - - private void drawGradientOverlay(Canvas c) { - mGradientPaint.setShader(mForegroundGradient); - mGradientPaint.setAlpha(mForegroundAlpha); - c.drawRect(mForegroundRect, mGradientPaint); - } - - private void drawHoveringOverDeleteOverlay(Canvas c) { - if (mIsHoveringOverDeleteDropTarget) { - c.drawColor(HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR); - } - } - - protected void drawBg(Canvas canvas) { - if (mBackgroundAlpha > 0.0f) { - Drawable bg = mBackgroundDrawable; - - bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); - bg.setBounds(mBackgroundRect); - bg.draw(canvas); - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) { - canvas.save(); - } - drawBg(canvas); - super.dispatchDraw(canvas); - drawGradientOverlay(canvas); - if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) { - drawHoveringOverDeleteOverlay(canvas); - canvas.restore(); - } - } - - /** - * Because this view has fading outlines, it is essential that we enable hardware - * layers on the content (child) so that updating the alpha of the outlines doesn't - * result in the content layer being recreated. - */ - public void enableHardwareLayersForContent() { - View widget = getContent(); - if (widget != null) { - widget.setLayerType(LAYER_TYPE_HARDWARE, null); - } - } - - /** - * Because this view has fading outlines, it is essential that we enable hardware - * layers on the content (child) so that updating the alpha of the outlines doesn't - * result in the content layer being recreated. - */ - public void disableHardwareLayersForContent() { - View widget = getContent(); - if (widget != null) { - widget.setLayerType(LAYER_TYPE_NONE, null); - } - } - - public void enableHardwareLayers() { - setLayerType(LAYER_TYPE_HARDWARE, null); - } - - public void disableHardwareLayers() { - setLayerType(LAYER_TYPE_NONE, null); - } - - public View getContent() { - return getChildAt(0); - } - - public int getContentAppWidgetId() { - View content = getContent(); - if (content instanceof AppWidgetHostView) { - return ((AppWidgetHostView) content).getAppWidgetId(); - } else if (content instanceof KeyguardStatusView) { - return ((KeyguardStatusView) content).getAppWidgetId(); - } else { - return AppWidgetManager.INVALID_APPWIDGET_ID; - } - } - - public float getBackgroundAlpha() { - return mBackgroundAlpha; - } - - public void setBackgroundAlphaMultiplier(float multiplier) { - if (Float.compare(mBackgroundAlphaMultiplier, multiplier) != 0) { - mBackgroundAlphaMultiplier = multiplier; - invalidate(); - } - } - - public float getBackgroundAlphaMultiplier() { - return mBackgroundAlphaMultiplier; - } - - public void setBackgroundAlpha(float alpha) { - if (Float.compare(mBackgroundAlpha, alpha) != 0) { - mBackgroundAlpha = alpha; - invalidate(); - } - } - - public float getContentAlpha() { - return mContentAlpha; - } - - public void setContentAlpha(float alpha) { - mContentAlpha = alpha; - View content = getContent(); - if (content != null) { - content.setAlpha(alpha); - } - } - - /** - * Depending on whether the security is up, the widget size needs to change - * - * @param height The height of the widget, -1 for full height - */ - private void setWidgetHeight(int height) { - boolean needLayout = false; - View widget = getContent(); - if (widget != null) { - LayoutParams lp = (LayoutParams) widget.getLayoutParams(); - if (lp.height != height) { - needLayout = true; - lp.height = height; - } - } - if (needLayout) { - requestLayout(); - } - } - - public void setMaxChallengeTop(int top) { - boolean dirty = mMaxChallengeTop != top; - mMaxChallengeTop = top; - mSmallWidgetHeight = top - getPaddingTop(); - mSmallFrameHeight = top + getPaddingBottom(); - if (dirty && mIsSmall) { - setWidgetHeight(mSmallWidgetHeight); - setFrameHeight(mSmallFrameHeight); - } else if (dirty && mWidgetLockedSmall) { - setWidgetHeight(mSmallWidgetHeight); - } - } - - public boolean isSmall() { - return mIsSmall; - } - - public void adjustFrame(int challengeTop) { - int frameHeight = challengeTop + getPaddingBottom(); - setFrameHeight(frameHeight); - } - - public void shrinkWidget(boolean alsoShrinkFrame) { - mIsSmall = true; - setWidgetHeight(mSmallWidgetHeight); - - if (alsoShrinkFrame) { - setFrameHeight(mSmallFrameHeight); - } - } - - public int getSmallFrameHeight() { - return mSmallFrameHeight; - } - - public void shrinkWidget() { - shrinkWidget(true); - } - - public void setWidgetLockedSmall(boolean locked) { - if (locked) { - setWidgetHeight(mSmallWidgetHeight); - } - mWidgetLockedSmall = locked; - } - - public void resetSize() { - mIsSmall = false; - if (!mWidgetLockedSmall) { - setWidgetHeight(LayoutParams.MATCH_PARENT); - } - setFrameHeight(getMeasuredHeight()); - } - - public void setFrameHeight(int height) { - mFrameHeight = height; - mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(mFrameHeight, getMeasuredHeight())); - mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment,getMeasuredWidth() - - mFrameStrokeAdjustment, Math.min(getMeasuredHeight(), mFrameHeight) - - mFrameStrokeAdjustment); - updateGradient(); - invalidate(); - } - - public void hideFrame(Object caller) { - fadeFrame(caller, false, 0f, KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_OUT_DURATION); - } - - public void showFrame(Object caller) { - fadeFrame(caller, true, OUTLINE_ALPHA_MULTIPLIER, - KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_IN_DURATION); - } - - public void fadeFrame(Object caller, boolean takeControl, float alpha, int duration) { - if (takeControl) { - mBgAlphaController = caller; - } - - if (mBgAlphaController != caller && mBgAlphaController != null) { - return; - } - - if (mFrameFade != null) { - mFrameFade.cancel(); - mFrameFade = null; - } - PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", alpha); - mFrameFade = ObjectAnimator.ofPropertyValuesHolder(this, bgAlpha); - mFrameFade.setDuration(duration); - mFrameFade.start(); - } - - private void updateGradient() { - float x0 = mLeftToRight ? 0 : mForegroundRect.width(); - float x1 = mLeftToRight ? mForegroundRect.width(): 0; - mLeftToRightGradient = new LinearGradient(x0, 0f, x1, 0f, - mGradientColor, 0, Shader.TileMode.CLAMP); - mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f, - mGradientColor, 0, Shader.TileMode.CLAMP); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - if (!mIsSmall) { - mFrameHeight = h; - } - - // mFrameStrokeAdjustment is a cludge to prevent the overlay from drawing outside the - // rounded rect background. - mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment, - w - mFrameStrokeAdjustment, Math.min(h, mFrameHeight) - mFrameStrokeAdjustment); - - mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(h, mFrameHeight)); - updateGradient(); - invalidate(); - } - - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - performAppWidgetSizeCallbacksIfNecessary(); - } - - private void performAppWidgetSizeCallbacksIfNecessary() { - View content = getContent(); - if (!(content instanceof AppWidgetHostView)) return; - - if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) { - mPerformAppWidgetSizeUpdateOnBootComplete = true; - return; - } - - // TODO: there's no reason to force the AppWidgetHostView to catch duplicate size calls. - // We can do that even more cheaply here. It's not an issue right now since we're in the - // system process and hence no binder calls. - AppWidgetHostView awhv = (AppWidgetHostView) content; - float density = getResources().getDisplayMetrics().density; - - int width = (int) (content.getMeasuredWidth() / density); - int height = (int) (content.getMeasuredHeight() / density); - awhv.updateAppWidgetSize(null, width, height, width, height, true); - } - - void setOverScrollAmount(float r, boolean left) { - if (Float.compare(mOverScrollAmount, r) != 0) { - mOverScrollAmount = r; - mForegroundGradient = left ? mLeftToRightGradient : mRightToLeftGradient; - mForegroundAlpha = (int) Math.round((0.5f * r * 255)); - - // We bump up the alpha of the outline to hide the fact that the overlay is drawing - // over the rounded part of the frame. - float bgAlpha = Math.min(OUTLINE_ALPHA_MULTIPLIER + r * (1 - OUTLINE_ALPHA_MULTIPLIER), - 1f); - setBackgroundAlpha(bgAlpha); - invalidate(); - } - } - - public void onActive(boolean isActive) { - // hook for subclasses - } - - public boolean onUserInteraction(MotionEvent event) { - // hook for subclasses - return false; - } - - public void onBouncerShowing(boolean showing) { - // hook for subclasses - } - - public void setWorkerHandler(Handler workerHandler) { - mWorkerHandler = workerHandler; - } - - public Handler getWorkerHandler() { - return mWorkerHandler; - } - -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java deleted file mode 100644 index 770fafc..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java +++ /dev/null @@ -1,926 +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; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.animation.TimeInterpolator; -import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetManager; -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; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnLongClickListener; -import android.view.ViewGroup; -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 { - - ZInterpolator mZInterpolator = new ZInterpolator(0.5f); - private static float CAMERA_DISTANCE = 10000; - 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; - - // Related to the fading in / out background outlines - public static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375; - public static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100; - protected AnimatorSet mChildrenOutlineFadeAnimation; - protected int mScreenCenter; - private boolean mHasMeasure = false; - boolean showHintsAfterLayout = false; - - private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000; - private static final String TAG = "KeyguardWidgetPager"; - private boolean mCenterSmallWidgetsVertically; - - private int mPage = 0; - private Callbacks mCallbacks; - - private int mWidgetToResetAfterFadeOut; - protected boolean mShowingInitialHints = false; - - // A temporary handle to the Add-Widget view - private View mAddWidgetView; - private int mLastWidthMeasureSpec; - private int mLastHeightMeasureSpec; - - // Bouncer - private int mBouncerZoomInOutDuration = 250; - private float BOUNCER_SCALE_FACTOR = 0.67f; - - // Background worker thread: used here for persistence, also made available to widget frames - private final HandlerThread mBackgroundWorkerThread; - private final Handler mBackgroundWorkerHandler; - - public KeyguardWidgetPager(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardWidgetPager(Context context) { - this(null, null, 0); - } - - public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); - } - - setPageSwitchListener(this); - - mBackgroundWorkerThread = new HandlerThread("KeyguardWidgetPager Worker"); - mBackgroundWorkerThread.start(); - mBackgroundWorkerHandler = new Handler(mBackgroundWorkerThread.getLooper()); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - // Clean up the worker thread - mBackgroundWorkerThread.quit(); - } - - public void setViewStateManager(KeyguardViewStateManager viewStateManager) { - mViewStateManager = viewStateManager; - } - - public void setLockPatternUtils(LockPatternUtils l) { - mLockPatternUtils = l; - } - - @Override - public void onPageSwitching(View newPage, int newPageIndex) { - if (mViewStateManager != null) { - mViewStateManager.onPageSwitching(newPage, newPageIndex); - } - } - - @Override - public void onPageSwitched(View newPage, int newPageIndex) { - boolean showingClock = false; - if (newPage instanceof ViewGroup) { - ViewGroup vg = (ViewGroup) newPage; - if (vg.getChildAt(0) instanceof KeyguardStatusView) { - 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 (showingClock) { - setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK); - } else { - setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK); - } - - // Extend the display timeout if the user switches pages - if (mPage != newPageIndex) { - int oldPageIndex = mPage; - mPage = newPageIndex; - userActivity(); - KeyguardWidgetFrame oldWidgetPage = getWidgetPageAt(oldPageIndex); - if (oldWidgetPage != null) { - oldWidgetPage.onActive(false); - } - 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()) { - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_VIEW_SCROLLED); - onInitializeAccessibilityEvent(event); - onPopulateAccessibilityEvent(event); - mParent.requestSendAccessibilityEvent(this, event); - } - } - if (mViewStateManager != null) { - mViewStateManager.onPageSwitched(newPage, newPageIndex); - } - } - - @Override - public void sendAccessibilityEvent(int eventType) { - if (eventType != AccessibilityEvent.TYPE_VIEW_SCROLLED || isPageMoving()) { - super.sendAccessibilityEvent(eventType); - } - } - - private void updateWidgetFramesImportantForAccessibility() { - final int pageCount = getPageCount(); - for (int i = 0; i < pageCount; i++) { - KeyguardWidgetFrame frame = getWidgetPageAt(i); - updateWidgetFrameImportantForAccessibility(frame); - } - } - - private void updateWidgetFrameImportantForAccessibility(KeyguardWidgetFrame frame) { - if (frame.getContentAlpha() <= 0) { - frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - } else { - frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); - } - } - - private void userActivity() { - if (mCallbacks != null) { - mCallbacks.onUserActivityTimeoutChanged(); - mCallbacks.userActivity(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - return captureUserInteraction(ev) || super.onTouchEvent(ev); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - return captureUserInteraction(ev) || super.onInterceptTouchEvent(ev); - } - - private boolean captureUserInteraction(MotionEvent ev) { - KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage()); - return currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev); - } - - public void showPagingFeedback() { - // Nothing yet. - } - - public long getUserActivityTimeout() { - View page = getPageAt(mPage); - if (page instanceof ViewGroup) { - ViewGroup vg = (ViewGroup) page; - View view = vg.getChildAt(0); - if (!(view instanceof KeyguardStatusView) - && !(view instanceof KeyguardMultiUserSelectorView)) { - return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT; - } - } - return -1; - } - - public void setCallbacks(Callbacks callbacks) { - mCallbacks = callbacks; - } - - public interface Callbacks { - public void userActivity(); - public void onUserActivityTimeoutChanged(); - public void onAddView(View v); - public void onRemoveView(View v, boolean deletePermanently); - public void onRemoveViewAnimationCompleted(); - } - - public void addWidget(View widget) { - addWidget(widget, -1); - } - - public void onRemoveView(View v, final boolean deletePermanently) { - final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); - if (mCallbacks != null) { - mCallbacks.onRemoveView(v, deletePermanently); - } - mBackgroundWorkerHandler.post(new Runnable() { - @Override - public void run() { - mLockPatternUtils.removeAppWidget(appWidgetId); - } - }); - } - - @Override - public void onRemoveViewAnimationCompleted() { - if (mCallbacks != null) { - mCallbacks.onRemoveViewAnimationCompleted(); - } - } - - public void onAddView(View v, final int index) { - final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); - final int[] pagesRange = new int[mTempVisiblePagesRange.length]; - getVisiblePages(pagesRange); - boundByReorderablePages(true, pagesRange); - if (mCallbacks != null) { - mCallbacks.onAddView(v); - } - // Subtract from the index to take into account pages before the reorderable - // pages (e.g. the "add widget" page) - mBackgroundWorkerHandler.post(new Runnable() { - @Override - public void run() { - mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]); - } - }); - } - - /* - * We wrap widgets in a special frame which handles drawing the over scroll foreground. - */ - public void addWidget(View widget, int pageIndex) { - KeyguardWidgetFrame frame; - // All views contained herein should be wrapped in a KeyguardWidgetFrame - if (!(widget instanceof KeyguardWidgetFrame)) { - frame = new KeyguardWidgetFrame(getContext()); - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT); - lp.gravity = Gravity.TOP; - - // The framework adds a default padding to AppWidgetHostView. We don't need this padding - // for the Keyguard, so we override it to be 0. - widget.setPadding(0, 0, 0, 0); - frame.addView(widget, lp); - - // We set whether or not this widget supports vertical resizing. - if (widget instanceof AppWidgetHostView) { - AppWidgetHostView awhv = (AppWidgetHostView) widget; - AppWidgetProviderInfo info = awhv.getAppWidgetInfo(); - if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) { - frame.setWidgetLockedSmall(false); - } else { - // Lock the widget to be small. - frame.setWidgetLockedSmall(true); - if (mCenterSmallWidgetsVertically) { - lp.gravity = Gravity.CENTER; - } - } - } - } else { - frame = (KeyguardWidgetFrame) widget; - } - - ViewGroup.LayoutParams pageLp = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - frame.setOnLongClickListener(this); - frame.setWorkerHandler(mBackgroundWorkerHandler); - - if (pageIndex == -1) { - addView(frame, pageLp); - } else { - addView(frame, pageIndex, pageLp); - } - - // Update the frame content description. - View content = (widget == frame) ? frame.getContent() : widget; - if (content != null) { - String contentDescription = mContext.getString( - com.android.internal.R.string.keyguard_accessibility_widget, - content.getContentDescription()); - frame.setContentDescription(contentDescription); - } - updateWidgetFrameImportantForAccessibility(frame); - } - - /** - * Use addWidget() instead. - * @deprecated - */ - @Override - public void addView(View child, int index) { - enforceKeyguardWidgetFrame(child); - super.addView(child, index); - } - - /** - * Use addWidget() instead. - * @deprecated - */ - @Override - public void addView(View child, int width, int height) { - enforceKeyguardWidgetFrame(child); - super.addView(child, width, height); - } - - /** - * Use addWidget() instead. - * @deprecated - */ - @Override - public void addView(View child, LayoutParams params) { - enforceKeyguardWidgetFrame(child); - super.addView(child, params); - } - - /** - * Use addWidget() instead. - * @deprecated - */ - @Override - public void addView(View child, int index, LayoutParams params) { - enforceKeyguardWidgetFrame(child); - super.addView(child, index, params); - } - - private void enforceKeyguardWidgetFrame(View child) { - if (!(child instanceof KeyguardWidgetFrame)) { - throw new IllegalArgumentException( - "KeyguardWidgetPager children must be KeyguardWidgetFrames"); - } - } - - public KeyguardWidgetFrame getWidgetPageAt(int index) { - // This is always a valid cast as we've guarded the ability to - return (KeyguardWidgetFrame) getChildAt(index); - } - - protected void onUnhandledTap(MotionEvent ev) { - showPagingFeedback(); - } - - @Override - protected void onPageBeginMoving() { - if (mViewStateManager != null) { - mViewStateManager.onPageBeginMoving(); - } - if (!isReordering(false)) { - showOutlinesAndSidePages(); - } - userActivity(); - } - - @Override - protected void onPageEndMoving() { - if (mViewStateManager != null) { - mViewStateManager.onPageEndMoving(); - } - - // In the reordering case, the pages will be faded appropriately on completion - // of the zoom in animation. - if (!isReordering(false)) { - hideOutlinesAndSidePages(); - } - } - - protected void enablePageContentLayers() { - int children = getChildCount(); - for (int i = 0; i < children; i++) { - getWidgetPageAt(i).enableHardwareLayersForContent(); - } - } - - protected void disablePageContentLayers() { - int children = getChildCount(); - for (int i = 0; i < children; i++) { - getWidgetPageAt(i).disableHardwareLayersForContent(); - } - } - - /* - * This interpolator emulates the rate at which the perceived scale of an object changes - * as its distance from a camera increases. When this interpolator is applied to a scale - * animation on a view, it evokes the sense that the object is shrinking due to moving away - * from the camera. - */ - static class ZInterpolator implements TimeInterpolator { - private float focalLength; - - public ZInterpolator(float foc) { - focalLength = foc; - } - - public float getInterpolation(float input) { - return (1.0f - focalLength / (focalLength + input)) / - (1.0f - focalLength / (focalLength + 1.0f)); - } - } - - @Override - protected void overScroll(float amount) { - acceleratedOverScroll(amount); - } - - float backgroundAlphaInterpolator(float r) { - return Math.min(1f, r); - } - - private void updatePageAlphaValues(int screenCenter) { - } - - public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) { - if (showSidePages) { - return 1f; - } else { - return index == mCurrentPage ? 1.0f : 0f; - } - } - - public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) { - if (showSidePages) { - return getAlphaForPage(screenCenter, index, showSidePages) - * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER; - } else { - return 0f; - } - } - - protected boolean isOverScrollChild(int index, float scrollProgress) { - boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; - return (isInOverscroll && (index == 0 && scrollProgress < 0 || - index == getChildCount() - 1 && scrollProgress > 0)); - } - - @Override - protected void screenScrolled(int screenCenter) { - mScreenCenter = screenCenter; - updatePageAlphaValues(screenCenter); - for (int i = 0; i < getChildCount(); i++) { - KeyguardWidgetFrame v = getWidgetPageAt(i); - if (v == mDragView) continue; - if (v != null) { - float scrollProgress = getScrollProgress(screenCenter, v, i); - - v.setCameraDistance(mDensity * CAMERA_DISTANCE); - - if (isOverScrollChild(i, scrollProgress) && PERFORM_OVERSCROLL_ROTATION) { - float pivotX = v.getMeasuredWidth() / 2; - float pivotY = v.getMeasuredHeight() / 2; - v.setPivotX(pivotX); - v.setPivotY(pivotY); - v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress); - v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0); - } else { - v.setRotationY(0f); - v.setOverScrollAmount(0, false); - } - - float alpha = v.getAlpha(); - // If the view has 0 alpha, we set it to be invisible so as to prevent - // it from accepting touches - if (alpha == 0) { - v.setVisibility(INVISIBLE); - } else if (v.getVisibility() != VISIBLE) { - v.setVisibility(VISIBLE); - } - } - } - } - - public boolean isWidgetPage(int pageIndex) { - if (pageIndex < 0 || pageIndex >= getChildCount()) { - return false; - } - View v = getChildAt(pageIndex); - if (v != null && v instanceof KeyguardWidgetFrame) { - KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v; - return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID; - } - return false; - } - - /** - * Returns the bounded set of pages that are re-orderable. The range is fully inclusive. - */ - @Override - void boundByReorderablePages(boolean isReordering, int[] range) { - if (isReordering) { - // Remove non-widget pages from the range - while (range[1] >= range[0] && !isWidgetPage(range[1])) { - range[1]--; - } - while (range[0] <= range[1] && !isWidgetPage(range[0])) { - range[0]++; - } - } - } - - protected void reorderStarting() { - showOutlinesAndSidePages(); - } - - @Override - protected void onStartReordering() { - super.onStartReordering(); - enablePageContentLayers(); - reorderStarting(); - } - - @Override - protected void onEndReordering() { - super.onEndReordering(); - hideOutlinesAndSidePages(); - } - - void showOutlinesAndSidePages() { - animateOutlinesAndSidePages(true); - } - - void hideOutlinesAndSidePages() { - animateOutlinesAndSidePages(false); - } - - void updateChildrenContentAlpha(float sidePageAlpha) { - int count = getChildCount(); - for (int i = 0; i < count; i++) { - KeyguardWidgetFrame child = getWidgetPageAt(i); - if (i != mCurrentPage) { - child.setBackgroundAlpha(sidePageAlpha); - child.setContentAlpha(0f); - } else { - child.setBackgroundAlpha(0f); - child.setContentAlpha(1f); - } - } - } - - public void showInitialPageHints() { - mShowingInitialHints = true; - updateChildrenContentAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); - } - - @Override - void setCurrentPage(int currentPage) { - super.setCurrentPage(currentPage); - updateChildrenContentAlpha(0.0f); - updateWidgetFramesImportantForAccessibility(); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - mHasMeasure = false; - } - - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - mLastWidthMeasureSpec = widthMeasureSpec; - mLastHeightMeasureSpec = heightMeasureSpec; - - int maxChallengeTop = -1; - View parent = (View) getParent(); - boolean challengeShowing = false; - // Widget pages need to know where the top of the sliding challenge is so that they - // now how big the widget should be when the challenge is up. We compute it here and - // then propagate it to each of our children. - if (parent.getParent() instanceof SlidingChallengeLayout) { - SlidingChallengeLayout scl = (SlidingChallengeLayout) parent.getParent(); - int top = scl.getMaxChallengeTop(); - - // This is a bit evil, but we need to map a coordinate relative to the SCL into a - // coordinate relative to our children, hence we subtract the top padding.s - maxChallengeTop = top - getPaddingTop(); - challengeShowing = scl.isChallengeShowing(); - - int count = getChildCount(); - for (int i = 0; i < count; i++) { - KeyguardWidgetFrame frame = getWidgetPageAt(i); - frame.setMaxChallengeTop(maxChallengeTop); - // On the very first measure pass, if the challenge is showing, we need to make sure - // that the widget on the current page is small. - if (challengeShowing && i == mCurrentPage && !mHasMeasure) { - frame.shrinkWidget(); - } - } - } - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - mHasMeasure = true; - } - - void animateOutlinesAndSidePages(final boolean show) { - animateOutlinesAndSidePages(show, -1); - } - - public void setWidgetToResetOnPageFadeOut(int widget) { - mWidgetToResetAfterFadeOut = widget; - } - - public int getWidgetToResetOnPageFadeOut() { - return mWidgetToResetAfterFadeOut; - } - - void animateOutlinesAndSidePages(final boolean show, int duration) { - if (mChildrenOutlineFadeAnimation != null) { - mChildrenOutlineFadeAnimation.cancel(); - mChildrenOutlineFadeAnimation = null; - } - int count = getChildCount(); - PropertyValuesHolder alpha; - ArrayList<Animator> anims = new ArrayList<Animator>(); - - if (duration == -1) { - duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION : - CHILDREN_OUTLINE_FADE_OUT_DURATION; - } - - int curPage = getNextPage(); - for (int i = 0; i < count; i++) { - float finalContentAlpha; - if (show) { - finalContentAlpha = getAlphaForPage(mScreenCenter, i, true); - } else if (!show && i == curPage) { - finalContentAlpha = 1f; - } else { - finalContentAlpha = 0f; - } - KeyguardWidgetFrame child = getWidgetPageAt(i); - - alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalContentAlpha); - ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha); - anims.add(a); - - float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i, true) : 0f; - child.fadeFrame(this, show, finalOutlineAlpha, duration); - } - - mChildrenOutlineFadeAnimation = new AnimatorSet(); - mChildrenOutlineFadeAnimation.playTogether(anims); - - mChildrenOutlineFadeAnimation.setDuration(duration); - mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - if (show) { - enablePageContentLayers(); - } - } - - @Override - public void onAnimationEnd(Animator animation) { - if (!show) { - disablePageContentLayers(); - KeyguardWidgetFrame frame = getWidgetPageAt(mWidgetToResetAfterFadeOut); - if (frame != null && !(frame == getWidgetPageAt(mCurrentPage) && - mViewStateManager.isChallengeOverlapping())) { - frame.resetSize(); - } - mWidgetToResetAfterFadeOut = -1; - mShowingInitialHints = false; - } - updateWidgetFramesImportantForAccessibility(); - } - }); - mChildrenOutlineFadeAnimation.start(); - } - - @Override - public boolean onLongClick(View v) { - // Disallow long pressing to reorder if the challenge is showing - boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() && - mViewStateManager.isChallengeOverlapping(); - if (!isChallengeOverlapping && startReordering()) { - return true; - } - return false; - } - - public void removeWidget(View view) { - if (view instanceof KeyguardWidgetFrame) { - removeView(view); - } else { - // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget(). - // This supports legacy hard-coded "widgets" like KeyguardTransportControlView. - int pos = getWidgetPageIndex(view); - if (pos != -1) { - KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos); - frame.removeView(view); - removeView(frame); - } else { - Slog.w(TAG, "removeWidget() can't find:" + view); - } - } - } - - public int getWidgetPageIndex(View view) { - if (view instanceof KeyguardWidgetFrame) { - return indexOfChild(view); - } else { - // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget() - return indexOfChild((KeyguardWidgetFrame)view.getParent()); - } - } - - @Override - protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) { - KeyguardWidgetFrame child = getWidgetPageAt(viewIndex); - child.setIsHoveringOverDeleteDropTarget(isHovering); - } - - // ChallengeLayout.OnBouncerStateChangedListener - @Override - public void onBouncerStateChanged(boolean bouncerActive) { - if (bouncerActive) { - zoomOutToBouncer(); - } else { - zoomInFromBouncer(); - } - } - - void setBouncerAnimationDuration(int duration) { - mBouncerZoomInOutDuration = duration; - } - - // Zoom in after the bouncer is dismissed - void zoomInFromBouncer() { - if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) { - mZoomInOutAnim.cancel(); - } - final View currentPage = getPageAt(getCurrentPage()); - if (currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f) { - mZoomInOutAnim = new AnimatorSet(); - mZoomInOutAnim.playTogether( - ObjectAnimator.ofFloat(currentPage, "scaleX", 1f), - ObjectAnimator.ofFloat(currentPage , "scaleY", 1f)); - mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration); - mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f)); - mZoomInOutAnim.start(); - } - if (currentPage instanceof KeyguardWidgetFrame) { - ((KeyguardWidgetFrame)currentPage).onBouncerShowing(false); - } - } - - // Zoom out after the bouncer is initiated - void zoomOutToBouncer() { - if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) { - mZoomInOutAnim.cancel(); - } - int curPage = getCurrentPage(); - View currentPage = getPageAt(curPage); - if (shouldSetTopAlignedPivotForWidget(curPage)) { - currentPage.setPivotY(0); - // Note: we are working around the issue that setting the x-pivot to the same value as it - // was does not actually work. - currentPage.setPivotX(0); - currentPage.setPivotX(currentPage.getMeasuredWidth() / 2); - } - if (!(currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f)) { - mZoomInOutAnim = new AnimatorSet(); - mZoomInOutAnim.playTogether( - ObjectAnimator.ofFloat(currentPage, "scaleX", BOUNCER_SCALE_FACTOR), - ObjectAnimator.ofFloat(currentPage, "scaleY", BOUNCER_SCALE_FACTOR)); - mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration); - mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f)); - mZoomInOutAnim.start(); - } - if (currentPage instanceof KeyguardWidgetFrame) { - ((KeyguardWidgetFrame)currentPage).onBouncerShowing(true); - } - } - - void setAddWidgetEnabled(boolean enabled) { - if (mAddWidgetView != null && enabled) { - addView(mAddWidgetView, 0); - // We need to force measure the PagedView so that the calls to update the scroll - // position below work - measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec); - // Bump up the current page to account for the addition of the new page - setCurrentPage(mCurrentPage + 1); - mAddWidgetView = null; - } else if (mAddWidgetView == null && !enabled) { - View addWidget = findViewById(com.android.internal.R.id.keyguard_add_widget); - if (addWidget != null) { - mAddWidgetView = addWidget; - removeView(addWidget); - } - } - } - - boolean isAddPage(int pageIndex) { - View v = getChildAt(pageIndex); - return v != null && v.getId() == com.android.internal.R.id.keyguard_add_widget; - } - - boolean isCameraPage(int pageIndex) { - View v = getChildAt(pageIndex); - return v != null && v instanceof CameraWidgetFrame; - } - - @Override - 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/LiftToActivateListener.java b/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java deleted file mode 100644 index 818108c..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/LiftToActivateListener.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.view.MotionEvent; -import android.view.View; -import android.view.accessibility.AccessibilityManager; - -/** - * Hover listener that implements lift-to-activate interaction for - * accessibility. May be added to multiple views. - */ -class LiftToActivateListener implements View.OnHoverListener { - /** Manager used to query accessibility enabled state. */ - private final AccessibilityManager mAccessibilityManager; - - private boolean mCachedClickableState; - - public LiftToActivateListener(Context context) { - mAccessibilityManager = (AccessibilityManager) context.getSystemService( - Context.ACCESSIBILITY_SERVICE); - } - - @Override - public boolean onHover(View v, MotionEvent event) { - // When touch exploration is turned on, lifting a finger while - // inside the view bounds should perform a click action. - if (mAccessibilityManager.isEnabled() - && mAccessibilityManager.isTouchExplorationEnabled()) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_HOVER_ENTER: - // Lift-to-type temporarily disables double-tap - // activation by setting the view as not clickable. - mCachedClickableState = v.isClickable(); - v.setClickable(false); - break; - case MotionEvent.ACTION_HOVER_EXIT: - final int x = (int) event.getX(); - final int y = (int) event.getY(); - if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop()) - && (x < v.getWidth() - v.getPaddingRight()) - && (y < v.getHeight() - v.getPaddingBottom())) { - v.performClick(); - } - v.setClickable(mCachedClickableState); - break; - } - } - - // Pass the event to View.onHoverEvent() to handle accessibility. - v.onHoverEvent(event); - - // Consume the event so it doesn't fall through to other views. - return true; - } -}
\ No newline at end of file diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java deleted file mode 100644 index 0ca46c3..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java +++ /dev/null @@ -1,566 +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; - -import com.android.internal.R; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayout { - private static final String TAG = "MultiPaneChallengeLayout"; - - final int mOrientation; - private boolean mIsBouncing; - - public static final int HORIZONTAL = LinearLayout.HORIZONTAL; - public static final int VERTICAL = LinearLayout.VERTICAL; - public static final int ANIMATE_BOUNCE_DURATION = 350; - - private KeyguardSecurityContainer mChallengeView; - private View mUserSwitcherView; - private View mScrimView; - private OnBouncerStateChangedListener mBouncerListener; - - private final Rect mTempRect = new Rect(); - private final Rect mZeroPadding = new Rect(); - - private final DisplayMetrics mDisplayMetrics; - - private final OnClickListener mScrimClickListener = new OnClickListener() { - @Override - public void onClick(View v) { - hideBouncer(); - } - }; - - public MultiPaneChallengeLayout(Context context) { - this(context, null); - } - - public MultiPaneChallengeLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public MultiPaneChallengeLayout(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - final TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.MultiPaneChallengeLayout, defStyleAttr, 0); - mOrientation = a.getInt(R.styleable.MultiPaneChallengeLayout_orientation, - HORIZONTAL); - a.recycle(); - - final Resources res = getResources(); - mDisplayMetrics = res.getDisplayMetrics(); - - setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE); - } - - @Override - public boolean isChallengeShowing() { - return true; - } - - @Override - public boolean isChallengeOverlapping() { - return false; - } - - @Override - public void showChallenge(boolean b) { - } - - @Override - public int getBouncerAnimationDuration() { - return ANIMATE_BOUNCE_DURATION; - } - - @Override - public void showBouncer() { - if (mIsBouncing) return; - mIsBouncing = true; - if (mScrimView != null) { - if (mChallengeView != null) { - mChallengeView.showBouncer(ANIMATE_BOUNCE_DURATION); - } - - Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f); - anim.setDuration(ANIMATE_BOUNCE_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mScrimView.setVisibility(VISIBLE); - } - }); - anim.start(); - } - if (mBouncerListener != null) { - mBouncerListener.onBouncerStateChanged(true); - } - } - - @Override - public void hideBouncer() { - if (!mIsBouncing) return; - mIsBouncing = false; - if (mScrimView != null) { - if (mChallengeView != null) { - mChallengeView.hideBouncer(ANIMATE_BOUNCE_DURATION); - } - - Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f); - anim.setDuration(ANIMATE_BOUNCE_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mScrimView.setVisibility(INVISIBLE); - } - }); - anim.start(); - } - if (mBouncerListener != null) { - mBouncerListener.onBouncerStateChanged(false); - } - } - - @Override - public boolean isBouncing() { - return mIsBouncing; - } - - @Override - public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) { - mBouncerListener = listener; - } - - @Override - public void requestChildFocus(View child, View focused) { - if (mIsBouncing && child != mChallengeView) { - // Clear out of the bouncer if the user tries to move focus outside of - // the security challenge view. - hideBouncer(); - } - super.requestChildFocus(child, focused); - } - - void setScrimView(View scrim) { - if (mScrimView != null) { - mScrimView.setOnClickListener(null); - } - mScrimView = scrim; - mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f); - mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE); - mScrimView.setFocusable(true); - mScrimView.setOnClickListener(mScrimClickListener); - } - - private int getVirtualHeight(LayoutParams lp, int height, int heightUsed) { - int virtualHeight = height; - final View root = getRootView(); - if (root != null) { - // This calculation is super dodgy and relies on several assumptions. - // Specifically that the root of the window will be padded in for insets - // and that the window is LAYOUT_IN_SCREEN. - virtualHeight = mDisplayMetrics.heightPixels - root.getPaddingTop(); - } - if (lp.childType == LayoutParams.CHILD_TYPE_WIDGET || - lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) { - // Always measure the widget pager/user switcher as if there were no IME insets - // on the window. We want to avoid resizing widgets when possible as it can - // be ugly/expensive. This lets us simply clip them instead. - return virtualHeight - heightUsed; - } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) { - return height; - } - return Math.min(virtualHeight - heightUsed, height); - } - - @Override - protected void onMeasure(final int widthSpec, final int heightSpec) { - if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY || - MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) { - throw new IllegalArgumentException( - "MultiPaneChallengeLayout must be measured with an exact size"); - } - - final int width = MeasureSpec.getSize(widthSpec); - final int height = MeasureSpec.getSize(heightSpec); - setMeasuredDimension(width, height); - - int widthUsed = 0; - int heightUsed = 0; - - // First pass. Find the challenge view and measure the user switcher, - // which consumes space in the layout. - mChallengeView = null; - mUserSwitcherView = null; - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { - if (mChallengeView != null) { - throw new IllegalStateException( - "There may only be one child of type challenge"); - } - if (!(child instanceof KeyguardSecurityContainer)) { - throw new IllegalArgumentException( - "Challenge must be a KeyguardSecurityContainer"); - } - mChallengeView = (KeyguardSecurityContainer) child; - } else if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) { - if (mUserSwitcherView != null) { - throw new IllegalStateException( - "There may only be one child of type userSwitcher"); - } - mUserSwitcherView = child; - - if (child.getVisibility() == GONE) continue; - - int adjustedWidthSpec = widthSpec; - int adjustedHeightSpec = heightSpec; - if (lp.maxWidth >= 0) { - adjustedWidthSpec = MeasureSpec.makeMeasureSpec( - Math.min(lp.maxWidth, width), MeasureSpec.EXACTLY); - } - if (lp.maxHeight >= 0) { - adjustedHeightSpec = MeasureSpec.makeMeasureSpec( - Math.min(lp.maxHeight, height), MeasureSpec.EXACTLY); - } - // measureChildWithMargins will resolve layout direction for the LayoutParams - measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0); - - // Only subtract out space from one dimension. Favor vertical. - // Offset by 1.5x to add some balance along the other edge. - if (Gravity.isVertical(lp.gravity)) { - heightUsed += child.getMeasuredHeight() * 1.5f; - } else if (Gravity.isHorizontal(lp.gravity)) { - widthUsed += child.getMeasuredWidth() * 1.5f; - } - } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { - setScrimView(child); - child.measure(widthSpec, heightSpec); - } - } - - // Second pass. Measure everything that's left. - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER || - lp.childType == LayoutParams.CHILD_TYPE_SCRIM || - child.getVisibility() == GONE) { - // Don't need to measure GONE children, and the user switcher was already measured. - continue; - } - - final int virtualHeight = getVirtualHeight(lp, height, heightUsed); - - int adjustedWidthSpec; - int adjustedHeightSpec; - if (lp.centerWithinArea > 0) { - if (mOrientation == HORIZONTAL) { - adjustedWidthSpec = MeasureSpec.makeMeasureSpec( - (int) ((width - widthUsed) * lp.centerWithinArea + 0.5f), - MeasureSpec.EXACTLY); - adjustedHeightSpec = MeasureSpec.makeMeasureSpec( - virtualHeight, MeasureSpec.EXACTLY); - } else { - adjustedWidthSpec = MeasureSpec.makeMeasureSpec( - width - widthUsed, MeasureSpec.EXACTLY); - adjustedHeightSpec = MeasureSpec.makeMeasureSpec( - (int) (virtualHeight * lp.centerWithinArea + 0.5f), - MeasureSpec.EXACTLY); - } - } else { - adjustedWidthSpec = MeasureSpec.makeMeasureSpec( - width - widthUsed, MeasureSpec.EXACTLY); - adjustedHeightSpec = MeasureSpec.makeMeasureSpec( - virtualHeight, MeasureSpec.EXACTLY); - } - if (lp.maxWidth >= 0) { - adjustedWidthSpec = MeasureSpec.makeMeasureSpec( - Math.min(lp.maxWidth, MeasureSpec.getSize(adjustedWidthSpec)), - MeasureSpec.EXACTLY); - } - if (lp.maxHeight >= 0) { - adjustedHeightSpec = MeasureSpec.makeMeasureSpec( - Math.min(lp.maxHeight, MeasureSpec.getSize(adjustedHeightSpec)), - MeasureSpec.EXACTLY); - } - - measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0); - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - final Rect padding = mTempRect; - padding.left = getPaddingLeft(); - padding.top = getPaddingTop(); - padding.right = getPaddingRight(); - padding.bottom = getPaddingBottom(); - final int width = r - l; - final int height = b - t; - - // Reserve extra space in layout for the user switcher by modifying - // local padding during this layout pass - if (mUserSwitcherView != null && mUserSwitcherView.getVisibility() != GONE) { - layoutWithGravity(width, height, mUserSwitcherView, padding, true); - } - - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - // We did the user switcher above if we have one. - if (child == mUserSwitcherView || child.getVisibility() == GONE) continue; - - if (child == mScrimView) { - child.layout(0, 0, width, height); - continue; - } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) { - layoutWithGravity(width, height, child, mZeroPadding, false); - continue; - } - - layoutWithGravity(width, height, child, padding, false); - } - } - - private void layoutWithGravity(int width, int height, View child, Rect padding, - boolean adjustPadding) { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - final int heightUsed = padding.top + padding.bottom - getPaddingTop() - getPaddingBottom(); - height = getVirtualHeight(lp, height, heightUsed); - - final int gravity = Gravity.getAbsoluteGravity(lp.gravity, getLayoutDirection()); - - final boolean fixedLayoutSize = lp.centerWithinArea > 0; - final boolean fixedLayoutHorizontal = fixedLayoutSize && mOrientation == HORIZONTAL; - final boolean fixedLayoutVertical = fixedLayoutSize && mOrientation == VERTICAL; - - final int adjustedWidth; - final int adjustedHeight; - if (fixedLayoutHorizontal) { - final int paddedWidth = width - padding.left - padding.right; - adjustedWidth = (int) (paddedWidth * lp.centerWithinArea + 0.5f); - adjustedHeight = height; - } else if (fixedLayoutVertical) { - final int paddedHeight = height - getPaddingTop() - getPaddingBottom(); - adjustedWidth = width; - adjustedHeight = (int) (paddedHeight * lp.centerWithinArea + 0.5f); - } else { - adjustedWidth = width; - adjustedHeight = height; - } - - final boolean isVertical = Gravity.isVertical(gravity); - final boolean isHorizontal = Gravity.isHorizontal(gravity); - final int childWidth = child.getMeasuredWidth(); - final int childHeight = child.getMeasuredHeight(); - - int left = padding.left; - int top = padding.top; - int right = left + childWidth; - int bottom = top + childHeight; - switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) { - case Gravity.TOP: - top = fixedLayoutVertical ? - padding.top + (adjustedHeight - childHeight) / 2 : padding.top; - bottom = top + childHeight; - if (adjustPadding && isVertical) { - padding.top = bottom; - padding.bottom += childHeight / 2; - } - break; - case Gravity.BOTTOM: - bottom = fixedLayoutVertical - ? padding.top + height - (adjustedHeight - childHeight) / 2 - : padding.top + height; - top = bottom - childHeight; - if (adjustPadding && isVertical) { - padding.bottom = height - top; - padding.top += childHeight / 2; - } - break; - case Gravity.CENTER_VERTICAL: - top = padding.top + (height - childHeight) / 2; - bottom = top + childHeight; - break; - } - switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { - case Gravity.LEFT: - left = fixedLayoutHorizontal ? - padding.left + (adjustedWidth - childWidth) / 2 : padding.left; - right = left + childWidth; - if (adjustPadding && isHorizontal && !isVertical) { - padding.left = right; - padding.right += childWidth / 2; - } - break; - case Gravity.RIGHT: - right = fixedLayoutHorizontal - ? width - padding.right - (adjustedWidth - childWidth) / 2 - : width - padding.right; - left = right - childWidth; - if (adjustPadding && isHorizontal && !isVertical) { - padding.right = width - left; - padding.left += childWidth / 2; - } - break; - case Gravity.CENTER_HORIZONTAL: - final int paddedWidth = width - padding.left - padding.right; - left = (paddedWidth - childWidth) / 2; - right = left + childWidth; - break; - } - child.layout(left, top, right, bottom); - } - - @Override - public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { - return new LayoutParams(getContext(), attrs, this); - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : - p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : - new LayoutParams(p); - } - - @Override - protected ViewGroup.LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(); - } - - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams; - } - - public static class LayoutParams extends MarginLayoutParams { - - public float centerWithinArea = 0; - - public int childType = 0; - - public static final int CHILD_TYPE_NONE = 0; - public static final int CHILD_TYPE_WIDGET = 1; - public static final int CHILD_TYPE_CHALLENGE = 2; - public static final int CHILD_TYPE_USER_SWITCHER = 3; - public static final int CHILD_TYPE_SCRIM = 4; - public static final int CHILD_TYPE_PAGE_DELETE_DROP_TARGET = 7; - - public int gravity = Gravity.NO_GRAVITY; - - public int maxWidth = -1; - public int maxHeight = -1; - - public LayoutParams() { - this(WRAP_CONTENT, WRAP_CONTENT); - } - - LayoutParams(Context c, AttributeSet attrs, MultiPaneChallengeLayout parent) { - super(c, attrs); - - final TypedArray a = c.obtainStyledAttributes(attrs, - R.styleable.MultiPaneChallengeLayout_Layout); - - centerWithinArea = a.getFloat( - R.styleable.MultiPaneChallengeLayout_Layout_layout_centerWithinArea, 0); - childType = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_childType, - CHILD_TYPE_NONE); - gravity = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_gravity, - Gravity.NO_GRAVITY); - maxWidth = a.getDimensionPixelSize( - R.styleable.MultiPaneChallengeLayout_Layout_layout_maxWidth, -1); - maxHeight = a.getDimensionPixelSize( - R.styleable.MultiPaneChallengeLayout_Layout_layout_maxHeight, -1); - - // Default gravity settings based on type and parent orientation - if (gravity == Gravity.NO_GRAVITY) { - if (parent.mOrientation == HORIZONTAL) { - switch (childType) { - case CHILD_TYPE_WIDGET: - gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; - break; - case CHILD_TYPE_CHALLENGE: - gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; - break; - case CHILD_TYPE_USER_SWITCHER: - gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - break; - } - } else { - switch (childType) { - case CHILD_TYPE_WIDGET: - gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - break; - case CHILD_TYPE_CHALLENGE: - gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - break; - case CHILD_TYPE_USER_SWITCHER: - gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - break; - } - } - } - - a.recycle(); - } - - public LayoutParams(int width, int height) { - super(width, height); - } - - public LayoutParams(ViewGroup.LayoutParams source) { - super(source); - } - - public LayoutParams(MarginLayoutParams source) { - super(source); - } - - public LayoutParams(LayoutParams source) { - this((MarginLayoutParams) source); - - centerWithinArea = source.centerWithinArea; - childType = source.childType; - gravity = source.gravity; - maxWidth = source.maxWidth; - maxHeight = source.maxHeight; - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java deleted file mode 100644 index 7969c7d..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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/NumPadKey.java b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java deleted file mode 100644 index a0038bc..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java +++ /dev/null @@ -1,128 +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; - -import android.content.Context; -import android.content.res.TypedArray; -import android.text.SpannableStringBuilder; -import android.text.style.TextAppearanceSpan; -import android.util.AttributeSet; -import android.view.HapticFeedbackConstants; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -import com.android.internal.R; -import com.android.internal.widget.LockPatternUtils; - -public class NumPadKey extends Button { - // list of "ABC", etc per digit, starting with '0' - static String sKlondike[]; - - int mDigit = -1; - int mTextViewResId; - TextView mTextView = null; - boolean mEnableHaptics; - - private View.OnClickListener mListener = new View.OnClickListener() { - @Override - public void onClick(View thisView) { - if (mTextView == null) { - if (mTextViewResId > 0) { - final View v = NumPadKey.this.getRootView().findViewById(mTextViewResId); - if (v != null && v instanceof TextView) { - mTextView = (TextView) v; - } - } - } - // check for time-based lockouts - if (mTextView != null && mTextView.isEnabled()) { - mTextView.append(String.valueOf(mDigit)); - } - doHapticKeyClick(); - } - }; - - public NumPadKey(Context context) { - this(context, null); - } - - public NumPadKey(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public NumPadKey(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey); - mDigit = a.getInt(R.styleable.NumPadKey_digit, mDigit); - setTextViewResId(a.getResourceId(R.styleable.NumPadKey_textView, 0)); - - setOnClickListener(mListener); - setOnHoverListener(new LiftToActivateListener(context)); - setAccessibilityDelegate(new ObscureSpeechDelegate(context)); - - mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled(); - - SpannableStringBuilder builder = new SpannableStringBuilder(); - builder.append(String.valueOf(mDigit)); - if (mDigit >= 0) { - if (sKlondike == null) { - sKlondike = context.getResources().getStringArray( - R.array.lockscreen_num_pad_klondike); - } - if (sKlondike != null && sKlondike.length > mDigit) { - final String extra = sKlondike[mDigit]; - final int extraLen = extra.length(); - if (extraLen > 0) { - builder.append(" "); - builder.append(extra); - builder.setSpan( - new TextAppearanceSpan(context, R.style.TextAppearance_NumPadKey_Klondike), - builder.length()-extraLen, builder.length(), 0); - } - } - } - setText(builder); - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - // Reset the "announced headset" flag when detached. - ObscureSpeechDelegate.sAnnouncedHeadset = false; - } - - public void setTextView(TextView tv) { - mTextView = tv; - } - - public void setTextViewResId(int resId) { - mTextView = null; - mTextViewResId = resId; - } - - // Cause a VIRTUAL_KEY vibration - public void doHapticKeyClick() { - if (mEnableHaptics) { - performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING - | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java deleted file mode 100644 index af043ab..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/ObscureSpeechDelegate.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.ContentResolver; -import android.content.Context; -import android.media.AudioManager; -import android.provider.Settings; -import android.view.View; -import android.view.View.AccessibilityDelegate; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.android.internal.R; - -/** - * Accessibility delegate that obscures speech for a view when the user has - * not turned on the "speak passwords" preference and is not listening - * through headphones. - */ -class ObscureSpeechDelegate extends AccessibilityDelegate { - /** Whether any client has announced the "headset" notification. */ - static boolean sAnnouncedHeadset = false; - - private final ContentResolver mContentResolver; - private final AudioManager mAudioManager; - - public ObscureSpeechDelegate(Context context) { - mContentResolver = context.getContentResolver(); - mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - } - - @Override - public void sendAccessibilityEvent(View host, int eventType) { - super.sendAccessibilityEvent(host, eventType); - - // Play the "headset required" announcement the first time the user - // places accessibility focus on a key. - if ((eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) - && !sAnnouncedHeadset && shouldObscureSpeech()) { - sAnnouncedHeadset = true; - host.announceForAccessibility(host.getContext().getString( - R.string.keyboard_headset_required_to_hear_password)); - } - } - - @Override - public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(host, event); - - if ((event.getEventType() != AccessibilityEvent.TYPE_ANNOUNCEMENT) - && shouldObscureSpeech()) { - event.getText().clear(); - event.setContentDescription(host.getContext().getString( - R.string.keyboard_password_character_no_headset)); - } - } - - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host, info); - - if (shouldObscureSpeech()) { - final Context ctx = host.getContext(); - info.setText(null); - info.setContentDescription( - ctx.getString(R.string.keyboard_password_character_no_headset)); - } - } - - @SuppressWarnings("deprecation") - private boolean shouldObscureSpeech() { - // The user can optionally force speaking passwords. - if (Settings.Secure.getInt(mContentResolver, - Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0) { - return false; - } - - // Always speak if the user is listening through headphones. - if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) { - return false; - } - - // Don't speak since this key is used to type a password. - return true; - } -}
\ No newline at end of file diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java deleted file mode 100644 index 10562e8..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java +++ /dev/null @@ -1,2569 +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; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.PointF; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.InputDevice; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.animation.AnimationUtils; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; -import android.widget.Scroller; - -import com.android.internal.R; - -import java.util.ArrayList; - -/** - * An abstraction of the original Workspace which supports browsing through a - * sequential list of "pages" - */ -public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener { - private static final String TAG = "WidgetPagedView"; - private static final boolean DEBUG = false; - protected static final int INVALID_PAGE = -1; - - // the min drag distance for a fling to register, to prevent random page shifts - private static final int MIN_LENGTH_FOR_FLING = 25; - - protected static final int PAGE_SNAP_ANIMATION_DURATION = 750; - protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950; - protected static final float NANOTIME_DIV = 1000000000.0f; - - private static final float OVERSCROLL_ACCELERATE_FACTOR = 2; - private static final float OVERSCROLL_DAMP_FACTOR = 0.14f; - - private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f; - // The page is moved more than halfway, automatically move to the next page on touch up. - private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f; - - // The following constants need to be scaled based on density. The scaled versions will be - // assigned to the corresponding member variables below. - private static final int FLING_THRESHOLD_VELOCITY = 500; - 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. - 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; - - static final int AUTOMATIC_PAGE_SPACING = -1; - - protected int mFlingThresholdVelocity; - protected int mMinFlingVelocity; - protected int mMinSnapVelocity; - - protected float mDensity; - protected float mSmoothingTime; - protected float mTouchX; - - protected boolean mFirstLayout = true; - - protected int mCurrentPage; - protected int mChildCountOnLastMeasure; - - protected int mNextPage = INVALID_PAGE; - protected int mMaxScrollX; - protected Scroller mScroller; - private VelocityTracker mVelocityTracker; - - private float mParentDownMotionX; - private float mParentDownMotionY; - private float mDownMotionX; - private float mDownMotionY; - private float mDownScrollX; - protected float mLastMotionX; - protected float mLastMotionXRemainder; - protected float mLastMotionY; - protected float mTotalMotionX; - private int mLastScreenCenter = -1; - private int[] mChildOffsets; - private int[] mChildRelativeOffsets; - private int[] mChildOffsetsWithLayoutScale; - - protected final static int TOUCH_STATE_REST = 0; - protected final static int TOUCH_STATE_SCROLLING = 1; - protected final static int TOUCH_STATE_PREV_PAGE = 2; - protected final static int TOUCH_STATE_NEXT_PAGE = 3; - protected final static int TOUCH_STATE_REORDERING = 4; - - protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f; - - protected int mTouchState = TOUCH_STATE_REST; - protected boolean mForceScreenScrolled = false; - - protected OnLongClickListener mLongClickListener; - - protected int mTouchSlop; - private int mPagingTouchSlop; - private int mMaximumVelocity; - private int mMinimumWidth; - protected int mPageSpacing; - protected int mCellCountX = 0; - protected int mCellCountY = 0; - protected boolean mAllowOverScroll = true; - protected int mUnboundedScrollX; - protected int[] mTempVisiblePagesRange = new int[2]; - protected boolean mForceDrawAllChildrenNextFrame; - - // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise - // it is equal to the scaled overscroll position. We use a separate value so as to prevent - // the screens from continuing to translate beyond the normal bounds. - protected int mOverScrollX; - - // parameter that adjusts the layout to be optimized for pages with that scale factor - protected float mLayoutScale = 1.0f; - - protected static final int INVALID_POINTER = -1; - - protected int mActivePointerId = INVALID_POINTER; - - private PageSwitchListener mPageSwitchListener; - - protected ArrayList<Boolean> mDirtyPageContent; - - // If true, syncPages and syncPageItems will be called to refresh pages - protected boolean mContentIsRefreshable = true; - - // If true, modify alpha of neighboring pages as user scrolls left/right - protected boolean mFadeInAdjacentScreens = false; - - // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding - // to switch to a new page - protected boolean mUsePagingTouchSlop = true; - - // If true, the subclass should directly update scrollX itself in its computeScroll method - // (SmoothPagedView does this) - protected boolean mDeferScrollUpdate = false; - - protected boolean mIsPageMoving = false; - - // All syncs and layout passes are deferred until data is ready. - protected boolean mIsDataReady = true; - - // Scrolling indicator - private ValueAnimator mScrollIndicatorAnimator; - private View mScrollIndicator; - private int mScrollIndicatorPaddingLeft; - private int mScrollIndicatorPaddingRight; - private boolean mShouldShowScrollIndicator = false; - private boolean mShouldShowScrollIndicatorImmediately = false; - protected static final int sScrollIndicatorFadeInDuration = 150; - protected static final int sScrollIndicatorFadeOutDuration = 650; - protected static final int sScrollIndicatorFlashDuration = 650; - - // The viewport whether the pages are to be contained (the actual view may be larger than the - // viewport) - private Rect mViewport = new Rect(); - - // Reordering - // We use the min scale to determine how much to expand the actually PagedView measured - // dimensions such that when we are zoomed out, the view is not clipped - private int REORDERING_DROP_REPOSITION_DURATION = 200; - protected int REORDERING_REORDER_REPOSITION_DURATION = 300; - protected int REORDERING_ZOOM_IN_OUT_DURATION = 250; - private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300; - private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f; - private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150; - private float mMinScale = 1f; - protected View mDragView; - protected AnimatorSet mZoomInOutAnim; - private Runnable mSidePageHoverRunnable; - private int mSidePageHoverIndex = -1; - // This variable's scope is only for the duration of startReordering() and endReordering() - private boolean mReorderingStarted = false; - // This variable's scope is for the duration of startReordering() and after the zoomIn() - // animation after endReordering() - private boolean mIsReordering; - // The runnable that settles the page after snapToPage and animateDragViewToOriginalPosition - private int NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT = 2; - private int mPostReorderingPreZoomInRemainingAnimationCount; - private Runnable mPostReorderingPreZoomInRunnable; - - // Edge swiping - private boolean mOnlyAllowEdgeSwipes = false; - private boolean mDownEventOnEdge = false; - private int mEdgeSwipeRegionSize = 0; - - // Convenience/caching - private Matrix mTmpInvMatrix = new Matrix(); - private float[] mTmpPoint = new float[2]; - private Rect mTmpRect = new Rect(); - private Rect mAltTmpRect = new Rect(); - - // Fling to delete - private int FLING_TO_DELETE_FADE_OUT_DURATION = 350; - private float FLING_TO_DELETE_FRICTION = 0.035f; - // The degrees specifies how much deviation from the up vector to still consider a fling "up" - private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f; - protected int mFlingToDeleteThresholdVelocity = -1400; - // Drag to delete - private boolean mDeferringForDelete = false; - private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250; - private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350; - - // Drop to delete - private View mDeleteDropTarget; - - // Bouncer - private boolean mTopAlignPageWhenShrinkingForBouncer = false; - - public interface PageSwitchListener { - void onPageSwitching(View newPage, int newPageIndex); - void onPageSwitched(View newPage, int newPageIndex); - } - - public PagedView(Context context) { - this(context, null); - } - - public PagedView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PagedView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.PagedView, defStyle, 0); - setPageSpacing(a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0)); - mScrollIndicatorPaddingLeft = - a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingLeft, 0); - mScrollIndicatorPaddingRight = - a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingRight, 0); - a.recycle(); - - Resources r = getResources(); - mEdgeSwipeRegionSize = r.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size); - mTopAlignPageWhenShrinkingForBouncer = - r.getBoolean(R.bool.kg_top_align_page_shrink_on_bouncer_visible); - - setHapticFeedbackEnabled(false); - init(); - } - - /** - * Initializes various states for this workspace. - */ - protected void init() { - mDirtyPageContent = new ArrayList<Boolean>(); - mDirtyPageContent.ensureCapacity(32); - mScroller = new Scroller(getContext(), new ScrollInterpolator()); - mCurrentPage = 0; - - final ViewConfiguration configuration = ViewConfiguration.get(getContext()); - mTouchSlop = configuration.getScaledTouchSlop(); - mPagingTouchSlop = configuration.getScaledPagingTouchSlop(); - mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - mDensity = getResources().getDisplayMetrics().density; - - // Scale the fling-to-delete threshold by the density - mFlingToDeleteThresholdVelocity = - (int) (mFlingToDeleteThresholdVelocity * mDensity); - - mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity); - mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity); - mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity); - setOnHierarchyChangeListener(this); - } - - void setDeleteDropTarget(View v) { - mDeleteDropTarget = v; - } - - // Convenience methods to map points from self to parent and vice versa - float[] mapPointFromViewToParent(View v, float x, float y) { - mTmpPoint[0] = x; - mTmpPoint[1] = y; - v.getMatrix().mapPoints(mTmpPoint); - mTmpPoint[0] += v.getLeft(); - mTmpPoint[1] += v.getTop(); - return mTmpPoint; - } - float[] mapPointFromParentToView(View v, float x, float y) { - mTmpPoint[0] = x - v.getLeft(); - mTmpPoint[1] = y - v.getTop(); - v.getMatrix().invert(mTmpInvMatrix); - mTmpInvMatrix.mapPoints(mTmpPoint); - return mTmpPoint; - } - - void updateDragViewTranslationDuringDrag() { - float x = mLastMotionX - mDownMotionX + getScrollX() - mDownScrollX; - float y = mLastMotionY - mDownMotionY; - mDragView.setTranslationX(x); - mDragView.setTranslationY(y); - - if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + x + ", " + y); - } - - public void setMinScale(float f) { - mMinScale = f; - requestLayout(); - } - - @Override - public void setScaleX(float scaleX) { - super.setScaleX(scaleX); - if (isReordering(true)) { - float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY); - mLastMotionX = p[0]; - mLastMotionY = p[1]; - updateDragViewTranslationDuringDrag(); - } - } - - // Convenience methods to get the actual width/height of the PagedView (since it is measured - // to be larger to account for the minimum possible scale) - int getViewportWidth() { - return mViewport.width(); - } - int getViewportHeight() { - return mViewport.height(); - } - - // Convenience methods to get the offset ASSUMING that we are centering the pages in the - // PagedView both horizontally and vertically - int getViewportOffsetX() { - return (getMeasuredWidth() - getViewportWidth()) / 2; - } - int getViewportOffsetY() { - return (getMeasuredHeight() - getViewportHeight()) / 2; - } - - public void setPageSwitchListener(PageSwitchListener pageSwitchListener) { - mPageSwitchListener = pageSwitchListener; - if (mPageSwitchListener != null) { - mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage); - } - } - - /** - * Called by subclasses to mark that data is ready, and that we can begin loading and laying - * out pages. - */ - protected void setDataIsReady() { - mIsDataReady = true; - } - - protected boolean isDataReady() { - return mIsDataReady; - } - - /** - * Returns the index of the currently displayed page. - * - * @return The index of the currently displayed page. - */ - int getCurrentPage() { - return mCurrentPage; - } - - int getNextPage() { - return (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; - } - - int getPageCount() { - return getChildCount(); - } - - View getPageAt(int index) { - return getChildAt(index); - } - - protected int indexToPage(int index) { - return index; - } - - /** - * Updates the scroll of the current page immediately to its final scroll position. We use this - * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of - * the previous tab page. - */ - protected void updateCurrentPageScroll() { - int offset = getChildOffset(mCurrentPage); - int relOffset = getRelativeChildOffset(mCurrentPage); - int newX = offset - relOffset; - scrollTo(newX, 0); - mScroller.setFinalX(newX); - mScroller.forceFinished(true); - } - - /** - * Sets the current page. - */ - void setCurrentPage(int currentPage) { - notifyPageSwitching(currentPage); - if (!mScroller.isFinished()) { - mScroller.abortAnimation(); - } - // don't introduce any checks like mCurrentPage == currentPage here-- if we change the - // the default - if (getChildCount() == 0) { - return; - } - - mForceScreenScrolled = true; - mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1)); - updateCurrentPageScroll(); - updateScrollingIndicator(); - notifyPageSwitched(); - invalidate(); - } - - public void setOnlyAllowEdgeSwipes(boolean enable) { - mOnlyAllowEdgeSwipes = enable; - } - - protected void notifyPageSwitching(int whichPage) { - if (mPageSwitchListener != null) { - mPageSwitchListener.onPageSwitching(getPageAt(whichPage), whichPage); - } - } - - protected void notifyPageSwitched() { - if (mPageSwitchListener != null) { - mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage); - } - } - - protected void pageBeginMoving() { - if (!mIsPageMoving) { - mIsPageMoving = true; - onPageBeginMoving(); - } - } - - protected void pageEndMoving() { - if (mIsPageMoving) { - mIsPageMoving = false; - onPageEndMoving(); - } - } - - protected boolean isPageMoving() { - return mIsPageMoving; - } - - // a method that subclasses can override to add behavior - protected void onPageBeginMoving() { - } - - // a method that subclasses can override to add behavior - protected void onPageEndMoving() { - } - - /** - * Registers the specified listener on each page contained in this workspace. - * - * @param l The listener used to respond to long clicks. - */ - @Override - public void setOnLongClickListener(OnLongClickListener l) { - mLongClickListener = l; - final int count = getPageCount(); - for (int i = 0; i < count; i++) { - getPageAt(i).setOnLongClickListener(l); - } - } - - @Override - public void scrollBy(int x, int y) { - scrollTo(mUnboundedScrollX + x, getScrollY() + y); - } - - @Override - public void scrollTo(int x, int y) { - mUnboundedScrollX = x; - - if (x < 0) { - super.scrollTo(0, y); - if (mAllowOverScroll) { - overScroll(x); - } - } else if (x > mMaxScrollX) { - super.scrollTo(mMaxScrollX, y); - if (mAllowOverScroll) { - overScroll(x - mMaxScrollX); - } - } else { - mOverScrollX = x; - super.scrollTo(x, y); - } - - mTouchX = x; - mSmoothingTime = System.nanoTime() / NANOTIME_DIV; - - // Update the last motion events when scrolling - if (isReordering(true)) { - float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY); - mLastMotionX = p[0]; - mLastMotionY = p[1]; - updateDragViewTranslationDuringDrag(); - } - } - - // we moved this functionality to a helper function so SmoothPagedView can reuse it - protected boolean computeScrollHelper() { - if (mScroller.computeScrollOffset()) { - // Don't bother scrolling if the page does not need to be moved - if (getScrollX() != mScroller.getCurrX() - || getScrollY() != mScroller.getCurrY() - || mOverScrollX != mScroller.getCurrX()) { - scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); - } - invalidate(); - return true; - } else if (mNextPage != INVALID_PAGE) { - mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1)); - mNextPage = INVALID_PAGE; - notifyPageSwitched(); - - // We don't want to trigger a page end moving unless the page has settled - // and the user has stopped scrolling - if (mTouchState == TOUCH_STATE_REST) { - pageEndMoving(); - } - - onPostReorderingAnimationCompleted(); - return true; - } - return false; - } - - @Override - public void computeScroll() { - computeScrollHelper(); - } - - protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) { - return mTopAlignPageWhenShrinkingForBouncer; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (!mIsDataReady || getChildCount() == 0) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - return; - } - - // We measure the dimensions of the PagedView to be larger than the pages so that when we - // zoom out (and scale down), the view is still contained in the parent - View parent = (View) getParent(); - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - // NOTE: We multiply by 1.5f to account for the fact that depending on the offset of the - // viewport, we can be at most one and a half screens offset once we scale down - DisplayMetrics dm = getResources().getDisplayMetrics(); - int maxSize = Math.max(dm.widthPixels, dm.heightPixels); - int parentWidthSize = (int) (1.5f * maxSize); - int parentHeightSize = maxSize; - int scaledWidthSize = (int) (parentWidthSize / mMinScale); - int scaledHeightSize = (int) (parentHeightSize / mMinScale); - mViewport.set(0, 0, widthSize, heightSize); - - if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - return; - } - - // Return early if we aren't given a proper dimension - if (widthSize <= 0 || heightSize <= 0) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - return; - } - - /* Allow the height to be set as WRAP_CONTENT. This allows the particular case - * of the All apps view on XLarge displays to not take up more space then it needs. Width - * is still not allowed to be set as WRAP_CONTENT since many parts of the code expect - * each page to have the same width. - */ - final int verticalPadding = getPaddingTop() + getPaddingBottom(); - final int horizontalPadding = getPaddingLeft() + getPaddingRight(); - - // The children are given the same width and height as the workspace - // unless they were set to WRAP_CONTENT - if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize); - if (DEBUG) Log.d(TAG, "PagedView.scaledSize: " + scaledWidthSize + ", " + scaledHeightSize); - if (DEBUG) Log.d(TAG, "PagedView.parentSize: " + parentWidthSize + ", " + parentHeightSize); - if (DEBUG) Log.d(TAG, "PagedView.horizontalPadding: " + horizontalPadding); - if (DEBUG) Log.d(TAG, "PagedView.verticalPadding: " + verticalPadding); - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - // disallowing padding in paged view (just pass 0) - final View child = getPageAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - int childWidthMode; - if (lp.width == LayoutParams.WRAP_CONTENT) { - childWidthMode = MeasureSpec.AT_MOST; - } else { - childWidthMode = MeasureSpec.EXACTLY; - } - - int childHeightMode; - if (lp.height == LayoutParams.WRAP_CONTENT) { - childHeightMode = MeasureSpec.AT_MOST; - } else { - childHeightMode = MeasureSpec.EXACTLY; - } - - final int childWidthMeasureSpec = - MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode); - final int childHeightMeasureSpec = - MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode); - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } - setMeasuredDimension(scaledWidthSize, scaledHeightSize); - - // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions. - // We also wait until we set the measured dimensions before flushing the cache as well, to - // ensure that the cache is filled with good values. - invalidateCachedOffsets(); - - if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) { - setCurrentPage(mCurrentPage); - } - mChildCountOnLastMeasure = getChildCount(); - - if (childCount > 0) { - if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getViewportWidth() + ", " - + getChildWidth(0)); - - // Calculate the variable page spacing if necessary - if (mPageSpacing == AUTOMATIC_PAGE_SPACING) { - // The gap between pages in the PagedView should be equal to the gap from the page - // to the edge of the screen (so it is not visible in the current screen). To - // account for unequal padding on each side of the paged view, we take the maximum - // of the left/right gap and use that as the gap between each page. - int offset = getRelativeChildOffset(0); - int spacing = Math.max(offset, widthSize - offset - - getChildAt(0).getMeasuredWidth()); - setPageSpacing(spacing); - } - } - - updateScrollingIndicatorPosition(); - - if (childCount > 0) { - mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1); - } else { - mMaxScrollX = 0; - } - } - - public void setPageSpacing(int pageSpacing) { - mPageSpacing = pageSpacing; - invalidateCachedOffsets(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - if (!mIsDataReady || getChildCount() == 0) { - return; - } - - if (DEBUG) Log.d(TAG, "PagedView.onLayout()"); - final int childCount = getChildCount(); - - int offsetX = getViewportOffsetX(); - int offsetY = getViewportOffsetY(); - - // Update the viewport offsets - mViewport.offset(offsetX, offsetY); - - int childLeft = offsetX + getRelativeChildOffset(0); - for (int i = 0; i < childCount; i++) { - final View child = getPageAt(i); - int childTop = offsetY + getPaddingTop(); - if (child.getVisibility() != View.GONE) { - final int childWidth = getScaledMeasuredWidth(child); - final int childHeight = child.getMeasuredHeight(); - - if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop); - child.layout(childLeft, childTop, - childLeft + child.getMeasuredWidth(), childTop + childHeight); - childLeft += childWidth + mPageSpacing; - } - } - - if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) { - setHorizontalScrollBarEnabled(false); - updateCurrentPageScroll(); - setHorizontalScrollBarEnabled(true); - mFirstLayout = false; - } - } - - protected void screenScrolled(int screenCenter) { - } - - @Override - public void onChildViewAdded(View parent, View child) { - // This ensures that when children are added, they get the correct transforms / alphas - // in accordance with any scroll effects. - mForceScreenScrolled = true; - invalidate(); - invalidateCachedOffsets(); - } - - @Override - public void onChildViewRemoved(View parent, View child) { - mForceScreenScrolled = true; - invalidate(); - invalidateCachedOffsets(); - } - - protected void invalidateCachedOffsets() { - int count = getChildCount(); - if (count == 0) { - mChildOffsets = null; - mChildRelativeOffsets = null; - mChildOffsetsWithLayoutScale = null; - return; - } - - mChildOffsets = new int[count]; - mChildRelativeOffsets = new int[count]; - mChildOffsetsWithLayoutScale = new int[count]; - for (int i = 0; i < count; i++) { - mChildOffsets[i] = -1; - mChildRelativeOffsets[i] = -1; - mChildOffsetsWithLayoutScale[i] = -1; - } - } - - protected int getChildOffset(int index) { - if (index < 0 || index > getChildCount() - 1) return 0; - - int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ? - mChildOffsets : mChildOffsetsWithLayoutScale; - - if (childOffsets != null && childOffsets[index] != -1) { - return childOffsets[index]; - } else { - if (getChildCount() == 0) - return 0; - - int offset = getRelativeChildOffset(0); - for (int i = 0; i < index; ++i) { - offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing; - } - if (childOffsets != null) { - childOffsets[index] = offset; - } - return offset; - } - } - - protected int getRelativeChildOffset(int index) { - if (index < 0 || index > getChildCount() - 1) return 0; - - if (mChildRelativeOffsets != null && mChildRelativeOffsets[index] != -1) { - return mChildRelativeOffsets[index]; - } else { - final int padding = getPaddingLeft() + getPaddingRight(); - final int offset = getPaddingLeft() + - (getViewportWidth() - padding - getChildWidth(index)) / 2; - if (mChildRelativeOffsets != null) { - mChildRelativeOffsets[index] = offset; - } - return offset; - } - } - - protected int getScaledMeasuredWidth(View child) { - // This functions are called enough times that it actually makes a difference in the - // profiler -- so just inline the max() here - final int measuredWidth = child.getMeasuredWidth(); - final int minWidth = mMinimumWidth; - final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth; - return (int) (maxWidth * mLayoutScale + 0.5f); - } - - void boundByReorderablePages(boolean isReordering, int[] range) { - // Do nothing - } - - // TODO: Fix this - protected void getVisiblePages(int[] range) { - range[0] = 0; - range[1] = getPageCount() - 1; - - /* - final int pageCount = getChildCount(); - - if (pageCount > 0) { - final int screenWidth = getViewportWidth(); - int leftScreen = 0; - int rightScreen = 0; - int offsetX = getViewportOffsetX() + getScrollX(); - View currPage = getPageAt(leftScreen); - while (leftScreen < pageCount - 1 && - currPage.getX() + currPage.getWidth() - - currPage.getPaddingRight() < offsetX) { - leftScreen++; - currPage = getPageAt(leftScreen); - } - rightScreen = leftScreen; - currPage = getPageAt(rightScreen + 1); - while (rightScreen < pageCount - 1 && - currPage.getX() - currPage.getPaddingLeft() < offsetX + screenWidth) { - rightScreen++; - currPage = getPageAt(rightScreen + 1); - } - - // TEMP: this is a hacky way to ensure that animations to new pages are not clipped - // because we don't draw them while scrolling? - range[0] = Math.max(0, leftScreen - 1); - range[1] = Math.min(rightScreen + 1, getChildCount() - 1); - } else { - range[0] = -1; - range[1] = -1; - } - */ - } - - protected boolean shouldDrawChild(View child) { - return child.getAlpha() > 0; - } - - @Override - protected void dispatchDraw(Canvas canvas) { - int halfScreenSize = getViewportWidth() / 2; - // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. - // Otherwise it is equal to the scaled overscroll position. - int screenCenter = mOverScrollX + halfScreenSize; - - if (screenCenter != mLastScreenCenter || mForceScreenScrolled) { - // set mForceScreenScrolled before calling screenScrolled so that screenScrolled can - // set it for the next frame - mForceScreenScrolled = false; - screenScrolled(screenCenter); - mLastScreenCenter = screenCenter; - } - - // Find out which screens are visible; as an optimization we only call draw on them - final int pageCount = getChildCount(); - if (pageCount > 0) { - getVisiblePages(mTempVisiblePagesRange); - final int leftScreen = mTempVisiblePagesRange[0]; - final int rightScreen = mTempVisiblePagesRange[1]; - if (leftScreen != -1 && rightScreen != -1) { - final long drawingTime = getDrawingTime(); - // Clip to the bounds - canvas.save(); - canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(), - getScrollY() + getBottom() - getTop()); - - // Draw all the children, leaving the drag view for last - for (int i = pageCount - 1; i >= 0; i--) { - final View v = getPageAt(i); - if (v == mDragView) continue; - if (mForceDrawAllChildrenNextFrame || - (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) { - drawChild(canvas, v, drawingTime); - } - } - // Draw the drag view on top (if there is one) - if (mDragView != null) { - drawChild(canvas, mDragView, drawingTime); - } - - mForceDrawAllChildrenNextFrame = false; - canvas.restore(); - } - } - } - - @Override - public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { - int page = indexToPage(indexOfChild(child)); - if (page != mCurrentPage || !mScroller.isFinished()) { - snapToPage(page); - return true; - } - return false; - } - - @Override - protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { - int focusablePage; - if (mNextPage != INVALID_PAGE) { - focusablePage = mNextPage; - } else { - focusablePage = mCurrentPage; - } - View v = getPageAt(focusablePage); - if (v != null) { - return v.requestFocus(direction, previouslyFocusedRect); - } - return false; - } - - @Override - public boolean dispatchUnhandledMove(View focused, int direction) { - if (direction == View.FOCUS_LEFT) { - if (getCurrentPage() > 0) { - snapToPage(getCurrentPage() - 1); - return true; - } - } else if (direction == View.FOCUS_RIGHT) { - if (getCurrentPage() < getPageCount() - 1) { - snapToPage(getCurrentPage() + 1); - return true; - } - } - return super.dispatchUnhandledMove(focused, direction); - } - - @Override - public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { - if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) { - getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode); - } - if (direction == View.FOCUS_LEFT) { - if (mCurrentPage > 0) { - getPageAt(mCurrentPage - 1).addFocusables(views, direction, focusableMode); - } - } else if (direction == View.FOCUS_RIGHT){ - if (mCurrentPage < getPageCount() - 1) { - getPageAt(mCurrentPage + 1).addFocusables(views, direction, focusableMode); - } - } - } - - /** - * If one of our descendant views decides that it could be focused now, only - * pass that along if it's on the current page. - * - * This happens when live folders requery, and if they're off page, they - * end up calling requestFocus, which pulls it on page. - */ - @Override - public void focusableViewAvailable(View focused) { - View current = getPageAt(mCurrentPage); - View v = focused; - while (true) { - if (v == current) { - super.focusableViewAvailable(focused); - return; - } - if (v == this) { - return; - } - ViewParent parent = v.getParent(); - if (parent instanceof View) { - v = (View)v.getParent(); - } else { - return; - } - } - } - - /** - * Return true if a tap at (x, y) should trigger a flip to the previous page. - */ - protected boolean hitsPreviousPage(float x, float y) { - return (x < getViewportOffsetX() + getRelativeChildOffset(mCurrentPage) - mPageSpacing); - } - - /** - * Return true if a tap at (x, y) should trigger a flip to the next page. - */ - protected boolean hitsNextPage(float x, float y) { - return (x > (getViewportOffsetX() + getViewportWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing)); - } - - /** Returns whether x and y originated within the buffered viewport */ - private boolean isTouchPointInViewportWithBuffer(int x, int y) { - mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top, - mViewport.right + mViewport.width() / 2, mViewport.bottom); - return mTmpRect.contains(x, y); - } - - /** Returns whether x and y originated within the current page view bounds */ - private boolean isTouchPointInCurrentPage(int x, int y) { - View v = getPageAt(getCurrentPage()); - if (v != null) { - mTmpRect.set((v.getLeft() - getScrollX()), 0, (v.getRight() - getScrollX()), - v.getBottom()); - return mTmpRect.contains(x, y); - } - return false; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (DISABLE_TOUCH_INTERACTION) { - return false; - } - - /* - * This method JUST determines whether we want to intercept the motion. - * If we return true, onTouchEvent will be called and we do the actual - * scrolling there. - */ - acquireVelocityTrackerAndAddMovement(ev); - - // Skip touch handling if there are no pages to swipe - if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev); - - /* - * Shortcut the most recurring case: the user is in the dragging - * state and he is moving his finger. We want to intercept this - * motion. - */ - final int action = ev.getAction(); - if ((action == MotionEvent.ACTION_MOVE) && - (mTouchState == TOUCH_STATE_SCROLLING)) { - return true; - } - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_MOVE: { - /* - * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check - * whether the user has moved far enough from his original down touch. - */ - if (mActivePointerId != INVALID_POINTER) { - determineScrollingStart(ev); - break; - } - // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN - // event. in that case, treat the first occurence of a move event as a ACTION_DOWN - // i.e. fall through to the next case (don't break) - // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events - // while it's small- this was causing a crash before we checked for INVALID_POINTER) - } - - case MotionEvent.ACTION_DOWN: { - final float x = ev.getX(); - final float y = ev.getY(); - // Remember location of down touch - mDownMotionX = x; - mDownMotionY = y; - mDownScrollX = getScrollX(); - mLastMotionX = x; - mLastMotionY = y; - float[] p = mapPointFromViewToParent(this, x, y); - mParentDownMotionX = p[0]; - mParentDownMotionY = p[1]; - mLastMotionXRemainder = 0; - mTotalMotionX = 0; - mActivePointerId = ev.getPointerId(0); - - // Determine if the down event is within the threshold to be an edge swipe - int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize; - int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize; - if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) { - mDownEventOnEdge = true; - } - - /* - * If being flinged and user touches the screen, initiate drag; - * otherwise don't. mScroller.isFinished should be false when - * being flinged. - */ - final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX()); - final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop); - if (finishedScrolling) { - mTouchState = TOUCH_STATE_REST; - mScroller.abortAnimation(); - } else { - if (isTouchPointInViewportWithBuffer((int) mDownMotionX, (int) mDownMotionY)) { - mTouchState = TOUCH_STATE_SCROLLING; - } else { - mTouchState = TOUCH_STATE_REST; - } - } - - // check if this can be the beginning of a tap on the side of the pages - // to scroll the current page - if (!DISABLE_TOUCH_SIDE_PAGES) { - if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) { - if (getChildCount() > 0) { - if (hitsPreviousPage(x, y)) { - mTouchState = TOUCH_STATE_PREV_PAGE; - } else if (hitsNextPage(x, y)) { - mTouchState = TOUCH_STATE_NEXT_PAGE; - } - } - } - } - break; - } - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - resetTouchState(); - // Just intercept the touch event on up if we tap outside the strict viewport - if (!isTouchPointInCurrentPage((int) mLastMotionX, (int) mLastMotionY)) { - return true; - } - break; - - case MotionEvent.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - releaseVelocityTracker(); - break; - } - - /* - * The only time we want to intercept motion events is if we are in the - * drag mode. - */ - return mTouchState != TOUCH_STATE_REST; - } - - protected void determineScrollingStart(MotionEvent ev) { - determineScrollingStart(ev, 1.0f); - } - - /* - * Determines if we should change the touch state to start scrolling after the - * user moves their touch point too far. - */ - protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) { - // Disallow scrolling if we don't have a valid pointer index - final int pointerIndex = ev.findPointerIndex(mActivePointerId); - if (pointerIndex == -1) return; - - // Disallow scrolling if we started the gesture from outside the viewport - final float x = ev.getX(pointerIndex); - final float y = ev.getY(pointerIndex); - if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return; - - // If we're only allowing edge swipes, we break out early if the down event wasn't - // at the edge. - if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return; - - final int xDiff = (int) Math.abs(x - mLastMotionX); - final int yDiff = (int) Math.abs(y - mLastMotionY); - - final int touchSlop = Math.round(touchSlopScale * mTouchSlop); - boolean xPaged = xDiff > mPagingTouchSlop; - boolean xMoved = xDiff > touchSlop; - boolean yMoved = yDiff > touchSlop; - - if (xMoved || xPaged || yMoved) { - if (mUsePagingTouchSlop ? xPaged : xMoved) { - // Scroll if the user moved far enough along the X axis - mTouchState = TOUCH_STATE_SCROLLING; - mTotalMotionX += Math.abs(mLastMotionX - x); - mLastMotionX = x; - mLastMotionXRemainder = 0; - mTouchX = getViewportOffsetX() + getScrollX(); - mSmoothingTime = System.nanoTime() / NANOTIME_DIV; - pageBeginMoving(); - } - } - } - - protected float getMaxScrollProgress() { - return 1.0f; - } - - protected float getBoundedScrollProgress(int screenCenter, View v, int page) { - final int halfScreenSize = getViewportWidth() / 2; - - screenCenter = Math.min(mScrollX + halfScreenSize, screenCenter); - screenCenter = Math.max(halfScreenSize, screenCenter); - - return getScrollProgress(screenCenter, v, page); - } - - protected float getScrollProgress(int screenCenter, View v, int page) { - final int halfScreenSize = getViewportWidth() / 2; - - int totalDistance = getScaledMeasuredWidth(v) + mPageSpacing; - int delta = screenCenter - (getChildOffset(page) - - getRelativeChildOffset(page) + halfScreenSize); - - float scrollProgress = delta / (totalDistance * 1.0f); - scrollProgress = Math.min(scrollProgress, getMaxScrollProgress()); - scrollProgress = Math.max(scrollProgress, - getMaxScrollProgress()); - return scrollProgress; - } - - // This curve determines how the effect of scrolling over the limits of the page dimishes - // as the user pulls further and further from the bounds - private float overScrollInfluenceCurve(float f) { - f -= 1.0f; - return f * f * f + 1.0f; - } - - protected void acceleratedOverScroll(float amount) { - int screenSize = getViewportWidth(); - - // We want to reach the max over scroll effect when the user has - // over scrolled half the size of the screen - float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize); - - if (f == 0) return; - - // Clamp this factor, f, to -1 < f < 1 - if (Math.abs(f) >= 1) { - f /= Math.abs(f); - } - - int overScrollAmount = (int) Math.round(f * screenSize); - if (amount < 0) { - mOverScrollX = overScrollAmount; - super.scrollTo(0, getScrollY()); - } else { - mOverScrollX = mMaxScrollX + overScrollAmount; - super.scrollTo(mMaxScrollX, getScrollY()); - } - invalidate(); - } - - protected void dampedOverScroll(float amount) { - int screenSize = getViewportWidth(); - - float f = (amount / screenSize); - - if (f == 0) return; - f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f))); - - // Clamp this factor, f, to -1 < f < 1 - if (Math.abs(f) >= 1) { - f /= Math.abs(f); - } - - int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize); - if (amount < 0) { - mOverScrollX = overScrollAmount; - super.scrollTo(0, getScrollY()); - } else { - mOverScrollX = mMaxScrollX + overScrollAmount; - super.scrollTo(mMaxScrollX, getScrollY()); - } - invalidate(); - } - - protected void overScroll(float amount) { - dampedOverScroll(amount); - } - - protected float maxOverScroll() { - // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not - // exceed). Used to find out how much extra wallpaper we need for the over scroll effect - float f = 1.0f; - f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f))); - return OVERSCROLL_DAMP_FACTOR * f; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (DISABLE_TOUCH_INTERACTION) { - return false; - } - - // Skip touch handling if there are no pages to swipe - if (getChildCount() <= 0) return super.onTouchEvent(ev); - - acquireVelocityTrackerAndAddMovement(ev); - - final int action = ev.getAction(); - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - /* - * If being flinged and user touches, stop the fling. isFinished - * will be false if being flinged. - */ - if (!mScroller.isFinished()) { - mScroller.abortAnimation(); - } - - // Remember where the motion event started - mDownMotionX = mLastMotionX = ev.getX(); - mDownMotionY = mLastMotionY = ev.getY(); - mDownScrollX = getScrollX(); - float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); - mParentDownMotionX = p[0]; - mParentDownMotionY = p[1]; - mLastMotionXRemainder = 0; - mTotalMotionX = 0; - mActivePointerId = ev.getPointerId(0); - - // Determine if the down event is within the threshold to be an edge swipe - int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize; - int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize; - if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) { - mDownEventOnEdge = true; - } - - if (mTouchState == TOUCH_STATE_SCROLLING) { - pageBeginMoving(); - } - break; - - case MotionEvent.ACTION_MOVE: - 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; - - mTotalMotionX += Math.abs(deltaX); - - // Only scroll and update mLastMotionX if we have moved some discrete amount. We - // keep the remainder because we are actually testing if we've moved from the last - // scrolled position (which is discrete). - if (Math.abs(deltaX) >= 1.0f) { - mTouchX += deltaX; - mSmoothingTime = System.nanoTime() / NANOTIME_DIV; - if (!mDeferScrollUpdate) { - scrollBy((int) deltaX, 0); - if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX); - } else { - invalidate(); - } - mLastMotionX = x; - mLastMotionXRemainder = deltaX - (int) deltaX; - } else { - awakenScrollBars(); - } - } else if (mTouchState == TOUCH_STATE_REORDERING) { - // Update the last motion position - mLastMotionX = ev.getX(); - mLastMotionY = ev.getY(); - - // Update the parent down so that our zoom animations take this new movement into - // account - float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); - mParentDownMotionX = pt[0]; - mParentDownMotionY = pt[1]; - updateDragViewTranslationDuringDrag(); - - // Find the closest page to the touch point - final int dragViewIndex = indexOfChild(mDragView); - int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE * - getViewportWidth()); - int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0] - + bufferSize); - int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0] - - bufferSize); - - // Change the drag view if we are hovering over the drop target - boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget( - (int) mParentDownMotionX, (int) mParentDownMotionY); - setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete); - - if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge); - if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge); - if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX); - if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY); - if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX); - if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY); - - float parentX = mParentDownMotionX; - int pageIndexToSnapTo = -1; - if (parentX < leftBufferEdge && dragViewIndex > 0) { - pageIndexToSnapTo = dragViewIndex - 1; - } else if (parentX > rightBufferEdge && dragViewIndex < getChildCount() - 1) { - pageIndexToSnapTo = dragViewIndex + 1; - } - - final int pageUnderPointIndex = pageIndexToSnapTo; - if (pageUnderPointIndex > -1 && !isHoveringOverDelete) { - mTempVisiblePagesRange[0] = 0; - mTempVisiblePagesRange[1] = getPageCount() - 1; - boundByReorderablePages(true, mTempVisiblePagesRange); - if (mTempVisiblePagesRange[0] <= pageUnderPointIndex && - pageUnderPointIndex <= mTempVisiblePagesRange[1] && - pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) { - mSidePageHoverIndex = pageUnderPointIndex; - mSidePageHoverRunnable = new Runnable() { - @Override - public void run() { - // Update the down scroll position to account for the fact that the - // current page is moved - mDownScrollX = getChildOffset(pageUnderPointIndex) - - getRelativeChildOffset(pageUnderPointIndex); - - // Setup the scroll to the correct page before we swap the views - snapToPage(pageUnderPointIndex); - - // For each of the pages between the paged view and the drag view, - // animate them from the previous position to the new position in - // the layout (as a result of the drag view moving in the layout) - int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1; - int lowerIndex = (dragViewIndex < pageUnderPointIndex) ? - dragViewIndex + 1 : pageUnderPointIndex; - int upperIndex = (dragViewIndex > pageUnderPointIndex) ? - dragViewIndex - 1 : pageUnderPointIndex; - for (int i = lowerIndex; i <= upperIndex; ++i) { - View v = getChildAt(i); - // dragViewIndex < pageUnderPointIndex, so after we remove the - // drag view all subsequent views to pageUnderPointIndex will - // shift down. - int oldX = getViewportOffsetX() + getChildOffset(i); - int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta); - - // Animate the view translation from its old position to its new - // position - AnimatorSet anim = (AnimatorSet) v.getTag(); - if (anim != null) { - anim.cancel(); - } - - v.setTranslationX(oldX - newX); - anim = new AnimatorSet(); - anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION); - anim.playTogether( - ObjectAnimator.ofFloat(v, "translationX", 0f)); - anim.start(); - v.setTag(anim); - } - - removeView(mDragView); - onRemoveView(mDragView, false); - addView(mDragView, pageUnderPointIndex); - onAddView(mDragView, pageUnderPointIndex); - mSidePageHoverIndex = -1; - } - }; - postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT); - } - } else { - removeCallbacks(mSidePageHoverRunnable); - mSidePageHoverIndex = -1; - } - } else { - determineScrollingStart(ev); - } - break; - - case MotionEvent.ACTION_UP: - if (mTouchState == TOUCH_STATE_SCROLLING) { - final int activePointerId = mActivePointerId; - final int pointerIndex = ev.findPointerIndex(activePointerId); - final float x = ev.getX(pointerIndex); - final VelocityTracker velocityTracker = mVelocityTracker; - velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - int velocityX = (int) velocityTracker.getXVelocity(activePointerId); - final int deltaX = (int) (x - mDownMotionX); - final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage)); - boolean isSignificantMove = Math.abs(deltaX) > pageWidth * - SIGNIFICANT_MOVE_THRESHOLD; - - mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x); - - boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING && - Math.abs(velocityX) > mFlingThresholdVelocity; - - // In the case that the page is moved far to one direction and then is flung - // in the opposite direction, we use a threshold to determine whether we should - // just return to the starting page, or if we should skip one further. - boolean returnToOriginalPage = false; - if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD && - Math.signum(velocityX) != Math.signum(deltaX) && isFling) { - returnToOriginalPage = true; - } - - int finalPage; - // We give flings precedence over large moves, which is why we short-circuit our - // test for a large move if a fling has been registered. That is, a large - // move to the left and fling to the right will register as a fling to the right. - if (((isSignificantMove && deltaX > 0 && !isFling) || - (isFling && velocityX > 0)) && mCurrentPage > 0) { - finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1; - snapToPageWithVelocity(finalPage, velocityX); - } else if (((isSignificantMove && deltaX < 0 && !isFling) || - (isFling && velocityX < 0)) && - mCurrentPage < getChildCount() - 1) { - finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1; - snapToPageWithVelocity(finalPage, velocityX); - } else { - snapToDestination(); - } - } else if (mTouchState == TOUCH_STATE_PREV_PAGE) { - // at this point we have not moved beyond the touch slop - // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so - // we can just page - int nextPage = Math.max(0, mCurrentPage - 1); - if (nextPage != mCurrentPage) { - snapToPage(nextPage); - } else { - snapToDestination(); - } - } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) { - // at this point we have not moved beyond the touch slop - // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so - // we can just page - int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1); - if (nextPage != mCurrentPage) { - snapToPage(nextPage); - } else { - snapToDestination(); - } - } else if (mTouchState == TOUCH_STATE_REORDERING) { - // Update the last motion position - mLastMotionX = ev.getX(); - mLastMotionY = ev.getY(); - - // Update the parent down so that our zoom animations take this new movement into - // account - float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); - mParentDownMotionX = pt[0]; - mParentDownMotionY = pt[1]; - updateDragViewTranslationDuringDrag(); - boolean handledFling = false; - if (!DISABLE_FLING_TO_DELETE) { - // Check the velocity and see if we are flinging-to-delete - PointF flingToDeleteVector = isFlingingToDelete(); - if (flingToDeleteVector != null) { - onFlingToDelete(flingToDeleteVector); - handledFling = true; - } - } - if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX, - (int) mParentDownMotionY)) { - onDropToDelete(); - } - } else { - onUnhandledTap(ev); - } - - // Remove the callback to wait for the side page hover timeout - removeCallbacks(mSidePageHoverRunnable); - // End any intermediate reordering states - resetTouchState(); - break; - - case MotionEvent.ACTION_CANCEL: - if (mTouchState == TOUCH_STATE_SCROLLING) { - snapToDestination(); - } - resetTouchState(); - break; - - case MotionEvent.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - break; - } - - return true; - } - - //public abstract void onFlingToDelete(View v); - public abstract void onRemoveView(View v, boolean deletePermanently); - public abstract void onRemoveViewAnimationCompleted(); - public abstract void onAddView(View v, int index); - - private void resetTouchState() { - releaseVelocityTracker(); - endReordering(); - mTouchState = TOUCH_STATE_REST; - mActivePointerId = INVALID_POINTER; - mDownEventOnEdge = false; - } - - protected void onUnhandledTap(MotionEvent ev) {} - - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { - switch (event.getAction()) { - case MotionEvent.ACTION_SCROLL: { - // Handle mouse (or ext. device) by shifting the page depending on the scroll - final float vscroll; - final float hscroll; - if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) { - vscroll = 0; - hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); - } else { - vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL); - hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL); - } - if (hscroll != 0 || vscroll != 0) { - if (hscroll > 0 || vscroll > 0) { - scrollRight(); - } else { - scrollLeft(); - } - return true; - } - } - } - } - return super.onGenericMotionEvent(event); - } - - private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) { - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(ev); - } - - private void releaseVelocityTracker() { - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - } - - private void onSecondaryPointerUp(MotionEvent ev) { - final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> - MotionEvent.ACTION_POINTER_INDEX_SHIFT; - final int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - // TODO: Make this decision more intelligent. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - mLastMotionX = mDownMotionX = ev.getX(newPointerIndex); - mLastMotionY = ev.getY(newPointerIndex); - mLastMotionXRemainder = 0; - mActivePointerId = ev.getPointerId(newPointerIndex); - if (mVelocityTracker != null) { - mVelocityTracker.clear(); - } - } - } - - @Override - public void requestChildFocus(View child, View focused) { - super.requestChildFocus(child, focused); - int page = indexToPage(indexOfChild(child)); - if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) { - snapToPage(page); - } - } - - protected int getChildIndexForRelativeOffset(int relativeOffset) { - final int childCount = getChildCount(); - int left; - int right; - for (int i = 0; i < childCount; ++i) { - left = getRelativeChildOffset(i); - right = (left + getScaledMeasuredWidth(getPageAt(i))); - if (left <= relativeOffset && relativeOffset <= right) { - return i; - } - } - return -1; - } - - protected int getChildWidth(int index) { - // This functions are called enough times that it actually makes a difference in the - // profiler -- so just inline the max() here - final int measuredWidth = getPageAt(index).getMeasuredWidth(); - final int minWidth = mMinimumWidth; - return (minWidth > measuredWidth) ? minWidth : measuredWidth; - } - - int getPageNearestToPoint(float x) { - int index = 0; - for (int i = 0; i < getChildCount(); ++i) { - if (x < getChildAt(i).getRight() - getScrollX()) { - return index; - } else { - index++; - } - } - return Math.min(index, getChildCount() - 1); - } - - int getPageNearestToCenterOfScreen() { - int minDistanceFromScreenCenter = Integer.MAX_VALUE; - int minDistanceFromScreenCenterIndex = -1; - int screenCenter = getViewportOffsetX() + getScrollX() + (getViewportWidth() / 2); - final int childCount = getChildCount(); - for (int i = 0; i < childCount; ++i) { - View layout = (View) getPageAt(i); - int childWidth = getScaledMeasuredWidth(layout); - int halfChildWidth = (childWidth / 2); - int childCenter = getViewportOffsetX() + getChildOffset(i) + halfChildWidth; - int distanceFromScreenCenter = Math.abs(childCenter - screenCenter); - if (distanceFromScreenCenter < minDistanceFromScreenCenter) { - minDistanceFromScreenCenter = distanceFromScreenCenter; - minDistanceFromScreenCenterIndex = i; - } - } - return minDistanceFromScreenCenterIndex; - } - - protected void snapToDestination() { - snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION); - } - - private static class ScrollInterpolator implements Interpolator { - public ScrollInterpolator() { - } - - public float getInterpolation(float t) { - t -= 1.0f; - return t*t*t*t*t + 1; - } - } - - // We want the duration of the page snap animation to be influenced by the distance that - // the screen has to travel, however, we don't want this duration to be effected in a - // purely linear fashion. Instead, we use this method to moderate the effect that the distance - // of travel has on the overall snap duration. - float distanceInfluenceForSnapDuration(float f) { - f -= 0.5f; // center the values about 0. - f *= 0.3f * Math.PI / 2.0f; - return (float) Math.sin(f); - } - - protected void snapToPageWithVelocity(int whichPage, int velocity) { - whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1)); - int halfScreenSize = getViewportWidth() / 2; - - if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage)); - if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): " - + getViewportWidth() + ", " + getChildWidth(whichPage)); - final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage); - int delta = newX - mUnboundedScrollX; - int duration = 0; - - if (Math.abs(velocity) < mMinFlingVelocity) { - // If the velocity is low enough, then treat this more as an automatic page advance - // as opposed to an apparent physical response to flinging - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); - return; - } - - // Here we compute a "distance" that will be used in the computation of the overall - // snap duration. This is a function of the actual distance that needs to be traveled; - // we keep this value close to half screen size in order to reduce the variance in snap - // duration as a function of the distance the page needs to travel. - float distanceRatio = Math.min(1f, 1.0f * Math.abs(delta) / (2 * halfScreenSize)); - float distance = halfScreenSize + halfScreenSize * - distanceInfluenceForSnapDuration(distanceRatio); - - velocity = Math.abs(velocity); - velocity = Math.max(mMinSnapVelocity, velocity); - - // we want the page's snap velocity to approximately match the velocity at which the - // user flings, so we scale the duration by a value near to the derivative of the scroll - // interpolator at zero, ie. 5. We use 4 to make it a little slower. - duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); - - snapToPage(whichPage, delta, duration); - } - - protected void snapToPage(int whichPage) { - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); - } - protected void snapToPageImmediately(int whichPage) { - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true); - } - - protected void snapToPage(int whichPage, int duration) { - snapToPage(whichPage, duration, false); - } - protected void snapToPage(int whichPage, int duration, boolean immediate) { - whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1)); - - if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage)); - if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getViewportWidth() + ", " - + getChildWidth(whichPage)); - int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage); - final int sX = mUnboundedScrollX; - final int delta = newX - sX; - snapToPage(whichPage, delta, duration, immediate); - } - - protected void snapToPage(int whichPage, int delta, int duration) { - snapToPage(whichPage, delta, duration, false); - } - protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) { - mNextPage = whichPage; - notifyPageSwitching(whichPage); - View focusedChild = getFocusedChild(); - if (focusedChild != null && whichPage != mCurrentPage && - focusedChild == getPageAt(mCurrentPage)) { - focusedChild.clearFocus(); - } - - pageBeginMoving(); - awakenScrollBars(duration); - if (immediate) { - duration = 0; - } else if (duration == 0) { - duration = Math.abs(delta); - } - - if (!mScroller.isFinished()) mScroller.abortAnimation(); - mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration); - - notifyPageSwitched(); - - // Trigger a compute() to finish switching pages if necessary - if (immediate) { - computeScroll(); - } - - mForceScreenScrolled = true; - invalidate(); - } - - public void scrollLeft() { - if (mScroller.isFinished()) { - if (mCurrentPage > 0) snapToPage(mCurrentPage - 1); - } else { - if (mNextPage > 0) snapToPage(mNextPage - 1); - } - } - - public void scrollRight() { - if (mScroller.isFinished()) { - if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1); - } else { - if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1); - } - } - - public int getPageForView(View v) { - int result = -1; - if (v != null) { - ViewParent vp = v.getParent(); - int count = getChildCount(); - for (int i = 0; i < count; i++) { - if (vp == getPageAt(i)) { - return i; - } - } - } - return result; - } - - public static class SavedState extends BaseSavedState { - int currentPage = -1; - - SavedState(Parcelable superState) { - super(superState); - } - - private SavedState(Parcel in) { - super(in); - currentPage = in.readInt(); - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(currentPage); - } - - public static final Parcelable.Creator<SavedState> CREATOR = - new Parcelable.Creator<SavedState>() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } - - protected View getScrollingIndicator() { - return null; - } - - protected boolean isScrollingIndicatorEnabled() { - return false; - } - - Runnable hideScrollingIndicatorRunnable = new Runnable() { - @Override - public void run() { - hideScrollingIndicator(false); - } - }; - - protected void flashScrollingIndicator(boolean animated) { - removeCallbacks(hideScrollingIndicatorRunnable); - showScrollingIndicator(!animated); - postDelayed(hideScrollingIndicatorRunnable, sScrollIndicatorFlashDuration); - } - - protected void showScrollingIndicator(boolean immediately) { - mShouldShowScrollIndicator = true; - mShouldShowScrollIndicatorImmediately = true; - if (getChildCount() <= 1) return; - if (!isScrollingIndicatorEnabled()) return; - - mShouldShowScrollIndicator = false; - getScrollingIndicator(); - if (mScrollIndicator != null) { - // Fade the indicator in - updateScrollingIndicatorPosition(); - mScrollIndicator.setVisibility(View.VISIBLE); - cancelScrollingIndicatorAnimations(); - if (immediately) { - mScrollIndicator.setAlpha(1f); - } else { - mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f); - mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration); - mScrollIndicatorAnimator.start(); - } - } - } - - protected void cancelScrollingIndicatorAnimations() { - if (mScrollIndicatorAnimator != null) { - mScrollIndicatorAnimator.cancel(); - } - } - - protected void hideScrollingIndicator(boolean immediately) { - if (getChildCount() <= 1) return; - if (!isScrollingIndicatorEnabled()) return; - - getScrollingIndicator(); - if (mScrollIndicator != null) { - // Fade the indicator out - updateScrollingIndicatorPosition(); - cancelScrollingIndicatorAnimations(); - if (immediately) { - mScrollIndicator.setVisibility(View.INVISIBLE); - mScrollIndicator.setAlpha(0f); - } else { - mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f); - mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration); - mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() { - private boolean cancelled = false; - @Override - public void onAnimationCancel(android.animation.Animator animation) { - cancelled = true; - } - @Override - public void onAnimationEnd(Animator animation) { - if (!cancelled) { - mScrollIndicator.setVisibility(View.INVISIBLE); - } - } - }); - mScrollIndicatorAnimator.start(); - } - } - } - - /** - * To be overridden by subclasses to determine whether the scroll indicator should stretch to - * fill its space on the track or not. - */ - protected boolean hasElasticScrollIndicator() { - return true; - } - - private void updateScrollingIndicator() { - if (getChildCount() <= 1) return; - if (!isScrollingIndicatorEnabled()) return; - - getScrollingIndicator(); - if (mScrollIndicator != null) { - updateScrollingIndicatorPosition(); - } - if (mShouldShowScrollIndicator) { - showScrollingIndicator(mShouldShowScrollIndicatorImmediately); - } - } - - private void updateScrollingIndicatorPosition() { - if (!isScrollingIndicatorEnabled()) return; - if (mScrollIndicator == null) return; - int numPages = getChildCount(); - int pageWidth = getViewportWidth(); - int lastChildIndex = Math.max(0, getChildCount() - 1); - int maxScrollX = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex); - int trackWidth = pageWidth - mScrollIndicatorPaddingLeft - mScrollIndicatorPaddingRight; - int indicatorWidth = mScrollIndicator.getMeasuredWidth() - - mScrollIndicator.getPaddingLeft() - mScrollIndicator.getPaddingRight(); - - float offset = Math.max(0f, Math.min(1f, (float) getScrollX() / maxScrollX)); - int indicatorSpace = trackWidth / numPages; - int indicatorPos = (int) (offset * (trackWidth - indicatorSpace)) + mScrollIndicatorPaddingLeft; - if (hasElasticScrollIndicator()) { - if (mScrollIndicator.getMeasuredWidth() != indicatorSpace) { - mScrollIndicator.getLayoutParams().width = indicatorSpace; - mScrollIndicator.requestLayout(); - } - } else { - int indicatorCenterOffset = indicatorSpace / 2 - indicatorWidth / 2; - indicatorPos += indicatorCenterOffset; - } - mScrollIndicator.setTranslationX(indicatorPos); - } - - // Animate the drag view back to the original position - void animateDragViewToOriginalPosition() { - if (mDragView != null) { - AnimatorSet anim = new AnimatorSet(); - anim.setDuration(REORDERING_DROP_REPOSITION_DURATION); - anim.playTogether( - ObjectAnimator.ofFloat(mDragView, "translationX", 0f), - ObjectAnimator.ofFloat(mDragView, "translationY", 0f)); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - onPostReorderingAnimationCompleted(); - } - }); - anim.start(); - } - } - - // "Zooms out" the PagedView to reveal more side pages - protected boolean zoomOut() { - if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) { - mZoomInOutAnim.cancel(); - } - - if (!(getScaleX() < 1f || getScaleY() < 1f)) { - mZoomInOutAnim = new AnimatorSet(); - mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION); - mZoomInOutAnim.playTogether( - ObjectAnimator.ofFloat(this, "scaleX", mMinScale), - ObjectAnimator.ofFloat(this, "scaleY", mMinScale)); - mZoomInOutAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - // Show the delete drop target - if (mDeleteDropTarget != null) { - mDeleteDropTarget.setVisibility(View.VISIBLE); - mDeleteDropTarget.animate().alpha(1f) - .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mDeleteDropTarget.setAlpha(0f); - } - }); - } - } - }); - mZoomInOutAnim.start(); - return true; - } - return false; - } - - protected void onStartReordering() { - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - announceForAccessibility(mContext.getString( - R.string.keyguard_accessibility_widget_reorder_start)); - } - - // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.) - mTouchState = TOUCH_STATE_REORDERING; - mIsReordering = true; - - // Mark all the non-widget pages as invisible - getVisiblePages(mTempVisiblePagesRange); - boundByReorderablePages(true, mTempVisiblePagesRange); - for (int i = 0; i < getPageCount(); ++i) { - if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) { - getPageAt(i).setAlpha(0f); - } - } - - // We must invalidate to trigger a redraw to update the layers such that the drag view - // is always drawn on top - invalidate(); - } - - private void onPostReorderingAnimationCompleted() { - // Trigger the callback when reordering has settled - --mPostReorderingPreZoomInRemainingAnimationCount; - if (mPostReorderingPreZoomInRunnable != null && - mPostReorderingPreZoomInRemainingAnimationCount == 0) { - mPostReorderingPreZoomInRunnable.run(); - mPostReorderingPreZoomInRunnable = null; - } - } - - protected void onEndReordering() { - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - announceForAccessibility(mContext.getString( - R.string.keyguard_accessibility_widget_reorder_end)); - } - mIsReordering = false; - - // Mark all the non-widget pages as visible again - getVisiblePages(mTempVisiblePagesRange); - boundByReorderablePages(true, mTempVisiblePagesRange); - for (int i = 0; i < getPageCount(); ++i) { - if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) { - getPageAt(i).setAlpha(1f); - } - } - } - - public boolean startReordering() { - int dragViewIndex = getPageNearestToCenterOfScreen(); - mTempVisiblePagesRange[0] = 0; - mTempVisiblePagesRange[1] = getPageCount() - 1; - boundByReorderablePages(true, mTempVisiblePagesRange); - mReorderingStarted = true; - - // Check if we are within the reordering range - if (mTempVisiblePagesRange[0] <= dragViewIndex && - dragViewIndex <= mTempVisiblePagesRange[1]) { - if (zoomOut()) { - // Find the drag view under the pointer - mDragView = getChildAt(dragViewIndex); - - onStartReordering(); - } - return true; - } - return false; - } - - boolean isReordering(boolean testTouchState) { - boolean state = mIsReordering; - if (testTouchState) { - state &= (mTouchState == TOUCH_STATE_REORDERING); - } - return state; - } - void endReordering() { - // For simplicity, we call endReordering sometimes even if reordering was never started. - // In that case, we don't want to do anything. - if (!mReorderingStarted) return; - mReorderingStarted = false; - - // If we haven't flung-to-delete the current child, then we just animate the drag view - // back into position - final Runnable onCompleteRunnable = new Runnable() { - @Override - public void run() { - onEndReordering(); - } - }; - if (!mDeferringForDelete) { - mPostReorderingPreZoomInRunnable = new Runnable() { - public void run() { - zoomIn(onCompleteRunnable); - }; - }; - - mPostReorderingPreZoomInRemainingAnimationCount = - NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT; - // Snap to the current page - snapToPage(indexOfChild(mDragView), 0); - // Animate the drag view back to the front position - animateDragViewToOriginalPosition(); - } else { - // Handled in post-delete-animation-callbacks - } - } - - // "Zooms in" the PagedView to highlight the current page - protected boolean zoomIn(final Runnable onCompleteRunnable) { - if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) { - mZoomInOutAnim.cancel(); - } - if (getScaleX() < 1f || getScaleY() < 1f) { - mZoomInOutAnim = new AnimatorSet(); - mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION); - mZoomInOutAnim.playTogether( - ObjectAnimator.ofFloat(this, "scaleX", 1f), - ObjectAnimator.ofFloat(this, "scaleY", 1f)); - mZoomInOutAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - // Hide the delete drop target - if (mDeleteDropTarget != null) { - mDeleteDropTarget.animate().alpha(0f) - .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mDeleteDropTarget.setVisibility(View.GONE); - } - }); - } - } - @Override - public void onAnimationCancel(Animator animation) { - mDragView = null; - } - @Override - public void onAnimationEnd(Animator animation) { - mDragView = null; - if (onCompleteRunnable != null) { - onCompleteRunnable.run(); - } - } - }); - mZoomInOutAnim.start(); - return true; - } else { - if (onCompleteRunnable != null) { - onCompleteRunnable.run(); - } - } - return false; - } - - /* - * Flinging to delete - IN PROGRESS - */ - private PointF isFlingingToDelete() { - ViewConfiguration config = ViewConfiguration.get(getContext()); - mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity()); - - if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) { - // Do a quick dot product test to ensure that we are flinging upwards - PointF vel = new PointF(mVelocityTracker.getXVelocity(), - mVelocityTracker.getYVelocity()); - PointF upVec = new PointF(0f, -1f); - float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) / - (vel.length() * upVec.length())); - if (theta <= Math.toRadians(FLING_TO_DELETE_MAX_FLING_DEGREES)) { - return vel; - } - } - return null; - } - - /** - * Creates an animation from the current drag view along its current velocity vector. - * For this animation, the alpha runs for a fixed duration and we update the position - * progressively. - */ - private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener { - private View mDragView; - private PointF mVelocity; - private Rect mFrom; - private long mPrevTime; - private float mFriction; - - private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f); - - public FlingAlongVectorAnimatorUpdateListener(View dragView, PointF vel, Rect from, - long startTime, float friction) { - mDragView = dragView; - mVelocity = vel; - mFrom = from; - mPrevTime = startTime; - mFriction = 1f - (mDragView.getResources().getDisplayMetrics().density * friction); - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float t = ((Float) animation.getAnimatedValue()).floatValue(); - long curTime = AnimationUtils.currentAnimationTimeMillis(); - - mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f); - mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f); - - mDragView.setTranslationX(mFrom.left); - mDragView.setTranslationY(mFrom.top); - mDragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t)); - - mVelocity.x *= mFriction; - mVelocity.y *= mFriction; - mPrevTime = curTime; - } - }; - - private Runnable createPostDeleteAnimationRunnable(final View dragView) { - return new Runnable() { - @Override - public void run() { - int dragViewIndex = indexOfChild(dragView); - - // For each of the pages around the drag view, animate them from the previous - // position to the new position in the layout (as a result of the drag view moving - // in the layout) - // NOTE: We can make an assumption here because we have side-bound pages that we - // will always have pages to animate in from the left - getVisiblePages(mTempVisiblePagesRange); - boundByReorderablePages(true, mTempVisiblePagesRange); - boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]); - boolean slideFromLeft = (isLastWidgetPage || - dragViewIndex > mTempVisiblePagesRange[0]); - - // Setup the scroll to the correct page before we swap the views - if (slideFromLeft) { - snapToPageImmediately(dragViewIndex - 1); - } - - int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]); - int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1); - int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 ); - int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex); - ArrayList<Animator> animations = new ArrayList<Animator>(); - for (int i = lowerIndex; i <= upperIndex; ++i) { - View v = getChildAt(i); - // dragViewIndex < pageUnderPointIndex, so after we remove the - // drag view all subsequent views to pageUnderPointIndex will - // shift down. - int oldX = 0; - int newX = 0; - if (slideFromLeft) { - if (i == 0) { - // Simulate the page being offscreen with the page spacing - oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i) - - mPageSpacing; - } else { - oldX = getViewportOffsetX() + getChildOffset(i - 1); - } - newX = getViewportOffsetX() + getChildOffset(i); - } else { - oldX = getChildOffset(i) - getChildOffset(i - 1); - newX = 0; - } - - // Animate the view translation from its old position to its new - // position - AnimatorSet anim = (AnimatorSet) v.getTag(); - if (anim != null) { - anim.cancel(); - } - - // Note: Hacky, but we want to skip any optimizations to not draw completely - // hidden views - v.setAlpha(Math.max(v.getAlpha(), 0.01f)); - v.setTranslationX(oldX - newX); - anim = new AnimatorSet(); - anim.playTogether( - ObjectAnimator.ofFloat(v, "translationX", 0f), - ObjectAnimator.ofFloat(v, "alpha", 1f)); - animations.add(anim); - v.setTag(anim); - } - - AnimatorSet slideAnimations = new AnimatorSet(); - slideAnimations.playTogether(animations); - slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION); - slideAnimations.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - final Runnable onCompleteRunnable = new Runnable() { - @Override - public void run() { - mDeferringForDelete = false; - onEndReordering(); - onRemoveViewAnimationCompleted(); - } - }; - zoomIn(onCompleteRunnable); - } - }); - slideAnimations.start(); - - removeView(dragView); - onRemoveView(dragView, true); - } - }; - } - - public void onFlingToDelete(PointF vel) { - final long startTime = AnimationUtils.currentAnimationTimeMillis(); - - // NOTE: Because it takes time for the first frame of animation to actually be - // called and we expect the animation to be a continuation of the fling, we have - // to account for the time that has elapsed since the fling finished. And since - // we don't have a startDelay, we will always get call to update when we call - // start() (which we want to ignore). - final TimeInterpolator tInterpolator = new TimeInterpolator() { - private int mCount = -1; - private long mStartTime; - private float mOffset; - /* Anonymous inner class ctor */ { - mStartTime = startTime; - } - - @Override - public float getInterpolation(float t) { - if (mCount < 0) { - mCount++; - } else if (mCount == 0) { - mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() - - mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION); - mCount++; - } - return Math.min(1f, mOffset + t); - } - }; - - final Rect from = new Rect(); - final View dragView = mDragView; - from.left = (int) dragView.getTranslationX(); - from.top = (int) dragView.getTranslationY(); - AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel, - from, startTime, FLING_TO_DELETE_FRICTION); - - final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView); - - // Create and start the animation - ValueAnimator mDropAnim = new ValueAnimator(); - mDropAnim.setInterpolator(tInterpolator); - mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION); - mDropAnim.setFloatValues(0f, 1f); - mDropAnim.addUpdateListener(updateCb); - mDropAnim.addListener(new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animation) { - onAnimationEndRunnable.run(); - } - }); - mDropAnim.start(); - mDeferringForDelete = true; - } - - /* Drag to delete */ - private boolean isHoveringOverDeleteDropTarget(int x, int y) { - if (mDeleteDropTarget != null) { - mAltTmpRect.set(0, 0, 0, 0); - View parent = (View) mDeleteDropTarget.getParent(); - if (parent != null) { - parent.getGlobalVisibleRect(mAltTmpRect); - } - mDeleteDropTarget.getGlobalVisibleRect(mTmpRect); - mTmpRect.offset(-mAltTmpRect.left, -mAltTmpRect.top); - return mTmpRect.contains(x, y); - } - return false; - } - - protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {} - - private void onDropToDelete() { - final View dragView = mDragView; - - final float toScale = 0f; - final float toAlpha = 0f; - - // Create and start the complex animation - ArrayList<Animator> animations = new ArrayList<Animator>(); - AnimatorSet motionAnim = new AnimatorSet(); - motionAnim.setInterpolator(new DecelerateInterpolator(2)); - motionAnim.playTogether( - ObjectAnimator.ofFloat(dragView, "scaleX", toScale), - ObjectAnimator.ofFloat(dragView, "scaleY", toScale)); - animations.add(motionAnim); - - AnimatorSet alphaAnim = new AnimatorSet(); - alphaAnim.setInterpolator(new LinearInterpolator()); - alphaAnim.playTogether( - ObjectAnimator.ofFloat(dragView, "alpha", toAlpha)); - animations.add(alphaAnim); - - final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView); - - AnimatorSet anim = new AnimatorSet(); - anim.playTogether(animations); - anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animation) { - onAnimationEndRunnable.run(); - } - }); - anim.start(); - - mDeferringForDelete = true; - } - - /* Accessibility */ - @Override - public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - info.setScrollable(getPageCount() > 1); - if (getCurrentPage() < getPageCount() - 1) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); - } - if (getCurrentPage() > 0) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); - } - } - - @Override - public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - event.setScrollable(true); - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { - event.setFromIndex(mCurrentPage); - event.setToIndex(mCurrentPage); - event.setItemCount(getChildCount()); - } - } - - @Override - public boolean performAccessibilityAction(int action, Bundle arguments) { - if (super.performAccessibilityAction(action, arguments)) { - return true; - } - switch (action) { - case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { - if (getCurrentPage() < getPageCount() - 1) { - scrollRight(); - return true; - } - } break; - case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { - if (getCurrentPage() > 0) { - scrollLeft(); - return true; - } - } break; - } - return false; - } - - @Override - public boolean onHoverEvent(android.view.MotionEvent event) { - return true; - } -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java deleted file mode 100644 index 7760279..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java +++ /dev/null @@ -1,31 +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; - -public interface SecurityMessageDisplay { - public void setMessage(CharSequence msg, boolean important); - - public void setMessage(int resId, boolean important); - - public void setMessage(int resId, boolean important, Object... formatArgs); - - public void setTimeout(int timeout_ms); - - public void showBouncer(int animationDuration); - - public void hideBouncer(int animationDuration); -} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java deleted file mode 100644 index 073225f..0000000 --- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java +++ /dev/null @@ -1,1244 +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; - -import com.android.internal.R; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.FloatProperty; -import android.util.Log; -import android.util.Property; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.accessibility.AccessibilityManager; -import android.view.animation.Interpolator; -import android.widget.Scroller; - -/** - * This layout handles interaction with the sliding security challenge views - * that overlay/resize other keyguard contents. - */ -public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout { - private static final String TAG = "SlidingChallengeLayout"; - private static final boolean DEBUG = false; - - // The drag handle is measured in dp above & below the top edge of the - // challenge view; these parameters change based on whether the challenge - // is open or closed. - private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp - private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp - private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp - private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp - - private static final int HANDLE_ANIMATE_DURATION = 250; // ms - - // Drawn to show the drag handle in closed state; crossfades to the challenge view - // when challenge is fully visible - private boolean mEdgeCaptured; - - private DisplayMetrics mDisplayMetrics; - - // Initialized during measurement from child layoutparams - private View mExpandChallengeView; - private KeyguardSecurityContainer mChallengeView; - private View mScrimView; - private View mWidgetsView; - - // Range: 0 (fully hidden) to 1 (fully visible) - private float mChallengeOffset = 1.f; - private boolean mChallengeShowing = true; - private boolean mChallengeShowingTargetState = true; - private boolean mWasChallengeShowing = true; - private boolean mIsBouncing = false; - - private final Scroller mScroller; - private ObjectAnimator mFader; - private int mScrollState; - private OnChallengeScrolledListener mScrollListener; - private OnBouncerStateChangedListener mBouncerListener; - - public static final int SCROLL_STATE_IDLE = 0; - public static final int SCROLL_STATE_DRAGGING = 1; - public static final int SCROLL_STATE_SETTLING = 2; - public static final int SCROLL_STATE_FADING = 3; - - private static final int CHALLENGE_FADE_OUT_DURATION = 100; - private static final int CHALLENGE_FADE_IN_DURATION = 160; - - private static final int MAX_SETTLE_DURATION = 600; // ms - - // ID of the pointer in charge of a current drag - private int mActivePointerId = INVALID_POINTER; - private static final int INVALID_POINTER = -1; - - // True if the user is currently dragging the slider - private boolean mDragging; - // True if the user may not drag until a new gesture begins - private boolean mBlockDrag; - - private VelocityTracker mVelocityTracker; - private int mMinVelocity; - private int mMaxVelocity; - private float mGestureStartX, mGestureStartY; // where did you first touch the screen? - private int mGestureStartChallengeBottom; // where was the challenge at that time? - - private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view - private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line - private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view - private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line - - private int mDragHandleEdgeSlop; - private int mChallengeBottomBound; // Number of pixels from the top of the challenge view - // that should remain on-screen - - private int mTouchSlop; - private int mTouchSlopSquare; - - float mHandleAlpha; - float mFrameAlpha; - float mFrameAnimationTarget = Float.MIN_VALUE; - private ObjectAnimator mHandleAnimation; - private ObjectAnimator mFrameAnimation; - - private boolean mHasGlowpad; - - // We have an internal and external version, and we and them together. - private boolean mChallengeInteractiveExternal = true; - private boolean mChallengeInteractiveInternal = true; - - static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA = - new FloatProperty<SlidingChallengeLayout>("handleAlpha") { - @Override - public void setValue(SlidingChallengeLayout view, float value) { - view.mHandleAlpha = value; - view.invalidate(); - } - - @Override - public Float get(SlidingChallengeLayout view) { - return view.mHandleAlpha; - } - }; - - // True if at least one layout pass has happened since the view was attached. - private boolean mHasLayout; - - private static final Interpolator sMotionInterpolator = new Interpolator() { - public float getInterpolation(float t) { - t -= 1.0f; - return t * t * t * t * t + 1.0f; - } - }; - - private static final Interpolator sHandleFadeInterpolator = new Interpolator() { - public float getInterpolation(float t) { - return t * t; - } - }; - - private final Runnable mEndScrollRunnable = new Runnable () { - public void run() { - completeChallengeScroll(); - } - }; - - private final OnClickListener mScrimClickListener = new OnClickListener() { - @Override - public void onClick(View v) { - hideBouncer(); - } - }; - - private final OnClickListener mExpandChallengeClickListener = new OnClickListener() { - @Override - public void onClick(View v) { - if (!isChallengeShowing()) { - showChallenge(true); - } - } - }; - - /** - * Listener interface that reports changes in scroll state of the challenge area. - */ - public interface OnChallengeScrolledListener { - /** - * The scroll state itself changed. - * - * <p>scrollState will be one of the following:</p> - * - * <ul> - * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li> - * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging - * the challenge area.</li> - * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating - * into place.</li> - * </ul> - * - * <p>Do not perform expensive operations (e.g. layout) - * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p> - * - * @param scrollState The new scroll state of the challenge area. - */ - public void onScrollStateChanged(int scrollState); - - /** - * The precise position of the challenge area has changed. - * - * <p>NOTE: It is NOT safe to modify layout or call any View methods that may - * result in a requestLayout anywhere in your view hierarchy as a result of this call. - * It may be called during drawing.</p> - * - * @param scrollPosition New relative position of the challenge area. - * 1.f = fully visible/ready to be interacted with. - * 0.f = fully invisible/inaccessible to the user. - * @param challengeTop Position of the top edge of the challenge view in px in the - * SlidingChallengeLayout's coordinate system. - */ - public void onScrollPositionChanged(float scrollPosition, int challengeTop); - } - - public SlidingChallengeLayout(Context context) { - this(context, null); - } - - public SlidingChallengeLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mScroller = new Scroller(context, sMotionInterpolator); - - final ViewConfiguration vc = ViewConfiguration.get(context); - mMinVelocity = vc.getScaledMinimumFlingVelocity(); - mMaxVelocity = vc.getScaledMaximumFlingVelocity(); - - final Resources res = getResources(); - mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size); - - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - mTouchSlopSquare = mTouchSlop * mTouchSlop; - - mDisplayMetrics = res.getDisplayMetrics(); - final float density = mDisplayMetrics.density; - - // top half of the lock icon, plus another 25% to be sure - mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f); - mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f); - mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f); - mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f); - - // how much space to account for in the handle when closed - mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding); - - setWillNotDraw(false); - setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE); - } - - public void setHandleAlpha(float alpha) { - if (mExpandChallengeView != null) { - mExpandChallengeView.setAlpha(alpha); - } - } - - public void setChallengeInteractive(boolean interactive) { - mChallengeInteractiveExternal = interactive; - if (mExpandChallengeView != null) { - mExpandChallengeView.setEnabled(interactive); - } - } - - void animateHandle(boolean visible) { - if (mHandleAnimation != null) { - mHandleAnimation.cancel(); - mHandleAnimation = null; - } - final float targetAlpha = visible ? 1.f : 0.f; - if (targetAlpha == mHandleAlpha) { - return; - } - mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha); - mHandleAnimation.setInterpolator(sHandleFadeInterpolator); - mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION); - mHandleAnimation.start(); - } - - private void sendInitialListenerUpdates() { - if (mScrollListener != null) { - int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0; - mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop); - mScrollListener.onScrollStateChanged(mScrollState); - } - } - - public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) { - mScrollListener = listener; - if (mHasLayout) { - sendInitialListenerUpdates(); - } - } - - public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) { - mBouncerListener = listener; - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - - mHasLayout = false; - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - removeCallbacks(mEndScrollRunnable); - mHasLayout = false; - } - - @Override - public void requestChildFocus(View child, View focused) { - if (mIsBouncing && child != mChallengeView) { - // Clear out of the bouncer if the user tries to move focus outside of - // the security challenge view. - hideBouncer(); - } - super.requestChildFocus(child, focused); - } - - // We want the duration of the page snap animation to be influenced by the distance that - // the screen has to travel, however, we don't want this duration to be effected in a - // purely linear fashion. Instead, we use this method to moderate the effect that the distance - // of travel has on the overall snap duration. - float distanceInfluenceForSnapDuration(float f) { - f -= 0.5f; // center the values about 0. - f *= 0.3f * Math.PI / 2.0f; - return (float) Math.sin(f); - } - - void setScrollState(int state) { - if (mScrollState != state) { - mScrollState = state; - - animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); - if (mScrollListener != null) { - mScrollListener.onScrollStateChanged(state); - } - } - } - - void completeChallengeScroll() { - setChallengeShowing(mChallengeShowingTargetState); - mChallengeOffset = mChallengeShowing ? 1.f : 0.f; - setScrollState(SCROLL_STATE_IDLE); - mChallengeInteractiveInternal = true; - mChallengeView.setLayerType(LAYER_TYPE_NONE, null); - } - - void setScrimView(View scrim) { - if (mScrimView != null) { - mScrimView.setOnClickListener(null); - } - mScrimView = scrim; - mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE); - mScrimView.setFocusable(true); - mScrimView.setOnClickListener(mScrimClickListener); - } - - /** - * Animate the bottom edge of the challenge view to the given position. - * - * @param y desired final position for the bottom edge of the challenge view in px - * @param velocity velocity in - */ - void animateChallengeTo(int y, int velocity) { - if (mChallengeView == null) { - // Nothing to do. - return; - } - - cancelTransitionsInProgress(); - - mChallengeInteractiveInternal = false; - mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); - final int sy = mChallengeView.getBottom(); - final int dy = y - sy; - if (dy == 0) { - completeChallengeScroll(); - return; - } - - setScrollState(SCROLL_STATE_SETTLING); - - final int childHeight = mChallengeView.getHeight(); - final int halfHeight = childHeight / 2; - final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight); - final float distance = halfHeight + halfHeight * - distanceInfluenceForSnapDuration(distanceRatio); - - int duration = 0; - velocity = Math.abs(velocity); - if (velocity > 0) { - duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); - } else { - final float childDelta = (float) Math.abs(dy) / childHeight; - duration = (int) ((childDelta + 1) * 100); - } - duration = Math.min(duration, MAX_SETTLE_DURATION); - - mScroller.startScroll(0, sy, 0, dy, duration); - postInvalidateOnAnimation(); - } - - private void setChallengeShowing(boolean showChallenge) { - if (mChallengeShowing == showChallenge) { - return; - } - mChallengeShowing = showChallenge; - - if (mExpandChallengeView == null || mChallengeView == null) { - // These might not be here yet if we haven't been through layout. - // If we haven't, the first layout pass will set everything up correctly - // based on mChallengeShowing as set above. - return; - } - - if (mChallengeShowing) { - mExpandChallengeView.setVisibility(View.INVISIBLE); - mChallengeView.setVisibility(View.VISIBLE); - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - mChallengeView.requestAccessibilityFocus(); - mChallengeView.announceForAccessibility(mContext.getString( - R.string.keyguard_accessibility_unlock_area_expanded)); - } - } else { - mExpandChallengeView.setVisibility(View.VISIBLE); - mChallengeView.setVisibility(View.INVISIBLE); - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - mExpandChallengeView.requestAccessibilityFocus(); - mChallengeView.announceForAccessibility(mContext.getString( - R.string.keyguard_accessibility_unlock_area_collapsed)); - } - } - } - - /** - * @return true if the challenge is at all visible. - */ - public boolean isChallengeShowing() { - return mChallengeShowing; - } - - @Override - public boolean isChallengeOverlapping() { - return mChallengeShowing; - } - - @Override - public boolean isBouncing() { - return mIsBouncing; - } - - @Override - public int getBouncerAnimationDuration() { - return HANDLE_ANIMATE_DURATION; - } - - @Override - public void showBouncer() { - if (mIsBouncing) return; - mWasChallengeShowing = mChallengeShowing; - mIsBouncing = true; - showChallenge(true); - if (mScrimView != null) { - Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f); - anim.setDuration(HANDLE_ANIMATE_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mScrimView.setVisibility(VISIBLE); - } - }); - anim.start(); - } - if (mChallengeView != null) { - mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION); - } - - if (mBouncerListener != null) { - mBouncerListener.onBouncerStateChanged(true); - } - } - - @Override - public void hideBouncer() { - if (!mIsBouncing) return; - if (!mWasChallengeShowing) showChallenge(false); - mIsBouncing = false; - - if (mScrimView != null) { - Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f); - anim.setDuration(HANDLE_ANIMATE_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mScrimView.setVisibility(GONE); - } - }); - anim.start(); - } - if (mChallengeView != null) { - mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION); - } - if (mBouncerListener != null) { - mBouncerListener.onBouncerStateChanged(false); - } - } - - private int getChallengeMargin(boolean expanded) { - return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop; - } - - private float getChallengeAlpha() { - float x = mChallengeOffset - 1; - return x * x * x + 1.f; - } - - @Override - public void requestDisallowInterceptTouchEvent(boolean allowIntercept) { - // We'll intercept whoever we feel like! ...as long as it isn't a challenge view. - // If there are one or more pointers in the challenge view before we take over - // touch events, onInterceptTouchEvent will set mBlockDrag. - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(ev); - - final int action = ev.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: - mGestureStartX = ev.getX(); - mGestureStartY = ev.getY(); - mBlockDrag = false; - break; - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - resetTouch(); - break; - - case MotionEvent.ACTION_MOVE: - final int count = ev.getPointerCount(); - for (int i = 0; i < count; i++) { - final float x = ev.getX(i); - final float y = ev.getY(i); - if (!mIsBouncing && mActivePointerId == INVALID_POINTER - && (crossedDragHandle(x, y, mGestureStartY) - || (isInChallengeView(x, y) && - mScrollState == SCROLL_STATE_SETTLING))) { - mActivePointerId = ev.getPointerId(i); - mGestureStartX = x; - mGestureStartY = y; - mGestureStartChallengeBottom = getChallengeBottom(); - mDragging = true; - mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); - } else if (mChallengeShowing && isInChallengeView(x, y)) { - mBlockDrag = true; - } - } - break; - } - - if (mBlockDrag || isChallengeInteractionBlocked()) { - mActivePointerId = INVALID_POINTER; - mDragging = false; - } - - return mDragging; - } - - private boolean isChallengeInteractionBlocked() { - return !mChallengeInteractiveExternal || !mChallengeInteractiveInternal; - } - - private void resetTouch() { - mVelocityTracker.recycle(); - mVelocityTracker = null; - mActivePointerId = INVALID_POINTER; - mDragging = mBlockDrag = false; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(ev); - - final int action = ev.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: - mBlockDrag = false; - mGestureStartX = ev.getX(); - mGestureStartY = ev.getY(); - break; - - case MotionEvent.ACTION_CANCEL: - if (mDragging && !isChallengeInteractionBlocked()) { - showChallenge(0); - } - resetTouch(); - break; - - case MotionEvent.ACTION_POINTER_UP: - if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) { - break; - } - case MotionEvent.ACTION_UP: - if (mDragging && !isChallengeInteractionBlocked()) { - mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); - showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId)); - } - resetTouch(); - break; - - case MotionEvent.ACTION_MOVE: - if (!mDragging && !mBlockDrag && !mIsBouncing) { - final int count = ev.getPointerCount(); - for (int i = 0; i < count; i++) { - final float x = ev.getX(i); - final float y = ev.getY(i); - - if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) || - (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) - && mActivePointerId == INVALID_POINTER - && !isChallengeInteractionBlocked()) { - mGestureStartX = x; - mGestureStartY = y; - mActivePointerId = ev.getPointerId(i); - mGestureStartChallengeBottom = getChallengeBottom(); - mDragging = true; - mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); - break; - } - } - } - // Not an else; this can be set above. - if (mDragging) { - // No-op if already in this state, but set it here in case we arrived - // at this point from either intercept or the above. - setScrollState(SCROLL_STATE_DRAGGING); - - final int index = ev.findPointerIndex(mActivePointerId); - if (index < 0) { - // Oops, bogus state. We lost some touch events somewhere. - // Just drop it with no velocity and let things settle. - resetTouch(); - showChallenge(0); - return true; - } - final float y = ev.getY(index); - final float pos = Math.min(y - mGestureStartY, - getLayoutBottom() - mChallengeBottomBound); - - moveChallengeTo(mGestureStartChallengeBottom + (int) pos); - } - break; - } - return true; - } - - /** - * The lifecycle of touch events is subtle and it's very easy to do something - * that will cause bugs that will be nasty to track when overriding this method. - * Normally one should always override onInterceptTouchEvent instead. - * - * To put it another way, don't try this at home. - */ - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - final int action = ev.getActionMasked(); - boolean handled = false; - if (action == MotionEvent.ACTION_DOWN) { - // Defensive programming: if we didn't get the UP or CANCEL, reset anyway. - mEdgeCaptured = false; - } - if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) { - // Normally we would need to do a lot of extra stuff here. - // We can only get away with this because we haven't padded in - // the widget pager or otherwise transformed it during layout. - // We also don't support things like splitting MotionEvents. - - // We set handled to captured even if dispatch is returning false here so that - // we don't send a different view a busted or incomplete event stream. - handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev); - } - - if (!handled && !mEdgeCaptured) { - handled = super.dispatchTouchEvent(ev); - } - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - mEdgeCaptured = false; - } - - return handled; - } - - private boolean isEdgeSwipeBeginEvent(MotionEvent ev) { - if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) { - return false; - } - - final float x = ev.getX(); - return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop; - } - - /** - * We only want to add additional vertical space to the drag handle when the panel is fully - * closed. - */ - private int getDragHandleSizeAbove() { - return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove; - } - private int getDragHandleSizeBelow() { - return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow; - } - - private boolean isInChallengeView(float x, float y) { - return isPointInView(x, y, mChallengeView); - } - - private boolean isInDragHandle(float x, float y) { - return isPointInView(x, y, mExpandChallengeView); - } - - private boolean isPointInView(float x, float y, View view) { - if (view == null) { - return false; - } - return x >= view.getLeft() && y >= view.getTop() - && x < view.getRight() && y < view.getBottom(); - } - - private boolean crossedDragHandle(float x, float y, float initialY) { - - final int challengeTop = mChallengeView.getTop(); - final boolean horizOk = x >= 0 && x < getWidth(); - - final boolean vertOk; - if (mChallengeShowing) { - vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) && - y > challengeTop + getDragHandleSizeBelow(); - } else { - vertOk = initialY > challengeTop + getDragHandleSizeBelow() && - y < challengeTop - getDragHandleSizeAbove(); - } - return horizOk && vertOk; - } - - private int makeChildMeasureSpec(int maxSize, int childDimen) { - final int mode; - final int size; - switch (childDimen) { - case LayoutParams.WRAP_CONTENT: - mode = MeasureSpec.AT_MOST; - size = maxSize; - break; - case LayoutParams.MATCH_PARENT: - mode = MeasureSpec.EXACTLY; - size = maxSize; - break; - default: - mode = MeasureSpec.EXACTLY; - size = Math.min(maxSize, childDimen); - break; - } - return MeasureSpec.makeMeasureSpec(size, mode); - } - - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY || - MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) { - throw new IllegalArgumentException( - "SlidingChallengeLayout must be measured with an exact size"); - } - - final int width = MeasureSpec.getSize(widthSpec); - final int height = MeasureSpec.getSize(heightSpec); - setMeasuredDimension(width, height); - - // Find one and only one challenge view. - final View oldChallengeView = mChallengeView; - final View oldExpandChallengeView = mChallengeView; - mChallengeView = null; - mExpandChallengeView = null; - final int count = getChildCount(); - - // First iteration through the children finds special children and sets any associated - // state. - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { - if (mChallengeView != null) { - throw new IllegalStateException( - "There may only be one child with layout_isChallenge=\"true\""); - } - if (!(child instanceof KeyguardSecurityContainer)) { - throw new IllegalArgumentException( - "Challenge must be a KeyguardSecurityContainer"); - } - mChallengeView = (KeyguardSecurityContainer) child; - if (mChallengeView != oldChallengeView) { - mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE); - } - // We're going to play silly games with the frame's background drawable later. - if (!mHasLayout) { - // Set up the margin correctly based on our content for the first run. - mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null; - lp.leftMargin = lp.rightMargin = getChallengeMargin(true); - } - } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) { - if (mExpandChallengeView != null) { - throw new IllegalStateException( - "There may only be one child with layout_childType" - + "=\"expandChallengeHandle\""); - } - mExpandChallengeView = child; - if (mExpandChallengeView != oldExpandChallengeView) { - mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE); - mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener); - } - } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { - setScrimView(child); - } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) { - mWidgetsView = child; - } - } - - // We want to measure the challenge view first, since the KeyguardWidgetPager - // needs to do things its measure pass that are dependent on the challenge view - // having been measured. - if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) { - // This one's a little funny. If the IME is present - reported in the form - // of insets on the root view - we only give the challenge the space it would - // have had if the IME wasn't there in order to keep the rest of the layout stable. - // We base this on the layout_maxHeight on the challenge view. If it comes out - // negative or zero, either we didn't have a maxHeight or we're totally out of space, - // so give up and measure as if this rule weren't there. - int challengeHeightSpec = heightSpec; - final View root = getRootView(); - if (root != null) { - final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams(); - final int specSize = MeasureSpec.getSize(heightSpec); - final int windowHeight = mDisplayMetrics.heightPixels - root.getPaddingTop(); - final int diff = windowHeight - specSize; - final int maxChallengeHeight = lp.maxHeight - diff; - if (maxChallengeHeight > 0) { - challengeHeightSpec = makeChildMeasureSpec(maxChallengeHeight, lp.height); - } - } - measureChildWithMargins(mChallengeView, widthSpec, 0, challengeHeightSpec, 0); - } - - // Measure the rest of the children - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == GONE) { - continue; - } - // Don't measure the challenge view twice! - if (child == mChallengeView) continue; - - // Measure children. Widget frame measures special, so that we can ignore - // insets for the IME. - int parentWidthSpec = widthSpec, parentHeightSpec = heightSpec; - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) { - final View root = getRootView(); - if (root != null) { - // This calculation is super dodgy and relies on several assumptions. - // Specifically that the root of the window will be padded in for insets - // and that the window is LAYOUT_IN_SCREEN. - final int windowWidth = mDisplayMetrics.widthPixels; - final int windowHeight = mDisplayMetrics.heightPixels - root.getPaddingTop(); - parentWidthSpec = MeasureSpec.makeMeasureSpec( - windowWidth, MeasureSpec.EXACTLY); - parentHeightSpec = MeasureSpec.makeMeasureSpec( - windowHeight, MeasureSpec.EXACTLY); - } - } - measureChildWithMargins(child, parentWidthSpec, 0, parentHeightSpec, 0); - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - final int paddingLeft = getPaddingLeft(); - final int paddingTop = getPaddingTop(); - final int paddingRight = getPaddingRight(); - final int paddingBottom = getPaddingBottom(); - final int width = r - l; - final int height = b - t; - - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - - if (child.getVisibility() == GONE) continue; - - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { - // Challenge views pin to the bottom, offset by a portion of their height, - // and center horizontally. - final int center = (paddingLeft + width - paddingRight) / 2; - final int childWidth = child.getMeasuredWidth(); - final int childHeight = child.getMeasuredHeight(); - final int left = center - childWidth / 2; - final int layoutBottom = height - paddingBottom - lp.bottomMargin; - // We use the top of the challenge view to position the handle, so - // we never want less than the handle size showing at the bottom. - final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound) - * (1 - mChallengeOffset)); - child.setAlpha(getChallengeAlpha()); - child.layout(left, bottom - childHeight, left + childWidth, bottom); - } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) { - final int center = (paddingLeft + width - paddingRight) / 2; - final int left = center - child.getMeasuredWidth() / 2; - final int right = left + child.getMeasuredWidth(); - final int bottom = height - paddingBottom - lp.bottomMargin; - final int top = bottom - child.getMeasuredHeight(); - child.layout(left, top, right, bottom); - } else { - // Non-challenge views lay out from the upper left, layered. - child.layout(paddingLeft + lp.leftMargin, - paddingTop + lp.topMargin, - paddingLeft + child.getMeasuredWidth(), - paddingTop + child.getMeasuredHeight()); - } - } - - if (!mHasLayout) { - mHasLayout = true; - } - } - - @Override - public void draw(Canvas c) { - super.draw(c); - if (DEBUG) { - final Paint debugPaint = new Paint(); - debugPaint.setColor(0x40FF00CC); - // show the isInDragHandle() rect - c.drawRect(mDragHandleEdgeSlop, - mChallengeView.getTop() - getDragHandleSizeAbove(), - getWidth() - mDragHandleEdgeSlop, - mChallengeView.getTop() + getDragHandleSizeBelow(), - debugPaint); - } - } - - public void computeScroll() { - super.computeScroll(); - - if (!mScroller.isFinished()) { - if (mChallengeView == null) { - // Can't scroll if the view is missing. - Log.e(TAG, "Challenge view missing in computeScroll"); - mScroller.abortAnimation(); - return; - } - - mScroller.computeScrollOffset(); - moveChallengeTo(mScroller.getCurrY()); - - if (mScroller.isFinished()) { - post(mEndScrollRunnable); - } - } - } - - private void cancelTransitionsInProgress() { - if (!mScroller.isFinished()) { - mScroller.abortAnimation(); - completeChallengeScroll(); - } - if (mFader != null) { - mFader.cancel(); - } - } - - public void fadeInChallenge() { - fadeChallenge(true); - } - - public void fadeOutChallenge() { - fadeChallenge(false); - } - - public void fadeChallenge(final boolean show) { - if (mChallengeView != null) { - - cancelTransitionsInProgress(); - float alpha = show ? 1f : 0f; - int duration = show ? CHALLENGE_FADE_IN_DURATION : CHALLENGE_FADE_OUT_DURATION; - mFader = ObjectAnimator.ofFloat(mChallengeView, "alpha", alpha); - mFader.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - onFadeStart(show); - } - @Override - public void onAnimationEnd(Animator animation) { - onFadeEnd(show); - } - }); - mFader.setDuration(duration); - mFader.start(); - } - } - - private int getMaxChallengeBottom() { - if (mChallengeView == null) return 0; - final int layoutBottom = getLayoutBottom(); - final int challengeHeight = mChallengeView.getMeasuredHeight(); - - return (layoutBottom + challengeHeight - mChallengeBottomBound); - } - - private int getMinChallengeBottom() { - return getLayoutBottom(); - } - - - private void onFadeStart(boolean show) { - mChallengeInteractiveInternal = false; - mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); - - if (show) { - moveChallengeTo(getMinChallengeBottom()); - } - - setScrollState(SCROLL_STATE_FADING); - } - - private void onFadeEnd(boolean show) { - mChallengeInteractiveInternal = true; - setChallengeShowing(show); - - if (!show) { - moveChallengeTo(getMaxChallengeBottom()); - } - - mChallengeView.setLayerType(LAYER_TYPE_NONE, null); - mFader = null; - setScrollState(SCROLL_STATE_IDLE); - } - - public int getMaxChallengeTop() { - if (mChallengeView == null) return 0; - - final int layoutBottom = getLayoutBottom(); - final int challengeHeight = mChallengeView.getMeasuredHeight(); - return layoutBottom - challengeHeight; - } - - /** - * Move the bottom edge of mChallengeView to a new position and notify the listener - * if it represents a change in position. Changes made through this method will - * be stable across layout passes. If this method is called before first layout of - * this SlidingChallengeLayout it will have no effect. - * - * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system. - * @return true if the challenge view was moved - */ - private boolean moveChallengeTo(int bottom) { - if (mChallengeView == null || !mHasLayout) { - return false; - } - - final int layoutBottom = getLayoutBottom(); - final int challengeHeight = mChallengeView.getHeight(); - - bottom = Math.max(getMinChallengeBottom(), - Math.min(bottom, getMaxChallengeBottom())); - - float offset = 1.f - (float) (bottom - layoutBottom) / - (challengeHeight - mChallengeBottomBound); - mChallengeOffset = offset; - if (offset > 0 && !mChallengeShowing) { - setChallengeShowing(true); - } - - mChallengeView.layout(mChallengeView.getLeft(), - bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom); - - mChallengeView.setAlpha(getChallengeAlpha()); - if (mScrollListener != null) { - mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop()); - } - postInvalidateOnAnimation(); - return true; - } - - /** - * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with - * the bottom edge of mChallengeView when the challenge is fully opened. - */ - private int getLayoutBottom() { - final int bottomMargin = (mChallengeView == null) - ? 0 - : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; - final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin; - return layoutBottom; - } - - /** - * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'. - */ - private int getChallengeBottom() { - if (mChallengeView == null) return 0; - - return mChallengeView.getBottom(); - } - - /** - * Show or hide the challenge view, animating it if necessary. - * @param show true to show, false to hide - */ - public void showChallenge(boolean show) { - showChallenge(show, 0); - if (!show) { - // Block any drags in progress so that callers can use this to disable dragging - // for other touch interactions. - mBlockDrag = true; - } - } - - private void showChallenge(int velocity) { - boolean show = false; - if (Math.abs(velocity) > mMinVelocity) { - show = velocity < 0; - } else { - show = mChallengeOffset >= 0.5f; - } - showChallenge(show, velocity); - } - - private void showChallenge(boolean show, int velocity) { - if (mChallengeView == null) { - setChallengeShowing(false); - return; - } - - if (mHasLayout) { - mChallengeShowingTargetState = show; - final int layoutBottom = getLayoutBottom(); - animateChallengeTo(show ? layoutBottom : - layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity); - } - } - - @Override - public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { - return new LayoutParams(getContext(), attrs); - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : - p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : - new LayoutParams(p); - } - - @Override - protected ViewGroup.LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(); - } - - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams; - } - - public static class LayoutParams extends MarginLayoutParams { - public int childType = CHILD_TYPE_NONE; - public static final int CHILD_TYPE_NONE = 0; - public static final int CHILD_TYPE_CHALLENGE = 2; - public static final int CHILD_TYPE_SCRIM = 4; - public static final int CHILD_TYPE_WIDGETS = 5; - public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6; - - public int maxHeight; - - public LayoutParams() { - this(MATCH_PARENT, WRAP_CONTENT); - } - - public LayoutParams(int width, int height) { - super(width, height); - } - - public LayoutParams(android.view.ViewGroup.LayoutParams source) { - super(source); - } - - public LayoutParams(MarginLayoutParams source) { - super(source); - } - - public LayoutParams(LayoutParams source) { - super(source); - - childType = source.childType; - } - - public LayoutParams(Context c, AttributeSet attrs) { - super(c, attrs); - - final TypedArray a = c.obtainStyledAttributes(attrs, - R.styleable.SlidingChallengeLayout_Layout); - childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType, - CHILD_TYPE_NONE); - maxHeight = a.getDimensionPixelSize( - R.styleable.SlidingChallengeLayout_Layout_layout_maxHeight, 0); - a.recycle(); - } - } -} |