Merge "Keep quick settings brightness icon/dialog level in sync." into jb-mr1-dev
diff --git a/api/17.txt b/api/17.txt
index 91dc71f..f236a74 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -20347,7 +20347,6 @@
     method public android.view.WindowManager getWindowManager();
     method public boolean isFullscreen();
     method public boolean isInteractive();
-    method public boolean isLowProfile();
     method public boolean isScreenBright();
     method public void onActionModeFinished(android.view.ActionMode);
     method public void onActionModeStarted(android.view.ActionMode);
@@ -20372,7 +20371,6 @@
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void setFullscreen(boolean);
     method public void setInteractive(boolean);
-    method public void setLowProfile(boolean);
     method public void setScreenBright(boolean);
     field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService";
diff --git a/api/current.txt b/api/current.txt
index 91dc71f..f236a74 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20347,7 +20347,6 @@
     method public android.view.WindowManager getWindowManager();
     method public boolean isFullscreen();
     method public boolean isInteractive();
-    method public boolean isLowProfile();
     method public boolean isScreenBright();
     method public void onActionModeFinished(android.view.ActionMode);
     method public void onActionModeStarted(android.view.ActionMode);
@@ -20372,7 +20371,6 @@
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void setFullscreen(boolean);
     method public void setInteractive(boolean);
-    method public void setLowProfile(boolean);
     method public void setScreenBright(boolean);
     field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService";
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index dd51764..cb78763 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -22,6 +22,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
 import android.content.Intent;
+import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Handler;
 import android.os.IBinder;
@@ -401,6 +402,9 @@
      * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view.
      *
      * @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE
+     * @hide There is no reason to have this -- dreams can set this flag
+     * on their own content view, and from there can actually do the
+     * correct interactions with it (seeing when it is cleared etc).
      */
     public void setLowProfile(boolean lowProfile) {
         mLowProfile = lowProfile;
@@ -412,20 +416,23 @@
      * Returns whether or not this dream is in low profile mode. Defaults to true.
      *
      * @see #setLowProfile(boolean)
+     * @hide
      */
     public boolean isLowProfile() {
         return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile);
     }
 
     /**
-     * Sets View.SYSTEM_UI_FLAG_FULLSCREEN on the content view.
+     * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
+     * on the dream's window.
      *
-     * @param fullscreen True to set View.SYSTEM_UI_FLAG_FULLSCREEN
+     * @param fullscreen If true, the fullscreen flag will be set; else it
+     * will be cleared.
      */
     public void setFullscreen(boolean fullscreen) {
         mFullscreen = fullscreen;
-        int flag = View.SYSTEM_UI_FLAG_FULLSCREEN;
-        applySystemUiVisibilityFlags(mFullscreen ? flag : 0, flag);
+        int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+        applyWindowFlags(mFullscreen ? flag : 0, flag);
     }
 
     /**
@@ -434,7 +441,7 @@
      * @see #setFullscreen(boolean)
      */
     public boolean isFullscreen() {
-        return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_FULLSCREEN, mFullscreen);
+        return mFullscreen;
     }
 
     /**
@@ -565,6 +572,7 @@
         mWindow.setCallback(this);
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
+        mWindow.setFormat(PixelFormat.OPAQUE);
 
         if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
                 windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -573,9 +581,12 @@
         lp.type = WindowManager.LayoutParams.TYPE_DREAM;
         lp.token = windowToken;
         lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
-        lp.flags |= ( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+        lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                     | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                     | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
+                    | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
                     | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
                     );
         mWindow.setAttributes(lp);
@@ -588,9 +599,8 @@
         if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
         try {
             applySystemUiVisibilityFlags(
-                    (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0)
-                  | (mFullscreen ? View.SYSTEM_UI_FLAG_FULLSCREEN : 0),
-                    View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
+                    (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+                    View.SYSTEM_UI_FLAG_LOW_PROFILE);
             getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
         } catch (Throwable t) {
             Slog.w("Crashed adding window view", t);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 86bbc55..6d5705d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -574,7 +574,8 @@
             final boolean flagsChanged = mCurWindowFlags != mWindowFlags ||
                     mCurWindowPrivateFlags != mWindowPrivateFlags;
             if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged
-                    || typeChanged || flagsChanged || redrawNeeded) {
+                    || typeChanged || flagsChanged || redrawNeeded
+                    || !mIWallpaperEngine.mShownReported) {
 
                 if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
                         + " format=" + formatChanged + " size=" + sizeChanged);
@@ -739,6 +740,7 @@
                         if (redrawNeeded) {
                             mSession.finishDrawing(mWindow);
                         }
+                        mIWallpaperEngine.reportShown();
                     }
                 } catch (RemoteException ex) {
                 }
@@ -950,6 +952,7 @@
         final IBinder mWindowToken;
         final int mWindowType;
         final boolean mIsPreview;
+        boolean mShownReported;
         int mReqWidth;
         int mReqHeight;
         
@@ -1002,6 +1005,18 @@
             }
         }
 
+        public void reportShown() {
+            if (!mShownReported) {
+                mShownReported = true;
+                try {
+                    mConnection.engineShown(this);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Wallpaper host disappeared", e);
+                    return;
+                }
+            }
+        }
+
         public void destroy() {
             Message msg = mCaller.obtainMessage(DO_DETACH);
             mCaller.sendMessage(msg);
@@ -1020,12 +1035,6 @@
                     mEngine = engine;
                     mActiveEngines.add(engine);
                     engine.attach(this);
-                    try {
-                        mConnection.engineShown(this);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Wallpaper host disappeared", e);
-                        return;
-                    }
                     return;
                 }
                 case DO_DETACH: {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f7ba38c..e3250f9 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -201,8 +201,9 @@
 
     /**
      * Block until the given window has been drawn to the screen.
+     * Returns true if really waiting, false if the window does not exist.
      */
-    void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
+    boolean waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
 
     /**
      * Device has a software navigation bar (separate from the status bar).
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 876b7d84..a9b6e09 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -189,7 +189,7 @@
         if (opaque != mOpaque) {
             mOpaque = opaque;
             if (mLayer != null) {
-                updateLayer();
+                updateLayerAndInvalidate();
             }
         }
     }
@@ -310,6 +310,7 @@
         super.onSizeChanged(w, h, oldw, oldh);
         if (mSurface != null) {
             nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+            updateLayer();
             if (mListener != null) {
                 mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
             }
@@ -352,9 +353,7 @@
                 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                     // Per SurfaceTexture's documentation, the callback may be invoked
                     // from an arbitrary thread
-                    synchronized (mLock) {
-                        mUpdateLayer = true;
-                    }
+                    updateLayer();
 
                     if (Looper.myLooper() == Looper.getMainLooper()) {
                         invalidate();
@@ -379,9 +378,7 @@
 
             // Since we are updating the layer, force an update to ensure its
             // parameters are correct (width, height, transform, etc.)
-            synchronized (mLock) {
-                mUpdateLayer = true;
-            }
+            updateLayer();
             mMatrixChanged = true;
 
             mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
@@ -404,7 +401,7 @@
             // updates listener
             if (visibility == VISIBLE) {
                 mSurface.setOnFrameAvailableListener(mUpdateListener);
-                updateLayer();
+                updateLayerAndInvalidate();
             } else {
                 mSurface.setOnFrameAvailableListener(null);
             }
@@ -412,7 +409,15 @@
     }
 
     private void updateLayer() {
-        mUpdateLayer = true;
+        synchronized (mLock) {
+            mUpdateLayer = true;
+        }
+    }
+
+    private void updateLayerAndInvalidate() {
+        synchronized (mLock) {
+            mUpdateLayer = true;
+        }
         invalidate();
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index be2d5b3..0475283 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2322,7 +2322,13 @@
             mAccessibilityFocusedHost.getDrawingRect(bounds);
             if (mView instanceof ViewGroup) {
                 ViewGroup viewGroup = (ViewGroup) mView;
-                viewGroup.offsetDescendantRectToMyCoords(mAccessibilityFocusedHost, bounds);
+                try {
+                    viewGroup.offsetDescendantRectToMyCoords(mAccessibilityFocusedHost, bounds);
+                } catch (IllegalArgumentException iae) {
+                    Log.e(TAG, "Temporary detached view that was neither removed not reattached: "
+                            + mAccessibilityFocusedHost);
+                    return;
+                }
             }
         } else {
             if (mAccessibilityFocusedVirtualView == null) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6e51270..eb3f72e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -298,12 +298,14 @@
          * Window type: the status bar.  There can be only one status bar
          * window; it is placed at the top of the screen, and all other
          * windows are shifted down so they are below it.
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
     
         /**
          * Window type: the search bar.  There can be only one search bar
          * window; it is placed at the top of the screen.
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
     
@@ -312,22 +314,26 @@
          * user interaction with the phone (in particular incoming calls).
          * These windows are normally placed above all applications, but behind
          * the status bar.
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
     
         /**
          * Window type: system window, such as low power alert. These windows
          * are always on top of application windows.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
         
         /**
          * Window type: keyguard window.
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
         
         /**
          * Window type: transient notifications.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
         
@@ -335,6 +341,7 @@
          * Window type: system overlay windows, which need to be displayed
          * on top of everything else.  These windows must not take input
          * focus, or they will interfere with the keyguard.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
         
@@ -342,22 +349,26 @@
          * Window type: priority phone UI, which needs to be displayed even if
          * the keyguard is active.  These windows must not take input
          * focus, or they will interfere with the keyguard.
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
         
         /**
          * Window type: panel that slides out from the status bar
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
     
         /**
          * Window type: dialogs that the keyguard shows
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
         
         /**
          * Window type: internal system error windows, appear on top of
          * everything they can.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
         
@@ -365,23 +376,27 @@
          * Window type: internal input methods windows, which appear above
          * the normal UI.  Application windows may be resized or panned to keep
          * the input focus visible while this window is displayed.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
 
         /**
          * Window type: internal input methods dialog windows, which appear above
          * the current input method window.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
 
         /**
          * Window type: wallpaper window, placed behind any window that wants
          * to sit on top of the wallpaper.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
 
         /**
          * Window type: panel that slides out from over the status bar
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
 
@@ -393,6 +408,8 @@
          * This is exactly like {@link #TYPE_SYSTEM_OVERLAY} except that only the
          * system itself is allowed to create these overlays.  Applications cannot
          * obtain permission to create secure system overlays.
+         *
+         * In multiuser systems shows only on the owning user's window.
          * @hide
          */
         public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
@@ -400,24 +417,28 @@
         /**
          * Window type: the drag-and-drop pseudowindow.  There is only one
          * drag layer (at most), and it is placed on top of all other windows.
+         * In multiuser systems shows only on the owning user's window.
          * @hide
          */
         public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;
 
         /**
          * Window type: panel that slides out from under the status bar
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
 
         /**
          * Window type: (mouse) pointer
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
 
         /**
          * Window type: Navigation bar (when distinct from status bar)
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
@@ -425,6 +446,7 @@
         /**
          * Window type: The volume level overlay/dialog shown when the user
          * changes the system volume.
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
@@ -432,6 +454,7 @@
         /**
          * Window type: The boot progress dialog, goes on top of everything
          * in the world.
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
@@ -439,30 +462,35 @@
         /**
          * Window type: Fake window to consume touch events when the navigation
          * bar is hidden.
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
 
         /**
          * Window type: Dreams (screen saver) window, just above keyguard.
+         * In multiuser systems shows only on the owning user's window.
          * @hide
          */
         public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
 
         /**
          * Window type: Navigation bar panel (when navigation bar is distinct from status bar)
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
 
         /**
          * Window type: Behind the universe of the real windows.
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_UNIVERSE_BACKGROUND = FIRST_SYSTEM_WINDOW+25;
 
         /**
          * Window type: Display overlay window.  Used to simulate secondary display devices.
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
@@ -470,11 +498,20 @@
         /**
          * Window type: Magnification overlay window. Used to highlight the magnified
          * portion of a display when accessibility magnification is enabled.
+         * In multiuser systems shows on all users' windows.
          * @hide
          */
         public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
 
         /**
+         * Window type: Recents. Same layer as {@link #TYPE_SYSTEM_DIALOG} but only appears on
+         * one user's screen.
+         * In multiuser systems shows on all users' windows.
+         * @hide
+         */
+        public static final int TYPE_RECENTS_OVERLAY = FIRST_SYSTEM_WINDOW+28;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
@@ -879,6 +916,14 @@
          */
         public static final int PRIVATE_FLAG_SET_NEEDS_MENU_KEY = 0x00000008;
 
+        /** In a multiuser system if this flag is set and the owner is a system process then this
+         * window will appear on all user screens. This overrides the default behavior of window
+         * types that normally only appear on the owning user's screen. Refer to each window type
+         * to determine its default behavior.
+         *
+         * {@hide} */
+        public static final int PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010;
+
         /**
          * Control flags that are private to the platform.
          * @hide
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 04b5e11..4ccb502 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -501,6 +501,16 @@
     public int checkAddPermission(WindowManager.LayoutParams attrs);
 
     /**
+     * Check permissions when adding a window.
+     *
+     * @param attrs The window's LayoutParams.
+     *
+     * @return True if the window may only be shown to the current user, false if the window can
+     * be shown on all users' windows.
+     */
+    public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs);
+
+    /**
      * Sanitize the layout parameters coming from a client.  Allows the policy
      * to do things like ensure that windows of a specific type can't take
      * input focus.
@@ -1058,18 +1068,13 @@
      * Called when we have started keeping the screen on because a window
      * requesting this has become visible.
      */
-    public void screenOnStartedLw();
+    public void keepScreenOnStartedLw();
 
     /**
      * Called when we have stopped keeping the screen on because the last window
      * requesting this is no longer visible.
      */
-    public void screenOnStoppedLw();
-
-    /**
-     * Return false to disable key repeat events from being generated.
-     */
-    public boolean allowKeyRepeat();
+    public void keepScreenOnStoppedLw();
 
     /**
      * Inform the policy that the user has chosen a preferred orientation ("rotation lock"). 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 1f70c66..150caf3 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -629,7 +629,7 @@
             jint count, jint flags, jint offset, jint opt) {
         jfloat scalarArray[count];
 
-        TextLayout::getTextRunAdvances(paint, text, start, count, count, flags,
+        TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags,
                 scalarArray, NULL /* dont need totalAdvance */);
 
         jint pos = offset - start;
diff --git a/core/res/res/layout/keyguard_multi_user_avatar.xml b/core/res/res/layout/keyguard_multi_user_avatar.xml
index d6a858f..0e851e3 100644
--- a/core/res/res/layout/keyguard_multi_user_avatar.xml
+++ b/core/res/res/layout/keyguard_multi_user_avatar.xml
@@ -47,6 +47,8 @@
             android:layout_gravity="center_vertical|left"
             android:textSize="16sp"
             android:textColor="#ffffff"
+            android:singleLine="true"
+            android:ellipsize="end"
             android:background="#808080" />
     </LinearLayout>
 </com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_status_view.xml b/core/res/res/layout/keyguard_status_view.xml
index c7f6863..951787b 100644
--- a/core/res/res/layout/keyguard_status_view.xml
+++ b/core/res/res/layout/keyguard_status_view.xml
@@ -59,6 +59,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="end"
             android:layout_marginTop="-16dp"
+            android:layout_marginBottom="24dp"
             android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
             android:singleLine="true"
             android:ellipsize="marquee"
@@ -69,7 +70,7 @@
         <TextView
             android:id="@+id/alarm_status"
             android:layout_gravity="end"
-            android:layout_marginTop="28dp"
+            android:layout_marginTop="4dp"
             android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
             android:singleLine="true"
             android:ellipsize="marquee"
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
index b707456..40ecd14 100644
--- a/data/fonts/Roboto-Bold.ttf
+++ b/data/fonts/Roboto-Bold.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
index 43bc15b..d9067c5 100644
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ b/data/fonts/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
index d9041db..88e4a5b 100644
--- a/data/fonts/Roboto-Italic.ttf
+++ b/data/fonts/Roboto-Italic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf
index 8224692..2ae4dec 100644
--- a/data/fonts/Roboto-Light.ttf
+++ b/data/fonts/Roboto-Light.ttf
Binary files differ
diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf
index 979a8ef..44177ef 100644
--- a/data/fonts/Roboto-LightItalic.ttf
+++ b/data/fonts/Roboto-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
index cf9968f..f592adf 100644
--- a/data/fonts/Roboto-Regular.ttf
+++ b/data/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf
index 9f3b93c..5ae4d7f 100644
--- a/data/fonts/Roboto-Thin.ttf
+++ b/data/fonts/Roboto-Thin.ttf
Binary files differ
diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf
index 9c53b16..9cd3927 100644
--- a/data/fonts/Roboto-ThinItalic.ttf
+++ b/data/fonts/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf
index 7fd9dd8..21c10f5 100644
--- a/data/fonts/RobotoCondensed-Bold.ttf
+++ b/data/fonts/RobotoCondensed-Bold.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf
index b0dba13..d8edd2d 100644
--- a/data/fonts/RobotoCondensed-BoldItalic.ttf
+++ b/data/fonts/RobotoCondensed-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf
index 48f02b5..4dec2cf 100644
--- a/data/fonts/RobotoCondensed-Italic.ttf
+++ b/data/fonts/RobotoCondensed-Italic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf
index d7254f4..875ea1a 100644
--- a/data/fonts/RobotoCondensed-Regular.ttf
+++ b/data/fonts/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
index a483522..04af57b 100644
--- a/docs/html/design/patterns/app-structure.jd
+++ b/docs/html/design/patterns/app-structure.jd
@@ -86,6 +86,9 @@
   through the navigation hierarchy.</li>
 </ul>
 
+<p>For more discussion, see the <a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a>
+design guide.</p>
+
   </div>
   <div class="layout-content-col span-8">
 
@@ -164,6 +167,10 @@
   </div>
 </div>
 
+<p>For more discussion, see the <a href="{@docRoot}design/building-blocks/tabs.html">Tabs</a>
+design guide.</p>
+
+
 <h4>Allow cutting through hierarchies</h4>
 <p>Take advantage of shortcuts that allow people to reach their goals quicker. To allow top-level
 invocation of actions for a data item from within list or grid views, display prominent actions
@@ -183,6 +190,12 @@
 delete multiple items in the category view. Analyze which detail view actions are applicable to
 collections of items. Then use multi-select to allow application of those actions to multiple items
 in a category view.</p>
+
+
+<p>For more discussion, see the <a href="{@docRoot}design/patterns/selection.html">Selection</a>
+design guide.</p>
+
+
 <h2 id="details">Details</h2>
 
 <p>The detail view allows you to view and act on your data. The layout of the detail view depends on the data type being displayed, and therefore differs widely among apps.</p>
@@ -239,6 +252,10 @@
   thumbnail view control that lets people quickly jump to specific pages.
 </div>
 
+<p>For more discussion, see the <a href="{@docRoot}design/patterns/swipe-views.html">Swipe Views</a>
+design guide.</p>
+
+
 <h2 id="checklist">Checklist</h2>
 
 <ul>
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index 612c370..e9d22e6 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -78,6 +78,13 @@
   </div>
 </div>
 
+<div class="note develop">
+<p><strong>Developer Guide</strong></p>
+  <p>For information about how to create a contextual action bar, read
+  <a href="{@docRoot}guide/topics/ui/menus.html#CAB">Using the contextual action mode</a>.</p>
+</div>
+
+
 <h2 id="checklist">Checklist</h2>
 
 <ul>
diff --git a/docs/html/design/style/devices-displays.jd b/docs/html/design/style/devices-displays.jd
index df77c1b..18550d9 100644
--- a/docs/html/design/style/devices-displays.jd
+++ b/docs/html/design/style/devices-displays.jd
@@ -36,8 +36,21 @@
 
 <h4>Strategies</h4>
 <p>So where do you begin when designing for multiple screens? One approach is to work in the base
-standard (medium size, <acronym title="Medium density (160 dpi)">MDPI</acronym>) and scale it up or
+standard (normal size and <acronym title="Medium density (160 dpi)">MDPI</acronym>) and scale it up or
 down for the other buckets. Another approach is to start with the device with the largest screen
 size, and then scale down and figure out the UI compromises you'll need to make on smaller screens.</p>
-<p>For more detailed information on this topic, please visit <a href="http://developer.android.com/guide/practices/screens_support.html">Supporting Multiple
-Screens</a>.</p>
+
+<p>For details about designing layouts for larger screens, see the <a
+href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a> guide.</p>
+
+<div class="note develop">
+<p><strong>Developer Guide</strong></p>
+  <p>For information about how to build flexible layouts for multiple screen sizes and densities,
+  read
+  <a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a> and
+  <a href="{@docRoot}training/basics/fragments/index.html">Building a Dynamic UI with
+  Fragments</a>.</p>
+</div>
+
+
+
diff --git a/docs/html/design/style/themes.jd b/docs/html/design/style/themes.jd
index d4a6acf..e1899e3 100644
--- a/docs/html/design/style/themes.jd
+++ b/docs/html/design/style/themes.jd
@@ -38,5 +38,12 @@
 point for your customizations is a good idea. The system themes provide a solid foundation on top
 of which you can selectively implement your own visual stylings.</p>
 
+<div class="note develop">
+<p><strong>Developer Guide</strong></p>
+  <p>For information about how to apply themes such as Holo Light and Dark, and 
+  how to build your own themes, see the
+  <a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> API guide.</p>
+</div>
+
   </div>
 </div>
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
index 84103b9..ad3121c 100644
--- a/docs/html/distribute/distribute_toc.cs
+++ b/docs/html/distribute/distribute_toc.cs
@@ -28,9 +28,7 @@
        <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">
            <span class="en">Publishing Checklist</span>
           </a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">
-          <span class="en">App Quality</span>
-         </a></li>
+
      </ul>
   </li>
   
@@ -79,6 +77,26 @@
      </ul>
    </li>
 
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">
+      <span class="en">App Quality</span></a>
+    </div>
+    <ul>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">
+          <span class="en">Core App Quality</span>
+         </a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">
+          <span class="en">Tablet App Quality</span>
+         </a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">
+          <span class="en">Improving App Quality</span>
+         </a></li>
+
+    </ul>
+  </li> 
+
+
 <!--    
    <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/after.html">
@@ -92,17 +110,17 @@
   </li> 
 -->
 
-<!--  
   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/strategies/index.html">
-      <span class="en">Strategies</span></a>
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">
+      <span class="en">Spotlight</span></a>
     </div>
     <ul>
-          <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/featuring.html">Featuring</a></li>
-          <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">App Quality</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">
+          <span class="en">Tablet Stories</span>
+         </a></li>
     </ul>
   </li> 
--->
+
   <li class="nav-section">
     <div class="nav-section-header empty">
       <a href="<?cs var:toroot ?>distribute/open.html">
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
index 4980eda..d5c6dfa 100644
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ b/docs/html/distribute/googleplay/about/monetizing.jd
@@ -42,7 +42,7 @@
 <h3 id="payment-methods">Convenient payment options</h3>
 
 <p>Users can purchase your products on Google Play using several convenient
-payment methods&mdash;credit cards, Direct Carrier Billing, and Google Play balance.</p>
+payment methods&mdash;credit cards, Direct Carrier Billing, gift cards, and Google Play balance.</p>
 
 <p><span style="font-weight:500">Credit card</span> is the most common method of payment. Users can pay using any credit card
 that they’ve registered in Google Play. To make it easy for users to get started,
@@ -52,8 +52,9 @@
 <div class="sidebox">
 <h2>Payment methods on Google Play</h2>
 <ul>
-<li>Credit Card</li>
+<li>Credit card</li>
 <li>Direct Carrier Billing</li>
+<li>Gift card</li>
 <li>Google Play balance (stored value)</li>
 </ul>
 </div>
diff --git a/docs/html/distribute/googleplay/about/visibility.jd b/docs/html/distribute/googleplay/about/visibility.jd
index 47fa56e..38fb395 100644
--- a/docs/html/distribute/googleplay/about/visibility.jd
+++ b/docs/html/distribute/googleplay/about/visibility.jd
@@ -16,7 +16,7 @@
 <p>Google Play is the premier store for distributing Android apps. It’s
 preinstalled on more than 400 million devices worldwide, a number growing by
 more than a million every day. Android users have downloaded
-more than <strong style="text-wrap:none;">15 billion apps</strong> from Google
+more than <strong style="text-wrap:none;">25 billion apps</strong> from Google
 Play, growing at a rate of more than 1.5 billion per month.</p>
 
 <p>When you publish on Google Play, you put your apps in front of Android's huge
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 6ea0f53..463343d 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -6,20 +6,21 @@
 <ol>
 <li><a href="#process">1. Understand the publishing process</a></li>
 <li><a href="#policies">2. Understand Google Play policies</a></li>
