am 05728277: am c6df397e: am a76f1dfc: am c7255569: Merge "Doc change: fix broken link in publishing steps TOC." into jb-dev-docs

* commit '0572827720e191b3e6fe4466ae09058f5d578c57':
  Doc change: fix broken link in publishing steps TOC.
diff --git a/core/java/com/android/internal/widget/FaceUnlockView.java b/core/java/com/android/internal/widget/FaceUnlockView.java
new file mode 100644
index 0000000..c8d65fc
--- /dev/null
+++ b/core/java/com/android/internal/widget/FaceUnlockView.java
@@ -0,0 +1,67 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+public class FaceUnlockView extends RelativeLayout {
+    private static final String TAG = "FaceUnlockView";
+
+    public FaceUnlockView(Context context) {
+        this(context, null);
+    }
+
+    public FaceUnlockView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    private int resolveMeasured(int measureSpec, int desired)
+    {
+        int result = 0;
+        int specSize = MeasureSpec.getSize(measureSpec);
+        switch (MeasureSpec.getMode(measureSpec)) {
+            case MeasureSpec.UNSPECIFIED:
+                result = desired;
+                break;
+            case MeasureSpec.AT_MOST:
+                result = Math.max(specSize, desired);
+                break;
+            case MeasureSpec.EXACTLY:
+            default:
+                result = specSize;
+        }
+        return result;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        final int minimumWidth = getSuggestedMinimumWidth();
+        final int minimumHeight = getSuggestedMinimumHeight();
+        int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
+        int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
+
+        viewWidth = viewHeight = Math.min(viewWidth, viewHeight);
+        Log.v(TAG, "FaceUnlockView dimensions: " + viewWidth + "x" + viewHeight);
+        setMeasuredDimension(viewWidth, viewHeight);
+    }
+}
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index bb455bd..67ac1d5 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -50,14 +50,14 @@
 
         <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
             android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="@dimen/keyguard_security_width"
+            android:layout_height="@dimen/keyguard_security_height"
             androidprv:layout_childType="challenge"
             androidprv:layout_centerWithinArea="0.55">
             <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
                 android:id="@+id/view_flipper"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:clipChildren="false"
                 android:clipToPadding="false"
                 android:paddingLeft="@dimen/keyguard_security_view_margin"
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index ed55e61..5444471 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -51,8 +51,8 @@
 
         <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
             android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="@dimen/keyguard_security_width"
+            android:layout_height="@dimen/keyguard_security_height"
             androidprv:layout_childType="challenge"
             android:layout_marginLeft="@dimen/kg_edge_swipe_region_size"
             android:layout_marginRight="@dimen/kg_edge_swipe_region_size"
@@ -60,8 +60,8 @@
             android:gravity="bottom|center_horizontal">
             <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
                 android:id="@+id/view_flipper"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:clipChildren="false"
                 android:clipToPadding="false"
                 android:paddingLeft="@dimen/keyguard_security_view_margin"
diff --git a/core/res/res/layout/keyguard_face_unlock_view.xml b/core/res/res/layout/keyguard_face_unlock_view.xml
index ae7984c..976d0c6 100644
--- a/core/res/res/layout/keyguard_face_unlock_view.xml
+++ b/core/res/res/layout/keyguard_face_unlock_view.xml
@@ -30,10 +30,10 @@
         android:layout_height="wrap_content"
         />
 
-    <RelativeLayout
+    <com.android.internal.widget.FaceUnlockView
         android:id="@+id/face_unlock_area_view"
         android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/face_unlock_height"
+        android:layout_height="0dp"
         android:background="@*android:drawable/intro_bg"
         android:gravity="center"
         android:layout_weight="1">
@@ -55,8 +55,7 @@
             android:background="#00000000"
             android:src="@*android:drawable/ic_facial_backup"
         />
