Merge "Updated assets." into jb-mr1-lockscreen-dev
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 6624eb8..a300776 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -3495,25 +3495,29 @@
}
/**
- * Returns true if video snapshot is supported. That is, applications
+ * <p>Returns true if video snapshot is supported. That is, applications
* can call {@link #takePicture(Camera.ShutterCallback,
- * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}
- * during recording. Applications do not need to call {@link
- * #startPreview()} after taking a picture. The preview will be still
- * active. Other than that, taking a picture during recording is
- * identical to taking a picture normally. All settings and methods
- * related to takePicture work identically. Ex: {@link
- * #getPictureSize()}, {@link #getSupportedPictureSizes()}, {@link
- * #setJpegQuality(int)}, {@link #setRotation(int)}, and etc. The
- * picture will have an EXIF header. {@link #FLASH_MODE_AUTO} and {@link
- * #FLASH_MODE_ON} also still work, but the video will record the flash.
+ * Camera.PictureCallback, Camera.PictureCallback,
+ * Camera.PictureCallback)} during recording. Applications do not need
+ * to call {@link #startPreview()} after taking a picture. The preview
+ * will be still active. Other than that, taking a picture during
+ * recording is identical to taking a picture normally. All settings and
+ * methods related to takePicture work identically. Ex:
+ * {@link #getPictureSize()}, {@link #getSupportedPictureSizes()},
+ * {@link #setJpegQuality(int)}, {@link #setRotation(int)}, and etc. The
+ * picture will have an EXIF header. {@link #FLASH_MODE_AUTO} and
+ * {@link #FLASH_MODE_ON} also still work, but the video will record the
+ * flash.</p>
*
- * Applications can set shutter callback as null to avoid the shutter
+ * <p>Applications can set shutter callback as null to avoid the shutter
* sound. It is also recommended to set raw picture and post view
- * callbacks to null to avoid the interrupt of preview display.
+ * callbacks to null to avoid the interrupt of preview display.</p>
*
- * Field-of-view of the recorded video may be different from that of the
- * captured pictures.
+ * <p>Field-of-view of the recorded video may be different from that of the
+ * captured pictures. The maximum size of a video snapshot may be
+ * smaller than that for regular still captures. If the current picture
+ * size is set higher than can be supported by video snapshot, the
+ * picture will be captured at the maximum supported size instead.</p>
*
* @return true if video snapshot is supported.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f482335..b94f0b9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3229,6 +3229,13 @@
"lock_screen_appwidget_ids";
/**
+ * Id of the appwidget shown on the lock screen when appwidgets are disabled.
+ * @hide
+ */
+ public static final String LOCK_SCREEN_FALLBACK_APPWIDGET_ID =
+ "lock_screen_fallback_appwidget_id";
+
+ /**
* Index of the lockscreen appwidget to restore, -1 if none.
* @hide
*/
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 5397eb6..b1a44c5 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -289,13 +289,7 @@
public void setError(CharSequence error, Drawable icon) {
mError = TextUtils.stringOrSpannedString(error);
mErrorWasChanged = true;
- final Drawables dr = mTextView.mDrawables;
- if (dr != null) {
- mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
- dr.mDrawableBottom);
- } else {
- mTextView.setCompoundDrawables(null, null, icon, null);
- }
+
if (mError == null) {
if (mErrorPopup != null) {
if (mErrorPopup.isShowing()) {
@@ -304,10 +298,21 @@
mErrorPopup = null;
}
+
+ setErrorIcon(null);
+ } else if (mTextView.isFocused()) {
+ showError();
+ setErrorIcon(icon);
+ }
+ }
+
+ private void setErrorIcon(Drawable icon) {
+ final Drawables dr = mTextView.mDrawables;
+ if (dr != null) {
+ mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
+ dr.mDrawableBottom);
} else {
- if (mTextView.isFocused()) {
- showError();
- }
+ mTextView.setCompoundDrawables(null, null, icon, null);
}
}
@@ -316,6 +321,8 @@
if (mErrorPopup.isShowing()) {
mErrorPopup.dismiss();
}
+
+ setErrorIcon(null);
}
mShowErrorAfterAttach = false;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e5e1a2b..26eaafb 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -18,6 +18,7 @@
import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
+import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -35,6 +36,7 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import android.view.IWindowManager;
import android.view.View;
import android.widget.Button;
@@ -109,6 +111,11 @@
public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
/**
+ * Tells the keyguard to show the widget with the specified id when the keyguard is created.
+ */
+ public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
+
+ /**
* Options used to lock the device upon user switch.
*/
public static final Bundle USER_SWITCH_LOCK_OPTIONS = new Bundle();
@@ -1112,6 +1119,25 @@
return sb.toString();
}
+ // appwidget used when appwidgets are disabled (we make an exception for
+ // default clock widget)
+ public void writeFallbackAppWidgetId(int appWidgetId) {
+ Settings.Secure.putIntForUser(mContentResolver,
+ Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
+ appWidgetId,
+ UserHandle.USER_CURRENT);
+ }
+
+ // appwidget used when appwidgets are disabled (we make an exception for
+ // default clock widget)
+ public int getFallbackAppWidgetId() {
+ return Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID,
+ UserHandle.USER_CURRENT);
+ }
+
private void writeAppWidgets(int[] appWidgetIds) {
Settings.Secure.putStringForUser(mContentResolver,
Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
@@ -1162,21 +1188,6 @@
return true;
}
- public int getStickyAppWidgetIndex() {
- return Settings.Secure.getIntForUser(
- mContentResolver,
- Settings.Secure.LOCK_SCREEN_STICKY_APPWIDGET,
- -1,
- UserHandle.USER_CURRENT);
- }
-
- public void setStickyAppWidgetIndex(int value) {
- Settings.Secure.putIntForUser(mContentResolver,
- Settings.Secure.LOCK_SCREEN_STICKY_APPWIDGET,
- value,
- UserHandle.USER_CURRENT);
- }
-
private long getLong(String secureSettingKey, long defaultValue) {
try {
return getLockSettings().getLong(secureSettingKey, defaultValue,
@@ -1325,5 +1336,15 @@
public boolean getPowerButtonInstantlyLocks() {
return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
}
+
+ public static boolean isSafeModeEnabled() {
+ try {
+ return IWindowManager.Stub.asInterface(
+ ServiceManager.getService("window")).isSafeModeEnabled();
+ } catch (RemoteException e) {
+ // Shouldn't happen!
+ }
+ return false;
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 406f644..5397a29 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3168,8 +3168,7 @@
if (lidOpen) {
if (keyguardIsShowingTq()) {
- mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
- KeyEvent.KEYCODE_POWER, mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(KeyEvent.KEYCODE_POWER);
} else {
mPowerManager.wakeUp(SystemClock.uptimeMillis());
}
@@ -3388,11 +3387,10 @@
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
result = 0;
- if (down && isWakeKey) {
+ if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
if (keyguardActive) {
- // If the keyguard is showing, let it decide what to do with the wake key.
- mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode,
- mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ // If the keyguard is showing, let it wake the device when ready.
+ mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
} else {
// Otherwise, wake the device ourselves.
result |= ACTION_WAKE_UP;
@@ -3614,6 +3612,40 @@
return result;
}
+ /**
+ * When the screen is off we ignore some keys that might otherwise typically
+ * be considered wake keys. We filter them out here.
+ *
+ * {@link KeyEvent#KEYCODE_POWER} is notably absent from this list because it
+ * is always considered a wake key.
+ */
+ private boolean isWakeKeyWhenScreenOff(int keyCode) {
+ switch (keyCode) {
+ // ignore volume keys unless docked
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ return mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
+ // ignore media and camera keys
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ case KeyEvent.KEYCODE_CAMERA:
+ return false;
+ }
+ return true;
+ }
+
+
/** {@inheritDoc} */
@Override
public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
index f3ea992..a38e86d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
@@ -85,10 +85,21 @@
protected void onFinishInflate() {
super.onFinishInflate();
mSeparator = getResources().getString(R.string.kg_text_message_separator);
- KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
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.
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
index cab4ed9..cd7324c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
@@ -64,6 +64,18 @@
}
@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);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 9fe3144..1ee0e86 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -57,7 +57,7 @@
import java.util.List;
public class KeyguardHostView extends KeyguardViewBase {
- private static final String TAG = "KeyguardViewHost";
+ private static final String TAG = "KeyguardHostView";
// Use this to debug all of keyguard
public static boolean DEBUG = KeyguardViewMediator.DEBUG;
@@ -73,6 +73,10 @@
private boolean mIsVerifyUnlockOnly;
private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
+ private int mAppWidgetToShow;
+
+ private boolean mBootCompleted = false;
+ private boolean mCheckAppWidgetConsistencyOnBootCompleted = false;
protected Runnable mLaunchRunnable;
@@ -82,11 +86,16 @@
private KeyguardSecurityModel mSecurityModel;
private KeyguardViewStateManager mViewStateManager;
- int mLocalStickyWidget = -1;
boolean mPersitentStickyWidgetLoaded = false;
private Rect mTempRect = new Rect();
+ private int mDisabledFeatures;
+
+ private boolean mCameraDisabled;
+
+ private boolean mSafeModeEnabled;
+
/*package*/ interface TransportCallback {
void onListenerDetached();
void onListenerAttached();
@@ -113,8 +122,40 @@
mSecurityModel = new KeyguardSecurityModel(context);
mViewStateManager = new KeyguardViewStateManager(this);
+
+ DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ mDisabledFeatures = getDisabledFeatures(dpm);
+ mCameraDisabled = dpm.getCameraDisabled(null);
+ }
+
+ mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
+
+ 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 KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onBootCompleted() {
+ mBootCompleted = true;
+ if (mCheckAppWidgetConsistencyOnBootCompleted) {
+ checkAppWidgetConsistency();
+ mSwitchPageRunnable.run();
+ mCheckAppWidgetConsistencyOnBootCompleted = false;
+ }
+ }
+ };
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean result = super.onTouchEvent(ev);
@@ -177,9 +218,10 @@
}
addDefaultWidgets();
- addWidgetsFromSettings();
- mSwitchPageRunnable.run();
+ addWidgetsFromSettings();
+ checkAppWidgetConsistency();
+ mSwitchPageRunnable.run();
// This needs to be called after the pages are all added.
mViewStateManager.showUsabilityHints();
@@ -187,6 +229,24 @@
updateSecurityViews();
}
+ 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++) {
@@ -219,12 +279,14 @@
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);
}
private AppWidgetHost getAppWidgetHost() {
@@ -722,7 +784,6 @@
// 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);
- saveStickyWidgetIndex();
checkAppWidgetConsistency();
showPrimarySecurityScreen(true);
getSecurityView(mCurrentSecuritySelection).onPause();
@@ -821,15 +882,18 @@
}
}
- private boolean addWidget(int appId, int pageIndex) {
+ private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
if (appWidgetInfo != null) {
AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo);
addWidget(view, pageIndex);
return true;
} else {
- Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting");
- mLockPatternUtils.removeAppWidget(appId);
+ if (updateDbIfFailed) {
+ Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting");
+ mAppWidgetHost.deleteAppWidgetId(appId);
+ mLockPatternUtils.removeAppWidget(appId);
+ }
return false;
}
}
@@ -885,9 +949,28 @@
LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
- View addWidget = inflater.inflate(R.layout.keyguard_add_widget, null, true);
- mAppWidgetContainer.addWidget(addWidget);
- if (mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
+ if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
+ View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
+ mAppWidgetContainer.addWidget(addWidget);
+ View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
+ addWidgetButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+ if (appWidgetId != -1) {
+ mActivityLauncher.launchWidgetPicker(appWidgetId);
+ } else {
+ Log.e(TAG, "Unable to allocate an AppWidget id in lock screen");
+ }
+ }
+ });
+ }
+
+ // 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()
+ && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
View cameraWidget =
CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher);
if (cameraWidget != null) {
@@ -895,24 +978,11 @@
}
}
- View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
- addWidgetButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
- if (appWidgetId != -1) {
- mActivityLauncher.launchWidgetPicker(appWidgetId);
- } else {
- Log.e(TAG, "Unable to allocate an AppWidget id in lock screen");
- }
- }
- });
-
enableUserSelectorIfNecessary();
initializeTransportControl();
}
- private void removeTransportFromWidgetPager() {
+ private boolean removeTransportFromWidgetPager() {
int page = getWidgetPosition(R.id.keyguard_transport_control);
if (page != -1) {
mAppWidgetContainer.removeWidget(mTransportControl);
@@ -921,8 +991,9 @@
KeyguardHostView.this.addView(mTransportControl);
mTransportControl.setVisibility(View.GONE);
mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE);
- mTransportControl.post(mSwitchPageRunnable);
+ return true;
}
+ return false;
}
private void addTransportToWidgetPager() {
@@ -951,8 +1022,9 @@
mTransportControl.setKeyguardCallback(new TransportCallback() {
@Override
public void onListenerDetached() {
- removeTransportFromWidgetPager();
- mTransportControl.post(mSwitchPageRunnable);
+ if (removeTransportFromWidgetPager()) {
+ mTransportControl.post(mSwitchPageRunnable);
+ }
}
@Override
@@ -969,14 +1041,15 @@
}
}
- private int getAddPageIndex() {
+ private int getInsertPageIndex() {
View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
- int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
- // This shouldn't happen, but just to be safe!
- if (addPageIndex < 0) {
- addPageIndex = 0;
+ int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget);
+ if (insertionIndex < 0) {
+ insertionIndex = 0; // no add widget page found
+ } else {
+ insertionIndex++; // place after add widget
}
- return addPageIndex;
+ return insertionIndex;
}
private void addDefaultStatusWidget(int index) {
@@ -986,18 +1059,11 @@
}
private void addWidgetsFromSettings() {
- DevicePolicyManager dpm =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
- final int currentUser = mLockPatternUtils.getCurrentUser();
- final int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser);
- if ((disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) {
- Log.v(TAG, "Keyguard widgets disabled because of device policy admin");
- return;
- }
+ if (mSafeModeEnabled || widgetsDisabledByDpm()) {
+ return;
}
- int addPageIndex = getAddPageIndex();
+ int insertionIndex = getInsertPageIndex();
// Add user-selected widget
final int[] widgets = mLockPatternUtils.getAppWidgets();
@@ -1007,50 +1073,95 @@
} else {
for (int i = widgets.length -1; i >= 0; i--) {
if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
- addDefaultStatusWidget(addPageIndex + 1);
+ 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], addPageIndex + 1);
+ addWidget(widgets[i], insertionIndex, true);
}
}
}
- checkAppWidgetConsistency();
}
+ 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 (!mBootCompleted) {
+ mCheckAppWidgetConsistencyOnBootCompleted = true;
+ return;
+ }
final int childCount = mAppWidgetContainer.getChildCount();
boolean widgetPageExists = false;
for (int i = 0; i < childCount; i++) {
- if (isWidgetPage(i)) {
+ if (mAppWidgetContainer.isWidgetPage(i)) {
widgetPageExists = true;
break;
}
}
if (!widgetPageExists) {
- final int addPageIndex = getAddPageIndex();
+ final int insertPageIndex = getInsertPageIndex();
- Resources res = getContext().getResources();
- ComponentName defaultAppWidget = new ComponentName(
- res.getString(R.string.widget_default_package_name),
- res.getString(R.string.widget_default_class_name));
+ final boolean userAddedWidgetsEnabled = !widgetsDisabledByDpm();
+ boolean addedDefaultAppWidget = false;
- // Note: we don't support configuring the widget
- int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
- boolean bindSuccessful = false;
- try {
- mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
- bindSuccessful = true;
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
+ 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 (!(bindSuccessful && addWidget(appWidgetId, addPageIndex + 1))) {
- addDefaultStatusWidget(addPageIndex + 1);
+ if (!addedDefaultAppWidget) {
+ addDefaultStatusWidget(insertPageIndex);
}
- mAppWidgetContainer.onAddView(
- mAppWidgetContainer.getChildAt(addPageIndex + 1), addPageIndex + 1);
+
+ // trigger DB updates only if user-added widgets are enabled
+ if (!mSafeModeEnabled && userAddedWidgetsEnabled) {
+ mAppWidgetContainer.onAddView(
+ mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex);
+ }
}
}
@@ -1094,7 +1205,6 @@
@Override
public Parcelable onSaveInstanceState() {
if (DEBUG) Log.d(TAG, "onSaveInstanceState");
- saveStickyWidgetIndex();
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.transportState = mViewStateManager.getTransportState();
@@ -1118,9 +1228,7 @@
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
- if (!hasWindowFocus) {
- saveStickyWidgetIndex();
- } else if (mShowSecurityWhenReturn) {
+ if (hasWindowFocus && mShowSecurityWhenReturn) {
SlidingChallengeLayout slider =
(SlidingChallengeLayout) findViewById(R.id.sliding_layout);
if (slider != null) {
@@ -1163,56 +1271,29 @@
return false;
}
- private int getStickyWidget() {
- // The first time we query the persistent state. From that point, we use a locally updated
- // notion of the sticky widget page.
- if (!mPersitentStickyWidgetLoaded) {
- mLocalStickyWidget = mLockPatternUtils.getStickyAppWidgetIndex();
- mPersitentStickyWidgetLoaded = true;
- }
- return mLocalStickyWidget;
- }
-
- public void updateStickyWidget(int index) {
- if (index < 0 || index >= mAppWidgetContainer.getChildCount()) {
- return;
- }
- if (mAppWidgetContainer.isAddPage(index)) {
- return;
- }
- if (mAppWidgetContainer.isCameraPage(index)) {
- return;
- }
- if (isMusicPage(index)) {
- return;
- }
-
- mLocalStickyWidget = index;
- }
-
boolean isMusicPage(int pageIndex) {
return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
}
private int getAppropriateWidgetPage(boolean isMusicPlaying) {
// 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) {
+ mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
+ return i;
+ }
+ }
+ mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
+ }
// if music playing, show transport
if (isMusicPlaying) {
if (DEBUG) Log.d(TAG, "Music playing, show transport");
return mAppWidgetContainer.getWidgetPageIndex(mTransportControl);
}
- // if we have a valid sticky widget, show it
- int stickyWidgetIndex = getStickyWidget();
- if (stickyWidgetIndex > -1
- && stickyWidgetIndex < mAppWidgetContainer.getChildCount()
- && !mAppWidgetContainer.isAddPage(stickyWidgetIndex)
- && !mAppWidgetContainer.isCameraPage(stickyWidgetIndex)) {
- if (DEBUG) Log.d(TAG, "Valid sticky widget found, show page " + stickyWidgetIndex);
- return stickyWidgetIndex;
- }
-
// else show the right-most widget (except for camera)
int rightMost = mAppWidgetContainer.getChildCount() - 1;
if (mAppWidgetContainer.isCameraPage(rightMost)) {
@@ -1222,13 +1303,6 @@
return rightMost;
}
- private void saveStickyWidgetIndex() {
- if (DEBUG) Log.d(TAG, "saveStickyWidgetIndex: " + mLocalStickyWidget);
- if (mPersitentStickyWidgetLoaded && mLocalStickyWidget >= 0) {
- mLockPatternUtils.setStickyAppWidgetIndex(mLocalStickyWidget);
- }
- }
-
private void enableUserSelectorIfNecessary() {
if (!UserManager.supportsMultipleUsers()) {
return; // device doesn't support multi-user mode
@@ -1300,6 +1374,11 @@
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()) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
index 5fb8cf0..51f0418 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -81,6 +81,8 @@
private static final int MSG_USER_SWITCHED = 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 KeyguardUpdateMonitor sInstance;
@@ -152,6 +154,9 @@
case MSG_KEYGUARD_VISIBILITY_CHANGED:
handleKeyguardVisibilityChanged(msg.arg1);
break;
+ case MSG_BOOT_COMPLETED:
+ handleBootCompleted();
+ break;
}
}
@@ -198,6 +203,8 @@
} 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));
}
}
};
@@ -340,6 +347,7 @@
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_BOOT_COMPLETED);
context.registerReceiver(mBroadcastReceiver, filter);
try {
@@ -420,6 +428,18 @@
}
/**
+ * Handle {@link #MSG_BOOT_COMPLETED}
+ */
+ protected void handleBootCompleted() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBootCompleted();
+ }
+ }
+ }
+
+ /**
* Handle {@link #MSG_USER_SWITCHED}
*/
protected void handleUserRemoved(int userId) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
index 8c9ac8b..1ba1388 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
@@ -99,4 +99,12 @@
* Called when a user is removed.
*/
void onUserRemoved(int userId) { }
+
+ /**
+ * Called when boot completed.
+ *
+ * Note, this callback will only be received if boot complete occurs after registering with
+ * KeyguardUpdateMonitor.
+ */
+ void onBootCompleted() { }
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
index 9e3424d..6fcacd3 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
@@ -260,4 +260,5 @@
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
index 6d88652..365c530 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -18,6 +18,7 @@
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;
@@ -240,6 +241,11 @@
if (options.getBoolean(LockPatternUtils.KEYGUARD_SHOW_SECURITY_CHALLENGE)) {
mKeyguardView.showNextSecurityScreenIfPresent();
}
+ int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
+ mKeyguardView.goToWidget(widgetToShow);
+ }
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 3648d99..5e19271 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -175,7 +175,7 @@
* Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)}
* is called to make sure the device doesn't sleep before it has a chance to poke
* the wake lock.
- * @see #wakeWhenReadyLocked(int)
+ * @see #wakeWhenReady(int)
*/
private PowerManager.WakeLock mWakeAndHandOff;
@@ -935,8 +935,8 @@
* @see #handleWakeWhenReady
* @see #onWakeKeyWhenKeyguardShowingTq(int)
*/
- private void wakeWhenReadyLocked(int keyCode) {
- if (DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")");
+ 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
@@ -1014,54 +1014,14 @@
* action should be posted to a handler.
*
* @param keyCode The keycode of the key that woke the device
- * @param isDocked True if the device is in the dock
- * @return Whether we poked the wake lock (and turned the screen on)
*/
- public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode, boolean isDocked) {
+ public void onWakeKeyWhenKeyguardShowingTq(int keyCode) {
if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")");
- if (isWakeKeyWhenKeyguardShowing(keyCode, isDocked)) {
- // give the keyguard view manager a chance to adjust the state of the
- // keyguard based on the key that woke the device before poking
- // the wake lock
- wakeWhenReadyLocked(keyCode);
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * When the keyguard is showing we ignore some keys that might otherwise typically
- * be considered wake keys. We filter them out here.
- *
- * {@link KeyEvent#KEYCODE_POWER} is notably absent from this list because it
- * is always considered a wake key.
- */
- private boolean isWakeKeyWhenKeyguardShowing(int keyCode, boolean isDocked) {
- switch (keyCode) {
- // ignore volume keys unless docked
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- return isDocked;
-
- // ignore media and camera keys
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- case KeyEvent.KEYCODE_CAMERA:
- return false;
- }
- return true;
+ // 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);
}
/**
@@ -1073,17 +1033,14 @@
* The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}.
* Be sure not to take any action that takes a long time; any significant
* action should be posted to a handler.
- *
- * @return Whether we poked the wake lock (and turned the screen on)
*/
- public boolean onWakeMotionWhenKeyguardShowingTq() {
+ 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
- wakeWhenReadyLocked(KeyEvent.KEYCODE_UNKNOWN);
- return true;
+ wakeWhenReady(KeyEvent.KEYCODE_UNKNOWN);
}
public void keyguardDone(boolean authenticated, boolean wakeup) {
@@ -1350,7 +1307,7 @@
}
/**
- * Handle message sent by {@link #wakeWhenReadyLocked(int)}
+ * Handle message sent by {@link #wakeWhenReady(int)}
* @param keyCode The key that woke the device.
* @see #WAKE_WHEN_READY
*/
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
index 922ced2..4948343 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -147,10 +147,6 @@
// We only modify the page state if it is not currently under control by the slider.
// This prevents conflicts.
- if (mKeyguardHostView != null) {
- mKeyguardHostView.updateStickyWidget(newPageIndex);
- }
-
// If the page hasn't switched, don't bother with any of this
if (mCurrentPage == newPageIndex) return;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index c930ecc..f20b8d4 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -22,9 +22,9 @@
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.content.res.Resources;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.AttributeSet;
@@ -38,7 +38,6 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
-import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import java.util.ArrayList;
@@ -69,8 +68,6 @@
private int mPage = 0;
private Callbacks mCallbacks;
- private boolean mCameraWidgetEnabled;
-
private int mWidgetToResetAfterFadeOut;
// Bouncer
@@ -97,10 +94,6 @@
setPageSwitchListener(this);
- Resources r = getResources();
- mCameraWidgetEnabled = r.getBoolean(R.bool.kg_enable_camera_default_widget);
- mCenterSmallWidgetsVertically =
- r.getBoolean(com.android.internal.R.bool.kg_center_small_widgets_vertically);
mBackgroundWorkerThread = new HandlerThread("KeyguardWidgetPager Worker");
mBackgroundWorkerThread.start();
mBackgroundWorkerHandler = new Handler(mBackgroundWorkerThread.getLooper());
@@ -180,6 +173,22 @@
}
}
+ 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();
@@ -312,6 +321,7 @@
content.getContentDescription());
frame.setContentDescription(contentDescription);
}
+ updateWidgetFrameImportantForAccessibility(frame);
}
/**
@@ -485,35 +495,31 @@
}
}
+ 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;
+ }
+
@Override
void boundByReorderablePages(boolean isReordering, int[] range) {
if (isReordering) {
- if (isAddWidgetPageVisible()) {
+ // 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]++;
}
- if (isMusicWidgetVisible()) {
- range[1]--;
- }
- if (isCameraWidgetVisible()) {
- range[1]--;
- }
}
}
- /*
- * Special widgets
- */
- boolean isAddWidgetPageVisible() {
- // TODO: Make proper test once we decide whether the add-page is always showing
- return true;
- }
- boolean isMusicWidgetVisible() {
- return mViewStateManager.getTransportState() != KeyguardViewStateManager.TRANSPORT_GONE;
- }
- boolean isCameraWidgetVisible() {
- return mCameraWidgetEnabled;
- }
-
protected void reorderStarting() {
showOutlinesAndSidePages();
}
@@ -559,6 +565,12 @@
}
@Override
+ void setCurrentPage(int currentPage) {
+ super.setCurrentPage(currentPage);
+ updateWidgetFramesImportantForAccessibility();
+ }
+
+ @Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mHasMeasure = false;
@@ -669,6 +681,7 @@
}
mWidgetToResetAfterFadeOut = -1;
}
+ updateWidgetFramesImportantForAccessibility();
}
});
mChildrenOutlineFadeAnimation.start();
@@ -761,7 +774,7 @@
boolean isAddPage(int pageIndex) {
View v = getChildAt(pageIndex);
- return v != null && v.getId() == R.id.keyguard_add_widget;
+ return v != null && v.getId() == com.android.internal.R.id.keyguard_add_widget;
}
boolean isCameraPage(int pageIndex) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
index 3bc39eb..97e7f95 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
@@ -16,21 +16,22 @@
package com.android.internal.policy.impl.keyguard;
+import com.android.internal.R;
+
import android.animation.Animator;
-import android.animation.AnimatorSet;
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;
-import com.android.internal.R;
-
public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayout {
private static final String TAG = "MultiPaneChallengeLayout";
@@ -47,7 +48,8 @@
private OnBouncerStateChangedListener mBouncerListener;
private final Rect mTempRect = new Rect();
- private final Context mContext;
+
+ private final DisplayMetrics mDisplayMetrics;
private final OnClickListener mScrimClickListener = new OnClickListener() {
@Override
@@ -67,13 +69,14 @@
public MultiPaneChallengeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mContext = context;
-
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();
}
@Override
@@ -169,15 +172,32 @@
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;
+ }
+ return Math.min(virtualHeight - heightUsed, height);
+ }
+
@Override
- protected void onMeasure(int widthSpec, int heightSpec) {
+ 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");
}
- float squashedLayoutThreshold =
- mContext.getResources().getDimension(R.dimen.kg_squashed_layout_threshold);
final int width = MeasureSpec.getSize(widthSpec);
final int height = MeasureSpec.getSize(heightSpec);
@@ -213,32 +233,26 @@
mUserSwitcherView = child;
if (child.getVisibility() == GONE) continue;
- if (height < squashedLayoutThreshold) {
- int zero = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
- measureChild(child, zero, zero);
- } else {
- int adjustedWidthSpec = widthSpec;
- int adjustedHeightSpec = heightSpec;
- if (lp.maxWidth >= 0) {
- adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
- Math.min(lp.maxWidth, MeasureSpec.getSize(widthSpec)),
- MeasureSpec.EXACTLY);
- }
- if (lp.maxHeight >= 0) {
- adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
- Math.min(lp.maxHeight, MeasureSpec.getSize(heightSpec)),
- 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;
- }
+ 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);
@@ -258,6 +272,8 @@
continue;
}
+ final int virtualHeight = getVirtualHeight(lp, height, heightUsed);
+
int adjustedWidthSpec;
int adjustedHeightSpec;
if (lp.centerWithinArea > 0) {
@@ -266,19 +282,19 @@
(int) ((width - widthUsed) * lp.centerWithinArea + 0.5f),
MeasureSpec.EXACTLY);
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(heightSpec) - heightUsed, MeasureSpec.EXACTLY);
+ virtualHeight, MeasureSpec.EXACTLY);
} else {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(widthSpec) - widthUsed, MeasureSpec.EXACTLY);
+ width - widthUsed, MeasureSpec.EXACTLY);
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
- (int) ((height - heightUsed) * lp.centerWithinArea + 0.5f),
+ (int) (virtualHeight * lp.centerWithinArea + 0.5f),
MeasureSpec.EXACTLY);
}
} else {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(widthSpec) - widthUsed, MeasureSpec.EXACTLY);
+ width - widthUsed, MeasureSpec.EXACTLY);
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(heightSpec) - heightUsed, MeasureSpec.EXACTLY);
+ virtualHeight, MeasureSpec.EXACTLY);
}
if (lp.maxWidth >= 0) {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
@@ -331,6 +347,9 @@
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;
@@ -382,8 +401,7 @@
}
break;
case Gravity.CENTER_VERTICAL:
- final int paddedHeight = height - padding.top - padding.bottom;
- top = padding.top + (paddedHeight - childHeight) / 2;
+ top = padding.top + (height - childHeight) / 2;
bottom = top + childHeight;
break;
}