-<li><a href="#rating">3. Determine your content rating</a></li>
-<li><a href="#countries">4. Determine country distribution</a></li>
-<li><a href="#size">5. Confirm the app's overall size</a></li>
-<li><a href="#compatibility">6. Confirm app compatibility ranges</a></li>
-<li><a href="#free-priced">7. Decide on free or priced</a></li>
-<li><a href="#inapp-billing">8. Consider In-app Billing</a></li>
-<li><a href="#pricing">9. Set prices for your apps</a></li>
-<li><a href="#localize">10. Start localization</a></li>
-<li><a href="#localize">11. Prepare promotional graphics</a></li>
-<li><a href="#apk">12. Build the release-ready APK</a></li>
-<li><a href="#product-page">13. Complete the product details</a></li>
-<li><a href="#badges">14. Use Google Play badges and links to your promotional campaigns</a></li>
-<li><a href="#final-checks">15. Final checks and publishing</a></li>
-<li><a href="#support">16. Support users after launch</a></li>
+<li><a href="#core-app-quality">3. Test for Core App Quality</a></li>
+<li><a href="#rating">4. Determine your content rating</a></li>
+<li><a href="#countries">5. Determine country distribution</a></li>
+<li><a href="#size">6. Confirm the app's overall size</a></li>
+<li><a href="#compatibility">7. Confirm app compatibility ranges</a></li>
+<li><a href="#free-priced">8. Decide on free or priced</a></li>
+<li><a href="#inapp-billing">9. Consider In-app Billing</a></li>
+<li><a href="#pricing">10. Set prices for your apps</a></li>
+<li><a href="#localize">11. Start localization early</a></li>
+<li><a href="#localize">12. Prepare promotional graphics</a></li>
+<li><a href="#apk">13. Build the release-ready APK</a></li>
+<li><a href="#product-page">14. Complete the product details</a></li>
+<li><a href="#badges">15. Use Google Play badges</a></li>
+<li><a href="#final-checks">16. Final checks and publishing</a></li>
+<li><a href="#support">17. Support users after launch</a></li>
 </ol>
 </div></div>
 
@@ -86,7 +87,39 @@
 </tr>
 </table>
 
-<h2 id="rating">3. Determine your app's content rating</h2>
+<h2 id="core-app-quality">3. Test for Core App Quality</h2>
+
+<p>Before you publish an app on Google Play, it's important to make sure that
+it meets the basic quality expectations for all Android apps, on all of the devices that you
+are targeting. You can check your app's quality by setting up a test
+environment and testing the app against a short set of <strong>core app quality criteria</strong>.
+For complete information, see the <a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>. 
+</p>
+
+<p>If your app is targeting tablet devices, make sure that it delivers a rich, compelling
+experience to your tablet customers. See the <a
+href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a>
+for recommendations on ways to optimize your app for tablets.</p>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
+Guidelines</a></strong> &mdash; A set of core quality criteria that all Android
+apps should meet on all targeted devices.</li>
+<li><strong><a
+href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
+Checklist</a></strong> &mdash; A set recommendations for delivering the best
+possible experience to tablet users.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="rating">4. Determine your app's content rating</h2>
 
 <p>Google Play requires you to set a content rating for your app, which informs
 Google Play users of its maturity level. Before you publish, you should confirm
@@ -115,7 +148,7 @@
 </tr>
 </table>
 
-<h2 id="countries">4. Determine country distribution</h2>
+<h2 id="countries">5. Determine country distribution</h2>
 
 <p>Google Play lets you control what countries and territories your app is
 distributed to. For widest reach and the largest potential customer base, you
@@ -149,7 +182,7 @@
 </tr>
 </table>
 
-<h2 id="size">5. Confirm the app's overall size</h2>
+<h2 id="size">6. Confirm the app's overall size</h2>
 
 <p>The overall size of your app can affect its design and how you publish it on
 Google Play. Currently, the maximum size for an APK published on Google Play is
@@ -180,7 +213,7 @@
 </tr>
 </table>
 
-<h2 id="compatibility">6. Confirm the app's platform and screen compatibility ranges</h2>
+<h2 id="compatibility">7. Confirm the app's platform and screen compatibility ranges</h2>
 
 <p>Before publishing, it's important to make sure that your app is designed to
 run properly on the Android platform versions and device screen sizes that you
@@ -217,7 +250,7 @@
 </tr>
 </table>
 
-<h2 id="free-priced">7. Decide whether your app will be free or priced</h2>
+<h2 id="free-priced">8. Decide whether your app will be free or priced</h2>
 
 <p>On Google Play, you can publish apps as free to download or priced. Free apps
 can be downloaded by any Android user in Google Play.
@@ -249,7 +282,7 @@
 </tr>
 </table>
 
-<h2 id="inapp-billing">8. Consider using In-app Billing</h2>
+<h2 id="inapp-billing">9. Consider using In-app Billing</h2>
 
 <p>Google Play <a href="{@docRoot}guide/google/play/billing/index.html">In-app
 Billing</a> lets you sell digital content in your applications. You can use the
@@ -275,7 +308,7 @@
 </tr>
 </table>
 
-<h2 id="pricing">9. Set prices for your products</h2>
+<h2 id="pricing">10. Set prices for your products</h2>
 
 <p>If your app is priced or you will sell in-app products, Google Play lets you
 set prices for your products in a variety of currencies, for users in markets
@@ -308,7 +341,7 @@
 </tr>
 </table>
 
-<h2 id="localize">10. Start localization</h2>
+<h2 id="localize">11. Start localization</h2>
 
 <p>With your country targeting in mind, it's a good idea to assess your localization
 needs and start the work of localizing well in advance of your target
@@ -344,7 +377,7 @@
 </tr>
 </table>
 
-<h2 id="graphics">11. Prepare promotional graphics</h2>
+<h2 id="graphics">12. Prepare promotional graphics</h2>
 
 <p>When you publish on Google Play, you can supply a variety of high-quality
 graphic assets to showcase your app or brand. After you publish, these appear on
@@ -375,7 +408,7 @@
 </tr>
 </table>
 
-<h2 id="apk">12. Build and upload the release-ready APK</h2>
+<h2 id="apk">13. Build and upload the release-ready APK</h2>
 
 <p>When you are satisfied that your app meets your UI, compatibility, and
 quality requirements, you can build the release-ready version of the app. The
@@ -407,7 +440,7 @@
 </tr>
 </table>
 
-<h2 id="product-page">13. Complete the app's product details</h2>
+<h2 id="product-page">14. Complete the app's product details</h2>
 
 <p>On Google Play, your app's product information is shown to users on its
 product details page, the page that users visit to learn more about your app and
@@ -431,6 +464,10 @@
 page, make sure that you can enter or upload it to the Developer Console, until 
 the page is complete and ready for publishing. </p>
 
+<p>If your app is targeting tablet devices, make sure to include at least one screen
+shot of the app running on a tablet, and highlight your app's support for tablets
+in the app description, release notes, promotional campaigns, and elsewhere.</p>
+
 <table>
 <tr>
 <td><p>Related resources:</p>
@@ -444,7 +481,7 @@
 </tr>
 </table>
 
-<h2 id="badges">14. Use Google Play badges and links in your promotional
+<h2 id="badges">15. Use Google Play badges and links in your promotional
 campaigns</h2>
 
 <p>Google Play badges give you an officially branded way of promoting your app
@@ -473,7 +510,7 @@
 </tr>
 </table>
 
-<h2 id="final-checks">15. Final checks and publishing</h2> 
+<h2 id="final-checks">16. Final checks and publishing</h2> 
 
 <p>When you think you are ready to publish, sign in to the Developer Console and take a few moments for a few
 final checks:</p>
@@ -511,7 +548,7 @@
 </table>
 
 
-<h2 id="support">16. Support users after launch</h2>
+<h2 id="support">17. Support users after launch</h2>
 
 <p>After you publish an app or an app update, it's crucial for you to support
 your customers. Prompt and courteous support can provide a better experience for