-
-    </RelativeLayout>
+    </com.android.internal.widget.FaceUnlockView>
 
     <include layout="@layout/keyguard_emergency_carrier_area"
         android:id="@+id/keyguard_selector_fade_container"
diff --git a/core/res/res/layout/keyguard_password_view.xml b/core/res/res/layout/keyguard_password_view.xml
index a184415..b6faf5b 100644
--- a/core/res/res/layout/keyguard_password_view.xml
+++ b/core/res/res/layout/keyguard_password_view.xml
@@ -22,73 +22,61 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_gravity="center">
+    android:gravity="bottom"
+    >
 
-    <FrameLayout
+    <Space
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_weight="1">
+        android:layout_weight="1"
+        />
 
-        <include layout="@layout/keyguard_message_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
 
-        <LinearLayout
-            android:layout_height="wrap_content"
-            android:layout_width="match_parent"
-            android:orientation="vertical"
-            android:layout_gravity="center">
+    <!-- Password entry field -->
+    <!-- Note: the entire container is styled to look like the edit field,
+         since the backspace/IME switcher looks better inside -->
+     <LinearLayout
+         android:layout_height="wrap_content"
+         android:layout_width="match_parent"
+         android:orientation="horizontal"
+         android:background="#70000000"
+         android:layout_marginTop="8dp"
+         android:layout_marginBottom="8dp"
+         >
 
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
+         <EditText android:id="@+id/passwordEntry"
+             android:layout_width="0dip"
+             android:layout_height="wrap_content"
+             android:layout_weight="1"
+             android:gravity="center_horizontal"
+             android:layout_gravity="center_vertical"
+             android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+             android:singleLine="true"
+             android:textStyle="normal"
+             android:inputType="textPassword"
+             android:textSize="36sp"
+             android:background="@null"
+             android:textAppearance="?android:attr/textAppearanceMedium"
+             android:textColor="#ffffffff"
+             android:imeOptions="flagForceAscii|actionDone"
+             />
 
-                <!-- Password entry field -->
-                <!-- Note: the entire container is styled to look like the edit field,
-                     since the backspace/IME switcher looks better inside -->
-                <LinearLayout
-                    android:layout_gravity="center_vertical|fill_horizontal"
-                    android:layout_height="wrap_content"
-                    android:layout_width="match_parent"
-                    android:orientation="horizontal"
-                    android:background="#70000000"
-                    android:layout_marginStart="4dip"
-                    android:layout_marginEnd="4dip">
+         <ImageView android:id="@+id/switch_ime_button"
+             android:layout_width="wrap_content"
+             android:layout_height="wrap_content"
+             android:src="@*android:drawable/ic_lockscreen_ime"
+             android:clickable="true"
+             android:padding="8dip"
+             android:layout_gravity="center"
+             android:background="?android:attr/selectableItemBackground"
+             android:visibility="gone"
+             />
 
-                    <EditText android:id="@+id/passwordEntry"
-                        android:layout_width="0dip"
-                        android:layout_height="wrap_content"
-                        android:layout_weight="1"
-                        android:gravity="center_horizontal"
-                        android:layout_gravity="center_vertical"
-                        android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-                        android:singleLine="true"
-                        android:textStyle="normal"
-                        android:inputType="textPassword"
-                        android:textSize="36sp"
-                        android:background="@null"
-                        android:textAppearance="?android:attr/textAppearanceMedium"
-                        android:textColor="#ffffffff"
-                        android:imeOptions="flagForceAscii|actionDone"
-                        />
-
-                    <ImageView android:id="@+id/switch_ime_button"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:src="@*android:drawable/ic_lockscreen_ime"
-                        android:clickable="true"
-                        android:padding="8dip"
-                        android:layout_gravity="center"
-                        android:background="?android:attr/selectableItemBackground"
-                        android:visibility="gone"
-                        />
-
-                </LinearLayout>
-            </LinearLayout>
         </LinearLayout>