diff --git a/docs/html/distribute/googleplay/quality/core.jd b/docs/html/distribute/googleplay/quality/core.jd
new file mode 100644
index 0000000..291550f
--- /dev/null
+++ b/docs/html/distribute/googleplay/quality/core.jd
@@ -0,0 +1,803 @@
+page.title=Core App Quality Guidelines
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Quality Criteria</h2>
+  <ol>
+    <li><a href="#ux">Design and Interaction</a></li>
+        <li><a href="#fn">Functionality</a></li>
+        <li><a href="#ps">Performance and Stability</a></li>
+        <li><a href="#listing">Google Play</a></li>
+
+  </ol>
+  
+  <h2>Testing</h2>
+  <ol>
+    <li><a href="#test-environment">Setting Up a Test Environment</a></li>
+        <li><a href="#tests">Test Procedures</a></li>
+        </ol>
+
+  <h2>You Should Also Read</h2>
+  <ol>
+    <li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
+        <li><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
+  </ol>
+  
+
+</div>
+</div>
+
+<p>App quality directly influences the long-term success of your app&mdash;in
+terms of installs, user rating and reviews, engagement, and user retention.
+Android users expect high-quality apps, even more so if they've spent money on
+them.</p>
+
+<p>This document helps you assess basic aspects of quality in your app through a
+compact set of <em>core app quality criteria</em> and associated tests. All
+Android apps should meet these criteria.</p>
+
+<p>Before publishing your app, make sure to test it against these criteria to
+ensure that it functions well on many devices, meets Android standards for
+navigation and design, and is prepared for promotional opportunities in the
+Google Play Store. Your testing will go well beyond what's described here&mdash;the
+purpose of this document is to specify the essential characteristics
+of basic quality so that you can include them in your test plans.</p>
+
+<p>If your app is targeting tablet devices, make sure that it delivers a rich,
+compelling experience to your tablet customers. See the <a
+href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
+Checklist</a> for recommendations on ways to optimize your app for tablets.</p>
+
+
+<h2 id="ux">Visual Design and User Interaction</h2>
+
+<p>These criteria ensure that your app provides standard Android visual design
+and interaction patterns where appropriate, for a consistent and intuitive
+user experience.</p>
+
+<table>
+	<tr>
+		<th style="width:2px;">
+			Area
+		</th>
+		<th style="width:54px;">
+			ID
+		</th>
+		
+
+		<th>
+			Description
+		</th>
+		<th style="width:54px;">
+			Tests
+		</th>
+	</tr>
+	<tr id="UX-B1">
+	<td>Standard design</td>
+		<td>
+		UX-B1	
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App follows <a href="{@docRoot}design/index.html">Android Design</a> guidelines and uses common <a href="{@docRoot}design/patterns/index.html">UI patterns and icons</a>:</p>
+			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+			<li>App does not redefine the expected function of a system icon (such as the Back button).</li>
+			<li>App does not replace a system icon with a completely different icon if it triggers the standard UI behavior. </li>
+			<li>If the app provides a customized version of a standard system icon, the icon strongly resembles the system icon and triggers the standard system behavior.</li>
+			<li>App does not redefine or misuse Android UI patterns, such that icons or behaviors could be misleading or confusing to users.</li>
+			</ol>
+		</td>
+		<td><a href="#core">CR-all</a></td>
+	</tr>
+
+
+	<tr>
+		<td rowspan="3">Navigation</td>
+		<td id="UX-N1">
+			UX-N1
+		</td>
+
+		<td>
+			<p>App supports standard system <a href="{@docRoot}design/patterns/navigation.html">Back button navigation</a> and does not make use of any custom, on-screen "Back button" prompts.</p>
+		</td>
+		<td><a href="#core">CR-3</a></td>
+	</tr>
+	<tr>
+		<td id="UX-N2">
+			UX-N2 
+		</td>
+		<td>
+			<p>All dialogs are dismissable using the Back button.</p>
+		</td>
+		<td><a href="#core">CR-3</a></td>
+	</tr>
+
+	<tr  id="UX-N3">
+		<td>
+			UX-N3
+		</td>
+		<td>
+			Pressing the Home button at any point navigates to the Home screen of the device. 
+		</td>
+		<td><a href="#core">CR-1</a></td>
+	</tr>
+	<tr  id="UX-S1">
+			<td rowspan="2">Notifications</td>
+		<td>
+			UX-S1
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">Notifications follow Android Design <a href="{@docRoot}design/patterns/notifications.html">guidelines</a>. In particular:</p>
+			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+			<li>Multiple notifications are stacked into a single notification object, where possible.</li>
+			<li>Notifications are persistent only if related to ongoing events (such as music playback or a phone call).</li>
+			<li>Notifications do not contain advertising or content unrelated to the core function of the app, unless the user has opted in.</li>
+			</ol>
+
+		</td>
+		<td><a href="#core">CR-11</a></td>
+	</tr>
+	<tr id="UX-S2">
+
+		<td>
+			UX-S2
+		</td>
+
+		<td>
+		
+			<p style="margin-bottom:.5em;">App uses notifications only to:</p>
+			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+			<li>Indicate a change in context relating to the user personally (such as an incoming message), or</li>
+			<li>Expose information/controls relating to an ongoing event (such as music playback or a phone call).</li>
+			</ol>
+		</td>
+		<td><a href="#core">CR-11</a></td>
+	</tr>
+
+	</table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}design/index.html">Android Design</a></strong> &mdash; Overview of design and user experience best practices for Android apps. </li>
+<li><strong><a href="{@docRoot}design/patterns/navigation.html">Navigation with Back and Up</a></strong> &mdash; Android Design document describing standard navigation patterns. </li>
+<li><strong><a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a></strong> &mdash; Android Design document describing how to use the Action Bar. </li>
+<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> &mdash;  Android Design describing how to use various types of icons.</li>
+<li><strong><a href="{@docRoot}design/patterns/notifications.html">Notifications</a></strong> &mdash;  Android Design document describing how to design and use notifications. </li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="fn">Functionality</h2>
+
+<p>These criteria ensure that your app provides expected functional behavior with the appropriate level of permissions. </p>
+
+<table>
+	<tr>
+		<th style="width:2px;">
+			Area
+		</th>
+		<th style="width:54px;">
+			ID
+		</th>
+		
+
+		<th>
+			Description
+		</th>
+		<th style="width:54px;">
+			Tests
+		</th>
+	</tr>
+
+	<tr id="FN-P1">
+	<td rowspan="2">Permissions</td>
+		<td>
+		FN-P1
+		</td>                                                                                                                                                                      
+		<td>App requests only the <em>absolute minimum</em> permissions that it needs to support core functionality.
+		</td>
+		<td rowspan="2"><a href="#core">CR-11</a></td>
+	</tr>
+	<tr id="FN-P2">
+		<td>
+			FN-P2
+		</td>                                                                                                                                                                      
+		<td><p style="margin-bottom:.5em;">App does not request permissions to access sensitive data (such as Contacts or the System Log) or services that can cost the user money (such as the Dialer or SMS), unless related to a core capability of the app.
+		</td>
+	</tr>
+	<tr id="FN-L1">
+		<td>Install location</td>
+		<td>
+			FN-L1
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App functions normally when installed on SD card (if supported by app).</p>
+			
+			<p style="margin-bottom:.25em;">Supporting installation to SD card is recommended for most large apps (10MB+). See the <a href="{@docRoot}guide/topics/data/install-location.html">App Install Location</a> developer guide for information about which types of apps should support installation to SD card.</p>
+			</td>
+			
+			<td><a href="#SD-1">SD-1</a>
+			</td>
+	</tr>
+	<tr id="FN-A1">
+	<td rowspan="4">Audio</td>
+		<td>
+			FN-A1
+		</td>
+
+		<td>
+			Audio does not play when the screen is off, unless this is a core feature (for example, the app is a music player).
+		</td>
+		<td><a href="#core">CR-7</a></td>
+	</tr>
+	<tr id="FN-A2">
+		<td>
+			FN-A2
+		</td>
+		<td>
+			Audio does not <a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">play behind the lock screen</a>, unless this is a core feature.
+		</td>
+		<td><a href="#core">CR-8</a></td>
+	</tr>
+	<tr id="FN-A3">
+		<td>
+			FN-A3
+		</td>
+		<td>
+			Audio does not play on the home screen or over another app, unless this is a core feature.
+		</td>
+		<td><a href="#core">CR-1, <br />CR-2</a></td>
+	</tr>
+	<tr id="FN-A4">
+		<td>
+			FN-A4
+		</td>
+		<td>
+			Audio resumes when the app returns to the foreground, or indicates to the user that playback is in a paused state.
+		</td>
+		<td><a href="#core">CR-1, CR-8</a></td>
+	</tr>
+	<tr id="FN-U1">
+	<td rowspan="3">UI and Graphics</td>
+		<td>
+			FN-U1
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App supports both landscape and portrait orientations (if possible).</em></p>
+			<p style="margin-bottom:.25em;">Orientations expose largely the same features and actions and preserve functional parity.
+			Minor changes in content or views are acceptable.</p>
+		</td>
+		<td><a href="#core">CR-5</a></td>
+	</tr>
+	<tr id="FN-U2">
+		<td>
+			FN-U2
+		</td>
+		<td>
+		<p style="margin-bottom:.5em;">App uses the whole screen in both orientations and does not letterbox to account for orientation changes.</em></p>
+		<p style="margin-bottom:.25em;">Minor letterboxing to compensate for small variations in screen geometry is acceptable.</p>
+		</td>
+		<td><a href="#core">CR-5</a></td>
+	</tr>
+	<tr id="FN-U3">
+		<td>
+			FN-U3
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App correctly handles rapid transitions between display orientations without rendering problems.</p>
+		</td>
+		<td><a href="#core">CR-5</a></td>
+	</tr>
+	
+	<tr  id="FN-S1">
+		<td rowspan="2">User/app state</td>
+		<td>
+			FN-S1
+		</td>
+		<td>
+		<p style="margin-bottom:.5em;">App should not leave any services running when the app is in the background, unless related to a core capability of the app.</p>
+		<p style="margin-bottom:.25em;">For example, the app should not leave services running to maintain a network connection for notifications, to maintain a Bluetooth connection, or to keep the GPS powered-on.</p>
+		</td>
+		<td><a href="#core">CR-6</a></td>
+	</tr>
+	<tr  id="FN-S2">
+		<td>
+			FN-S2
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App correctly preserves and restores user or app state.</p>
+			<p style="margin-bottom:.25em;">App preserves user or app state when leaving the foreground and prevents accidental data loss due to back-navigation and other state changes. When returning to the foreground, the app must restore the preserved state and any significant stateful transaction that was pending, such as changes to editable fields, game progress, menus, videos, and other sections of the app or game.</p>
+			<ol style="margin-bottom:.25em;list-style-type:lower-alpha">
+			<li>When the app is resumed from the Recents app switcher, the app returns the user to the exact state in which it was last used.</li>
+			<li>When the app is resumed after the device wakes from sleep (locked) state, the app returns the user to the exact state in which it was last used.</li>
+			<li>When the app is relaunched from Home or All Apps, the app restores the app state as closely as possible to the previous state.</li>
+			<li>On Back keypresses, the app gives the user the option of saving any app or user state that would otherwise be lost on back-navigation.</li>
+			</ol>
+		</td>
+		<td><a href="#core">CR-1, CR-3, CR-5</a></td>
+	</tr>
+	
+</table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">Making Android Apps that Play Nice</a></strong> &mdash; Developer blog post discussing the audio lifecycle and expected audio behaviors for Android apps. </li>
+<li><strong><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></strong> &mdash; Developer guide describing how to implement back-navigation.</li>
+<li><strong><a href="{@docRoot}training/basics/activity-lifecycle/recreating.html">Recreating an Activity</a></strong> &mdash; Android Training class the shows how to preserve and restore app state.</li>
+
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="ps">Performance and Stability</h2>
+
+<p>To ensure a high user rating, your app needs to perform well and stay
+responsive on all of the devices and form factors and screens that it is
+targeting. These criteria ensure that the app provides the basic performance,
+stability, and responsiveness expected by users.</p>
+
+<table>
+	<tr>
+		<th style="width:2px;">
+			Area
+		</th>
+		<th style="width:54px;">
+			ID
+		</th>
+		<th>
+			Description
+		</th>
+		<th style="width:54px;">
+			Tests
+		</th>
+	</tr>
+	<tr  id="PS-S1">
+		<td>Stability</td>
+		<td>
+			PS-S1
+		</td>
+		<td>
+			App does not crash, force close, freeze, or otherwise function abnormally on any targeted device.
+		</td>
+		<td><a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a></td>
+	</tr>
+	
+	<tr id="PS-P1">
+	<td rowspan="2">Performance</td>
+		<td>
+			PS-P1
+		</td>
+		<td>
+			App loads quickly or provides onscreen feedback to the user (a progress indicator or similar cue) if the app
+			takes longer than two seconds to load.
+		</td>
+		<td>
+		    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
+		</td>
+	</tr>
+	<tr id="PS-P2">
+
+		<td>
+			PS-P2
+		</td>
+		<td>
+			With StrictMode enabled (see <a href="#strictmode">StrictMode Testing</a>, below), no red flashes (performance warnings from StrictMode) are visible when exercising the app, including
+			during game play, animations and UI transitions, and any other part of the app.
+		</td>
+		<td>
+		    <a href="#PM-1">PM-1</a>
+		</td>
+	</tr>
+	<tr id="PS-M1">
+		<td>Media</td>
+		<td>
+			PS-M1
+		</td>
+		<td>
+			Music and video playback is smooth, without crackle, stutter, or other artifacts, during normal app usage and load.
+		</td>
+		<td>
+		    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a>
+		</td>
+	</tr>
+	<tr id="PS-V1">
+		<td rowspan="2">Visual quality</td>
+	<td>
+			PS-V1
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.</p>
+			
+			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+			<li>App provides high-quality graphics for all targeted screen sizes and form factors, including for <a href="{@docRoot}distribute/googleplay/quality/tablet.html">larger-screen devices such as tablets</a>.</li>
+			<li>No aliasing at the edges of menus, buttons, and other UI elements is visible.</li>
+			</ol>
+		</td>
+		<td rowspan="2"><a href="#core">CR-all</a></td>
+	</tr>
+	<tr id="PS-V2">
+		<td>
+			PS-V2
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App displays text and text blocks in an acceptable manner. </p>
+			
+		 <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+			<li>Composition is acceptable in all supported form factors, including for larger-screen devices such as tablets.</li>
+			<li>No cut-off letters or words are visible.</li>
+			<li>No improper word wraps within buttons or icons are visible.</li>
+			<li>Sufficient spacing between text and surrounding elements.</li>
+			</ol>
+		</td>
+
+	</tr>
+</table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html">Using StrictMode</a></strong> &mdash; Developer blog post discussing StrictMode and how to use it for performance monitoring in your app. </li>
+<li><strong><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a></strong> &mdash; Developer guide describing best practices for keeping your app responsive.</li>
+<li><strong><a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">Multithreading for Performance</a></strong> &mdash; Developer blog post discussing ways to improve performance through multi-threading.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="listing">Google Play</h2>
+
+<p>To launch your app successfully on Google Play, raise its ratings, and make
+sure that it is ready for promotional activities in the store, follow the
+criteria below.</p>
+
+<table>
+	<tr>
+		<th style="width:2px;">
+			Area
+		</th>
+		<th style="width:54px;">
+			ID
+		</th>
+		<th>
+			Description
+		</th>
+		<th style="width:54px;">
+			Tests
+		</th>
+	</tr>
+	<tr id="GP-P1">
+	<td rowspan="2">Policies</td>
+		<td>
+			GP-P1
+		</td>
+		<td>
+			App strictly adheres to the terms of the <a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Content Policy</a> and does not offer inappropriate content, does not use intellectual property or brand of others, and so on.
+		</td>
+		<td>
+		<a href="#gp">GP-all</a>
+		</td>
+	</tr>
+	
+	<tr id="GP-P2">
+		<td>
+			GP-P2
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App maturity level is set appropriately, based on the 
+			<a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Content Rating Guidelines</a>.</p>
+			
+			<p style="margin-bottom:.25em;">Especially, note that apps that request permission to use the device location cannot be given the maturity level "Everyone". </p>
+		</td>
+			<td>
+		<a href="#gp">GP-1</a>
+		</td>
+	</tr>
+
+	<tr id="GP-D1">
+	<td rowspan="3">App&nbsp;Details Page</td>
+		<td>
+			GP-D1
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">App feature graphic follows the guidelines outlined in this
+			<a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">blog post</a>. Make sure that:</p>
+			
+			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+				<li>The app listing includes a high-quality feature graphic.</li>
+				<li>The feature graphic does not contain device images, screenshots, or small text that will be illegible when scaled down and displayed on the smallest screen size that your app is targeting.</li>
+			    <li>The feature graphic does not resemble an advertisement.</li>
+			</ol>
+			
+		
+		</td>
+		
+				<td>
+		<a href="#gp">GP-1, GP-2</a>
+		</td>
+	</tr>
+	<tr id="GP-D2">
+		<td>
+			GP-D2
+		</td>
+		<td>
+			App screenshots and videos do not show or reference non-Android devices. 
+		</td>
+		<td rowspan="2"><a href="#gp">GP-1</a></td>
+	</tr>
+	<tr id="GP-D3">
+		<td>
+			GP-D3
+		</td>
+		<td>
+			App screenshots or videos do not 
+			represent the content and experience of your app in a misleading way.
+		</td>
+	</tr>
+	<tr id="GP-X1">
+		<td>User Support</td>
+		<td>
+			GP-X1
+		</td>
+		<td>Common user-reported bugs in the Reviews tab of the Google Play page are addressed if they are
+			reproducible and occur on many different devices. If a bug occurs on only a few devices,
+			you should still address it if those devices are particularly popular or new.
+		</td>
+		
+				<td>
+		<a href="#gp">GP-1</a>
+		</td>
+		
+	</tr>
+</table>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="https://play.google.com/apps/publish/">Publishing Checklist</a></strong> &mdash; Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
+<li><strong><a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Program Policies</a></strong> — Guidelines for what is acceptable conent in Google Play. Please read and understand the and understand the policies before publishing.</p>
+<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=188189">Rating your application content for Google Play</a></strong> — Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
+<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=1078870">Graphic Assets for your Application
+</a></strong> — Details about the graphic assets you need to upload before publishing.</li>
+<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
+</a></strong> — Blog post discussing how to create an attractive, effective Featured Image for your app.</li>
+<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=113477&amp;topic=2364761&amp;ctx=topic">Supporting your users
+</a></strong> — Help Center document describing options for supporting users.</li>
+</ul>
+</td></tr>
+</table>
+
+
+<h2 id="test-environment">Setting Up a Test Environment</h2>
+
+<p>To assess the quality of your app, you need to set up a suitable
+hardware or emulator environment for testing. </p>
+
+<p>The ideal test environment would
+include a small number of actual hardware devices that represent key form
+factors and hardware/software combinations currently available to consumers.
+It's not necessary to test on <em>every</em> device that's on the market &mdash;
+rather, you should focus on a small number of representative devices, even using
+one or two devices per form factor. </p>
+
+<p>If you are not able to obtain actual hardware devices for testing, you should
+set up emulated devices (AVDs) to represent the most common form factors and
+hardware/software combinations. </p>
+
+<p>To go beyond basic testing, you can add more devices, more form factors, or
+new hardware/software combinations to your test environment. You can also
+increase the number or complexity of tests and quality criteria. </p>
+
+
+<h2 id="tests">
+  Test Procedures
+</h2>
+
+<p>These test procedures help you discover various types of quality issues in
+your app. You can combine the tests or integrate groups of tests together in
+your own test plans. See the sections above for references that associate
+specific criteria with specific tests. </p>
+
+<table>
+	<tr>
+		<th style="width:2px;">
+			Type
+		</th>
+		<th style="width:54px;">
+			Test
+		</th>
+		<th>
+			Description
+		</th>
+	</tr>
+	<tr>
+		<td rowspan="12" id="core">Core Suite</td>
+		<td>
+			CR-0
+		</td>
+		<td><p style="margin-bottom:.5em;">Navigate to all parts of the app &mdash; all screens, dialogs, settings, and all user flows. </p>
+		
+		<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+		<li>If the application allows for editing or content creation, game play, or media playback, make sure to enter those flows to create or modify content.</li>
+		<li>While exercising the app, introduce transient changes in network connectivity, battery function, GPS or location availability, system load, and so on. </li>
+			</ol>
+		</td>
+	</tr>
+	<tr id="tg2">
+		<td id="core">
+			CR-1
+		</td>
+		<td>From each app screen, press the device's Home key, then re-launch the app from the All Apps screen.
+		</td>
+	</tr>
+	<tr id="CR-2">
+		<td>
+			CR-2
+		</td>
+		<td>From each app screen, switch to another running app and then return to the app under test using the Recents app switcher.
+		</td>
+	</tr>
+
+	<tr id="CR-3">
+		<td>
+			CR-3
+		</td>
+		<td>From each app screen (and dialogs), press the Back button. 
+		</td>
+	</tr>
+		<tr id="CR-5">
+		<td>
+			CR-5
+		</td>
+		<td>From each app screen, rotate the device between landscape and portrait orientation at least three times.
+		</td>
+	</tr>
+	<tr id="CR-6">
+		<td>
+			CR-6
+		</td>
+		<td>Switch to another app to send the test app into the background. Go to Settings and check whether the test app has any services running while in the background. In Android 4.0 and higher, go to the Apps screen and find the app in the "Running" tab. In earlier versions, use "Manage Applications" to check for running services.
+		</td>
+	</tr>
+
+	
+	<tr  id="CR-7">
+		<td>
+			CR-7
+		</td>
+		<td>
+			Press the power button to put the device to sleep, then press the power button again to
+			awaken the screen.
+		</td>
+	</tr>
+	<tr id="CR-8">
+		<td>
+			CR-8
+		</td>
+		<td>
+			Set the device to lock when the power button is pressed. Press the power button to put the device to sleep, then press the power button again to
+			awaken the screen, then unlock the device.
+		</td>
+	</tr>
+	<tr id="CR-9">
+		<!-- Hardware features -->
+		<td>
+			CR-9
+		</td>
+		<td>
+			For devices that have slide-out keyboards, slide the keyboard in and out at least once.  For devices that have keyboard docks, attach the device to the keyboard dock.
+		</td>
+	</tr>
+	<tr id="CR-10">
+		<td>
+			CR-10
+		</td>
+		<td>
+			For devices that have an external display port, plug-in the external display.
+		</td>
+	</tr>
+	<tr id="CR-11">
+		<td>
+			CR-11
+		</td>
+		<td>Trigger and observe in the notications drawer all types of notifications that the app can display. Expand notifications where applicable (Android 4.1 and higher), and tap all actions offered.</td>
+	</tr>
+	<tr id="CR-12">
+		<td>
+			CR-12
+		</td>
+		<td>Examine the permissions requested by the app by going to Settings &gt; App Info.
+		</td>
+	</tr>
+	<tr id="tg3">
+	<td>Install on SD Card</td>
+		<td>
+			SD-1
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with app installed to <a href="{@docRoot}guide/topics/data/install-location.html">device SD card</a> (if supported by app).</p>
+			
+			<p style="margin-bottom:.25em;">To move the app to SD card, you can use Settings &gt; App Info &gt; Move to SD Card.</p>
+		</td>
+	</tr>
+	<tr id="tg3">
+			<td>Hardware acceleration</td>
+		<td>
+			HA-1
+		</td>
+		<td>
+			<p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with hardware acceleration enabled.</p>
+			
+			<p style="margin-bottom:.25em;">To force-enable hardware acceleration (where supported by device), add <code>hardware-accelerated="true"</code> to the <code>&lt;application&gt;</code> in the app manifest and recompile.</p>
+		</td>
+	</tr>
+	<tr id="tg3">
+			<td>Performance Monitoring</td>
+		<td>
+			PM-1
+		</td>
+		<td>
+		 <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href="#strictmode">as described below</a>. <p style="margin-bottom:.25em;">Pay close attention to garbage collection and its impact on the user experience.</p>
+		</td>
+	</tr>
+	<tr  id="gp">
+		<td rowspan="3">Google Play</td>
+		<td>
+			GP-1
+		</td>
+		<td>
+			Sign into the <a href="https://play.google.com/apps/publish/">Developer Console</a> to review your developer profile, app description, screenshots, feature graphic, maturity settings, and user feedback. 
+		</td>
+	</tr>
+	<tr  id="GP-2">
+		<td>
+			GP-2
+		</td>
+		<td>
+			Download your feature graphic and screenshots and scale them down to match the display sizes on the devices and form factors you are targeting.
+		</td>
+	</tr>
+	<tr  id="GP-3">
+		<td>
+			GP-3
+		</td>
+		<td>
+			Review all graphical assets, media, text, code libraries, and other content packaged in the app or expansion file download.
+		</td>
+	</tr>
+	<tr  id="GP-4">
+	<td>Payments</td>
+		<td>
+			GP-4
+		</td>
+		<td>
+			Navigate to all screens of your app and enter all in-app purchase flows.
+		</td>
+</tr>
+
+</table>
+
+<h3 id="strictmode">
+Testing with StrictMode
+</h3>
+
+<p>For performance testing, we recommend enabling 
+{@link android.os.StrictMode} in your app
+and using it to catch operations on the main thread and other threads that could
+affect performance, network accesses, file reads/writes, and so on.</p>
+
+<p>You can set up a monitoring policy per thread using 
+{@link android.os.StrictMode.ThreadPolicy.Builder} and enable all supported monitoring in the
+<code>ThreadPolicy</code> using 
+{@link android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.</p>
+
+<p>Make sure to enable <strong>visual notification</strong> of policy violations
+for the <code>ThreadPolicy</code> using {@link android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen() penaltyFlashScreen()}.</p>
diff --git a/docs/html/distribute/googleplay/quality/index.jd b/docs/html/distribute/googleplay/quality/index.jd
new file mode 100644
index 0000000..ef537b1
--- /dev/null
+++ b/docs/html/distribute/googleplay/quality/index.jd
@@ -0,0 +1,45 @@
+page.title=App Quality
+@jd:body
+
+<p>App quality directly influences the long-term success of your app&mdash;in
+terms of installs, user rating and reviews, engagement, and user retention.
+Android users expect high-quality apps, even more so if they've spent money on
+them. At the same time, users enjoy and value apps that put a priority on
+continuous improvement. </p>
+
+<p>Before you publish an app on Google Play, it's important to make sure that
+your app meets the basic quality expectations of users, across all of the form
+factors and device types that the app is targeting. The documents in this
+section help you assess your app's fundamental quality and address any
+issues that you find. </p>
+
+<div class="vspace size-1">
+  &nbsp;
+</div>
+<div class="layout-content-row">
+  <div class="layout-content-col span-4">
+    <h4>
+      Core App Quality
+    </h4>
+    <p>
+      A set of core quality criteria that all Android apps should meet on all targeted devices.
+    </p><a href="{@docRoot}distribute/googleplay/quality/core.html">Learn more »</a>
+  </div>
+  <div class="layout-content-col span-4">
+    <h4>
+      Tablet App Quality
+    </h4>
+    <p>
+      A set recommendations for delivering the best possible experience to tablet users.
+    </p><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Learn more »</a>
+  </div>
+  <div class="layout-content-col span-4">
+    <h4>
+      Improving App Quality
+    </h4>
+    <p>
+      Tips on continuously improving your app's quality, ratings, reviews, downloads, and engagement.
+    </p><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Learn more
+    »</a>
+  </div>
+</div>
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
new file mode 100644
index 0000000..f180f54
--- /dev/null
+++ b/docs/html/distribute/googleplay/quality/tablet.jd
@@ -0,0 +1,568 @@
+page.title=Tablet App Quality Checklist
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Checklist</h2>
+<ol>
+
+<li><a href="#core-app-quality">1. Test for Core App Quality</a></li>
+<li><a href="#optimize-layouts">2. Optimize your layouts</a></li>
+<li><a href="#use-extra-space">3. Use the extra screen area</a></li>
+<li><a href="#use-tablet-icons">4. Use assets designed for tablets</a></li>
+<li><a href="#adjust-font-sizes">5. Adjust fonts and touch targets</a></li>
+<li><a href="#adjust-widgets">6. Adjust homescreen widgets</a></li>
+<li><a href="#offer-full-feature-set">7. Offer the app's full feature set</a></li>
+<li><a href="#hardware-requirements">8. Don’t require hardware features</a></li>
+<li><a href="#support-screens">9. Declare tablet screen support</a></li>
+<li><a href="#google-play">10. Follow best practices for publishing in Google Play</a></li>
+
+</ol>
+<h2>Testing</h2>
+<ol>
+<li><a href="#test-environment">Setting Up a Test Environment</a></li>
+</ol>
+</div></div>
+
+
+<p>Before you publish an app on Google Play, it's important to make sure that
+the app meets the basic expectations of tablet users through compelling features
+and an intuitive, well-designed UI. </p>
+
+<p>Tablets are a growing part of the Android installed base that offers new
+opportunities for <a
+href="{@docRoot}distribute/googleplay/spotlight/tablets.html">user engagement
+and monetization</a>. If your app is targeting tablet users, this document helps
+you focus on key aspects of quality, feature set, and UI that can have a
+significant impact on the app's success. Each focus area is given as checklist
+item, with each one comprising several smaller tasks or best practices.</p>
+
+<p>Although the checklist tasks below are numbered for convenience, 
+you can handle them in any order and address them to the extent that you feel
+is right for your app. In the interest of delivering the best possible product
+to your customers, follow the checklist recommendations
+to the greatest extent possible. </p>
+
+<p>As you move through the checklist, you'll find links to support resources
+that can help you address the topics raised in each task.</p>
+
+
+<h2 id="core-app-quality">1. Test for Core App Quality</h2>
+
+<p>The first step in delivering a great tablet app experience is making sure
+that it meets the <em>core app
+quality criteria</em> for all of the devices and form factors that the app is
+targeting. For complete information, see the <a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Checklist</a>. 
+</p>
+
+<p>To assess the quality of your app on tablets &mdash; both for core app quality
+and tablet app quality &mdash; you need to set up a suitable
+hardware or emulator environment for testing. For more information, 
+see <a href="#test-environment">Setting Up a Test Environment</a>.</p>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a
+href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
+Guidelines</a></strong> &mdash; A set of core quality criteria that all Android
+apps should meet on all targeted devices.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="optimize-layouts">2. Optimize your layouts for larger screens</h2>
+
+<p>Android makes it easy to develop an app that runs well on a wide range of
+device screen sizes and form factors. This broad compatibility works in your
+favor, since it helps you design a single app that you can distribute widely to
+all of your targeted devices. However, to give your users the best possible
+experience on each screen configuration &mdash; in particular on tablets
+&mdash; you need to optimize your layouts and other UI components for each
+targeted screen configuration. On tablets, optimizing your UI lets you take
+full advantage of the additional screen available, such as to offer new features,
+present new content, or enhance the experience in other ways to deepen user
+engagement.</p>
+
+<p>If you developed your app for handsets and now want to distribute it to
+tablets, you can start by making minor adjustments to your layouts, fonts, and
+spacing. In some cases &mdash; such as for 7-inch tablets or for a game with
+large canvas &mdash; these adjustments may be all
+you need to make your app look great. In other cases, such as for larger
+tablets, you can redesign parts of your UI to replace "stretched UI" with an
+efficient multipane UI, easier navigation, and additional content. </p>
+
+<p>Here are some suggestions:</p>
+
+<div style="width:390px;float:right;margin:1.5em;margin-top:0em;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png" style="width:390px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:0em .5em .5em 2em"><span
+style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane layouts lead to awkward whitespace and excessive line lengths. Use padding to reduce the width of UI elements and consider using multi-pane layouts.</p>
+</div>
+
+<ul>
+<li>Provide custom layouts as needed for <code>large</code> and
+<code>xlarge</code> screens. You can also provide layouts that are loaded based
+on the screen's <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
+dimension</a> or the <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
+available width and height</a>. </li>
+<li>At a minimum, customize dimensions such as font sizes, margins, spacing for
+larger screens, to improve use of space and content legibility. </li>
+<li>Adjust positioning of UI controls so that they are easily accessible to
+users when holding a tablet, such as toward the sides when in
+landscape orientation.</li>
+<li>Padding of UI elements should normally be larger on tablets than on handsets. A
+<a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">48dp rhythm</a> (and a 16dp
+grid) is recommended.</li>
+<li>Adequately pad text content so that it is not aligned directly along screen edges.
+Use a minimum <code>16dp</code> padding around content near screen edges.</li>
+</ul>
+
+<p>In particular, make sure that your layouts do not appear "stretched"
+across the screen:</p>
+
+<ul>
+<li>Lines of text should not be excessively long &mdash; optimize for a maximum
+100 characters per line, with best results between 50 and 75.</li>
+<li>ListViews and menus should not use the full screen width.</li>
+<li>Use padding to manage the widths of onscreen elements or switch to a
+multi-pane UI for tablets (see next section).</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
+</a></strong> &mdash; Android Design document that explains ....</li>
+<li><strong><a href="http://developer.android.com/design/style/devices-displays.html">Devices and Displays
+</a></strong> &mdash; Android Design document that explains ....</li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
+<li><strong><a href="http://developer.android.com/guide/practices/screens_support.html#ConfigurationExamples">Configuration examples
+</a></strong> &mdash; Examples of how to declare layouts and other resources for specific screen sizes.</a></li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="use-extra-space">3. Take advantage of extra screen area available on tablets</h2>
+
+<div style="width:290px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png" style="width:280px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:0em .5em .5em 1.5em"><span
+style="font-weight:500;">Multi-pane layouts</span> result in a better visual balance on tablet screens, while offering more utility and legibility.</p>
+</div>
+
+<p>Tablet screens provide significantly more screen real estate to your app,
+especially when in landscape orientation. In particular, 10-inch tablets offer a
+greatly expanded  area, but even 7-inch tablets give you more space for
+displaying content and engaging users. </p>
+
+<p>As you consider the UI of your app when running on tablets, make sure that it
+is taking full advantage of extra screen area available on tablets. Here are
+some suggestions:</p>
+
+<ul>
+<li>Look for opportunities to include additional content or use an alternative
+treatment of existing content.</li>
+<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
+layouts</a> on tablet screens to combine single views into a compound view. This
+lets you use the additional screen area more efficiently and makes it easier for
+users to navigate your app. </li>
+<li>Plan how you want the panels of your compound views to reorganize when
+screen orientation changes.</li>
+
+
+
+<div style="width:490px;margin:1.5em auto 1.5em 0;">
+
+<div style="">
+<img src="{@docRoot}images/ui-ex-single-panes.png" style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
+<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:.5em"><span
+style="font-weight:500;">Compound views</span> combine several single views from a handset UI <em>(above)</em> into a richer, more efficient UI for tablets <em>(below)</em>. </p>
+</div>
+</div>
+
+<li>While a single screen is implemented as an {@link android.app.Activity}
+subclass, consider implementing individual content panels as {@link
+android.app.Fragment} subclasses. This lets you maximize code reuse across
+different form factors and across screens that share content.</li>
+<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
+different layouts in the appropriate screen size buckets (such as
+<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
+<code>sw600dp</code>/<code>sw720</code>).</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a></strong> &mdash; Android Design guide for using multi-pane UI, including examples of how to flatten navigation and integrate more content into your tablet UI.</li>
+<li><strong><a href="{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple Touchscreen Sizes</a></strong> &mdash; Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
+<li><strong><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></strong> &mdash; Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="use-tablet-icons">4. Use Icons and other assets that are designed for tablet screens</h2>
+
+<p>So that your app looks its best, make sure to use icons and other bitmap
+assets that are created specifically for the densities used by tablet screens.
+Specifically, you should create sets of alternative bitmap drawables for each
+density in the range commonly supported by tablets.</p>
+
+<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
+<tr>
+<th>Density </th>
+<th colspa>Launcher</th>
+<th>Action Bar</th>
+<th>Small/Contextual</th>
+<th>Notification</th>
+</tr>
+<tr>
+<td><code>mdpi</code></td>
+<td>48x48px</td>
+<td>32x32px</td>
+<td>16x16px</td>
+<td>24x24px</td>
+</tr>
+<tr>
+<td><code>hdpi</code></td>
+<td>72x72px</td>
+<td>48x48px</td>
+<td>24x24px</td>
+<td>36x36px</td>
+</tr>
+<tr>
+<td><code>tvdpi</code></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+</tr>
+<tr>
+<td><code>xhdpi</code></td>
+<td>96x96px</td>
+<td>64x64px</td>
+<td>32x32px</td>
+<td>48x48px</td>
+</tr>
+
+</table>
+
+<p>Other points to consider: </p>
+
+<ul>
+<li>Icons in the action bar, notifications, and launcher should be designed
+according to the icon design guidelines and have the same physical size on
+tablets as on phones.</li>
+<li>Use density-specific <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+resource qualifiers</a> to ensure that the proper set of alternative resources
+gets loaded.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> &mdash; Android Design document that shows how to use various types of icons.</li>
+<li><strong><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></strong> &mdash; Developer documentation on how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; API Guide documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
+<li><strong><a href="{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different Screens</a></strong> &mdash; Android Training class that takes you through the process of optimizing the user experience for different screen sizes and densities.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="adjust-font-sizes">5. Adjust font sizes and touch targets for tablet screens</h2>
+
+<p>To make sure your app is easy to use on tablets, take some time to adjust the
+font sizes and touch targets in your tablet UI, for all of the screen
+configurations you are targeting. You can adjust font sizes through <a
+href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
+href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
+resources</a>, and you can adjust touch targets through layouts and bitmap
+drawables, as discussed above. </p>
+
+<p>Here are some considerations:</p>
+<ul>
+<li>Text should not be excessively large or small on tablet screen sizes and
+densities. Make sure that labels are sized appropriately for the UI elements they
+correspond to, and ensure that there are no improper line breaks in labels,
+titles, and other elements.</li>
+<li>The recommended touch-target size for onscreen elements is 48dp (32dp
+minimum) &mdash; some adjustments may be needed in your tablet UI. Read <a
+href="http://developer.android.com/design/style/metrics-grids.html">Metrics and
+Grids
+</a> to learn about implementation strategies to help most of your users. To
+meet the accessibility needs of certain users, it may be appropriate to use
+larger touch targets. </li>
+<li>When possible, for smaller icons, expand the touchable area to more than
+48dp using {@link android.view.TouchDelegate} or just centering the icon within
+the transparent button.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
+</a></strong> &mdash; Android Design document that explains how to arrange and size touch targets and other UI elements on the screen.</li>
+<li><strong><a href="{@docRoot}design/style/typography.html">Typography</a></strong> &mdash; Android Design document that gives an overview of how to use typography in your apps. </li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
+<li><strong><a href="{@docRoot}training/multiscreen/screendensities.html">Supporting Different Densities</a></strong> &mdash; Android Training class that shows you how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="adjust-widgets">6. Adjust sizes of home screen widgets for tablet screens</h2>
+
+<p>If your app includes a home screen widget, here are a few points to consider
+to ensure a great user experience on tablet screens: </p>
+
+<ul>
+<li>Make sure that the widget's default height and width are set appropriately
+for tablet screens, as well as the minimum and maximum resize height and width.
+</li>
+<li>The widget should be resizable to 420dp or more, to span 5 or more home
+screen rows (if this is a vertical or square widget) or columns (if this is a
+horizontal or square widget). </li>
+<li>Make sure that 9-patch images render correctly.</li>
+<li>Use default system margins.</li>
+<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
+possible.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the AppWidgetProviderInfo Metadata
+</a></strong> &mdash; API Guide that explains how to set the height and width dimensions of a widget.</li>
+<li><strong><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design Guidelines</a></strong> &mdash; API Guide that provides best practices and techniques for designing and managing the size of widgets.  </li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="offer-full-feature-set">7. Offer the app's full feature set to tablet users</h2>
+
+<p>Let your tablet users experience the best features of your app. Here are
+some recommendations:</p>
+
+<ul>
+<li>Design your app to offer at least the same set of features on tablets as it does on
+handsets. </li>
+<li>In exceptional cases, your app might omit or replace certain features on
+tablets if they are not supported by the hardware or use-case of most tablets.
+For example:
+<ul>
+<li>If the handset uses telephony features but telephony is not available on the
+current tablet, you can omit or replace the related functionality.</li>
+<li>Many tablets have a GPS sensor, but most users would not normally carry
+their tablets while running. If your phone app provides functionality to let the
+user record a GPS track of their runs while carrying their phones, the app would not need to
+provide that functionality on tablets because the use-case is not
+compelling.</li>
+</ul>
+</li>
+<li>If you will omit a feature or capability from your tablet UI, make sure
+that it is not accessible to users or that it offers “graceful degradation”
+to a replacement feature (also see the section below on hardware features).</li>
+</ul>
+
+
+<h2 id="hardware-requirements">8. Don’t require hardware features that might not be available on tablets</h2>
+
+<p>Handsets and tablets typically offer slightly different hardware support for
+sensors, camera, telephony, and other features. For example, many tablets are
+available in a "Wi-Fi" configuration that does not include telephony support.</p>
+
+<p>To ensure that you can deliver a single APK broadly across the
+your full customer base, make sure that your app does not have built-in
+requirements for hardware features that aren't commonly available on tablets.
+</p>
+
+<ul>
+<li>Your app's manifest should not include <a
+href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
+elements for hardware features or capabilities that might not be
+available on tablets, except when they are declared with the
+<code>android:required=”false”</code> attribute. For example, your app should
+not <em>require</em> features such as:
+<ul>
+<li><code>android.hardware.telephony</code></li>
+<li><code>android.hardware.camera</code> (refers to back camera), or</li>
+<li><code>android.hardware.camera.front</code></li>
+</ul>
+</li>
+<li>Similarly, your app manifest should not include any <a
+href="{@docRoot}guide/topics/manifest/permission-element.html"><code>&lt;permission&gt;</code></a> elements that <a
+href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">imply
+feature requirements</a> that might not be appropriate for tablets, except when
+accompanied by a corresponding <code>&lt;uses-feature&gt;</code> element
+declared with the <code>android:required=”false”</code> attribute.</li>
+</ul>
+
+<p>In all cases, the app must function normally when the hardware features it
+uses are not available and should offer “graceful degradation” and alternative
+functionality where appropriate. For example, if GPS is not supported on the device,
+your app could let the user set their location manually. The app should do
+run-time checking for the hardware capability that it needs and handle as needed.</p>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">Permissions that Imply Feature Requirements</a></strong> &mdash; A list of permissions that may cause unwanted filtering if declared in your app's manifest.</li>
+<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a></strong> &mdash; Description and reference documentation for the <code>&lt;uses-feature&gt;</code> manifest element.</li>
+<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing the features required by your application</a></strong> &mdash; Description of how to determine the actual set of hardware and software requirements (explicit or implied) that your app requires.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="support-screens">9. Declare support for tablet screen configurations</h2>
+
+<p>To ensure that you can distribute your app to a broad range of tablets,
+declare all the screen sizes that your app supports in its manifest:</p>
+
+<ul>
+<li>Declare a <a
+href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a> element
+with appropriate attributes, as needed.</li>
+<li>If the app declares a <code>&lt;compatible-screens&gt;</code> element in the
+manifest, the element must include attributes that specify <em>all of the size and
+density combinations for tablet screens</em> that the app supports. Note that, if possible,
+you should avoid using this element in your app.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a></strong>
+&mdash; Description and reference documentation for the <code>&lt;supports-screens&gt;</code>
+manifest element.</li>
+<li><strong><a href="{@docRoot}guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring Screen Size
+Support</a></strong> &mdash; Developer documentation that explains the details of managing UI
+for best display on multiple screen sizes.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="google-play">10. Follow best practices for publishing in Google Play</h2>
+
+<ul>
+<li>Publish your app as a single APK for all screen sizes (handsets
+and tablets), with a single Google Play listing:
+  <ul style="margin-top:.25em;">
+    <li>Easier for users to find your app from search, browsing, or promotions</li>
+    <li>Easier for users to restore your app automatically if they get a new device.</li>
+    <li>Your ratings and download stats are consolidated across all devices.</li>
+    <li>Publishing a tablet app in a second listing can dilute ratings for your brand.</li>
+  </ul>
+</li>
+<li>If necessary, you can alternatively choose to deliver your app using <a 
+href="{@docRoot}guide/google/play/publishing/multiple-apks.html">Multiple APK Support</a>, 
+although in most cases using a single APK to reach all devices is strongly recommended.</li>
+
+<li>Highlight your app’s tablet capabilities in the product details page:
+  <ul style="margin-top:.25em;">
+    <li>Add <strong>at least one screenshot taken while the app is running on a
+    tablet</strong>. It's recommended that you add one screenshot of landscape orientation
+    and one of portrait orientation, if possible. These screenshots make it clear to users
+    that your app is designed for tablets and highlight all the effort you've put into designing
+    a great tablet app experience.</li>
+    <li>Mention tablet support in the app description.</li>
+    <li>Include information about tablet support in the app's release notes and update
+    information.</li>
+    <li>In your app's promo video, add shots of your app running on a tablet.</li>
+  </ul>
+</li>
+<li>Make sure you are distributing to tablet devices. Check the app's Supported Devices
+list in the <a href="https://play.google.com/apps/publish/">Developer Console</a>
+to make sure your app is not filtered from tablet devices that you want to target.</li>
+
+<li>Let tablet users know about your app! Plan a marketing or advertising campaign that
+highlights the use of your app on tablets.</li>
+</ul>
+
+<table>
+<tr>
+<td><p>Related resources:</p>
+<ul style="margin-top:-.5em;">
+<li><strong><a href="https://play.google.com/apps/publish/">Publishing Checklist</a></strong> &mdash; Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
+<li><strong><a href="https://play.google.com/apps/publish/">Google Play Android Developer Console</a></strong> &mdash; The tools console for publishing your app to Android users.</li>
+</ul>
+</td>
+</tr>
+</table>
+
+<h2 id="test-environment">Setting Up a Test Environment for Tablets</h2>
+
+<p>To assess the quality of your app on tablets &mdash; both for core app quality
+and tablet app quality &mdash; you need to set up a suitable
+hardware or emulator environment for testing. </p>
+
+<p>The ideal test environment would
+include a small number of actual hardware devices that represent key form
+factors and hardware/software combinations currently available to consumers.
+It's not necessary to test on <em>every</em> device that's on the market &mdash;
+rather, you should focus on a small number of representative devices, even using
+one or two devices per form factor.  The table below provides an overview of
+devices you could use for testing.</p>
+
+<p>If you are not able to obtain actual hardware devices for testing, you should
+set up emulated devices (AVDs) to represent the most common form factors and
+hardware/software combinations. See the table below for suggestions on the emulator
+configurations to use. </p>
+
+<p>To go beyond basic testing, you can add more devices, more form factors, or
+new hardware/software combinations to your test environment. For example, you
+could include mid-size tablets, tablets with more or fewer hardware/software
+features, and so on. You can also increase the number or complexity of tests
+and quality criteria. </p>
+
+<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
+include one or two devices from each row in the table below, with one of the
+listed chipsets, platform versions, and hardware feature configurations.</p>
+
+<table>
+<tr>
+<th>Type</th>
+<th>Size</th>
+<th>Density</th>
+<th>Version</th>
+<th>AVD Skin</th>
+</tr>
+
+<tr>
+<td>7-inch tablet</td>
+<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
+<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
+<td>Android 4.0+</td>
+<td>WXGA800-7in</td>
+</tr>
+<tr>
+<td><span style="white-space:nowrap">10-inch</span> tablet</td>
+<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
+<td><code>mdpi</code>,<br /><code>hdpi</code></td>
+<td>Android 3.2+</td>
+<td>WXGA800</td>
+</tr>
+</table>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
new file mode 100644
index 0000000..6acd914
--- /dev/null
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -0,0 +1,46 @@
+page.title=Spotlight
+walkthru=0
+header.hide=0
+
+@jd:body
+
+
+<p>Android developers, their apps, and their successes with Android and Google Play. </p>
+
+
+
+<div style="background: #F0F0F0;
+            border-top: 1px solid #DDD;
+            padding: 0px 0 24px 0;
+            overflow: auto;
+            clear:both;
+            margin-bottom:-10px;
+            margin-top:30px;"">
+   <div style="padding:0 0 0 29px;">
+        <h4>Developer Story: Robot Invader</h4>
+          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 17px 20px 9px 0;" src=
+            "//g0.gstatic.com/android/market/com.robotinvader.knightmare/hi-256-0-9e08d83bc8d01649e167131d197ada1cd1783fb0">
+          <div style="width:700px;">
+          <p style="margin-top:26px;margin-bottom:12px;">Robot Invader chose 
+              Android and Google Play as the launch platform for their first game,<br /> 
+              <a data-g-event="Developers Page" data-g-label="Case Study Link" href=
+              "//play.google.com/store/apps/details?id=com.robotinvader.knightmare"><em>Wind-up
+              Knight</em></a>.
+           </p>
+           <p>
+              Hear from the developers how Android helped them reach millions of users 
+              and more than 100 device models with a single app binary, then iterate rapidly to ensure
+              a great user experience.
+           </p>
+           </div>
+           <iframe style="float:left;
+             margin-right:24px;
+             margin-top:14px;" width="700" height="394" src=
+             "http://www.youtube.com/embed/hTtlLiUTowY" frameborder="0" allowfullscreen></iframe>
+   </div> 
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/tablets.jd b/docs/html/distribute/googleplay/spotlight/tablets.jd
new file mode 100644
index 0000000..f968a40
--- /dev/null
+++ b/docs/html/distribute/googleplay/spotlight/tablets.jd
@@ -0,0 +1,283 @@
+page.title=Developer Stories: The Opportunity of Android Tablets
+walkthru=0
+header.hide=0
+
+@jd:body
+
+
+<p>More and more, developers are investing in a full tablet experience
+for their apps and are seeing those investments pay off big. The increased
+screen area on tablets opens up a world of possibilities, allowing for more
+engagement with the user &mdash; which can mean an increase in usage as well as
+more monetization opportunities. And with the growing wave of Android tablets that
+continue to hit the market, it’s an important piece of any developer’s mobile
+offering. </p>
+
+<p>Here are some stories from developers who are seeing real results as they
+expand their offering to include Android tablets.</p>
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Mint: More screen real estate = more engagement</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh5.ggpht.com/0xAIZJ1uE05b4RHNHgBBTIH6nRdPTY660T104xY7O2GbHXwab6YVmpU5yYg8yacfBg=w124">
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+
+    <h5>About the app</h5> 
+    
+    
+    <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.mint">Mint.com Personal Finance</a> by Intuit Inc.</li>
+      <li>Financial management app targeting 7- to 10-inch tablets and phones</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>Able to offer richer UI features</li>
+      <li>Much higher user engagement</li>
+      <li>Longer sessions &mdash; more Android tablet users have sessions longer than 5 minutes</li>
+      </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.mint">
+  <img alt="Android app on Google Play"
+       src="http://developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+</a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">When Intuit was thinking about
+expanding their Mint mobile offering to include a version optimized for Android
+tablets, they knew that taking the layout that worked for phones and simply
+showing an enlarged version wouldn’t take full advantage of the opportunities
+that tablets afford.</p>
+    
+    <p>“We knew we had a lot more real estate, and we wanted to provide a more
+immersive experience for our users” said Ken Sun, Intuit Group Product Manager
+at Mint.</p>
+
+<p>Intuit’s Mint app, which has a 4-star rating on Google Play, brings a number
+of features to Android tablets that aren’t available for phones, including a
+more visual presentation of personal financial data.</p>
+
+<p>“Whereas our app for phones is used throughout the day for quick sessions,
+we’ve seen a larger percentage of our tablet usage happen in the evening, for
+much longer sessions,” said Sun. “People are doing a lot more than just checking
+their spending. They’re looking at historical trends, re-categorizing
+transactions, analyzing the data and setting financial goals for the future
+&mdash; digging much deeper and being more thoughtful. One example is how much
+users are interacting with their own budgets in the tablet app.  Customer budget
+operations (view, edit, drill-down, etc.) are 7x higher on Android tablets than
+they are on phones.”</p>
+
+<p>Fifty percent more Android tablet users have Mint sessions of 5 minutes or
+longer than they do on phones.  “We’ve found that phone usage is indicative of a
+customer’s regular financial check-in, while tablet usage points towards more
+analysis and interaction with that customer’s personal financial data.  This is
+the sort of immersive engagement experience we were looking for; the tablet and
+phone apps serve as great complements to each other."</p>
+  </div>
+
+  <div style="clear:both;margin-top:40px;width:auto;">
+  
+    <a href=""><img src="{@docRoot}images/distribute/mint.png"></a>
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">Making the most of tablet screens</span>: Mint used the extra screen area on tablets to offer quick access to additional tools and information.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin:3em auto"><!-- START STORY -->
+
+
+<h3>TinyCo: Monetization opportunities abound on tablets</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 30px 20px;" src=
+            "https://lh5.ggpht.com/mO1TPos65MWJF_n8ZrXMbNCqIqsvN4dQV_rwNOU3pF6N_Ii3lSiCPe_H_MP8C1MK5UKo=w124">
+
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5> 
+
+    <ul>
+                <li><a href="http://play.google.com/store/apps/details?id=com.tinyco.village">Tiny Village</a> by TinyCo</li>
+            <li>Game targeting 7- to 10-inch tablets and phones</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>35% higher average revenue per paying user (ARPPU)</li>
+      <li>Consistent increase in user retention</li>
+      <li>3x increase in downloads to Android tablets in the last 6 months</li>
+    </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.tinyco.village">
+  <img alt="Android app on Google Play"
+       src="http://developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+</a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">Over a year ago, developer
+TinyCo, makers of games such as Tiny Monsters, switched to a
+simultaneous launch strategy for their products. They chose Android as one of their
+primary launch platforms because of its large installed base and global reach. They
+also knew that the growing base of Android tablet users represented a huge
+opportunity. </p>
+    
+    <p>Tiny Village was their first title to take advantage of the strategy, and
+it proved to be a winning one &mdash; especially in terms of Android
+tablets.</p>
+    
+    <p> “With continued optimization of the gameplay experience and a genuine
+commitment to our Android offering through our Griffin engine, all of our
+metrics started to rise,” said Rajeev Nagpal, Head of Product at TinyCo. In
+fact, they’ve seen Android tablet downloads more than triple in the last six
+months.</p>
+
+    <p>One of the first things they noticed about usage of Tiny Village on
+tablets was an increase in average revenue per paying user (ARPPU)&mdash;about 35%
+higher than on smaller-screen devices such as phones. Additionally, average
+revenue per user ARPU is now about 35% higher as well. “The game is just much
+more immersive on tablet.”</p>
+
+    <p>In addition to an increase in monetization metrics, they’ve also seen a
+consistent increase in retention over other platforms. “These are really
+important metrics for games &mdash; if you can get users to both stay around
+longer and spend more while they’re there, you have a recipe for success.”</p>
+  </div>
+
+  <div style="clear:both;margin-top:40px;width:auto;">
+  
+    <a href=""><img src="{@docRoot}images/distribute/tinyvillage.png"></a>
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">More monetization
+on tablets</span>: On Android tablets TinyCo has seen higher ARPPU and user
+retention than on phones.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Instapaper: Riding the growing wave of Android tablets</h3>
+
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh3.ggpht.com/30KKcrIFO8V_wRfhnHaI9l0CLH_orIVFE7Xywtr9TBxAf0hi2BaZkKyBOs63Yfavpg=w124">
+
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+  
+  
+
+    <h5>About the app</h5> 
+    <ul>
+                <li><a href="http://play.google.com/store/apps/details?id=com.instapaper.android">Instapaper</a> by Mobelux</li>
+      <li>Content-browsing utility that targets 7- to 10-inch tablets and phones</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>Tablets are now 50% of the app's installed base.</li>
+    </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.instapaper.android">
+  <img alt="Android app on Google Play"
+       src="http://developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+</a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">Instapaper for Android is an app
+for saving web content to read later. Developer Mobelux decided that creating a
+great UI for Android tablet users would be an essential part of their initial launch
+plan.</p>
+    
+    <p>The app launched at the beginning of the summer of 2012, just in time to
+take advantage of a new tide of Android tablets, including the <span
+style="white-space:nowrap;">Nexus 7</span> tablet. The app has since seen huge
+popularity among tablet users, in particular, on Nexus 7. On the day that
+pre-orders of Nexus 7 began arriving, Mobelux saw a 600% jump in downloads of
+its app on Google Play.</p>
+
+    <p>“We saw a promising new set of Android tablets about to hit the market
+and wanted to position ourselves to be ready for them” said Jeff Rock of
+Mobelux. “It was a market that others were hesitant to explore, but the decision
+to prioritize tablets has paid off very well for us.”</p>
+
+    <p>Since that initial 600% jump in downloads, Instapaper for Android has
+continued to see a successful run on Android tablets. In fact, Android tablets
+now represent about 50% of their installed base. “With more and more Android
+tablets coming online, we’re excited to see how our investment in Android
+tablets continues to pay off.”</p>
+  </div>
+
+  <div style="clear:both;margin-top:40px;width:auto;">
+  
+    <a href=""><img src="{@docRoot}images/distribute/instapaper.png"></a>
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">Popular with
+tablet users</span>: A great tablet UI and browsing convenience make Instapaper
+popular with Android tablet users.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+
diff --git a/docs/html/distribute/googleplay/strategies/app-quality.jd b/docs/html/distribute/googleplay/strategies/app-quality.jd
index 6ea862b..ecc51dc 100644
--- a/docs/html/distribute/googleplay/strategies/app-quality.jd
+++ b/docs/html/distribute/googleplay/strategies/app-quality.jd
@@ -1,10 +1,10 @@
-page.title=Improving App Quality
+page.title=Improving App Quality After Launch
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Strategies:</h2>
-<ul>
+<h2>Strategies</h2>
+<ol>
 <li><a href="#listen">Listen to Your Users</a></li>
 <li><a href="#stability">Improve Stability and Eliminate Bugs</a></li>
 <li><a href="#responsiveness">Improve UI Responsiveness</a></li>
@@ -13,7 +13,14 @@
 <li><a href="#features">Deliver the Right Set of Features</a></li>
 <li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
 <li><a href="#details">Pay Attention to Details</a></li>
-</ul>
+</ol>
+
+<h2>You Should Also Read</h2>
+<ol>
+<li><a href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a></li>
+<li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
+</ol>
+
 </div>
 </div>
 
@@ -22,7 +29,7 @@
 <p>
 A better app can go a very long way: a higher quality app will translate to higher user ratings, generally better rankings, more downloads, and higher retention (longer install periods). High-quality apps also have a much higher likelihood of getting some unanticipated positive publicity such as being featured in Google Play or getting social media buzz.</p>
 <p>
-The upside to having a higher-quality app is obvious. However, it's not always clear how to make an app "better". The path to improving app quality isn't always well-lit. The term "quality" &mdash; along with "polish" and "fit and finish" &mdash; aren't always well-defined. Here we'll light the path by looking at some of the key factors in app quality and ways of improving your app along these dimensions.</p>
+The upside to having a higher-quality app is obvious. However, it's not always clear how to make an app "better".  This document looks at some of the key factors in app quality and ways of improving your app over time, after you've launched the app.</p>
 
 <h2 id="listen">Listen to Your Users</h2>
 <p>
@@ -52,15 +59,14 @@
 <p>
 You can improve your apps's UI responsiveness by moving long-running operations off the main thread to worker threads. Android offers built-in debugging facilities such as StrictMode for analyzing your app's performance and activities on the main thread. You can see more recommendations in <a href="http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>, a developer session from Google I/O 2010,</p>
 
-
 <div class="sidebox-wrapper">
 <div class="sidebox">
-<h2>More resources</h2>
+<h3>More resources</h3>
 <ul>
 <li><a href="{@docRoot}design/index.html">Android Design</a></li>
 <li><a href="{@docRoot}guide/practices/performance.html">Designing for Performance</a></li>
 <li><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a>
-<li><a href="{@docRoot}guide/practices/seamlessness.html">Designing for seamlessness</a>
+<li><a href="{@docRoot}guide/practices/seamlessness.html">Designing for Seamlessness</a>
 </li>
 </ul>
 </div></div>
@@ -73,18 +79,17 @@
 <h2 id="usability">Improve Usability</h2>
 <p>
 In usability and in app design too, you should listen carefully to your users. Ask a handful of real Android device users (friends, family, etc.) to try out your app and observe them as they interact with it. Look for cases where they get confused, are unsure of how to proceed, or are surprised by certain behaviors. Minimize these cases by rethinking some of the interactions in your app, perhaps working in some of the <a href="http://www.youtube.com/watch?v=M1ZBjlCRfz0">user interface patterns</a> the Android UI team discussed at Google I/O.</p>
-<p>
-In the same vein, two problems that can plague some Android user interfaces are small tap targets and excessively small font sizes. These are generally easy to fix and can make a big impact on usability and user satisfaction. As a general rule, optimize for ease of use and legibility, while minimizing, or at least carefully balancing, information density.</p>
 
 <div class="sidebox-wrapper">
 <div class="sidebox">
-<h2>More resources</h2>
-<ul>
-As you are designing or evaluating your app's UI, make sure to read and become familiar with the <a href="{@docRoot}design/index.html">Android Design</a> guidelines. Included are many examples of UI patterns, styles, and building blocks, as well as tools for the design process.</li>
-</ul>
+<p>
+As you are designing or evaluating your app's UI, make sure to read and become familiar with the <a href="/design/index.html">Android Design</a> guidelines. Included are many examples of UI patterns, styles, and building blocks, as well as tools for the design process.</p>
 </div></div>
 
 <p>
+In the same vein, two problems that can plague some Android user interfaces are small tap targets and excessively small font sizes. These are generally easy to fix and can make a big impact on usability and user satisfaction. As a general rule, optimize for ease of use and legibility, while minimizing, or at least carefully balancing, information density.</p>
+
+<p>
 Another way to incrementally improve usability, based on real-world data, is to implement <a href="http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your app to log usage of particular sections. Consider demoting infrequently used sections to the overflow menu in the <a href="{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them altogether. For often-used sections and UI elements, make sure they're immediately obvious and easily accessible in your app's UI so that users can get to them quickly.</p>
 <p>
 Lastly, usability is an extensive and well-documented subject, with close ties to interface design, cognitive science, and other disciplines.</p>
diff --git a/docs/html/images/distribute/instapaper.png b/docs/html/images/distribute/instapaper.png
new file mode 100644
index 0000000..ffbf052
--- /dev/null
+++ b/docs/html/images/distribute/instapaper.png
Binary files differ
diff --git a/docs/html/images/distribute/mint.png b/docs/html/images/distribute/mint.png
new file mode 100644
index 0000000..50d90d5
--- /dev/null
+++ b/docs/html/images/distribute/mint.png
Binary files differ
diff --git a/docs/html/images/distribute/tinyvillage.png b/docs/html/images/distribute/tinyvillage.png
new file mode 100644
index 0000000..cde77f0
--- /dev/null
+++ b/docs/html/images/distribute/tinyvillage.png
Binary files differ
diff --git a/docs/html/images/ui-ex-multi-pane.png b/docs/html/images/ui-ex-multi-pane.png
new file mode 100644
index 0000000..188bb8b
--- /dev/null
+++ b/docs/html/images/ui-ex-multi-pane.png
Binary files differ
diff --git a/docs/html/images/ui-ex-single-panes.png b/docs/html/images/ui-ex-single-panes.png
new file mode 100644
index 0000000..dff24a7
--- /dev/null
+++ b/docs/html/images/ui-ex-single-panes.png
Binary files differ
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index ab8e961..9e137ce 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -174,4 +174,7 @@
     <bool name="def_screensaver_activate_on_sleep">false</bool>
     <!-- ComponentName of the default screen saver (Settings.Secure.SCREENSAVER_COMPONENT) -->
     <string name="def_screensaver_component">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+
+    <!-- Default for Settings.Secure.USER_SETUP_COMPLETE -->
+    <bool name="def_user_setup_complete">false</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index a9869d9..0b61abe 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -68,7 +68,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 92;
+    private static final int DATABASE_VERSION = 93;
 
     private Context mContext;
     private int mUserHandle;
@@ -1449,6 +1449,30 @@
             upgradeVersion = 92;
         }
 
+        if (upgradeVersion == 92) {
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+                        + " VALUES(?,?);");
+                if (mUserHandle == UserHandle.USER_OWNER) {
+                    // consider existing primary users to have made it through user setup
+                    // if the globally-scoped device-provisioned bit is set
+                    // (indicating they already made it through setup as primary)
+                    int deviceProvisioned = getIntValueFromTable(db, TABLE_GLOBAL,
+                            Settings.Global.DEVICE_PROVISIONED, 0);
+                    loadSetting(stmt, Settings.Secure.USER_SETUP_COMPLETE,
+                            deviceProvisioned);
+                } else {
+                    // otherwise use the default
+                    loadBooleanSetting(stmt, Settings.Secure.USER_SETUP_COMPLETE,
+                            R.bool.def_user_setup_complete);
+                }
+            } finally {
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 93;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2016,6 +2040,9 @@
             loadBooleanSetting(stmt,
                     Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
                     R.bool.def_accessibility_display_magnification_auto_update);
+
+            loadBooleanSetting(stmt, Settings.Secure.USER_SETUP_COMPLETE,
+                    R.bool.def_user_setup_complete);
         } finally {
             if (stmt != null) stmt.close();
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 5672823..0a0474c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -284,7 +284,7 @@
         stateChecksums[STATE_SECURE] =
             writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
         stateChecksums[STATE_GLOBAL] =
-            writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, secureSettingsData, data);
+            writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
         stateChecksums[STATE_LOCALE] =
             writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
         stateChecksums[STATE_WIFI_SUPPLICANT] =
@@ -313,6 +313,8 @@
                 mSettingsHelper.applyAudioSettings();
             } else if (KEY_SECURE.equals(key)) {
                 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
+            } else if (KEY_GLOBAL.equals(key)) {
+                restoreSettings(data, Settings.Global.CONTENT_URI, null);
             } else if (NAIVE_WIFI_RESTORE && KEY_WIFI_SUPPLICANT.equals(key)) {
                 int retainedWifiState = enableWifi(false);
                 restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, data);
@@ -605,7 +607,7 @@
                 continue;
             }
 
-            final Uri destination = (movedToGlobal.contains(key))
+            final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
                     ? Settings.Global.CONTENT_URI
                     : contentUri;
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 76a5022..8086bbc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -556,59 +556,52 @@
             }
         }
 
-        // Okay, permission checks have cleared.  Reset to our own identity so we can
-        // manipulate all users' data with impunity.
-        long oldId = Binder.clearCallingIdentity();
-        try {
-            // Note: we assume that get/put operations for moved-to-global names have already
-            // been directed to the new location on the caller side (otherwise we'd fix them
-            // up here).
-            DatabaseHelper dbHelper;
-            SettingsCache cache;
+        // Note: we assume that get/put operations for moved-to-global names have already
+        // been directed to the new location on the caller side (otherwise we'd fix them
+        // up here).
+        DatabaseHelper dbHelper;
+        SettingsCache cache;
 
-            // Get methods
-            if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
-                if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
-                dbHelper = getOrEstablishDatabase(callingUser);
-                cache = sSystemCaches.get(callingUser);
-                return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
-            }
-            if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
-                if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
-                dbHelper = getOrEstablishDatabase(callingUser);
-                cache = sSecureCaches.get(callingUser);
-                return lookupValue(dbHelper, TABLE_SECURE, cache, request);
-            }
-            if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
-                if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
-                // fast path: owner db & cache are immutable after onCreate() so we need not
-                // guard on the attempt to look them up
-                return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
-                        sGlobalCache, request);
-            }
+        // Get methods
+        if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
+            dbHelper = getOrEstablishDatabase(callingUser);
+            cache = sSystemCaches.get(callingUser);
+            return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
+        }
+        if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
+            dbHelper = getOrEstablishDatabase(callingUser);
+            cache = sSecureCaches.get(callingUser);
+            return lookupValue(dbHelper, TABLE_SECURE, cache, request);
+        }
+        if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
+            // fast path: owner db & cache are immutable after onCreate() so we need not
+            // guard on the attempt to look them up
+            return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
+                    sGlobalCache, request);
+        }
 
-            // Put methods - new value is in the args bundle under the key named by
-            // the Settings.NameValueTable.VALUE static.
-            final String newValue = (args == null)
-                    ? null : args.getString(Settings.NameValueTable.VALUE);
+        // Put methods - new value is in the args bundle under the key named by
+        // the Settings.NameValueTable.VALUE static.
+        final String newValue = (args == null)
+        ? null : args.getString(Settings.NameValueTable.VALUE);
 