-    </FrameLayout>
+
     <include layout="@layout/keyguard_emergency_carrier_area"
              android:id="@+id/keyguard_selector_fade_container"
              android:layout_width="match_parent"
diff --git a/core/res/res/layout/keyguard_pin_view.xml b/core/res/res/layout/keyguard_pin_view.xml
index d62570b..19e0a27 100644
--- a/core/res/res/layout/keyguard_pin_view.xml
+++ b/core/res/res/layout/keyguard_pin_view.xml
@@ -21,8 +21,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/res/android"
     android:id="@+id/keyguard_pin_view"
-    android:layout_width="350dp"
-    android:layout_height="350dp"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:orientation="vertical"
     >
     <include layout="@layout/keyguard_message_area"
@@ -35,7 +35,7 @@
         android:orientation="horizontal"
         android:layout_weight="1"
         >
-        <TextView android:id="@+id/passwordEntry"
+        <TextView android:id="@+id/pinEntry"
             android:editable="true"
             android:layout_width="0dip"
             android:layout_height="match_parent"
@@ -78,7 +78,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="1"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -87,7 +87,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="2"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -96,7 +96,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="3"
             />
     </LinearLayout>
@@ -112,7 +112,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="4"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -121,7 +121,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="5"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -130,7 +130,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="6"
             />
     </LinearLayout>
@@ -146,7 +146,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="7"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -155,7 +155,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="8"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -164,7 +164,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="9"
             />
     </LinearLayout>
@@ -185,7 +185,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="0"
             />
         <ImageButton
diff --git a/core/res/res/values-sw380dp/dimens.xml b/core/res/res/values-sw380dp/dimens.xml
new file mode 100644
index 0000000..fc0e85d
--- /dev/null
+++ b/core/res/res/values-sw380dp/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<resources>
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">340dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-sw720dp/dimens.xml b/core/res/res/values-sw720dp/dimens.xml
index d6d2b66..ffb4e11 100644
--- a/core/res/res/values-sw720dp/dimens.xml
+++ b/core/res/res/values-sw720dp/dimens.xml
@@ -112,4 +112,9 @@
     <!-- Size of the text under the avator on the multiuser lockscreen. -->
     <dimen name="keyguard_avatar_name_size">12sp</dimen>
 
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">420dp</dimen>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">420dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b830e79..c0b2b1f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -303,6 +303,12 @@
     <!-- Touch slop for the global toggle accessibility gesture -->
     <dimen name="accessibility_touch_slop">80dip</dimen>
 
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">320dp</dimen>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">400dp</dimen>
+
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_margin">8dp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7ebf7e7..5a0088c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1269,6 +1269,7 @@
   <java-symbol type="id" name="option3" />
   <java-symbol type="id" name="password" />
   <java-symbol type="id" name="passwordEntry" />