-            final ContentValues values = new ContentValues();
-            values.put(Settings.NameValueTable.NAME, request);
-            values.put(Settings.NameValueTable.VALUE, newValue);
-            if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
-                if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
-                insertForUser(Settings.System.CONTENT_URI, values, callingUser);
-            } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
-                if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
-                insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
-            } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
-                if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
-                insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
-            } else {
-                Slog.w(TAG, "call() with invalid method: " + method);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(oldId);
+        final ContentValues values = new ContentValues();
+        values.put(Settings.NameValueTable.NAME, request);
+        values.put(Settings.NameValueTable.VALUE, newValue);
+        if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
+            insertForUser(Settings.System.CONTENT_URI, values, callingUser);
+        } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
+            insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
+        } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
+            insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
+        } else {
+            Slog.w(TAG, "call() with invalid method: " + method);
         }
 
         return null;
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png
deleted file mode 100644
index 5912301..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index 49ee056..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..a7bc3c5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..012a4e8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png
deleted file mode 100644
index a5f16e8..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index a4e0420..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..1ff9cbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..0ec78c0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png
deleted file mode 100644
index eb6d5a6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png
deleted file mode 100644
index 98d7b09..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_mirroring_notconnected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
new file mode 100644
index 0000000..88ea017
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
new file mode 100644
index 0000000..7573636
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
index 454d54a..2d7e441 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
@@ -21,6 +21,6 @@
     android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_mirroring"
+    android:drawableTop="@drawable/ic_qs_remote_display"
     android:text="@string/quick_settings_wifi_display_label"
     />
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2b74f56..61299c4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -449,7 +449,7 @@
     <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
     <string name="quick_settings_wifi_display_label">Wi-Fi Display</string>
     <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_wifi_display_no_connection_label">No Wi-Fi Display Connection</string>
+    <string name="quick_settings_wifi_display_no_connection_label">Wireless Display</string>
     <!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
     <string name="quick_settings_brightness_dialog_title">Brightness</string>
     <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 3c30f5d..07fd0ab 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -207,6 +207,7 @@
             if (intent.resolveActivity(mContext.getPackageManager()) != null) {
                 b.setNegativeButton(R.string.battery_low_why,
                         new DialogInterface.OnClickListener() {
+                    @Override
                     public void onClick(DialogInterface dialog, int which) {
                         mContext.startActivity(intent);
                         dismissLowBatteryWarning();
@@ -216,12 +217,15 @@
 
             AlertDialog d = b.create();
             d.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                    @Override
                     public void onDismiss(DialogInterface dialog) {
                         mLowBatteryDialog = null;
                         mBatteryLevelTextView = null;
                     }
                 });
             d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            d.getWindow().getAttributes().privateFlags |=
+                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
             d.show();
             mLowBatteryDialog = d;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 4962199..6ae09b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -160,7 +160,7 @@
             }
         }
         if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
-        if (!waiting) {
+        if (!waiting && mState != STATE_CLOSED) {
             // it's possible that nothing animated, so we replicate the termination 
             // conditions of panelExpansionChanged here
             go(STATE_CLOSED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 362bb1c..a8a92ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -105,7 +105,7 @@
             mTimeAnimator = new TimeAnimator();
             mTimeAnimator.setTimeListener(mAnimationCallback);
 
-            mPeekAnimator.cancel();
+            if (mPeekAnimator != null) mPeekAnimator.cancel();
 
             mTimeAnimator.start();
 
@@ -261,7 +261,7 @@
                         case MotionEvent.ACTION_MOVE:
                             final float h = rawY - mAbsPos[1] - mTouchOffset;
                             if (h > mPeekHeight) {
-                                if (mPeekAnimator.isRunning()) {
+                                if (mPeekAnimator != null && mPeekAnimator.isRunning()) {
                                     mPeekAnimator.cancel();
                                 }
                                 mJustPeeked = false;
@@ -385,7 +385,7 @@
 
     public void setExpandedHeight(float height) {
         if (DEBUG) LOG("setExpandedHeight(%.1f)", height);
-        mTracking = mRubberbanding = false;
+        mRubberbanding = false;
         if (mTimeAnimator.isRunning()) {
             post(mStopAnimator);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e587422..3aa81ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1269,8 +1269,8 @@
             return;
         }
 
-        // Ensure the panel is fully collapsed (just in case; bug 6765842)
- // @@@        mStatusBarView.collapseAllPanels(/*animate=*/ false);
+        // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
+        mStatusBarView.collapseAllPanels(/*animate=*/ false);
 
         mExpandedVisible = false;
         mPile.setLayoutTransitionsEnabled(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 4ef35aa..32ad429a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -562,6 +562,7 @@
             public void refreshView(QuickSettingsTileView view, State state) {
                 TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
                 tv.setText(state.label);
+                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
                 view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 8e891f6..95cb922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -524,9 +524,11 @@
                 (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
         if (status.getActiveDisplay() != null) {
             mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
+            mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
         } else {
             mWifiDisplayState.label = mContext.getString(
                     R.string.quick_settings_wifi_display_no_connection_label);
+            mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display;
         }
         mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ed9c6a3..e4ca8d8 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -17,7 +17,6 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
-import android.app.IUiModeManager;
 import android.app.ProgressDialog;
 import android.app.SearchManager;
 import android.app.UiModeManager;
@@ -101,6 +100,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
@@ -108,6 +108,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
@@ -119,6 +120,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
@@ -180,61 +182,11 @@
     static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
     static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
 
-    // wallpaper is at the bottom, though the window manager may move it.
-    static final int UNIVERSE_BACKGROUND_LAYER = 1;
-    static final int WALLPAPER_LAYER = 2;
-    static final int APPLICATION_LAYER = 2;
-    static final int PHONE_LAYER = 3;
-    static final int SEARCH_BAR_LAYER = 4;
-    static final int SYSTEM_DIALOG_LAYER = 5;
-    // toasts and the plugged-in battery thing
-    static final int TOAST_LAYER = 6;
-    // SIM errors and unlock.  Not sure if this really should be in a high layer.
-    static final int PRIORITY_PHONE_LAYER = 7;
-    // like the ANR / app crashed dialogs
-    static final int SYSTEM_ALERT_LAYER = 8;
-    // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_LAYER = 9;
-    // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_DIALOG_LAYER = 10;
-    // the keyguard; nothing on top of these can take focus, since they are
-    // responsible for power management when displayed.
-    static final int KEYGUARD_LAYER = 11;
-    static final int KEYGUARD_DIALOG_LAYER = 12;
-    // used for Dreams (screensavers with TYPE_DREAM windows)
-    static final int SCREENSAVER_LAYER = 13; 
-    static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
-    static final int STATUS_BAR_LAYER = 15;
-    static final int STATUS_BAR_PANEL_LAYER = 16;
-    // the on-screen volume indicator and controller shown when the user
-    // changes the device volume
-    static final int VOLUME_OVERLAY_LAYER = 17;
-    // things in here CAN NOT take focus, but are shown on top of everything else.
-    static final int SYSTEM_OVERLAY_LAYER = 18;
-    // the navigation bar, if available, shows atop most things
-    static final int NAVIGATION_BAR_LAYER = 19;
-    // some panels (e.g. search) need to show on top of the navigation bar
-    static final int NAVIGATION_BAR_PANEL_LAYER = 20;
-    // system-level error dialogs
-    static final int SYSTEM_ERROR_LAYER = 21;
-    // used to highlight the magnified portion of a display
-    static final int MAGNIFICATION_OVERLAY_LAYER = 22;
-    // used to simulate secondary display devices
-    static final int DISPLAY_OVERLAY_LAYER = 23;
-    // the drag layer: input for drag-and-drop is associated with this window,
-    // which sits above all other focusable windows
-    static final int DRAG_LAYER = 24;
-    static final int SECURE_SYSTEM_OVERLAY_LAYER = 25;
-    static final int BOOT_PROGRESS_LAYER = 26;
-    // the (mouse) pointer layer
-    static final int POINTER_LAYER = 27;
-    static final int HIDDEN_NAV_CONSUMER_LAYER = 28;
-
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
     static final int APPLICATION_PANEL_SUBLAYER = 1;
     static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-    
+
     static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
     static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
     static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -289,7 +241,7 @@
 
     // Vibrator pattern for haptic feedback of a long press.
     long[] mLongPressVibePattern;
-    
+
     // Vibrator pattern for haptic feedback of virtual key press.
     long[] mVirtualKeyVibePattern;
     
@@ -457,8 +409,10 @@
     WindowState mTopFullscreenOpaqueWindowState;
     boolean mTopIsFullscreen;
     boolean mForceStatusBar;
+    boolean mForceStatusBarFromKeyguard;
     boolean mHideLockScreen;
     boolean mDismissKeyguard;
+    boolean mNoDreamEnterAnim;
     boolean mHomePressed;
     boolean mHomeLongPressed;
     Intent mHomeIntent;
@@ -933,6 +887,12 @@
                     Intent.EXTRA_DOCK_STATE_UNDOCKED);
         }
 
+        // register for dream-related broadcasts
+        filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_DREAMING_STARTED);
+        filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+        context.registerReceiver(mDreamReceiver, filter);
+
         // register for multiuser-relevant broadcasts
         filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
         context.registerReceiver(mMultiuserReceiver, filter);
@@ -1199,6 +1159,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public int checkAddPermission(WindowManager.LayoutParams attrs) {
         int type = attrs.type;
         
@@ -1236,7 +1197,55 @@
         }
         return WindowManagerGlobal.ADD_OKAY;
     }
-    
+
+    @Override
+    public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs) {
+
+        // If this switch statement is modified, modify the comment in the declarations of
+        // the type in {@link WindowManager.LayoutParams} as well.
+        switch (attrs.type) {
+            default:
+                // These are the windows that by default are shown only to the user that created
+                // them. If this needs to be overridden, set
+                // {@link WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS} in
+                // {@link WindowManager.LayoutParams}. Note that permission
+                // {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} is required as well.
+                if ((attrs.privateFlags & PRIVATE_FLAG_SHOW_FOR_ALL_USERS) == 0) {
+                    return true;
+                }
+                break;
+
+            // These are the windows that by default are shown to all users. However, to
+            // protect against spoofing, check permissions below.
+            case TYPE_APPLICATION_STARTING:
+            case TYPE_BOOT_PROGRESS:
+            case TYPE_DISPLAY_OVERLAY:
+            case TYPE_HIDDEN_NAV_CONSUMER:
+            case TYPE_KEYGUARD:
+            case TYPE_KEYGUARD_DIALOG:
+            case TYPE_MAGNIFICATION_OVERLAY:
+            case TYPE_NAVIGATION_BAR:
+            case TYPE_NAVIGATION_BAR_PANEL:
+            case TYPE_PHONE:
+            case TYPE_POINTER:
+            case TYPE_PRIORITY_PHONE:
+            case TYPE_RECENTS_OVERLAY:
+            case TYPE_SEARCH_BAR:
+            case TYPE_STATUS_BAR:
+            case TYPE_STATUS_BAR_PANEL:
+            case TYPE_STATUS_BAR_SUB_PANEL:
+            case TYPE_SYSTEM_DIALOG:
+            case TYPE_UNIVERSE_BACKGROUND:
+            case TYPE_VOLUME_OVERLAY:
+                break;
+        }
+
+        // Check if third party app has set window to system window type.
+        return mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
+                        != PackageManager.PERMISSION_GRANTED;
+    }
+
     public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
         switch (attrs.type) {
             case TYPE_SYSTEM_OVERLAY:
@@ -1296,68 +1305,90 @@
     /** {@inheritDoc} */
     public int windowTypeToLayerLw(int type) {
         if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
-            return APPLICATION_LAYER;
+            return 2;
         }
         switch (type) {
-        case TYPE_STATUS_BAR:
-            return STATUS_BAR_LAYER;
-        case TYPE_STATUS_BAR_PANEL:
-            return STATUS_BAR_PANEL_LAYER;
-        case TYPE_STATUS_BAR_SUB_PANEL:
-            return STATUS_BAR_SUB_PANEL_LAYER;
-        case TYPE_SYSTEM_DIALOG:
-            return SYSTEM_DIALOG_LAYER;
-        case TYPE_SEARCH_BAR:
-            return SEARCH_BAR_LAYER;
-        case TYPE_PHONE:
-            return PHONE_LAYER;
-        case TYPE_KEYGUARD:
-            return KEYGUARD_LAYER;
-        case TYPE_KEYGUARD_DIALOG:
-            return KEYGUARD_DIALOG_LAYER;
-        case TYPE_SYSTEM_ALERT:
-            return SYSTEM_ALERT_LAYER;
-        case TYPE_SYSTEM_ERROR:
-            return SYSTEM_ERROR_LAYER;
-        case TYPE_INPUT_METHOD:
-            return INPUT_METHOD_LAYER;
-        case TYPE_INPUT_METHOD_DIALOG:
-            return INPUT_METHOD_DIALOG_LAYER;
-        case TYPE_VOLUME_OVERLAY:
-            return VOLUME_OVERLAY_LAYER;
-        case TYPE_SYSTEM_OVERLAY:
-            return SYSTEM_OVERLAY_LAYER;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
-            return SECURE_SYSTEM_OVERLAY_LAYER;
-        case TYPE_PRIORITY_PHONE:
-            return PRIORITY_PHONE_LAYER;
-        case TYPE_TOAST:
-            return TOAST_LAYER;
-        case TYPE_WALLPAPER:
-            return WALLPAPER_LAYER;
-        case TYPE_DRAG:
-            return DRAG_LAYER;
-        case TYPE_POINTER:
-            return POINTER_LAYER;
-        case TYPE_NAVIGATION_BAR:
-            return NAVIGATION_BAR_LAYER;
-        case TYPE_NAVIGATION_BAR_PANEL:
-            return NAVIGATION_BAR_PANEL_LAYER;
-        case TYPE_BOOT_PROGRESS:
-            return BOOT_PROGRESS_LAYER;
-        case TYPE_HIDDEN_NAV_CONSUMER:
-            return HIDDEN_NAV_CONSUMER_LAYER;
-        case TYPE_DREAM:
-            return SCREENSAVER_LAYER;
         case TYPE_UNIVERSE_BACKGROUND:
-            return UNIVERSE_BACKGROUND_LAYER;
-        case TYPE_DISPLAY_OVERLAY:
-            return DISPLAY_OVERLAY_LAYER;
+            return 1;
+        case TYPE_WALLPAPER:
+            // wallpaper is at the bottom, though the window manager may move it.
+            return 2;
+        case TYPE_PHONE:
+            return 3;
+        case TYPE_SEARCH_BAR:
+            return 4;
+        case TYPE_RECENTS_OVERLAY:
+        case TYPE_SYSTEM_DIALOG:
+            return 5;
+        case TYPE_TOAST:
+            // toasts and the plugged-in battery thing
+            return 6;
+        case TYPE_PRIORITY_PHONE:
+            // SIM errors and unlock.  Not sure if this really should be in a high layer.
+            return 7;
+        case TYPE_DREAM:
+            // used for Dreams (screensavers with TYPE_DREAM windows)
+            return 8;
+        case TYPE_SYSTEM_ALERT:
+            // like the ANR / app crashed dialogs
+            return 9;
+        case TYPE_INPUT_METHOD:
+            // on-screen keyboards and other such input method user interfaces go here.
+            return 10;
+        case TYPE_INPUT_METHOD_DIALOG:
+            // on-screen keyboards and other such input method user interfaces go here.
+            return 11;
+        case TYPE_KEYGUARD:
+            // the keyguard; nothing on top of these can take focus, since they are
+            // responsible for power management when displayed.
+            return 12;
+        case TYPE_KEYGUARD_DIALOG:
+            return 13;
+        case TYPE_STATUS_BAR_SUB_PANEL:
+            return 14;
+        case TYPE_STATUS_BAR:
+            return 15;
+        case TYPE_STATUS_BAR_PANEL:
+            return 16;
+        case TYPE_VOLUME_OVERLAY:
+            // the on-screen volume indicator and controller shown when the user
+            // changes the device volume
+            return 17;
+        case TYPE_SYSTEM_OVERLAY:
+            // the on-screen volume indicator and controller shown when the user
+            // changes the device volume
+            return 18;
+        case TYPE_NAVIGATION_BAR:
+            // the navigation bar, if available, shows atop most things
+            return 19;
+        case TYPE_NAVIGATION_BAR_PANEL:
+            // some panels (e.g. search) need to show on top of the navigation bar
+            return 20;
+        case TYPE_SYSTEM_ERROR:
+            // system-level error dialogs
+            return 21;
         case TYPE_MAGNIFICATION_OVERLAY:
-            return MAGNIFICATION_OVERLAY_LAYER;
+            // used to highlight the magnified portion of a display
+            return 22;
+        case TYPE_DISPLAY_OVERLAY:
+            // used to simulate secondary display devices
+            return 23;
+        case TYPE_DRAG:
+            // the drag layer: input for drag-and-drop is associated with this window,
+            // which sits above all other focusable windows
+            return 24;
+        case TYPE_SECURE_SYSTEM_OVERLAY:
+            return 25;
+        case TYPE_BOOT_PROGRESS:
+            return 26;
+        case TYPE_POINTER:
+            // the (mouse) pointer layer
+            return 27;
+        case TYPE_HIDDEN_NAV_CONSUMER:
+            return 28;
         }
         Log.e(TAG, "Unknown window type: " + type);
-        return APPLICATION_LAYER;
+        return 2;
     }
 
     /** {@inheritDoc} */
@@ -1378,11 +1409,11 @@
     }
 
     public int getMaxWallpaperLayer() {
-        return STATUS_BAR_LAYER;
+        return windowTypeToLayerLw(TYPE_STATUS_BAR);
     }
 
     public int getAboveUniverseLayer() {
-        return SYSTEM_ERROR_LAYER;
+        return windowTypeToLayerLw(TYPE_SYSTEM_ERROR);
     }
 
     public boolean hasSystemNavBar() {
@@ -1434,11 +1465,12 @@
     public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
         return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
     }
-    
+
     public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
         return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
                 && attrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
                 && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER
+                && attrs.type != WindowManager.LayoutParams.TYPE_DREAM
                 && attrs.type != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
     }
 
@@ -1510,6 +1542,7 @@
                     com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
             params.privateFlags |=
                     WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
+            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
             params.setTitle("Starting " + packageName);
 
             WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
@@ -1670,6 +1703,13 @@
                 if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
                 return com.android.internal.R.anim.app_starting_exit;
             }
+        } else if (win.getAttrs().type == TYPE_DREAM && mNoDreamEnterAnim
+                && transit == TRANSIT_ENTER) {
+            // Special case: we are animating in a dream, while the keyguard
+            // is shown.  We don't want an animation on the dream, because
+            // we need it shown immediately with the keyguard animating away
+            // to reveal it.
+            return -1;
         }
 
         return 0;
@@ -2859,10 +2899,12 @@
     public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
         mTopFullscreenOpaqueWindowState = null;
         mForceStatusBar = false;
+        mForceStatusBarFromKeyguard = false;
         
         mHideLockScreen = false;
         mAllowLockscreenWhenOn = false;
         mDismissKeyguard = false;
+        mNoDreamEnterAnim = false;
     }
 
     /** {@inheritDoc} */
@@ -2873,7 +2915,14 @@
         if (mTopFullscreenOpaqueWindowState == null &&
                 win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
             if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
-                mForceStatusBar = true;
+                if (attrs.type == TYPE_KEYGUARD) {
+                    mForceStatusBarFromKeyguard = true;
+                } else {
+                    mForceStatusBar = true;
+                }
+            }
+            if (attrs.type == TYPE_KEYGUARD) {
+                mNoDreamEnterAnim = true;
             }
             if (((attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW)
                         || attrs.type == TYPE_DREAM)
@@ -2882,13 +2931,18 @@
                     && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
                 if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
                 mTopFullscreenOpaqueWindowState = win;
+                if (attrs.type == TYPE_DREAM) {
+                    mNoDreamEnterAnim = true;
+                }
                 if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
-                    if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
                     mHideLockScreen = true;
+                    mForceStatusBarFromKeyguard = false;
                 }
                 if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
-                    if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
                     mDismissKeyguard = true;
+                    mForceStatusBarFromKeyguard = false;
                 }
                 if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                     mAllowLockscreenWhenOn = true;
@@ -2908,8 +2962,9 @@
 
         if (mStatusBar != null) {
             if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar
+                    + " forcefkg=" + mForceStatusBarFromKeyguard
                     + " top=" + mTopFullscreenOpaqueWindowState);
-            if (mForceStatusBar) {
+            if (mForceStatusBar || mForceStatusBarFromKeyguard) {
                 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced");
                 if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
             } else if (mTopFullscreenOpaqueWindowState != null) {
@@ -3567,6 +3622,21 @@
         }
     };
 
+    BroadcastReceiver mDreamReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
+                if (mKeyguardMediator != null) {
+                    mKeyguardMediator.onDreamingStarted();
+                }
+            } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+                if (mKeyguardMediator != null) {
+                    mKeyguardMediator.onDreamingStopped();
+                }
+            }
+        }
+    };
+
     BroadcastReceiver mMultiuserReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -3580,7 +3650,7 @@
         }
     };
 
-    /** {@inheritDoc} */
+    @Override
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
         synchronized (mLock) {
@@ -3596,7 +3666,7 @@
         }
     }
 
-    /** {@inheritDoc} */
+    @Override
     public void screenTurningOn(final ScreenOnListener screenOnListener) {
         EventLog.writeEvent(70000, 1);
         if (false) {
@@ -3604,64 +3674,83 @@
             here.fillInStackTrace();
             Slog.i(TAG, "Screen turning on...", here);
         }
-        if (screenOnListener != null) {
-            if (mKeyguardMediator != null) {
-                try {
-                    mWindowManager.setEventDispatching(true);
-                } catch (RemoteException unhandled) {
-                }
-                mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
-                    @Override public void onShown(IBinder windowToken) {
-                        if (windowToken != null) {
-                            try {
-                                mWindowManager.waitForWindowDrawn(windowToken,
-                                        new IRemoteCallback.Stub() {
-                                    @Override public void sendResult(Bundle data) {
-                                        Slog.i(TAG, "Lock screen displayed!");
-                                        screenOnListener.onScreenOn();
-                                        synchronized (mLock) {
-                                            mScreenOnFully = true;
-                                        }
-                                    }
-                                });
-                            } catch (RemoteException e) {
-                            }
-                        } else {
-                            Slog.i(TAG, "No lock screen!");
-                            screenOnListener.onScreenOn();
-                            synchronized (mLock) {
-                                mScreenOnFully = true;
-                            }
-                        }
-                    }
-                });
-            }
-        } else {
-            if (mKeyguardMediator != null) {
-                // Must set mScreenOn = true.
-                mKeyguardMediator.onScreenTurnedOn(null);
-            }
-            synchronized (mLock) {
-                mScreenOnFully = true;
-            }
-        }
+
         synchronized (mLock) {
             mScreenOnEarly = true;
             updateOrientationListenerLp();
             updateLockScreenTimeout();
         }
+
+        try {
+            mWindowManager.setEventDispatching(true);
+        } catch (RemoteException unhandled) {
+        }
+
+        waitForKeyguard(screenOnListener);
     }
 
-    /** {@inheritDoc} */
+    private void waitForKeyguard(final ScreenOnListener screenOnListener) {
+        if (mKeyguardMediator != null) {
+            if (screenOnListener != null) {
+                mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
+                    @Override
+                    public void onShown(IBinder windowToken) {
+                        waitForKeyguardWindowDrawn(windowToken, screenOnListener);
+                    }
+                });
+                return;
+            } else {
+                mKeyguardMediator.onScreenTurnedOn(null);
+            }
+        } else {
+            Slog.i(TAG, "No keyguard mediator!");
+        }
+        finishScreenTurningOn(screenOnListener);
+    }
+
+    private void waitForKeyguardWindowDrawn(IBinder windowToken,
+            final ScreenOnListener screenOnListener) {
+        if (windowToken != null) {
+            try {
+                if (mWindowManager.waitForWindowDrawn(
+                        windowToken, new IRemoteCallback.Stub() {
+                    @Override
+                    public void sendResult(Bundle data) {
+                        Slog.i(TAG, "Lock screen displayed!");
+                        finishScreenTurningOn(screenOnListener);
+                    }
+                })) {
+                    return;
+                }
+            } catch (RemoteException ex) {
+                // Can't happen in system process.
+            }
+        }
+
+        Slog.i(TAG, "No lock screen!");
+        finishScreenTurningOn(screenOnListener);
+    }
+
+    private void finishScreenTurningOn(ScreenOnListener screenOnListener) {
+        synchronized (mLock) {
+            mScreenOnFully = true;
+        }
+
+        if (screenOnListener != null) {
+            screenOnListener.onScreenOn();
+        }
+    }
+
+    @Override
     public boolean isScreenOnEarly() {
         return mScreenOnEarly;
     }
-    
-    /** {@inheritDoc} */
+
+    @Override
     public boolean isScreenOnFully() {
         return mScreenOnFully;
     }
-    
+
     /** {@inheritDoc} */
     public void enableKeyguard(boolean enabled) {
         if (mKeyguardMediator != null) {
@@ -4236,30 +4325,34 @@
         }
         return true;
     }
-    
-    public void screenOnStartedLw() {
+
+    @Override
+    public void keepScreenOnStartedLw() {
     }
 
-    public void screenOnStoppedLw() {
-        if (mPowerManager.isScreenOn()) {
-            if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
-                long curTime = SystemClock.uptimeMillis();
-                mPowerManager.userActivity(curTime, false);
-            }
+    @Override
+    public void keepScreenOnStoppedLw() {
+        if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
+            long curTime = SystemClock.uptimeMillis();
+            mPowerManager.userActivity(curTime, false);
         }
     }
 
-    public boolean allowKeyRepeat() {
-        // disable key repeat when screen is off
-        return mScreenOnEarly;
-    }
-
     private int updateSystemUiVisibilityLw() {
         // If there is no window focused, there will be nobody to handle the events
         // anyway, so just hang on in whatever state we're in until things settle down.
         if (mFocusedWindow == null) {
             return 0;
         }
+        if (mFocusedWindow.getAttrs().type == TYPE_KEYGUARD && mHideLockScreen == true) {
+            // We are updating at a point where the keyguard has gotten
+            // focus, but we were last in a state where the top window is
+            // hiding it.  This is probably because the keyguard as been
+            // shown while the top window was displayed, so we want to ignore
+            // it here because this is just a very transient change and it
+            // will quickly lose focus once it correctly gets hidden.
+            return 0;
+        }
         final int visibility = mFocusedWindow.getSystemUiVisibility()
                 & ~mResettingSystemUiFlags
                 & ~mForceClearedSystemUiFlags;
@@ -4406,9 +4499,11 @@
                 pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
         pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
                 pw.println(mTopFullscreenOpaqueWindowState);
-        pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
-                pw.print(" mForceStatusBar="); pw.print(mForceStatusBar);
+            pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
                 pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
+        pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
+                pw.print(" mForceStatusBarFromKeyguard=");
+                pw.println(mForceStatusBarFromKeyguard);
         pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
                 pw.print(" mHomePressed="); pw.println(mHomePressed);
         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index b9903dd..2f0d7d6 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -94,7 +94,7 @@
 
         Window window = getWindow();
         window.requestFeature(Window.FEATURE_NO_TITLE);
-        window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+        window.setType(WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY);
         window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         window.setTitle("Recents");
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 f0dfba1..8e9362e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -65,6 +65,7 @@
     private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs";
 
     private AppWidgetHost mAppWidgetHost;
+    private KeyguardWidgetRegion mAppWidgetRegion;
     private KeyguardWidgetPager mAppWidgetContainer;
     private ViewFlipper mSecurityViewContainer;
     private KeyguardSelectorView mKeyguardSelectorView;
@@ -142,9 +143,11 @@
 
     @Override
     protected void onFinishInflate() {
+        mAppWidgetRegion = (KeyguardWidgetRegion) findViewById(R.id.kg_widget_region);
+        mAppWidgetRegion.setVisibility(VISIBLE);
+        mAppWidgetRegion.setCallbacks(mWidgetCallbacks);
+
         mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
-        KeyguardWidgetRegion kgwr = (KeyguardWidgetRegion) findViewById(R.id.kg_widget_region);
-        kgwr.setVisibility(VISIBLE);
         mSecurityViewContainer = (ViewFlipper) findViewById(R.id.view_flipper);
         mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
 
@@ -181,6 +184,18 @@
         super.onAttachedToWindow();
         mAppWidgetHost.startListening();
         maybePopulateWidgets();
+        disableStatusViewInteraction();
+        showAppropriateWidgetPage();
+    }
+
+    private void disableStatusViewInteraction() {
+        // Disable all user interaction on status view. This is done to prevent falsing in the
+        // pocket from triggering useractivity and prevents 3rd party replacement widgets
+        // from responding to user interaction while in this position.
+        View statusView = findViewById(R.id.keyguard_status_view);
+        if (statusView instanceof KeyguardWidgetFrame) {
+            ((KeyguardWidgetFrame) statusView).setDisableUserInteraction(true);
+        }
     }
 
     @Override
@@ -197,6 +212,33 @@
         mAppWidgetContainer.addWidget(view);
     }
 
+    private KeyguardWidgetRegion.Callbacks mWidgetCallbacks
+            = new KeyguardWidgetRegion.Callbacks() {
+        @Override
+        public void userActivity() {
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.userActivity();
+            }
+        }
+
+        @Override
+        public void onUserActivityTimeoutChanged() {
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.onUserActivityTimeoutChanged();
+            }
+        }
+    };
+
+    @Override
+    public long getUserActivityTimeout() {
+        // Currently only considering user activity timeouts needed by widgets.
+        // Could also take into account longer timeouts for certain security views.
+        if (mAppWidgetRegion != null) {
+            return mAppWidgetRegion.getUserActivityTimeout();
+        }
+        return -1;
+    }
+
     private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
 
         public void userActivity(long timeout) {
@@ -254,17 +296,6 @@
         dialog.show();
     }
 
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_UP
-                && event.getKeyCode() == KeyEvent.KEYCODE_BACK
-                && mCurrentSecuritySelection != SecurityMode.None) {
-            mCallback.dismiss(false);
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
     private void showTimeoutDialog() {
         int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
         int messageId = 0;
@@ -684,10 +715,14 @@
         inflater.inflate(R.layout.keyguard_status_view, mAppWidgetContainer, true);
         inflater.inflate(R.layout.keyguard_transport_control_view, mAppWidgetContainer, true);
 
+        inflateAndAddUserSelectorWidgetIfNecessary();
+        initializeTransportControl();
+    }
+
+    private void initializeTransportControl() {
         mTransportControl =
             (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
 
-
         // This code manages showing/hiding the transport control. We keep it around and only
         // add it to the hierarchy if it needs to be present.
         if (mTransportControl != null) {
@@ -736,10 +771,8 @@
                 return;
             }
         }
-        inflateAndAddUserSelectorWidgetIfNecessary();
 
-        // Add status widget
-        View statusView = null;
+        // Replace status widget if selected by user in Settings
         int statusWidgetId = mLockPatternUtils.getStatusWidget();
         if (statusWidgetId != -1) {
             addWidget(statusWidgetId);
@@ -753,16 +786,6 @@
             mAppWidgetContainer.removeView(newStatusWidget);
             newStatusWidget.setId(R.id.keyguard_status_view);
             mAppWidgetContainer.addView(newStatusWidget, oldStatusWidgetPosition);
-            statusView = newStatusWidget;
-        } else {
-            statusView = findViewById(R.id.keyguard_status_view);
-        }
-
-        // Disable all user interaction on status view. This is done to prevent falsing in the
-        // pocket from triggering useractivity and prevents 3rd party replacement widgets
-        // from responding to user interaction while in this position.
-        if (statusView instanceof KeyguardWidgetFrame) {
-            ((KeyguardWidgetFrame) statusView).setDisableUserInteraction(true);
         }
 
         // Add user-selected widget
@@ -772,7 +795,6 @@
                 addWidget(widgets[i]);
             }
         }
-        showAppropriateWidgetPage();
     }
 
     private void showAppropriateWidgetPage() {
@@ -856,4 +878,12 @@
         mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector));
     }
 
+    public boolean handleBackKey() {
+        if (mCurrentSecuritySelection != SecurityMode.None) {
+            mCallback.dismiss(false);
+            return true;
+        }
+        return false;
+    }
+
 }
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 ad5de0e..3191f4a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
@@ -137,6 +137,12 @@
      */
     abstract public void cleanUp();
 
+    /**
+     * Gets the desired user activity timeout in milliseconds, or -1 if the
+     * default should be used.
+     */
+    abstract public long getUserActivityTimeout();
+
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (interceptMediaKey(event)) {
@@ -250,5 +256,4 @@
             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 fd52575..33ff71e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -129,6 +129,18 @@
             super.onConfigurationChanged(newConfig);
             maybeCreateKeyguardLocked(shouldEnableScreenRotation(), null);
         }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN
+                    && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+                    && mKeyguardView != null) {
+                if (mKeyguardView.handleBackKey()) {
+                    return true;
+                }
+            }
+            return super.dispatchKeyEvent(event);
+        }
     }
 
     SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
@@ -168,13 +180,17 @@
                         WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
             }
             lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
+            if (isActivity) {
+                lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+            }
             lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
-            lp.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
             lp.setTitle(isActivity ? "KeyguardMock" : "Keyguard");
             mWindowLayoutParams = lp;
             mViewManager.addView(mKeyguardHost, lp);
         }
+
         inflateKeyguardView(options);
+        updateUserActivityTimeoutInWindowLayoutParams();
         mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
 
         mKeyguardHost.restoreHierarchyState(mStateContainer);
@@ -209,6 +225,25 @@
         }
     }
 
+    public void updateUserActivityTimeout() {
+        updateUserActivityTimeoutInWindowLayoutParams();
+        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
+    }
+
+    private void updateUserActivityTimeoutInWindowLayoutParams() {
+        // Use the user activity timeout requested by the keyguard view, if any.
+        if (mKeyguardView != null) {
+            long timeout = mKeyguardView.getUserActivityTimeout();
+            if (timeout >= 0) {
+                mWindowLayoutParams.userActivityTimeout = timeout;
+                return;
+            }
+        }
+
+        // Otherwise, use the default timeout.
+        mWindowLayoutParams.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
+    }
+
     private void maybeEnableScreenRotation(boolean enableScreenRotation) {
         // TODO: move this outside
         if (enableScreenRotation) {
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 4c676a1..3ed952c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -259,9 +259,14 @@
         void wakeUp();
 
         /**
-         * Reports user activity and requests that the screen stay on for the specified
-         * amount of time.
-         * @param millis The amount of time in millis.
+         * Reports user activity and requests that the screen stay on.
+         */
+        void userActivity();
+
+        /**
+         * Reports user activity and requests that the screen stay on for at least
+         * the specified amount of time.
+         * @param millis The amount of time in millis.  This value is currently ignored.
          */
         void userActivity(long millis);
 
@@ -284,6 +289,12 @@
          * @param needsInput
          */
         void setNeedsInput(boolean needsInput);
+
+        /**
+         * Tell view mediator that the keyguard view's desired user activity timeout
+         * has changed and needs to be reapplied to the window.
+         */
+        void onUserActivityTimeoutChanged();
     }
 
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -400,6 +411,10 @@
             KeyguardViewMediator.this.wakeUp();
         }
 
+        public void userActivity() {
+            KeyguardViewMediator.this.userActivity();
+        }
+
         public void userActivity(long holdMs) {
             KeyguardViewMediator.this.userActivity(holdMs);
         }
@@ -416,6 +431,11 @@
         public void setNeedsInput(boolean needsInput) {
             mKeyguardViewManager.setNeedsInput(needsInput);
         }
+
+        @Override
+        public void onUserActivityTimeoutChanged() {
+            mKeyguardViewManager.updateUserActivityTimeout();
+        }
     };
 
     public void wakeUp() {
@@ -535,50 +555,7 @@
                 resetStateLocked(null);
             } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
                    || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
-                // if the screen turned off because of timeout or the user hit the power button
-                // and we don't need to lock immediately, set an alarm
-                // to enable it a little bit later (i.e, give the user a chance
-                // to turn the screen back on within a certain window without
-                // having to unlock the screen)
-                final ContentResolver cr = mContext.getContentResolver();
-
-                // From DisplaySettings
-                long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
-                        KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
-
-                // From SecuritySettings
-                final long lockAfterTimeout = Settings.Secure.getInt(cr,
-                        Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
-                        KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
-
-                // From DevicePolicyAdmin
-                final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
-                        .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
-
-                long timeout;
-                if (policyTimeout > 0) {
-                    // policy in effect. Make sure we don't go beyond policy limit.
-                    displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
-                    timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
-                } else {
-                    timeout = lockAfterTimeout;
-                }
-
-                if (timeout <= 0) {
-                    // Lock now
-                    mSuppressNextLockSound = true;
-                    doKeyguardLocked();
-                } else {
-                    // Lock in the future
-                    long when = SystemClock.elapsedRealtime() + timeout;
-                    Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
-                    intent.putExtra("seq", mDelayedShowingSequence);
-                    PendingIntent sender = PendingIntent.getBroadcast(mContext,
-                            0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
-                    if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
-                                     + mDelayedShowingSequence);
-                }
+                doKeyguardLaterLocked();
             } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
                 // Do not enable the keyguard if the prox sensor forced the screen off.
             } else {
@@ -587,13 +564,64 @@
         }
     }
 
+    private void doKeyguardLaterLocked() {
+        // if the screen turned off because of timeout or the user hit the power button
+        // and we don't need to lock immediately, set an alarm
+        // to enable it a little bit later (i.e, give the user a chance
+        // to turn the screen back on within a certain window without
+        // having to unlock the screen)
+        final ContentResolver cr = mContext.getContentResolver();
+
+        // From DisplaySettings
+        long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
+                KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
+
+        // From SecuritySettings
+        final long lockAfterTimeout = Settings.Secure.getInt(cr,
+                Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+                KEYGUARD_LOCK_AFTER_DELAY_DEFAULT);
+
+        // From DevicePolicyAdmin
+        final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
+                .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
+
+        long timeout;
+        if (policyTimeout > 0) {
+            // policy in effect. Make sure we don't go beyond policy limit.
+            displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
+            timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
+        } else {
+            timeout = lockAfterTimeout;
+        }
+
+        if (timeout <= 0) {
+            // Lock now
+            mSuppressNextLockSound = true;
+            doKeyguardLocked();
+        } else {
+            // Lock in the future
+            long when = SystemClock.elapsedRealtime() + timeout;
+            Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
+            intent.putExtra("seq", mDelayedShowingSequence);
+            PendingIntent sender = PendingIntent.getBroadcast(mContext,
+                    0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
+            if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+                             + mDelayedShowingSequence);
+        }
+    }
+
+    private void cancelDoKeyguardLaterLocked() {
+        mDelayedShowingSequence++;
+    }
+
     /**
      * Let's us know the screen was turned on.
      */
     public void onScreenTurnedOn(KeyguardViewManager.ShowListener showListener) {
         synchronized (this) {
             mScreenOn = true;
-            mDelayedShowingSequence++;
+            cancelDoKeyguardLaterLocked();
             if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
             if (showListener != null) {
                 notifyScreenOnLocked(showListener);
@@ -613,6 +641,29 @@
     }
 
     /**
+     * A dream started.  We should lock after the usual screen-off lock timeout but only
+     * if there is a secure lock pattern.
+     */
+    public void onDreamingStarted() {
+        synchronized (this) {
+            if (mScreenOn && mLockPatternUtils.isSecure()) {
+                doKeyguardLaterLocked();
+            }
+        }
+    }
+
+    /**
+     * A dream stopped.
+     */
+    public void onDreamingStopped() {
+        synchronized (this) {
+            if (mScreenOn) {
+                cancelDoKeyguardLaterLocked();
+            }
+        }
+    }
+
+    /**
      * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide
      * a way for external stuff to override normal keyguard behavior.  For instance
      * the phone app disables the keyguard when it receives incoming calls.
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
index e9ea2c3..47bf85b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
@@ -16,8 +16,6 @@
 package com.android.internal.policy.impl.keyguard;
 
 import android.content.Context;
-import android.os.PowerManager;
-import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -31,7 +29,9 @@
     KeyguardGlowStripView mRightStrip;
     KeyguardWidgetPager mPager;
     private int mPage = 0;
-    private PowerManager mPowerManager;
+    private Callbacks mCallbacks;
+
+    private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
 
     public KeyguardWidgetRegion(Context context) {
         this(context, null, 0);
@@ -43,7 +43,6 @@
 
     public KeyguardWidgetRegion(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
     }
 
     @Override
@@ -75,9 +74,10 @@
     @Override
     public void onPageSwitch(View newPage, int newPageIndex) {
         boolean showingStatusWidget = false;
-        if ((newPage instanceof ViewGroup)) {
+        if (newPage instanceof ViewGroup) {
             ViewGroup vg = (ViewGroup) newPage;
-            if (vg.getChildAt(0) instanceof KeyguardStatusView) {
+            View view = vg.getChildAt(0);
+            if (view instanceof KeyguardStatusView) {
                 showingStatusWidget = true;
             }
         }
@@ -91,8 +91,33 @@
 
         // Extend the display timeout if the user switches pages
         if (mPage != newPageIndex) {
-            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
             mPage = newPageIndex;
+            if (mCallbacks != null) {
+                mCallbacks.onUserActivityTimeoutChanged();
+                mCallbacks.userActivity();
+            }
         }
     }
+
+    public long getUserActivityTimeout() {
+        View page = mPager.getPageAt(mPage);
+        if (page instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) page;
+            View view = vg.getChildAt(0);
+            if (!(view instanceof KeyguardStatusView)
+                    && !(view instanceof KeyguardMultiUserSelectorView)) {
+                return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
+            }
+        }
+        return -1;
+    }
+
+    public void setCallbacks(Callbacks callbacks) {
+        mCallbacks = callbacks;
+    }
+
+    public interface Callbacks {
+        public void userActivity();
+        public void onUserActivityTimeoutChanged();
+    }
 }
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index f80ac18..1c9520d 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -787,6 +787,40 @@
                         event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
                                 + nsecs_t(iev.time.tv_usec) * 1000LL;
                         ALOGV("event time %lld, now %lld", event->when, now);
+
+                        // Bug 7291243: Add a guard in case the kernel generates timestamps
+                        // that appear to be far into the future because they were generated
+                        // using the wrong clock source.
+                        //
+                        // This can happen because when the input device is initially opened
+                        // it has a default clock source of CLOCK_REALTIME.  Any input events
+                        // enqueued right after the device is opened will have timestamps
+                        // generated using CLOCK_REALTIME.  We later set the clock source
+                        // to CLOCK_MONOTONIC but it is already too late.
+                        //
+                        // Invalid input event timestamps can result in ANRs, crashes and
+                        // and other issues that are hard to track down.  We must not let them
+                        // propagate through the system.
+                        //
+                        // Log a warning so that we notice the problem and recover gracefully.
+                        if (event->when >= now + 10 * 1000000000LL) {
+                            // Double-check.  Time may have moved on.
+                            nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
+                            if (event->when > time) {
+                                ALOGW("An input event from %s has a timestamp that appears to "
+                                        "have been generated using the wrong clock source "
+                                        "(expected CLOCK_MONOTONIC): "
+                                        "event time %lld, current time %lld, call time %lld.  "
+                                        "Using current time instead.",
+                                        device->path.string(), event->when, time, now);
+                                event->when = time;
+                            } else {
+                                ALOGV("Event time is ok but failed the fast path and required "
+                                        "an extra call to systemTime: "
+                                        "event time %lld, current time %lld, call time %lld.",
+                                        event->when, time, now);
+                            }
+                        }
 #else
                         event->when = now;
 #endif
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index cebfeb4..bc8df18 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -956,8 +956,9 @@
     size_t numMappers = mMappers.size();
     for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
 #if DEBUG_RAW_EVENTS
-        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x",
-                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value);
+        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
+                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
+                rawEvent->when);
 #endif
 
         if (mDropUntilNextSync) {
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 9be7045..c18fe0e 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -17,34 +17,28 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.widget.RemoteViews;
 
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.widget.IRemoteViewsAdapterConnection;
+import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
@@ -56,85 +50,11 @@
 {
     private static final String TAG = "AppWidgetService";
 
-    /*
-     * When identifying a Host or Provider based on the calling process, use the uid field.
-     * When identifying a Host or Provider based on a package manager broadcast, use the
-     * package given.
-     */
-
-    static class Provider {
-        int uid;
-        AppWidgetProviderInfo info;
-        ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
-        PendingIntent broadcast;
-        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
-        
-        int tag;    // for use while saving state (the index)
-    }
-
-    static class Host {
-        int uid;
-        int hostId;
-        String packageName;
-        ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
-        IAppWidgetHost callbacks;
-        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
-        
-        int tag;    // for use while saving state (the index)
-    }
-
-    static class AppWidgetId {
-        int appWidgetId;
-        Provider provider;
-        RemoteViews views;
-        Host host;
-    }
-
-    /**
-     * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
-     * This needs to be a static inner class since a reference to the ServiceConnection is held
-     * globally and may lead us to leak AppWidgetService instances (if there were more than one).
-     */
-    static class ServiceConnectionProxy implements ServiceConnection {
-        private final IBinder mConnectionCb;
-
-        ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
-            mConnectionCb = connectionCb;
-        }
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            final IRemoteViewsAdapterConnection cb =
-                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
-            try {
-                cb.onServiceConnected(service);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-        public void onServiceDisconnected(ComponentName name) {
-            disconnect();
-        }
-        public void disconnect() {
-            final IRemoteViewsAdapterConnection cb =
-                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
-            try {
-                cb.onServiceDisconnected();
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
     Context mContext;
     Locale mLocale;
     PackageManager mPackageManager;
-    AlarmManager mAlarmManager;
-    ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
-    int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
-    final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
-    ArrayList<Host> mHosts = new ArrayList<Host>();
     boolean mSafeMode;
 
-
     private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
 
     AppWidgetService(Context context) {
@@ -195,9 +115,16 @@
         }, UserHandle.ALL, userFilter, null, null);
     }
 
+    /**
+     * This returns the user id of the caller, if the caller is not the system process,
+     * otherwise it assumes that the calls are from the lockscreen and hence are meant for the
+     * current user. TODO: Instead, have lockscreen make explicit calls with userId
+     */
     private int getCallingOrCurrentUserId() {
         int callingUid = Binder.getCallingUid();
-        if (callingUid == android.os.Process.myUid()) {
+        // Also check the PID because Settings (power control widget) also runs as System UID
+        if (callingUid == android.os.Process.myUid()
+                && Binder.getCallingPid() == android.os.Process.myPid()) {
             try {
                 return ActivityManagerNative.getDefault().getCurrentUser().id;
             } catch (RemoteException re) {
@@ -272,13 +199,16 @@
     }
 
     public void onUserRemoved(int userId) {
-        AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
         if (userId < 1) return;
-
-        if (impl == null) {
-            AppWidgetServiceImpl.getSettingsFile(userId).delete();
-        } else {
-            impl.onUserRemoved();
+        synchronized (mAppWidgetServices) {
+            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+            mAppWidgetServices.remove(userId);
+    
+            if (impl == null) {
+                AppWidgetServiceImpl.getSettingsFile(userId).delete();
+            } else {
+                impl.onUserRemoved();
+            }
         }
     }
 
@@ -286,17 +216,23 @@
     }
 
     private AppWidgetServiceImpl getImplForUser(int userId) {
-        AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
-        if (service == null) {
-            Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
-            // TODO: Verify that it's a valid user
-            service = new AppWidgetServiceImpl(mContext, userId);
-            service.systemReady(mSafeMode);
-            // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
-            service.sendInitialBroadcasts();
-            mAppWidgetServices.append(userId, service);
+        boolean sendInitial = false;
+        AppWidgetServiceImpl service;
+        synchronized (mAppWidgetServices) {
+            service = mAppWidgetServices.get(userId);
+            if (service == null) {
+                Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
+                // TODO: Verify that it's a valid user
+                service = new AppWidgetServiceImpl(mContext, userId);
+                service.systemReady(mSafeMode);
+                // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
+                mAppWidgetServices.append(userId, service);
+                sendInitial = true;
+            }
         }
-
+        if (sendInitial) {
+            service.sendInitialBroadcasts();
+        }
         return service;
     }
 
@@ -325,15 +261,6 @@
         return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
     }
 
-    static int[] getAppWidgetIds(Provider p) {
-        int instancesSize = p.instances.size();
-        int appWidgetIds[] = new int[instancesSize];
-        for (int i=0; i<instancesSize; i++) {
-            appWidgetIds[i] = p.instances.get(i).appWidgetId;
-        }
-        return appWidgetIds;
-    }
-
     @Override
     public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
         return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
@@ -378,9 +305,15 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         // Dump the state of all the app widget providers
-        for (int i = 0; i < mAppWidgetServices.size(); i++) {
-            AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-            service.dump(fd, pw, args);
+        synchronized (mAppWidgetServices) {
+            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+            for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                pw.println("User: " + mAppWidgetServices.keyAt(i));
+                ipw.increaseIndent();
+                AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                service.dump(fd, ipw, args);
+                ipw.decreaseIndent();
+            }
         }
     }
 
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index e77f8cf..41617c8 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -87,6 +87,8 @@
     private static final String SETTINGS_FILENAME = "appwidgets.xml";
     private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
 
+    private static boolean DBG = false;
+
     /*
      * When identifying a Host or Provider based on the calling process, use the uid field. When
      * identifying a Host or Provider based on a package manager broadcast, use the package given.
@@ -208,7 +210,12 @@
         }
     }
 
+    private void log(String msg) {
+        Slog.i(TAG, "u=" + mUserId + ": " + msg);
+    }
+
     void onConfigurationChanged() {
+        if (DBG) log("Got onConfigurationChanged()");
         Locale revised = Locale.getDefault();
         if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
             mLocale = revised;
@@ -235,6 +242,7 @@
     }
 
     void onBroadcastReceived(Intent intent) {
+        if (DBG) log("onBroadcast " + intent);
         final String action = intent.getAction();
         boolean added = false;
         boolean changed = false;
@@ -425,7 +433,8 @@
             mAppWidgetIds.add(id);
 
             saveStateLocked();
-
+            if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
+                    + " id=" + appWidgetId);
             return appWidgetId;
         }
     }
@@ -518,6 +527,7 @@
     }
 
     void cancelBroadcasts(Provider p) {
+        if (DBG) log("cancelBroadcasts for " + p);
         if (p.broadcast != null) {
             mAlarmManager.cancel(p.broadcast);
             long token = Binder.clearCallingIdentity();
@@ -531,6 +541,8 @@
     }
 
     private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) {
+        if (DBG) log("bindAppWidgetIdImpl appwid=" + appWidgetId
+                + " provider=" + provider);
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mAppWidgetIds) {
@@ -825,12 +837,14 @@
     }
 
     public RemoteViews getAppWidgetViews(int appWidgetId) {
+        if (DBG) log("getAppWidgetViews id=" + appWidgetId);
         synchronized (mAppWidgetIds) {
             ensureStateLoadedLocked();
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
             if (id != null) {
                 return cloneIfLocalBinder(id.views);
             }
+            if (DBG) log("   couldn't find appwidgetid");
             return null;
         }
     }
@@ -854,7 +868,7 @@
         if (appWidgetIds == null) {
             return;
         }
-
+        if (DBG) log("updateAppWidgetIds views: " + views);
         int bitmapMemoryUsage = 0;
         if (views != null) {
             bitmapMemoryUsage = views.estimateMemoryUsage();
@@ -1280,8 +1294,8 @@
             intent.setComponent(p.info.provider);
             long token = Binder.clearCallingIdentity();
             try {
-                p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
-                        PendingIntent.FLAG_UPDATE_CURRENT);
+                p.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
+                        PendingIntent.FLAG_UPDATE_CURRENT, new UserHandle(mUserId));
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1353,7 +1367,7 @@
             p.uid = activityInfo.applicationInfo.uid;
 
             Resources res = mContext.getPackageManager()
-                    .getResourcesForApplication(activityInfo.applicationInfo);
+                    .getResourcesForApplicationAsUser(activityInfo.packageName, mUserId);
 
             TypedArray sa = res.obtainAttributes(attrs,
                     com.android.internal.R.styleable.AppWidgetProviderInfo);
@@ -1597,8 +1611,7 @@
 
                         final IPackageManager packageManager = AppGlobals.getPackageManager();
                         try {
-                            packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0,
-                                    UserHandle.getCallingUserId());
+                            packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, mUserId);
                         } catch (RemoteException e) {
                             String[] pkgs = mContext.getPackageManager()
                                     .currentToCanonicalPackageNames(new String[] { pkg });
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 40758d3..dbffa97 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -27,6 +27,7 @@
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.FileUtils;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.DropBoxManager;
 import android.os.RemoteException;
@@ -66,6 +67,14 @@
  * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
  * a degree Centigrade</p>
  * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
+ *
+ * <p>
+ * The battery service may be called by the power manager while holding its locks so
+ * we take care to post all outcalls into the activity manager to a handler.
+ *
+ * FIXME: Ideally the power manager would perform all of its calls into the battery
+ * service asynchronously itself.
+ * </p>
  */
 public final class BatteryService extends Binder {
     private static final String TAG = BatteryService.class.getSimpleName();
@@ -89,6 +98,7 @@
 
     private final Context mContext;
     private final IBatteryStats mBatteryStats;
+    private final Handler mHandler;
 
     private final Object mLock = new Object();
 
@@ -137,6 +147,7 @@
 
     public BatteryService(Context context, LightsService lights) {
         mContext = context;
+        mHandler = new Handler(true /*async*/);
         mLed = new Led(context, lights);
         mBatteryStats = BatteryStatsService.getService();
 
@@ -228,12 +239,18 @@
     private void shutdownIfNoPowerLocked() {
         // shut down gracefully if our battery is critically low and we are not powered.
         // wait until the system has booted before attempting to display the shutdown dialog.
-        if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
-                && ActivityManagerNative.isSystemReady()) {
-            Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
-            intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (ActivityManagerNative.isSystemReady()) {
+                        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+                        intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                    }
+                }
+            });
         }
     }
 
@@ -241,12 +258,18 @@
         // shut down gracefully if temperature is too high (> 68.0C by default)
         // wait until the system has booted before attempting to display the
         // shutdown dialog.
-        if (mBatteryTemperature > mShutdownBatteryTemperature
-                && ActivityManagerNative.isSystemReady()) {
-            Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
-            intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        if (mBatteryTemperature > mShutdownBatteryTemperature) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (ActivityManagerNative.isSystemReady()) {
+                        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+                        intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                    }
+                }
+            });
         }
     }
 