+  <java-symbol type="id" name="pinEntry" />
   <java-symbol type="id" name="pinDel" />
   <java-symbol type="id" name="pinDisplay" />
   <java-symbol type="id" name="owner_info" />
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index e0e11be..b3e4a88 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -36,8 +36,8 @@
     /**
      * Create a horizontal, circular geofence.
      *
-     * @param latitude latitude in degrees, between -90 and +90 inclusive
-     * @param longitude longitude in degrees, between -180 and +180 inclusive
+     * @param latitude latitude in degrees
+     * @param longitude longitude in degrees
      * @param radius radius in meters
      * @return a new geofence
      * @throws IllegalArgumentException if any parameters are out of range
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index 8e0061d..737e17f 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -33,8 +33,8 @@
  * Criteria} class allows providers to be selected based on
  * user-specified criteria.
  *
- * @deprecated Use the {@link LocationRequest} class to request location
- * instead of enumerating providers.
+ * @deprecated Use the {@link Criteria} class to request location instead of
+ * enumerating providers.
  */
 @Deprecated
 public class LocationProvider {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
index b38a9ed..3dd0a8f 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
@@ -21,12 +21,15 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Point;
 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;
@@ -47,10 +50,11 @@
     private final Handler mHandler = new Handler();
     private final KeyguardActivityLauncher mActivityLauncher;
     private final Callbacks mCallbacks;
+    private final WindowManager mWindowManager;
+    private final Point mRenderedSize = new Point();
 
     private View mWidgetView;
     private long mLaunchCameraStart;
-    private boolean mRendered;
     private boolean mActive;
     private boolean mChallengeActive;
     private boolean mTransitioning;
@@ -81,6 +85,7 @@
 
         mCallbacks = callbacks;
         mActivityLauncher = activityLauncher;
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     }
 
     public static CameraWidgetFrame create(Context context, Callbacks callbacks,
@@ -141,16 +146,22 @@
     }
 
     public void render() {
-        if (mRendered) return;
-
         try {
             int width = getRootView().getWidth();
             int height = getRootView().getHeight();
-            if (DEBUG) Log.d(TAG, String.format("render [%sx%s] %s",
-                    width, height, Integer.toHexString(hashCode())));
+            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;
             }
+            if (DEBUG) Log.d(TAG, String.format("render size=%sx%s instance=%s at %s",
+                    width, height,
+                    Integer.toHexString(hashCode()),
+                    SystemClock.uptimeMillis()));
+
             Bitmap offscreen = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
             Canvas c = new Canvas(offscreen);
             mWidgetView.measure(
@@ -159,7 +170,7 @@
             mWidgetView.layout(0, 0, width, height);
             mWidgetView.draw(c);
             ((ImageView)getChildAt(0)).setImageBitmap(offscreen);
-            mRendered = true;
+            mRenderedSize.set(width, height);
         } catch (Throwable t) {
             Log.w(TAG, "Error rendering camera widget", t);
             removeAllViews();
@@ -200,6 +211,7 @@
                 scaleX, scaleY,
                 startCenter, finishCenter));
 
+        enableWindowExitAnimation(false);
         animate()
             .scaleX(scale)
             .scaleY(scale)
@@ -305,11 +317,27 @@
         setScaleX(1);
         setScaleY(1);
         setTranslationY(0);
+        enableWindowExitAnimation(true);
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
+    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);
+    }
+
+    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) {
+            wlp.windowAnimations = newWindowAnimations;
+            mWindowManager.updateViewLayout(root, wlp);
+        }
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
index 9c21830..eabf5e0 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
@@ -87,13 +87,14 @@
         }
     }
 