@@ -373,25 +396,47 @@
             // Separate broadcast is sent for power connected / not connected
             // since the standard intent will not wake any applications and some
             // applications may want to have smart behavior based on this.
-            Intent statusIntent = new Intent();
-            statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             if (mPlugType != 0 && mLastPlugType == 0) {
-                statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
-                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
+                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                    }
+                });
             }
             else if (mPlugType == 0 && mLastPlugType != 0) {
-                statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
-                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
+                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                    }
+                });
             }
 
             if (sendBatteryLow) {
                 mSentLowBatteryBroadcast = true;
-                statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
-                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
+                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                    }
+                });
             } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
                 mSentLowBatteryBroadcast = false;
-                statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
-                mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
+                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+                    }
+                });
             }
 
             // Update the battery LED
@@ -416,7 +461,7 @@
 
     private void sendIntentLocked() {
         //  Pack up the values and broadcast them to everyone
-        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+        final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
 
@@ -446,7 +491,12 @@
                     ", icon:" + icon  + ", invalid charger:" + mInvalidCharger);
         }
 
-        ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+            }
+        });
     }
 
     private void logBatteryStatsLocked() {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 22fd508..e4998e11 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -2531,7 +2531,7 @@
         if (!TextUtils.isEmpty(inputMethodId)) {
             intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
         }
-        mContext.startActivity(intent);
+        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
     }
 
     private void showConfigureInputMethods() {
@@ -2539,7 +2539,7 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        mContext.startActivity(intent);
+        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
     }
 
     private boolean isScreenLocked() {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 8d6c604..85b488c 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -1029,11 +1029,20 @@
                 }
             }
 
+            final int currentUser;
+            final long token = Binder.clearCallingIdentity();
+            try {
+                currentUser = ActivityManager.getCurrentUser();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
             // If we're not supposed to beep, vibrate, etc. then don't.
             if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
                     && (!(old != null
                         && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
-                    && (r.userId == UserHandle.USER_ALL || r.userId == userId)
+                    && (r.userId == UserHandle.USER_ALL ||
+                        (r.userId == userId && r.userId == currentUser))
                     && mSystemReady) {
 
                 final AudioManager audioManager = (AudioManager) mContext
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index d1af2b0..e9e3163 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -37,6 +37,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.DreamService;
@@ -90,6 +91,8 @@
     private NotificationManager mNotificationManager;
 
     private StatusBarManager mStatusBarManager;
+
+    private final PowerManager mPowerManager;
     private final PowerManager.WakeLock mWakeLock;
 
     static Intent buildHomeIntent(String category) {
@@ -163,8 +166,8 @@
         mContext.registerReceiver(mBatteryReceiver,
                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
 
-        PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
 
         mConfiguration.setToDefaults();
 
@@ -502,7 +505,17 @@
             try {
                 IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
                         ServiceManager.getService(DreamService.DREAM_SERVICE));
-                dreamManagerService.dream();
+                if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
+                    // Wake up.
+                    // The power manager will wake up the system when it starts receiving power
+                    // but there is a race between that happening and the UI mode manager
+                    // starting a dream.  We want the system to already be awake
+                    // by the time this happens.  Otherwise the dream may not start.
+                    mPowerManager.wakeUp(SystemClock.uptimeMillis());
+
+                    // Dream.
+                    dreamManagerService.dream();
+                }
             } catch (RemoteException ex) {
                 Slog.e(TAG, "Could not start dream when docked.", ex);
             }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 98f561c..e0f3814 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -99,6 +99,13 @@
     static final String WALLPAPER_INFO = "wallpaper_info.xml";
 
     /**
+     * Name of the component used to display bitmap wallpapers from either the gallery or
+     * built-in wallpapers.
+     */
+    static final ComponentName IMAGE_WALLPAPER = new ComponentName("com.android.systemui",
+            "com.android.systemui.ImageWallpaper");
+
+    /**
      * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
      * that the wallpaper has changed. The CREATE is triggered when there is no
      * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
@@ -138,7 +145,7 @@
                         if (event == CLOSE_WRITE) {
                             mWallpaper.imageWallpaperPending = false;
                         }
-                        bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
+                        bindWallpaperComponentLocked(IMAGE_WALLPAPER, true,
                                 false, mWallpaper, null);
                         saveSettingsLocked(mWallpaper);
                     }
@@ -183,13 +190,6 @@
          */
         ComponentName nextWallpaperComponent;
 
-        /**
-         * Name of the component used to display bitmap wallpapers from either the gallery or
-         * built-in wallpapers.
-         */
-        ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
-                "com.android.systemui.ImageWallpaper");
-
         WallpaperConnection connection;
         long lastDiedTime;
         boolean wallpaperUpdating;
@@ -559,7 +559,7 @@
             wallpaper.imageWallpaperPending = false;
             if (userId != mCurrentUserId) return;
             if (bindWallpaperComponentLocked(defaultFailed
-                    ? wallpaper.imageWallpaperComponent
+                    ? IMAGE_WALLPAPER
                     : null, true, false, wallpaper, reply)) {
                 return;
             }
@@ -792,7 +792,7 @@
                 }
                 if (componentName == null) {
                     // Fall back to static image wallpaper
-                    componentName = wallpaper.imageWallpaperComponent;
+                    componentName = IMAGE_WALLPAPER;
                     //clearWallpaperComponentLocked();
                     //return;
                     if (DEBUG) Slog.v(TAG, "Using image wallpaper");
@@ -815,7 +815,7 @@
             WallpaperInfo wi = null;
             
             Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
-            if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
+            if (componentName != null && !componentName.equals(IMAGE_WALLPAPER)) {
                 // Make sure the selected service is actually a wallpaper service.
                 List<ResolveInfo> ris =
                         mIPackageManager.queryIntentServices(intent,
@@ -990,7 +990,7 @@
             out.attribute(null, "height", Integer.toString(wallpaper.height));
             out.attribute(null, "name", wallpaper.name);
             if (wallpaper.wallpaperComponent != null
-                    && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+                    && !wallpaper.wallpaperComponent.equals(IMAGE_WALLPAPER)) {
                 out.attribute(null, "component",
                         wallpaper.wallpaperComponent.flattenToShortString());
             }
@@ -1062,7 +1062,7 @@
                         if (wallpaper.nextWallpaperComponent == null
                                 || "android".equals(wallpaper.nextWallpaperComponent
                                         .getPackageName())) {
-                            wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
+                            wallpaper.nextWallpaperComponent = IMAGE_WALLPAPER;
                         }
                           
                         if (DEBUG) {
@@ -1124,7 +1124,7 @@
             loadSettingsLocked(0);
             wallpaper = mWallpaperMap.get(0);
             if (wallpaper.nextWallpaperComponent != null
-                    && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+                    && !wallpaper.nextWallpaperComponent.equals(IMAGE_WALLPAPER)) {
                 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
                         wallpaper, null)) {
                     // No such live wallpaper or other failure; fall back to the default
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5e9e223..6782f5e 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -643,6 +643,10 @@
         return mSecurityPolicy.mActiveWindowId;
     }
 
+    void onTouchInteractionEnd() {
+        mSecurityPolicy.onTouchInteractionEnd();
+    }
+
     private void switchUser(int userId) {
         synchronized (mLock) {
             // The user switched so we do not need to restore the current user
@@ -2178,16 +2182,24 @@
                         mActiveWindowId = windowId;
                     }
                 } break;
-                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
-                case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+                case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
                     mActiveWindowId = windowId;
                 } break;
-                case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: {
-                    mActiveWindowId = getFocusedWindowId();
-                } break;
             }
         }
 
+        public void onTouchInteractionEnd() {
+            // We want to set the active window to be current immediately
+            // after the user has stopped touching the screen since if the
+            // user types with the IME he should get a feedback for the
+            // letter typed in the text view which is in the input focused
+            // window. Note that we always deliver hover accessibility events
+            // (they are a result of user touching the screen) so change of
+            // the active window before all hover accessibility events from
+            // the touched window are delivered is fine.
+            mActiveWindowId = getFocusedWindowId();
+        }
+
         public int getRetrievalAllowingWindowLocked() {
             return mActiveWindowId;
         }
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index 14762a1..51ccd47 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -846,7 +846,6 @@
     private static final class DisplayContentObserver {
 
         private static final int MESSAGE_SHOW_VIEWPORT_FRAME = 1;
-        private static final int MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS = 2;
         private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3;
         private static final int MESSAGE_ON_WINDOW_TRANSITION = 4;
         private static final int MESSAGE_ON_ROTATION_CHANGED = 5;
@@ -892,7 +891,9 @@
                                 || info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
                             && (transition == WindowManagerPolicy.TRANSIT_EXIT
                                 || transition == WindowManagerPolicy.TRANSIT_HIDE)) {
-                        mHandler.sendMessageDelayed(message, mLongAnimationDuration);
+                        final long delay = (long) (2 * mLongAnimationDuration
+                                * mWindowAnimationScale);
+                        mHandler.sendMessageDelayed(message, delay);
                     } else {
                         message.sendToTarget();
                     }
@@ -1009,7 +1010,8 @@
                                 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
                                 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
                                 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
-                                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
+                                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
+                                case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
                                     Rect magnifiedRegionBounds = mMagnificationController
                                             .getMagnifiedRegionBounds();
                                     Rect touchableRegion = info.touchableRegion;
@@ -1169,10 +1171,6 @@
                     case MESSAGE_SHOW_VIEWPORT_FRAME: {
                         mViewport.setFrameShown(true, true);
                     } break;
-                    case MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS: {
-                        final boolean animate = message.arg1 == 1;
-                        mViewport.recomputeBounds(animate);
-                    } break;
                     case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
                         SomeArgs args = (SomeArgs) message.obj;
                         try {
@@ -1525,8 +1523,10 @@
             Rect magnifiedFrame = mTempRect1;
             magnifiedFrame.set(0, 0, 0, 0);
 
-            Rect notMagnifiedFrame = mTempRect2;
-            notMagnifiedFrame.set(0, 0, 0, 0);
+            DisplayInfo displayInfo = mDisplayProvider.getDisplayInfo();
+
+            Rect availableFrame = mTempRect2;
+            availableFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
 
             ArrayList<WindowInfo> infos = mTempWindowInfoList;
             infos.clear();
@@ -1541,18 +1541,16 @@
                     if (info.type == WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
                         continue;
                     }
+                    Rect windowFrame = mTempRect3;
+                    windowFrame.set(info.touchableRegion);
                     if (isWindowMagnified(info.type)) {
-                        Rect clippedFrame = mTempRect3;
-                        clippedFrame.set(info.touchableRegion);
-                        subtract(clippedFrame, notMagnifiedFrame);
-                        magnifiedFrame.union(clippedFrame);
+                        magnifiedFrame.union(windowFrame);
+                        magnifiedFrame.intersect(availableFrame);
                     } else {
-                        Rect clippedFrame = mTempRect3;
-                        clippedFrame.set(info.touchableRegion);
-                        subtract(clippedFrame, magnifiedFrame);
-                        notMagnifiedFrame.union(clippedFrame);
+                        subtract(windowFrame, magnifiedFrame);
+                        subtract(availableFrame, windowFrame);
                     }
-                    if (magnifiedFrame.bottom >= notMagnifiedFrame.top) {
+                    if (availableFrame.equals(magnifiedFrame)) {
                         break;
                     }
                 }
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index b3bf6fe..2688776 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -304,6 +304,7 @@
             mNext.clear();
         }
         mTouchExplorationInProgress = false;
+        mAms.onTouchInteractionEnd();
     }
 
     @Override
@@ -615,6 +616,7 @@
                 }
             } break;
             case MotionEvent.ACTION_UP:
+                mAms.onTouchInteractionEnd();
                 // We know that we do not need the pre-fed gesture points are not
                 // needed anymore since the last pointer just went up.
                 mStrokeBuffer.clear();
@@ -737,6 +739,7 @@
                  }
             } break;
             case MotionEvent.ACTION_UP: {
+                mAms.onTouchInteractionEnd();
                 // Announce the end of a new touch interaction.
                 sendAccessibilityEvent(
                         AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
@@ -782,6 +785,7 @@
                         AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
                 //$FALL-THROUGH$
             case MotionEvent.ACTION_POINTER_UP: {
+                mAms.onTouchInteractionEnd();
                 mLongPressingPointerId = -1;
                 mLongPressingPointerDeltaX = 0;
                 mLongPressingPointerDeltaY = 0;
@@ -819,6 +823,7 @@
                 }
             } break;
             case MotionEvent.ACTION_UP: {
+                mAms.onTouchInteractionEnd();
                 // Announce the end of gesture recognition.
                 sendAccessibilityEvent(
                         AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index b9f9df7..a1c1fa6 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -89,6 +89,9 @@
     // auto-brightness adjustment setting.
     private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
 
+    // The minimum reduction in brightness when dimmed.
+    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
+
     // If true, enables the use of the current time as an auto-brightness adjustment.
     // The basic idea here is to expand the dynamic range of auto-brightness
     // when it is especially dark outside.  The light sensor tends to perform
@@ -185,6 +188,12 @@
     // The dim screen brightness.
     private final int mScreenBrightnessDimConfig;
 
+    // The minimum allowed brightness.
+    private final int mScreenBrightnessRangeMinimum;
+
+    // The maximum allowed brightness.
+    private final int mScreenBrightnessRangeMaximum;
+
     // True if auto-brightness should be used.
     private boolean mUseSoftwareAutoBrightnessConfig;
 
@@ -343,8 +352,14 @@
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
 
         final Resources resources = context.getResources();
-        mScreenBrightnessDimConfig = resources.getInteger(
-                com.android.internal.R.integer.config_screenBrightnessDim);
+
+        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
+                com.android.internal.R.integer.config_screenBrightnessDim));
+
+        int screenBrightnessMinimum = Math.min(resources.getInteger(
+                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
+                mScreenBrightnessDimConfig);
+
         mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_automatic_brightness_available);
         if (mUseSoftwareAutoBrightnessConfig) {
@@ -362,12 +377,19 @@
                         + "which must be strictly increasing.  "
                         + "Auto-brightness will be disabled.");
                 mUseSoftwareAutoBrightnessConfig = false;
+            } else {
+                if (screenBrightness[0] < screenBrightnessMinimum) {
+                    screenBrightnessMinimum = screenBrightness[0];
+                }
             }
 
             mLightSensorWarmUpTimeConfig = resources.getInteger(
                     com.android.internal.R.integer.config_lightSensorWarmupTime);
         }
 
+        mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
+        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
+
         mElectronBeamAnimatesBacklightConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_animateScreenLights);
 
@@ -394,14 +416,14 @@
             final int n = brightness.length;
             float[] x = new float[n];
             float[] y = new float[n];
-            y[0] = (float)brightness[0] / PowerManager.BRIGHTNESS_ON;
+            y[0] = normalizeAbsoluteBrightness(brightness[0]);
             for (int i = 1; i < n; i++) {
                 x[i] = lux[i - 1];
-                y[i] = (float)brightness[i] / PowerManager.BRIGHTNESS_ON;
+                y[i] = normalizeAbsoluteBrightness(brightness[i]);
             }
 
             Spline spline = Spline.createMonotoneCubicSpline(x, y);