+    protected abstract int getPasswordTextViewId();
     protected abstract void resetState();
 
     @Override
     protected void onFinishInflate() {
         mLockPatternUtils = new LockPatternUtils(mContext);
 
-        mPasswordEntry = (TextView) findViewById(R.id.passwordEntry);
+        mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
         mPasswordEntry.setOnEditorActionListener(this);
         mPasswordEntry.addTextChangedListener(this);
 
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 ec89da2..edb9d51 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -48,7 +48,6 @@
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.widget.RemoteViews.OnClickHandler;
-import android.widget.TextView;
 
 import com.android.internal.R;
 import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -66,11 +65,6 @@
     // also referenced in SecuritySettings.java
     static final int APPWIDGET_HOST_ID = 0x4B455947;
 
-    // transport control states
-    private static final int TRANSPORT_GONE = 0;
-    private static final int TRANSPORT_INVISIBLE = 1;
-    private static final int TRANSPORT_VISIBLE = 2;
-
     private AppWidgetHost mAppWidgetHost;
     private KeyguardWidgetPager mAppWidgetContainer;
     private KeyguardSecurityViewFlipper mSecurityViewContainer;
@@ -90,7 +84,6 @@
     private KeyguardViewStateManager mViewStateManager;
 
     private Rect mTempRect = new Rect();
-    private int mTransportState = TRANSPORT_GONE;
 
     /*package*/ interface TransportCallback {
         void onListenerDetached();
@@ -144,7 +137,7 @@
     private int getWidgetPosition(int id) {
         final int children = mAppWidgetContainer.getChildCount();
         for (int i = 0; i < children; i++) {
-            if (mAppWidgetContainer.getChildAt(i).getId() == id) {
+            if (mAppWidgetContainer.getWidgetPageAt(i).getContent().getId() == id) {
                 return i;
             }
         }
@@ -864,7 +857,8 @@
         @Override
         LockPatternUtils getLockPatternUtils() {
             return mLockPatternUtils;
-        }};
+        }
+    };
 
     private void addDefaultWidgets() {
         LayoutInflater inflater = LayoutInflater.from(mContext);
@@ -906,6 +900,33 @@
         initializeTransportControl();
     }
 
+    private void removeTransportFromWidgetPager() {
+        int page = getWidgetPosition(R.id.keyguard_transport_control);
+        if (page != -1) {
+            mAppWidgetContainer.removeWidget(mTransportControl);
+
+            // XXX keep view attached so we still get show/hide events from AudioManager
+            KeyguardHostView.this.addView(mTransportControl);
+            mTransportControl.setVisibility(View.GONE);
+            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE);
+            mTransportControl.post(mSwitchPageRunnable);
+        }
+    }
+
+    private void addTransportToWidgetPager() {
+        if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
+            KeyguardHostView.this.removeView(mTransportControl);
+            // insert to left of camera if it exists, otherwise after right-most widget
+            int lastWidget = mAppWidgetContainer.getChildCount() - 1;
+            int position = 0; // handle no widget case
+            if (lastWidget >= 0) {
+                position = isCameraPage(lastWidget) ? lastWidget : lastWidget + 1;
+            }
+            mAppWidgetContainer.addWidget(mTransportControl, position);
+            mTransportControl.setVisibility(View.VISIBLE);
+        }
+    }
+
     private void initializeTransportControl() {
         mTransportControl =
             (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
@@ -917,24 +938,14 @@
             mTransportControl.setKeyguardCallback(new TransportCallback() {
                 @Override
                 public void onListenerDetached() {
-                    int page = getWidgetPosition(R.id.keyguard_transport_control);
-                    if (page != -1) {
-                        mAppWidgetContainer.removeView(mTransportControl);
-                        // XXX keep view attached so we still get show/hide events from AudioManager
-                        KeyguardHostView.this.addView(mTransportControl);
-                        mTransportControl.setVisibility(View.GONE);
-                        mTransportState = TRANSPORT_GONE;
-                        mTransportControl.post(mSwitchPageRunnable);
-                    }
+                    removeTransportFromWidgetPager();
+                    mTransportControl.post(mSwitchPageRunnable);
                 }
 
                 @Override
                 public void onListenerAttached() {
-                    if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
-                        KeyguardHostView.this.removeView(mTransportControl);
-                        mAppWidgetContainer.addView(mTransportControl, 0);
-                        mTransportControl.setVisibility(View.VISIBLE);
-                    }
+                    // Transport will be added when playstate changes...
+                    mTransportControl.post(mSwitchPageRunnable);
                 }
 
                 @Override
@@ -1027,7 +1038,7 @@
         saveStickyWidgetIndex();
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        ss.transportState = mTransportState;
+        ss.transportState = mViewStateManager.getTransportState();
         return ss;
     }
 
@@ -1040,7 +1051,7 @@
         }
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        mTransportState = ss.transportState;
+        mViewStateManager.setTransportState(ss.transportState);
         post(mSwitchPageRunnable);
     }
 
@@ -1054,12 +1065,14 @@
     }
 
     private void showAppropriateWidgetPage() {
-        boolean isMusicPlaying =
-                mTransportControl.isMusicPlaying() || mTransportState == TRANSPORT_VISIBLE;
+        int state = mViewStateManager.getTransportState();
+        boolean isMusicPlaying = mTransportControl.isMusicPlaying()
+                || state == KeyguardViewStateManager.TRANSPORT_VISIBLE;
         if (isMusicPlaying) {
-            mTransportState = TRANSPORT_VISIBLE;
-        } else if (mTransportState == TRANSPORT_VISIBLE) {
-            mTransportState = TRANSPORT_INVISIBLE;
+            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE);
+            addTransportToWidgetPager();
+        } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) {
+            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE);
         }
         int pageToShow = getAppropriateWidgetPage(isMusicPlaying);
         mAppWidgetContainer.setCurrentPage(pageToShow);
@@ -1081,7 +1094,7 @@
         // if music playing, show transport
         if (isMusicPlaying) {
             if (DEBUG) Log.d(TAG, "Music playing, show transport");
-            return mAppWidgetContainer.indexOfChild(mTransportControl);
+            return mAppWidgetContainer.getWidgetPageIndex(mTransportControl);
         }
 
         // if we have a valid sticky widget, show it
@@ -1119,6 +1132,10 @@
     }
 
     private void enableUserSelectorIfNecessary() {
+        if (!UserManager.supportsMultipleUsers()) {
+            return; // device doesn't support multi-user mode
+        }
+
         // if there are multiple users, we need to enable to multi-user switcher
         UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         List<UserInfo> users = mUm.getUsers(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
index bea9aec..8522401 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
@@ -47,6 +47,11 @@
     }
 
     @Override
+    protected int getPasswordTextViewId() {
+        return R.id.pinEntry;
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index b6334f0..b35450c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -60,6 +60,11 @@
     }
 
     @Override
+    protected int getPasswordTextViewId() {
+        return R.id.passwordEntry;
+    }
+
+    @Override
     public boolean needsInput() {
         return true;
     }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
index 89f220a..d284602 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -40,6 +40,7 @@
 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;
 
@@ -49,14 +50,13 @@
 /**
  * This is the widget responsible for showing music controls in keyguard.
  */
-public class KeyguardTransportControlView extends KeyguardWidgetFrame implements OnClickListener {
+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 MAXDIM = 512;
     private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
     protected static final boolean DEBUG = false;
     protected static final String TAG = "TransportControlView";
@@ -260,14 +260,6 @@
         mAttached = false;
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-//        int dim = Math.min(MAXDIM, Math.max(getWidth(), getHeight()));
-//        Log.v(TAG, "setting max bitmap size: " + dim + "x" + dim);
-//        mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
-    }
-
     class Metadata {
         private String artist;
         private String trackTitle;
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 85245ba..e42cf1d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -32,6 +32,13 @@
     private static final int SCREEN_ON_RING_HINT_DELAY = 300;
     Handler mMainQueue = new Handler(Looper.myLooper());
 
+    // transport control states
+    static final int TRANSPORT_GONE = 0;
+    static final int TRANSPORT_INVISIBLE = 1;
+    static final int TRANSPORT_VISIBLE = 2;
+
+    private int mTransportState = TRANSPORT_GONE;
+
     int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
 
     // Paged view state
@@ -58,6 +65,13 @@
         return false;
     }
 
+    public boolean isChallengeOverlapping() {
+        if (mChallengeLayout != null) {
+            return mChallengeLayout.isChallengeOverlapping();
+        }
+        return false;
+    }
+
     public void setSecurityViewContainer(KeyguardSecurityView container) {
         mKeyguardSecurityContainer = container;
     }
@@ -207,4 +221,12 @@
 
         mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
     }