-            if (false) {
+            if (DEBUG) {
                 Slog.d(TAG, "Auto-brightness spline: " + spline);
                 for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
                     Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
@@ -531,6 +553,7 @@
         final boolean mustNotify;
         boolean mustInitialize = false;
         boolean updateAutoBrightness = mTwilightChanged;
+        boolean screenOnWasBlocked = false;
         mTwilightChanged = false;
 
         synchronized (mLock) {
@@ -588,7 +611,6 @@
             if (mScreenOffBecauseOfProximity
                     && mProximity != PROXIMITY_POSITIVE) {
                 mScreenOffBecauseOfProximity = false;
-                setScreenOn(true);
                 sendOnProximityNegative();
             }
         } else {
@@ -602,30 +624,31 @@
         }
 
         // Set the screen brightness.
-        if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
-            // Screen is dimmed.  Overrides everything else.
-            animateScreenBrightness(
-                    clampScreenBrightness(mScreenBrightnessDimConfig),
-                    BRIGHTNESS_RAMP_RATE_FAST);
-            mUsingScreenAutoBrightness = false;
-        } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) {
+        if (wantScreenOn(mPowerRequest.screenState)) {
+            int target;
+            boolean slow;
             if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
                 // Use current auto-brightness value.
-                animateScreenBrightness(
-                        clampScreenBrightness(mScreenAutoBrightness),
-                        mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW :
-                                BRIGHTNESS_RAMP_RATE_FAST);
+                target = mScreenAutoBrightness;
+                slow = mUsingScreenAutoBrightness;
                 mUsingScreenAutoBrightness = true;
             } else {
                 // Light sensor is disabled or not ready yet.
                 // Use the current brightness setting from the request, which is expected
                 // provide a nominal default value for the case where auto-brightness
                 // is not ready yet.
-                animateScreenBrightness(
-                        clampScreenBrightness(mPowerRequest.screenBrightness),
-                        BRIGHTNESS_RAMP_RATE_FAST);
+                target = mPowerRequest.screenBrightness;
+                slow = false;
                 mUsingScreenAutoBrightness = false;
             }
+            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+                // Screen is dimmed.  Sets an upper bound on everything else.
+                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
+                        mScreenBrightnessDimConfig);
+                slow = false;
+            }
+            animateScreenBrightness(clampScreenBrightness(target),
+                    slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
         } else {
             // Screen is off.  Don't bother changing the brightness.
             mUsingScreenAutoBrightness = false;
@@ -639,20 +662,43 @@
                 // It is relatively short but if we cancel it and switch to the
                 // on animation immediately then the results are pretty ugly.
                 if (!mElectronBeamOffAnimator.isStarted()) {
-                    setScreenOn(true);
-                    if (USE_ELECTRON_BEAM_ON_ANIMATION) {
-                        if (!mElectronBeamOnAnimator.isStarted()) {
-                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
-                                mPowerState.dismissElectronBeam();
-                            } else if (mPowerState.prepareElectronBeam(true)) {
-                                mElectronBeamOnAnimator.start();
-                            } else {
-                                mElectronBeamOnAnimator.end();
-                            }
+                    if (mPowerRequest.blockScreenOn && !mPowerState.isScreenOn()) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Blocked screen on while screen currently off.");
                         }
+                        screenOnWasBlocked = true;
                     } else {
-                        mPowerState.setElectronBeamLevel(1.0f);
-                        mPowerState.dismissElectronBeam();
+                        setScreenOn(true);
+                        if (USE_ELECTRON_BEAM_ON_ANIMATION) {
+                            if (!mElectronBeamOnAnimator.isStarted()) {
+                                if (mPowerState.getElectronBeamLevel() == 1.0f) {
+                                    mPowerState.dismissElectronBeam();
+                                } else if (mPowerState.prepareElectronBeam(true)) {
+                                    mElectronBeamOnAnimator.start();
+                                } else {
+                                    mElectronBeamOnAnimator.end();
+                                }
+                            }
+                        } else {
+                            mPowerState.setElectronBeamLevel(1.0f);
+                            mPowerState.dismissElectronBeam();
+                        }
+                    }
+                } else {
+                    // FIXME: If the electron beam off animation is playing then we have a bit
+                    // of a problem.  The window manager policy would only have requested
+                    // to block screen on if it was about to start preparing the keyguard.
+                    // It's already too late to do anything about that.  Ideally we would
+                    // let the animation play out first but that would require making
+                    // some pretty deep changes to the power manager and we don't have
+                    // time just now.  For now, short-circuit the animation and get ready.
+                    if (mPowerRequest.blockScreenOn) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Blocked screen on while screen off animation running.");
+                        }
+                        screenOnWasBlocked = true;
+                        setScreenOn(false);
+                        mElectronBeamOffAnimator.end();
                     }
                 }
             } else {
@@ -677,12 +723,17 @@
         // We mostly care about the screen state here, ignoring brightness changes
         // which will be handled asynchronously.
         if (mustNotify
+                && !screenOnWasBlocked
                 && !mElectronBeamOnAnimator.isStarted()
                 && !mElectronBeamOffAnimator.isStarted()
                 && mPowerState.waitUntilClean(mCleanListener)) {
             synchronized (mLock) {
                 if (!mPendingRequestChangedLocked) {
                     mDisplayReadyLocked = true;
+
+                    if (DEBUG) {
+                        Slog.d(TAG, "Display ready!");
+                    }
                 }
             }
             sendOnStateChanged();
@@ -701,7 +752,25 @@
     }
 
     private int clampScreenBrightness(int value) {
-        return Math.min(Math.max(Math.max(value, mScreenBrightnessDimConfig), 0), 255);
+        return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
+    }
+
+    private static int clampAbsoluteBrightness(int value) {
+        return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
+    }
+
+    private static int clamp(int value, int min, int max) {
+        if (value <= min) {
+            return min;
+        }
+        if (value >= max) {
+            return max;
+        }
+        return value;
+    }
+
+    private static float normalizeAbsoluteBrightness(int value) {
+        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
     }
 
     private void animateScreenBrightness(int target, int rate) {
@@ -1027,6 +1096,8 @@
         pw.println();
         pw.println("Display Controller Configuration:");
         pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
+        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
+        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
         pw.println("  mUseSoftwareAutoBrightnessConfig="
                 + mUseSoftwareAutoBrightnessConfig);
         pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
index 2d74292..5f94414 100644
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -52,12 +52,20 @@
     // If true, enables automatic brightness control.
     public boolean useAutoBrightness;
 
+    // If true, prevents the screen from turning on if it is currently off.
+    // The display does not enter a "ready" state if this flag is true and the screen
+    // is off and is being prevented from turning on.  The window manager policy blocks
+    // screen on while it prepares the keyguard to prevent the user from seeing
+    // intermediate updates.
+    public boolean blockScreenOn;
+
     public DisplayPowerRequest() {
         screenState = SCREEN_STATE_BRIGHT;
         useProximitySensor = false;
         screenBrightness = PowerManager.BRIGHTNESS_ON;
         screenAutoBrightnessAdjustment = 0.0f;
         useAutoBrightness = false;
+        blockScreenOn = false;
     }
 
     public DisplayPowerRequest(DisplayPowerRequest other) {
@@ -70,6 +78,7 @@
         screenBrightness = other.screenBrightness;
         screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
         useAutoBrightness = other.useAutoBrightness;
+        blockScreenOn = other.blockScreenOn;
     }
 
     @Override
@@ -84,7 +93,8 @@
                 && useProximitySensor == other.useProximitySensor
                 && screenBrightness == other.screenBrightness
                 && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
-                && useAutoBrightness == other.useAutoBrightness;
+                && useAutoBrightness == other.useAutoBrightness
+                && blockScreenOn == other.blockScreenOn;
     }
 
     @Override
@@ -98,6 +108,7 @@
                 + ", useProximitySensor=" + useProximitySensor
                 + ", screenBrightness=" + screenBrightness
                 + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
-                + ", useAutoBrightness=" + useAutoBrightness;
+                + ", useAutoBrightness=" + useAutoBrightness
+                + ", blockScreenOn=" + blockScreenOn;
     }
 }
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index 3042124..5e05693 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -35,7 +35,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.ScreenOnListener;
 
 /**
  * Sends broadcasts about important power state changes.
@@ -71,8 +70,8 @@
     private final Context mContext;
     private final IBatteryStats mBatteryStats;
     private final SuspendBlocker mSuspendBlocker;
+    private final ScreenOnBlocker mScreenOnBlocker;
     private final WindowManagerPolicy mPolicy;
-    private final ScreenOnListener mScreenOnListener;
 
     private final NotifierHandler mHandler;
     private final Intent mScreenOnIntent;
@@ -95,14 +94,17 @@
     // True if a user activity message should be sent.
     private boolean mUserActivityPending;
 
+    // True if the screen on blocker has been acquired.
+    private boolean mScreenOnBlockerAcquired;
+
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
-            SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-            ScreenOnListener screenOnListener) {
+            SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
+            WindowManagerPolicy policy) {
         mContext = context;
         mBatteryStats = batteryStats;
         mSuspendBlocker = suspendBlocker;
+        mScreenOnBlocker = screenOnBlocker;
         mPolicy = policy;
-        mScreenOnListener = screenOnListener;
 
         mHandler = new NotifierHandler(looper);
         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -227,6 +229,10 @@
             if (mActualPowerState != POWER_STATE_AWAKE) {
                 mActualPowerState = POWER_STATE_AWAKE;
                 mPendingWakeUpBroadcast = true;
+                if (!mScreenOnBlockerAcquired) {
+                    mScreenOnBlockerAcquired = true;
+                    mScreenOnBlocker.acquire();
+                }
                 updatePendingBroadcastLocked();
             }
         }
@@ -387,6 +393,7 @@
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
 
         mPolicy.screenTurningOn(mScreenOnListener);
+
         try {
             ActivityManagerNative.getDefault().wakingUp();
         } catch (RemoteException e) {
@@ -402,6 +409,19 @@
         }
     }
 
+    private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
+            new WindowManagerPolicy.ScreenOnListener() {
+        @Override
+        public void onScreenOn() {
+            synchronized (mLock) {
+                if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
+                    mScreenOnBlockerAcquired = false;
+                    mScreenOnBlocker.release();
+                }
+            }
+        }
+    };
+
     private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index ae7b2d1..abbae5b 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -79,6 +79,8 @@
     private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
     // Message: Sent when the device enters or exits a napping or dreaming state.
     private static final int MSG_SANDMAN = 2;
+    // Message: Sent when the screen on blocker is released.
+    private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
 
     // Dirty bit: mWakeLocks changed
     private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -100,6 +102,8 @@
     private static final int DIRTY_BATTERY_STATE = 1 << 8;
     // Dirty bit: proximity state changed
     private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
+    // Dirty bit: screen on blocker state became held or unheld
+    private static final int DIRTY_SCREEN_ON_BLOCKER_RELEASED = 1 << 10;
 
     // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
     // The screen should be off or in the process of being turned off by the display controller.
@@ -222,6 +226,10 @@
     // The suspend blocker used to keep the CPU alive when wake locks have been acquired.
     private final SuspendBlocker mWakeLockSuspendBlocker;
 
+    // The screen on blocker used to keep the screen from turning on while the lock
+    // screen is coming up.
+    private final ScreenOnBlockerImpl mScreenOnBlocker;
+
     // True if systemReady() has been called.
     private boolean mSystemReady;
 
@@ -318,6 +326,7 @@
         synchronized (mLock) {
             mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService");
             mWakeLockSuspendBlocker.acquire();
+            mScreenOnBlocker = new ScreenOnBlockerImpl();
             mHoldingWakeLockSuspendBlocker = true;
             mWakefulness = WAKEFULNESS_AWAKE;
         }
@@ -368,9 +377,14 @@
             mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
             mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
 
-            mNotifier = new Notifier(mHandler.getLooper(), mContext, mBatteryStats,
+            // The notifier runs on the system server's main looper so as not to interfere
+            // with the animations and other critical functions of the power manager.
+            mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
                     createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
-                    mPolicy, mScreenOnListener);
+                    mScreenOnBlocker, mPolicy);
+
+            // The display power controller runs on the power manager service's
+            // own handler thread.
             mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
                     mContext, mNotifier, mLightsService, twilight,
                     createSuspendBlockerLocked("PowerManagerService.Display"),
@@ -1064,41 +1078,51 @@
     }
 
     private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(boolean wasPowered, int oldPlugType) {
-        if (mWakeUpWhenPluggedOrUnpluggedConfig) {
-            // FIXME: Need more accurate detection of wireless chargers.
-            //
-            // We are unable to accurately detect whether the device is resting on the
-            // charger unless it is actually receiving power.  This causes us some grief
-            // because the device might not appear to be plugged into the wireless charger
-            // unless it actually charging.
-            //
-            // To avoid spuriously waking the screen, we apply a special policy to
-            // wireless chargers.
-            //
-            // 1. Don't wake the device when unplugged from wireless charger because
-            //    it might be that the device is still resting on the wireless charger
-            //    but is not receiving power anymore because the battery is full.
-            //
-            // 2. Don't wake the device when plugged into a wireless charger if the
-            //    battery already appears to be mostly full.  This situation may indicate
-            //    that the device was resting on the charger the whole time and simply
-            //    wasn't receiving power because the battery was full.  We can't tell
-            //    whether the device was just placed on the charger or whether it has
-            //    been there for half of the night slowly discharging until it hit
-            //    the point where it needed to start charging again.
-            if (wasPowered && !mIsPowered
-                    && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
-                return false;
-            }
-            if (!wasPowered && mIsPowered
-                    && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
-                    && mBatteryService.getBatteryLevel() >=
-                            WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
-                return false;
-            }
-            return true;
+        // Don't wake when powered unless configured to do so.
+        if (!mWakeUpWhenPluggedOrUnpluggedConfig) {
+            return false;
         }
-        return false;
+
+        // FIXME: Need more accurate detection of wireless chargers.
+        //
+        // We are unable to accurately detect whether the device is resting on the
+        // charger unless it is actually receiving power.  This causes us some grief
+        // because the device might not appear to be plugged into the wireless charger
+        // unless it actually charging.
+        //
+        // To avoid spuriously waking the screen, we apply a special policy to
+        // wireless chargers.
+        //
+        // 1. Don't wake the device when unplugged from wireless charger because
+        //    it might be that the device is still resting on the wireless charger
+        //    but is not receiving power anymore because the battery is full.
+        //
+        // 2. Don't wake the device when plugged into a wireless charger if the
+        //    battery already appears to be mostly full.  This situation may indicate
+        //    that the device was resting on the charger the whole time and simply
+        //    wasn't receiving power because the battery was full.  We can't tell
+        //    whether the device was just placed on the charger or whether it has
+        //    been there for half of the night slowly discharging until it hit
+        //    the point where it needed to start charging again.
+        if (wasPowered && !mIsPowered
+                && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
+            return false;
+        }
+        if (!wasPowered && mIsPowered
+                && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
+                && mBatteryService.getBatteryLevel() >=
+                        WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
+            return false;
+        }
+
+        // If already dreaming and becoming powered, then don't wake.
+        if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
+                || mWakefulness == WAKEFULNESS_DREAMING)) {
+            return false;
+        }
+
+        // Otherwise wake up!
+        return true;
     }
 
     /**
@@ -1433,6 +1457,13 @@
         }
     }
 
+    private void handleScreenOnBlockerReleased() {
+        synchronized (mLock) {
+            mDirty |= DIRTY_SCREEN_ON_BLOCKER_RELEASED;
+            updatePowerStateLocked();
+        }
+    }
+
     /**
      * Updates the display power state asynchronously.
      * When the update is finished, mDisplayReady will be set to true.  The display
@@ -1444,8 +1475,8 @@
     private void updateDisplayPowerStateLocked(int dirty) {
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
-                | DIRTY_SETTINGS)) != 0) {
-            int newScreenState = getDesiredScreenPowerState();
+                | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
+            int newScreenState = getDesiredScreenPowerStateLocked();
             if (newScreenState != mDisplayPowerRequest.screenState) {
                 if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF
                         && mDisplayPowerRequest.screenState
@@ -1493,12 +1524,14 @@
 
             mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
 
+            mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
+
             mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest,
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
 
             if (DEBUG_SPEW) {
-                Slog.d(TAG, "updateScreenStateLocked: displayReady=" + mDisplayReady
+                Slog.d(TAG, "updateScreenStateLocked: mDisplayReady=" + mDisplayReady
                         + ", newScreenState=" + newScreenState
                         + ", mWakefulness=" + mWakefulness
                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
@@ -1517,7 +1550,7 @@
         return value >= -1.0f && value <= 1.0f;
     }
 
-    private int getDesiredScreenPowerState() {
+    private int getDesiredScreenPowerStateLocked() {
         if (mWakefulness == WAKEFULNESS_ASLEEP) {
             return DisplayPowerRequest.SCREEN_STATE_OFF;
         }
@@ -2070,6 +2103,9 @@
                 pw.println("  " + sb);
             }
 
+            pw.println();
+            pw.println("Screen On Blocker: " + mScreenOnBlocker);
+
             dpc = mDisplayPowerController;
         }
 
@@ -2152,13 +2188,6 @@
         }
     }
 
-    private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
-            new WindowManagerPolicy.ScreenOnListener() {
-        @Override
-        public void onScreenOn() {
-        }
-    };
-
     /**
      * Handler for asynchronous operations performed by the power manager.
      */
@@ -2176,6 +2205,9 @@
                 case MSG_SANDMAN:
                     handleSandman();
                     break;
+                case MSG_SCREEN_ON_BLOCKER_RELEASED:
+                    handleScreenOnBlockerReleased();
+                    break;
             }
         }
     }
@@ -2321,4 +2353,49 @@
             }
         }
     }
+
+    private final class ScreenOnBlockerImpl implements ScreenOnBlocker {
+        private int mNestCount;
+
+        public boolean isHeld() {
+            synchronized (this) {
+                return mNestCount != 0;
+            }
+        }
+
+        @Override
+        public void acquire() {
+            synchronized (this) {
+                mNestCount += 1;
+                if (DEBUG) {
+                    Slog.d(TAG, "Screen on blocked: mNestCount=" + mNestCount);
+                }
+            }
+        }
+
+        @Override
+        public void release() {
+            synchronized (this) {
+                mNestCount -= 1;
+                if (mNestCount < 0) {
+                    Log.wtf(TAG, "Screen on blocker was released without being acquired!",
+                            new Throwable());
+                    mNestCount = 0;
+                }
+                if (mNestCount == 0) {
+                    mHandler.sendEmptyMessage(MSG_SCREEN_ON_BLOCKER_RELEASED);
+                }
+                if (DEBUG) {
+                    Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            synchronized (this) {
+                return "held=" + (mNestCount != 0) + ", mNestCount=" + mNestCount;
+            }
+        }
+    };
 }
diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/java/com/android/server/power/ScreenOnBlocker.java
new file mode 100644
index 0000000..2bf0bcf
--- /dev/null
+++ b/services/java/com/android/server/power/ScreenOnBlocker.java
@@ -0,0 +1,41 @@
+/*
+ * 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.server.power;
+
+/**
+ * Low-level screen on blocker mechanism which is used to keep the screen off
+ * until the window manager is ready to show new content.
+ */
+interface ScreenOnBlocker {
+    /**
+     * Acquires the screen on blocker.
+     * Prevents the screen from turning on.
+     *
+     * Calls to acquire() nest and must be matched by the same number
+     * of calls to release().
+     */
+    void acquire();
+
+    /**
+     * Releases the screen on blocker.
+     * Allows the screen to turn on.
+     *
+     * It is an error to call release() if the screen on blocker has not been acquired.
+     * The system may crash.
+     */
+    void release();
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 8cc3d61..545d1a9 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
@@ -2083,6 +2084,7 @@
         WindowState attachedWindow = null;
         WindowState win = null;
         long origId;
+        final int type = attrs.type;
 
         synchronized(mWindowMap) {
             if (!mDisplayReady) {
@@ -2094,7 +2096,7 @@
                 return WindowManagerGlobal.ADD_DUPLICATE_ADD;
             }
 
-            if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
+            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                 attachedWindow = windowForClientLocked(null, attrs.token, false);
                 if (attachedWindow == null) {
                     Slog.w(TAG, "Attempted to add window with token that is not a window: "
@@ -2112,31 +2114,29 @@
             boolean addToken = false;
             WindowToken token = mTokenMap.get(attrs.token);
             if (token == null) {
-                if (attrs.type >= FIRST_APPLICATION_WINDOW
-                        && attrs.type <= LAST_APPLICATION_WINDOW) {
+                if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                     Slog.w(TAG, "Attempted to add application window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (attrs.type == TYPE_INPUT_METHOD) {
+                if (type == TYPE_INPUT_METHOD) {
                     Slog.w(TAG, "Attempted to add input method window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (attrs.type == TYPE_WALLPAPER) {
+                if (type == TYPE_WALLPAPER) {
                     Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (attrs.type == TYPE_DREAM) {
+                if (type == TYPE_DREAM) {
                     Slog.w(TAG, "Attempted to add Dream window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 token = new WindowToken(this, attrs.token, -1, false);
                 addToken = true;
-            } else if (attrs.type >= FIRST_APPLICATION_WINDOW
-                    && attrs.type <= LAST_APPLICATION_WINDOW) {
+            } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                 AppWindowToken atoken = token.appWindowToken;
                 if (atoken == null) {
                     Slog.w(TAG, "Attempted to add window with non-application token "
@@ -2147,25 +2147,25 @@
                           + token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_APP_EXITING;
                 }
-                if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
+                if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                     // No need for this guy!
                     if (localLOGV) Slog.v(
                             TAG, "**** NO NEED TO START: " + attrs.getTitle());
                     return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
                 }
-            } else if (attrs.type == TYPE_INPUT_METHOD) {
+            } else if (type == TYPE_INPUT_METHOD) {
                 if (token.windowType != TYPE_INPUT_METHOD) {
                     Slog.w(TAG, "Attempted to add input method window with bad token "
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (attrs.type == TYPE_WALLPAPER) {
+            } else if (type == TYPE_WALLPAPER) {
                 if (token.windowType != TYPE_WALLPAPER) {
                     Slog.w(TAG, "Attempted to add wallpaper window with bad token "
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (attrs.type == TYPE_DREAM) {
+            } else if (type == TYPE_DREAM) {
                 if (token.windowType != TYPE_DREAM) {
                     Slog.w(TAG, "Attempted to add Dream window with bad token "
                             + attrs.token + ".  Aborting.");
@@ -2185,6 +2185,7 @@
             }
 
             mPolicy.adjustWindowParamsLw(win.mAttrs);
+            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
 
             res = mPolicy.prepareAddWindowLw(win, attrs);
             if (res != WindowManagerGlobal.ADD_OKAY) {
@@ -2213,8 +2214,7 @@
             win.attach();
             mWindowMap.put(client.asBinder(), win);
 
-            if (attrs.type == TYPE_APPLICATION_STARTING &&
-                    token.appWindowToken != null) {
+            if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
                 token.appWindowToken.startingWindow = win;
                 if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken
                         + " startingWindow=" + win);
@@ -2222,19 +2222,19 @@
 
             boolean imMayMove = true;
 
-            if (attrs.type == TYPE_INPUT_METHOD) {
+            if (type == TYPE_INPUT_METHOD) {
                 win.mGivenInsetsPending = true;
                 mInputMethodWindow = win;
                 addInputMethodWindowToListLocked(win);
                 imMayMove = false;
-            } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
+            } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                 mInputMethodDialogs.add(win);
                 addWindowToListInOrderLocked(win, true);
                 adjustInputMethodDialogsLocked();
                 imMayMove = false;
             } else {
                 addWindowToListInOrderLocked(win, true);
-                if (attrs.type == TYPE_WALLPAPER) {
+                if (type == TYPE_WALLPAPER) {
                     mLastWallpaperTimeoutTime = 0;
                     adjustWallpaperWindowsLocked();
                 } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
@@ -5404,6 +5404,22 @@
         synchronized (mWindowMap) {
             mCurrentUserId = newUserId;
             mPolicy.setCurrentUserLw(newUserId);
+
+            // Hide windows that should not be seen by the new user.
+            DisplayContentsIterator iterator = new DisplayContentsIterator();
+            while (iterator.hasNext()) {
+                final WindowList windows = iterator.next().getWindowList();
+                for (int i = 0; i < windows.size(); i++) {
+                    final WindowState win = windows.get(i);
+                    if (win.isOtherUsersAppWindow()) {
+                        Slog.w(TAG, "current user violation " + newUserId + " hiding "
+                                + win + ", attrs=" + win.mAttrs.type + ", belonging to "
+                                + win.mOwnerUid);
+                        win.hideLw(false);
+                    }
+                }
+            }
+            performLayoutAndPlaceSurfacesLocked();
         }
     }
 
@@ -8221,7 +8237,9 @@
         int seq = mLayoutSeq+1;
         if (seq < 0) seq = 0;
         mLayoutSeq = seq;
-        
+
+        boolean behindDream = false;
+
         // First perform layout of any root windows (not attached
         // to another window).
         int topAttached = -1;
@@ -8231,7 +8249,8 @@
             // Don't do layout of a window if it is not visible, or
             // soon won't be visible, to avoid wasting time and funky
             // changes while a window is animating away.
-            final boolean gone = win.isGoneForLayoutLw();
+            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
+                    || win.isGoneForLayoutLw();
 
             if (DEBUG_LAYOUT && !win.mLayoutAttached) {
                 Slog.v(TAG, "1ST PASS " + win
@@ -8266,6 +8285,12 @@
                         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                         win.mContentChanged = false;
                     }
+                    if (win.mAttrs.type == TYPE_DREAM) {
+                        // Don't layout windows behind a dream, so that if it
+                        // does stuff like hide the status bar we won't get a
+                        // bad transition when it goes away.
+                        behindDream = true;
+                    }
                     win.mLayoutNeeded = false;
                     win.prelayout();
                     mPolicy.layoutWindowLw(win, win.mAttrs, null);
@@ -8290,6 +8315,8 @@
             mAnimator.mUniverseBackground = universeBackground;
         }
 
+        boolean attachedBehindDream = false;
+
         // Now perform layout of attached windows, which usually
         // depend on the position of the window they are attached to.
         // XXX does not deal with windows that are attached to windows
@@ -8307,6 +8334,9 @@
                 // if they want.  (We do the normal layout for INVISIBLE
                 // windows, since that means "perform layout as normal,
                 // just don't display").
+                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
+                    continue;
+                }
                 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
                         || !win.mHaveFrame || win.mLayoutNeeded) {
                     if (initial) {
@@ -8322,6 +8352,11 @@
                             + win.mContainingFrame + " mDisplayFrame="
                             + win.mDisplayFrame);
                 }
+            } else if (win.mAttrs.type == TYPE_DREAM) {
+                // Don't layout windows behind a dream, so that if it
+                // does stuff like hide the status bar we won't get a
+                // bad transition when it goes away.
+                attachedBehindDream = behindDream;
             }
         }
         
@@ -8784,6 +8819,7 @@
             final int type = attrs.type;
             if (canBeSeen
                     && (type == TYPE_SYSTEM_DIALOG
+                     || type == TYPE_RECENTS_OVERLAY
                      || type == TYPE_KEYGUARD
                      || type == TYPE_SYSTEM_ERROR)) {
                 mInnerFields.mSyswin = true;
@@ -9450,18 +9486,22 @@
         }
     }
 
-    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
-        synchronized (mWindowMap) {
-            WindowState win = windowForClientLocked(null, token, true);
-            if (win != null) {
-                Pair<WindowState, IRemoteCallback> pair =
-                        new Pair<WindowState, IRemoteCallback>(win, callback);
-                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
-                mH.sendMessageDelayed(m, 2000);
-                mWaitingForDrawn.add(pair);
-                checkDrawnWindowsLocked();
+    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
+        if (token != null && callback != null) {
+            synchronized (mWindowMap) {
+                WindowState win = windowForClientLocked(null, token, true);
+                if (win != null) {
+                    Pair<WindowState, IRemoteCallback> pair =
+                            new Pair<WindowState, IRemoteCallback>(win, callback);
+                    Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
+                    mH.sendMessageDelayed(m, 2000);
+                    mWaitingForDrawn.add(pair);
+                    checkDrawnWindowsLocked();
+                    return true;
+                }
             }
         }
+        return false;
     }
 
     void setHoldScreenLocked(final Session newHoldScreen) {
@@ -9475,10 +9515,10 @@
         final boolean state = mHoldingScreenWakeLock.isHeld();
         if (hold != state) {
             if (hold) {
-                mPolicy.screenOnStartedLw();
                 mHoldingScreenWakeLock.acquire();
+                mPolicy.keepScreenOnStartedLw();
             } else {
-                mPolicy.screenOnStoppedLw();
+                mPolicy.keepScreenOnStoppedLw();
                 mHoldingScreenWakeLock.release();
             }
         }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index d23448b..6e388f2 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -22,9 +22,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
 import com.android.server.input.InputWindowHandle;
 
@@ -36,7 +33,6 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
@@ -263,7 +259,10 @@
     DisplayContent  mDisplayContent;
 
     // UserId and appId of the owner. Don't display windows of non-current user.
-    final int mOwnerUid;
+    int mOwnerUid;
+
+    /** When true this window can be displayed on screens owther than mOwnerUid's */
+    private boolean mShowToOwnerOnly;
 
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
@@ -654,6 +653,7 @@
      * surface, or we are in the process of running an exit animation
      * that will remove the surface, or its app token has been hidden.
      */
+    @Override
     public boolean isVisibleLw() {
         final AppWindowToken atoken = mAppToken;
         return mHasSurface && mPolicyVisibility && !mAttachedHidden
@@ -669,6 +669,7 @@
      * for this "hidden behind keyguard" state rather than overloading
      * mPolicyVisibility.  Ungh.
      */
+    @Override
     public boolean isVisibleOrBehindKeyguardLw() {
         if (mRootToken.waitingToShow &&
                 mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
@@ -940,7 +941,7 @@
 
     boolean showLw(boolean doAnimation, boolean requestAnim) {
         if (isOtherUsersAppWindow()) {
-            Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+            Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
                     + this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
             return false;
         }
@@ -1025,15 +1026,12 @@
         return mDisplayContent.isDefaultDisplay;
     }
 
+    public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
+        mShowToOwnerOnly = showToOwnerOnly;
+    }
+
     boolean isOtherUsersAppWindow() {
-        final int type = mAttrs.type;
-        if ((UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId)
-                && (mOwnerUid != Process.SYSTEM_UID)
-                && (type >= TYPE_BASE_APPLICATION) && (type <= LAST_APPLICATION_WINDOW)
-                && (type != TYPE_APPLICATION_STARTING)) {
-            return true;
-        }
-        return false;
+        return mShowToOwnerOnly && UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId;
     }
 
     private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
@@ -1072,6 +1070,8 @@
         pw.print(prefix); pw.print("mDisplayId="); pw.print(mDisplayContent.getDisplayId());
                 pw.print(" mSession="); pw.print(mSession);
                 pw.print(" mClient="); pw.println(mClient.asBinder());
+        pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
+                pw.print(" mShowToOwnerOnly="); pw.println(mShowToOwnerOnly);
         pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
         pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
                 pw.print(" h="); pw.print(mRequestedHeight);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index acf452f..43f7a08 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1335,7 +1335,7 @@
     // This must be called while inside a transaction.
     boolean performShowLocked() {
         if (mWin.isOtherUsersAppWindow()) {
-            Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+            Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
                     + this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid);
             return false;
         }
@@ -1500,7 +1500,7 @@
             int attr = -1;
             Animation a = null;
             if (anim != 0) {
-                a = AnimationUtils.loadAnimation(mContext, anim);
+                a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;
             } else {
                 switch (transit) {
                     case WindowManagerPolicy.TRANSIT_ENTER:
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index dbd52a0..9ddaf63 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -414,8 +414,8 @@
     }
 
     @Override
-    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
-        // TODO Auto-generated method stub
+    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
+        return false;
     }
 
     @Override