+
+    public void setTransportState(int state) {
+        mTransportState = state;
+    }
+
+    public int getTransportState() {
+        return mTransportState;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index e9c90a7..b1ff049 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -62,7 +62,7 @@
     private float mBackgroundAlphaMultiplier = 1.0f;
     private Drawable mBackgroundDrawable;
     private Rect mBackgroundRect = new Rect();
-    private static int mSmallWidgetHeight;
+    private int mSmallWidgetHeight;
 
     // 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.
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 800ccc0..e24e9f9 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -24,7 +24,10 @@
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -33,7 +36,6 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.R;
-
 import com.android.internal.widget.LockPatternUtils;
 
 import java.util.ArrayList;
@@ -61,12 +63,17 @@
     private boolean mShowHintsOnLayout = false;
 
     private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
+    private static final String TAG = "KeyguardWidgetPager";
 
     private int mPage = 0;
     private Callbacks mCallbacks;
 
     private boolean mCameraWidgetEnabled;
 
+    // Background threads to deal with persistence
+    private HandlerThread mBgPersistenceWorkerThread;
+    private Handler mBgPersistenceWorkerHandler;
+
     public KeyguardWidgetPager(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -85,6 +92,9 @@
 
         Resources r = getResources();
         mCameraWidgetEnabled = r.getBoolean(R.bool.kg_enable_camera_default_widget);
+        mBgPersistenceWorkerThread = new HandlerThread("KeyguardWidgetPager Persistence");
+        mBgPersistenceWorkerThread.start();
+        mBgPersistenceWorkerHandler = new Handler(mBgPersistenceWorkerThread.getLooper());
     }
 
     public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
@@ -179,17 +189,28 @@
 
 
     public void onRemoveView(View v) {
-        int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        mLockPatternUtils.removeAppWidget(appWidgetId);
+        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+        mBgPersistenceWorkerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mLockPatternUtils.removeAppWidget(appWidgetId);
+            }
+        });
     }
 
-    public void onAddView(View v, int index) {
-        int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        getVisiblePages(mTempVisiblePagesRange);
-        boundByReorderablePages(true, mTempVisiblePagesRange);
+    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);
         // Subtract from the index to take into account pages before the reorderable
         // pages (e.g. the "add widget" page)
-        mLockPatternUtils.addAppWidget(appWidgetId, index - mTempVisiblePagesRange[0]);
+        mBgPersistenceWorkerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]);
+            }
+        });
     }
 
     /*
@@ -226,25 +247,40 @@
         }
     }
 
-    // We enforce that all children are KeyguardWidgetFrames
+    /**
+     * 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);
@@ -414,8 +450,7 @@
         return true;
     }
     boolean isMusicWidgetVisible() {
-        // TODO: Make proper test once we have music in the list
-        return false;
+        return mViewStateManager.getTransportState() != KeyguardViewStateManager.TRANSPORT_GONE;
     }
     boolean isCameraWidgetVisible() {
         return mCameraWidgetEnabled;
@@ -589,9 +624,37 @@
     @Override
     public boolean onLongClick(View v) {
         // Disallow long pressing to reorder if the challenge is showing
-        if (!mViewStateManager.isChallengeShowing() && startReordering()) {
+        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());
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
index 657a31f..099ea07 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -2072,15 +2072,15 @@
 
         // 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 (!mIsFlingingToDelete) {
             mPostReorderingPreZoomInRunnable = new Runnable() {
                 public void run() {
-                    Runnable onCompleteRunnable = new Runnable() {
-                        @Override
-                        public void run() {
-                            onEndReordering();
-                        }
-                    };
                     zoomIn(onCompleteRunnable);
                 };
             };
@@ -2091,6 +2091,8 @@
             snapToPage(indexOfChild(mDragView), 0);
             // Animate the drag view back to the front position
             animateDragViewToOriginalPosition();
+        } else {
+            zoomIn(onCompleteRunnable);
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
index 35eccbb..74b05dd 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
@@ -702,11 +702,13 @@
             } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
                 setScrimView(child);
             }
+
             if (child.getVisibility() == GONE) continue;
         }
 
-        // We want to measure the challenge view first, for various reasons that I'd rather
-        // not get into here.
+        // 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) {
             measureChildWithMargins(mChallengeView, widthSpec, 0, heightSpec, 0);
         }