Merge "Touch-exploration improvements to volume dialog." into lmp-dev
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 005baed..3d14c58 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -635,14 +635,7 @@
             if (mIcon != null) {
                 return mIcon;
             }
-            if (mIconFilename != null) {
-                try {
-                    return ActivityManagerNative.getDefault().
-                            getTaskDescriptionIcon(mIconFilename);
-                } catch (RemoteException e) {
-                }
-            }
-            return null;
+            return loadTaskDescriptionIcon(mIconFilename);
         }
 
         /** @hide */
@@ -650,6 +643,23 @@
             return mIconFilename;
         }
 
+        /** @hide */
+        public Bitmap getInMemoryIcon() {
+            return mIcon;
+        }
+
+        /** @hide */
+        public static Bitmap loadTaskDescriptionIcon(String iconFilename) {
+            if (iconFilename != null) {
+                try {
+                    return ActivityManagerNative.getDefault().
+                            getTaskDescriptionIcon(iconFilename);
+                } catch (RemoteException e) {
+                }
+            }
+            return null;
+        }
+
         /**
          * @return The color override on the theme's primary color.
          */
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 300301b..b492deb 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -702,6 +702,20 @@
     }
 
     /**
+     * Disable NFC hardware.
+     * @hide
+    */
+    @SystemApi
+    public boolean disable(boolean persist) {
+        try {
+            return sService.disable(persist);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+    /**
      * Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout,
      * use {@link #resumePolling()}.
      * @hide
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 946a3f7..c855e57 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -81,7 +81,7 @@
 
     /**
      * Intermediate density for screens that sit somewhere between
-     * {@link #DENSITY_XXHIGH} (480 dpi) and {@link #DENSITY_XXXHIGH} (560 dpi).
+     * {@link #DENSITY_XXHIGH} (480 dpi) and {@link #DENSITY_XXXHIGH} (640 dpi).
      * This is not a density that applications should target, instead relying
      * on the system to scale their {@link #DENSITY_XXXHIGH} assets for them.
      */
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index f64177d..3592687 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -276,13 +276,19 @@
 
             // Do not check this word if the user is currently editing it
             final boolean isEditing;
+
+            // Defer spell check when typing a word with an interior apostrophe.
+            // TODO: a better solution to this would be to make the word
+            // iterator locale-sensitive and include the apostrophe in
+            // languages that use it (such as English).
+            final boolean apostrophe = (selectionStart == end + 1 && editable.charAt(end) == '\'');
             if (mIsSentenceSpellCheckSupported) {
                 // Allow the overlap of the cursor and the first boundary of the spell check span
                 // no to skip the spell check of the following word because the
                 // following word will never be spell-checked even if the user finishes composing
-                isEditing = selectionEnd <= start || selectionStart > end;
+                isEditing = !apostrophe && (selectionEnd <= start || selectionStart > end);
             } else {
-                isEditing = selectionEnd < start || selectionStart > end;
+                isEditing = !apostrophe && (selectionEnd < start || selectionStart > end);
             }
             if (start >= 0 && end > start && isEditing) {
                 spellCheckSpan.setSpellCheckInProgress(true);
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 6796134..8ea28ec 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -478,7 +478,7 @@
 
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
-    int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
     struct stat fdStat;
     if (fstat(descriptor, &fdStat) == -1) {
@@ -486,22 +486,16 @@
         return nullObjectReturn("fstat return -1");
     }
 
-    // Duplicate the descriptor here to prevent leaking memory. A leak occurs
-    // if we only close the file descriptor and not the file object it is used to
-    // create.  If we don't explicitly clean up the file (which in turn closes the
-    // descriptor) the buffers allocated internally by fseek will be leaked.
-    int dupDescriptor = dup(descriptor);
+    // Restore the descriptor's offset on exiting this function.
+    AutoFDSeek autoRestore(descriptor);
 
-    FILE* file = fdopen(dupDescriptor, "r");
+    FILE* file = fdopen(descriptor, "r");
     if (file == NULL) {
-        // cleanup the duplicated descriptor since it will not be closed when the
-        // file is cleaned up (fclose).
-        close(dupDescriptor);
         return nullObjectReturn("Could not open file");
     }
 
     SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
-                         SkFILEStream::kCallerPasses_Ownership));
+                         SkFILEStream::kCallerRetains_Ownership));
 
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
     // ensures that SkImageDecoder::Factory never rewinds beyond the
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 14aa570..f7584d8 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -492,7 +492,7 @@
 
     @Override
     public Drawable mutate() {
-        if (!mMutated) {
+        if (!mMutated && super.mutate() == this) {
             final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null);
             setConstantState(newState);
             mMutated = true;
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index df1b126..ad0b415 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -151,7 +151,7 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mAnimatedVectorState = new AnimatedVectorDrawableState(mAnimatedVectorState);
+            mAnimatedVectorState.mVectorDrawable.mutate();
             mMutated = true;
         }
         return this;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 4fd98b7..c7aa98e 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -114,7 +114,8 @@
     /** Current dirty bounds, union of current and previous drawing bounds. */
     private final Rect mDirtyBounds = new Rect();
 
-    private final RippleState mState;
+    /** Mirrors mLayerState with some extra information. */
+    private RippleState mState;
 
     /** The masking layer, e.g. the layer with id R.id.mask. */
     private Drawable mMask;
@@ -885,18 +886,34 @@
         return mState;
     }
 
+    @Override
+    public Drawable mutate() {
+        super.mutate();
+
+        // LayerDrawable creates a new state using createConstantState, so
+        // this should always be a safe cast.
+        mState = (RippleState) mLayerState;
+        return this;
+    }
+
+    @Override
+    RippleState createConstantState(LayerState state, Resources res) {
+        return new RippleState(state, this, res);
+    }
+
     static class RippleState extends LayerState {
         int[] mTouchThemeAttrs;
         ColorStateList mColor = ColorStateList.valueOf(Color.MAGENTA);
         int mMaxRadius = RADIUS_AUTO;
 
-        public RippleState(RippleState orig, RippleDrawable owner, Resources res) {
+        public RippleState(LayerState orig, RippleDrawable owner, Resources res) {
             super(orig, owner, res);
 
-            if (orig != null) {
-                mTouchThemeAttrs = orig.mTouchThemeAttrs;
-                mColor = orig.mColor;
-                mMaxRadius = orig.mMaxRadius;
+            if (orig != null && orig instanceof RippleState) {
+                final RippleState origs = (RippleState) orig;
+                mTouchThemeAttrs = origs.mTouchThemeAttrs;
+                mColor = origs.mColor;
+                mMaxRadius = origs.mMaxRadius;
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index bbb0b50..8014837 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -507,9 +507,10 @@
                 pathRenderer.getAlpha());
         pathRenderer.setAlpha(alphaInFloat);
 
-        pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name);
-        if (pathRenderer.mRootName != null) {
-            pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer);
+        final String name = a.getString(R.styleable.VectorDrawable_name);
+        if (name != null) {
+            pathRenderer.mRootName = name;
+            pathRenderer.mVGTargetsMap.put(name, pathRenderer);
         }
     }
 
@@ -1313,9 +1314,15 @@
             // Account for any configuration changes.
             mChangingConfigurations |= a.getChangingConfigurations();
 
-            mPathName = a.getString(R.styleable.VectorDrawableClipPath_name);
-            mNodes = PathParser.createNodesFromPathData(a.getString(
-                    R.styleable.VectorDrawableClipPath_pathData));
+            final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+            if (pathName != null) {
+                mPathName = pathName;
+            }
+
+            final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
+            if (pathData != null) {
+                mNodes = PathParser.createNodesFromPathData(pathData);
+            }
         }
 
         @Override
@@ -1415,9 +1422,15 @@
             // Extract the theme attributes, if any.
             mThemeAttrs = a.extractThemeAttrs();
 
-            mPathName = a.getString(R.styleable.VectorDrawablePath_name);
-            mNodes = PathParser.createNodesFromPathData(a.getString(
-                    R.styleable.VectorDrawablePath_pathData));
+            final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
+            if (pathName != null) {
+                mPathName = pathName;
+            }
+
+            final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
+            if (pathData != null) {
+                mNodes = PathParser.createNodesFromPathData(pathData);
+            }
 
             mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
                     mFillColor);
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 71a05ab..5c2abc53 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4174,6 +4174,14 @@
                 AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 address);
         mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+        synchronized (mCurAudioRoutes) {
+            // Remove A2DP routes as well
+            if (mCurAudioRoutes.mBluetoothName != null) {
+                mCurAudioRoutes.mBluetoothName = null;
+                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+                        SENDMSG_NOOP, 0, 0, null, 0);
+            }
+        }
     }
 
     // must be called synchronized on mConnectedDevices
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 1de8a8b..3e5919f 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -141,26 +141,31 @@
 
         final ServiceConnection thisConnection = mServiceConnection = new MediaServiceConnection();
 
+        boolean bound = false;
         try {
-            mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+            if (mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
+                bound = true;
+            }
         } catch (Exception ex) {
             Log.e(TAG, "Failed binding to service " + mServiceComponent);
+        }
 
+        if (!bound) {
             // Tell them that it didn't work.  We are already on the main thread,
             // but we don't want to do callbacks inside of connect().  So post it,
             // and then check that we are on the same ServiceConnection.  We know
             // we won't also get an onServiceConnected or onServiceDisconnected,
             // so we won't be doing double callbacks.
             mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        // Ensure that nobody else came in or tried to connect again.
-                        if (thisConnection == mServiceConnection) {
-                            forceCloseConnection();
-                            mCallback.onConnectionFailed();
-                        }
+                @Override
+                public void run() {
+                    // Ensure that nobody else came in or tried to connect again.
+                    if (thisConnection == mServiceConnection) {
+                        forceCloseConnection();
+                        mCallback.onConnectionFailed();
                     }
-                });
+                }
+            });
         }
 
         if (DBG) {
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 06e40c5..5ce7f9f 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -49,7 +49,7 @@
  */
 public class MediaSessionLegacyHelper {
     private static final String TAG = "MediaSessionHelper";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final Object sLock = new Object();
     private static MediaSessionLegacyHelper sInstance;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 8e603ba..0d393bf 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -412,7 +412,7 @@
                 if (mCurrView != null) {
                     float delta = getPos(ev) - mInitialTouchPos;
                     float absDelta = Math.abs(delta);
-                    if (absDelta >= mFalsingThreshold) {
+                    if (absDelta >= getFalsingThreshold()) {
                         mTouchAboveFalsingThreshold = true;
                     }
                     // don't let items that can't be dismissed be dragged more than
@@ -466,6 +466,11 @@
         return true;
     }
 
+    private int getFalsingThreshold() {
+        float factor = mCallback.getFalsingThresholdFactor();
+        return (int) (mFalsingThreshold * factor);
+    }
+
     public interface Callback {
         View getChildAtPosition(MotionEvent ev);
 
@@ -489,6 +494,11 @@
          * @return if true, prevents the default alpha fading.
          */
         boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
+
+        /**
+         * @return The factor the falsing threshold should be multiplied with
+         */
+        float getFalsingThresholdFactor();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index bdb0ad3..330333a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -196,6 +196,11 @@
         return false;
     }
 
+    @Override
+    public float getFalsingThresholdFactor() {
+        return 1.0f;
+    }
+
     public void dismissChild(View v) {
         mSwipeHelper.dismissChild(v, 0);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 47c096f..1e247be 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -204,6 +204,11 @@
         return false;
     }
 
+    @Override
+    public float getFalsingThresholdFactor() {
+        return 1.0f;
+    }
+
     public void dismissChild(View v) {
         mSwipeHelper.dismissChild(v, 0);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index d4b403d..9d4fe66 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -177,16 +177,24 @@
                 if (t != null) {
                     Drawable cachedIcon = mApplicationIconCache.get(t.key);
                     Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
+
                     // Load the application icon if it is stale or we haven't cached one yet
                     if (cachedIcon == null) {
-                        ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
-                                t.key.userId);
-                        if (info != null) {
-                            cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+                        cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
+                                mContext.getResources());
+
+                        if (cachedIcon == null) {
+                            ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
+                                    t.key.userId);
+                            if (info != null) {
+                                cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+                            }
                         }
+
                         if (cachedIcon == null) {
                             cachedIcon = mDefaultApplicationIcon;
                         }
+
                         // At this point, even if we can't load the icon, we will set the default
                         // icon.
                         mApplicationIconCache.put(t.key, cachedIcon);
@@ -230,6 +238,17 @@
             }
         }
     }
+
+    Drawable getTaskDescriptionIcon(Task.TaskKey taskKey, Bitmap iconBitmap, String iconFilename,
+            SystemServicesProxy ssp, Resources res) {
+        Bitmap tdIcon = iconBitmap != null
+                ? iconBitmap
+                : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename);
+        if (tdIcon != null) {
+            return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
+        }
+        return null;
+    }
 }
 
 /* Recents task loader
@@ -321,15 +340,20 @@
         if (icon != null) {
             return icon;
         }
-        // Return the task description icon if it exists
-        if (td != null && td.getIcon() != null) {
-            icon = ssp.getBadgedIcon(new BitmapDrawable(res, td.getIcon()), taskKey.userId);
-            mApplicationIconCache.put(taskKey, icon);
-            return icon;
-        }
-        // If we are preloading this task, continue to load the activity icon
+
+        // If we are preloading this task, continue to load the task description icon or the
+        // activity icon
         if (preloadTask) {
-            // All short paths failed, load the icon from the activity info and cache it
+
+            // Return and cache the task description icon if it exists
+            Drawable tdDrawable = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
+                    td.getIconFilename(), ssp, res);
+            if (tdDrawable != null) {
+                mApplicationIconCache.put(taskKey, tdDrawable);
+                return tdDrawable;
+            }
+
+            // Load the icon from the activity info and cache it
             if (infoHandle.info == null) {
                 infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
                         taskKey.userId);
@@ -453,10 +477,17 @@
                 activityInfoCache.put(cnKey, infoHandle);
             }
 
+            Bitmap icon = t.taskDescription != null
+                    ? t.taskDescription.getInMemoryIcon()
+                    : null;
+            String iconFilename = t.taskDescription != null
+                    ? t.taskDescription.getIconFilename()
+                    : null;
+
             // Add the task to the stack
             Task task = new Task(taskKey, (t.id > -1), t.affiliatedTaskId, t.affiliatedTaskColor,
                     activityLabel, activityIcon, activityColor, (i == (taskCount - 1)),
-                    config.lockToAppEnabled);
+                    config.lockToAppEnabled, icon, iconFilename);
 
             if (preloadTask && loadTaskThumbnails) {
                 // Load the thumbnail from the cache if possible
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 406e03f..a7e2b0b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -124,7 +124,8 @@
     public boolean isActive;
     public boolean lockToThisTask;
     public boolean lockToTaskEnabled;
-
+    public Bitmap icon;
+    public String iconFilename;
     TaskCallbacks mCb;
 
     public Task() {
@@ -133,7 +134,8 @@
 
     public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor,
                 String activityTitle, Drawable activityIcon, int colorPrimary,
-                boolean lockToThisTask, boolean lockToTaskEnabled) {
+                boolean lockToThisTask, boolean lockToTaskEnabled, Bitmap icon,
+                String iconFilename) {
         boolean isInAffiliationGroup = (taskAffiliation != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
         this.key = key;
@@ -147,6 +149,8 @@
         this.isActive = isActive;
         this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
         this.lockToTaskEnabled = lockToTaskEnabled;
+        this.icon = icon;
+        this.iconFilename = iconFilename;
     }
 
     /** Copies the other task. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index c869ba4..0d5ebe7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -256,6 +256,9 @@
     }
 
     private void startActivateAnimation(boolean reverse) {
+        if (!isAttachedToWindow()) {
+            return;
+        }
         int widthHalf = mBackgroundNormal.getWidth()/2;
         int heightHalf = mBackgroundNormal.getActualHeight()/2;
         float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index a9c701a..6653254 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -303,8 +303,12 @@
     }
 
     private boolean isBelowFalsingThreshold() {
-        return Math.abs(mTranslation) < Math.abs(mTranslationOnDown)
-                + mMinTranslationAmount;
+        return Math.abs(mTranslation) < Math.abs(mTranslationOnDown) + getMinTranslationAmount();
+    }
+
+    private int getMinTranslationAmount() {
+        float factor = mCallback.getAffordanceFalsingFactor();
+        return (int) (mMinTranslationAmount * factor);
     }
 
     private void fling(float vel, final boolean snapBack) {
@@ -339,14 +343,14 @@
         translation = rightSwipePossible() ? translation : Math.max(0, translation);
         translation = leftSwipePossible() ? translation : Math.min(0, translation);
         float absTranslation = Math.abs(translation);
-        if (absTranslation > Math.abs(mTranslationOnDown) + mMinTranslationAmount ||
+        if (absTranslation > Math.abs(mTranslationOnDown) + getMinTranslationAmount() ||
                 mMotionPerformedByUser) {
             mMotionPerformedByUser = true;
         }
         if (translation != mTranslation || isReset) {
             KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
             KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
-            float alpha = absTranslation / mMinTranslationAmount;
+            float alpha = absTranslation / getMinTranslationAmount();
 
             // We interpolate the alpha of the other icons to 0
             float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
@@ -482,5 +486,10 @@
         View getLeftPreview();
 
         View getRightPreview();
+
+        /**
+         * @return The factor the minimum swipe amount should be multiplied with.
+         */
+        float getAffordanceFalsingFactor();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 80e9663..b9efb22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -706,7 +706,7 @@
             case MotionEvent.ACTION_MOVE:
                 final float h = y - mInitialTouchY;
                 setQsExpansion(h + mInitialHeightOnTouch);
-                if (h >= mQsFalsingThreshold) {
+                if (h >= getFalsingThreshold()) {
                     mQsTouchAboveFalsingThreshold = true;
                 }
                 trackMovement(event);
@@ -732,6 +732,11 @@
         }
     }
 
+    private int getFalsingThreshold() {
+        float factor = mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+        return (int) (mQsFalsingThreshold * factor);
+    }
+
     @Override
     public void onOverscrolled(float lastTouchX, float lastTouchY, int amount) {
         if (mIntercepting && shouldQuickSettingsIntercept(lastTouchX, lastTouchY,
@@ -1453,8 +1458,7 @@
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
             mAfforanceHelper.animateHideLeftRightIcon();
-        }
-        if (mQsExpanded) {
+        } else if (mQsExpanded) {
             mTwoFingerQsExpand = true;
         }
     }
@@ -1633,6 +1637,11 @@
     }
 
     @Override
+    public float getAffordanceFalsingFactor() {
+        return mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+    }
+
+    @Override
     protected float getPeekHeight() {
         if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
             return mNotificationStackScroller.getPeekHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 7f155a1d..84216a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -316,6 +316,11 @@
     }
 
     @Override
+    public float getFalsingThresholdFactor() {
+        return 1.0f;
+    }
+
+    @Override
     public void onChildDismissed(View v) {
         Log.v(TAG, "User swiped heads up to dismiss");
         mBar.onHeadsUpDismissed();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 67ba8d20..4a20406 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -547,6 +547,11 @@
         return false;
     }
 
+    @Override
+    public float getFalsingThresholdFactor() {
+        return mPhoneStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+    }
+
     public void onBeginDrag(View v) {
         setSwipingInProgress(true);
         mAmbientState.onBeginDrag(v);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 006f5db..6ea4497 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4093,6 +4093,7 @@
             } else {
                 intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
             }
+            mPowerManager.wakeUp(whenNanos / 1000000);
             mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
         }
         mCameraLensCoverState = lensCoverState;
@@ -5268,6 +5269,7 @@
     @Override
     public void systemBooted() {
         if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.bindService(mContext);
             mKeyguardDelegate.onBootCompleted();
         }
         synchronized (mLock) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index e9ca5c9..50fe7c7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -102,9 +102,12 @@
     };
 
     public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
+        mScrim = createScrim(context);
+    }
+
+    public void bindService(Context context) {
         Intent intent = new Intent();
         intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
-        mScrim = createScrim(context);
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                 Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
             if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
@@ -250,7 +253,6 @@
         if (mKeyguardService != null) {
             mKeyguardService.onSystemReady();
         } else {
-            if (DEBUG) Log.v(TAG, "onSystemReady() called before keyguard service was ready");
             mKeyguardState.systemIsReady = true;
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4d2fd4c..f535791 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6316,7 +6316,12 @@
                 mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
                 // Tell anyone interested that we are done booting!
                 SystemProperties.set("sys.boot_completed", "1");
-                SystemProperties.set("dev.bootcomplete", "1");
+
+                // And trigger dev.bootcomplete if we are not showing encryption progress
+                if (!"trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))
+                    || "".equals(SystemProperties.get("vold.encrypt_progress"))) {
+                    SystemProperties.set("dev.bootcomplete", "1");
+                }
                 for (int i=0; i<mStartedUsers.size(); i++) {
                     UserStartedState uss = mStartedUsers.valueAt(i);
                     if (uss.mState == UserStartedState.STATE_BOOTING) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a61d621..27184390 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10444,9 +10444,21 @@
         IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
         try {
-            if (dpm != null && (dpm.packageHasActiveAdmins(packageName, userId)
-                    || dpm.isDeviceOwner(packageName))) {
-                return true;
+            if (dpm != null) {
+                if (dpm.isDeviceOwner(packageName)) {
+                    return true;
+                }
+                int[] users;
+                if (userId == UserHandle.USER_ALL) {
+                    users = sUserManager.getUserIds();
+                } else {
+                    users = new int[]{userId};
+                }
+                for (int i = 0; i < users.length; ++i) {
+                    if (dpm.packageHasActiveAdmins(packageName, users[i])) {
+                        return true;
+                    }
+                }
             }
         } catch (RemoteException e) {
         }
@@ -10471,7 +10483,10 @@
         final PackageRemovedInfo info = new PackageRemovedInfo();
         final boolean res;
 
-        if (isPackageDeviceAdmin(packageName, userId)) {
+        final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
+                ? UserHandle.ALL : new UserHandle(userId);
+
+        if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
             Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
             return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
         }
@@ -10494,9 +10509,7 @@
 
         synchronized (mInstallLock) {
             if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
-            res = deletePackageLI(packageName,
-                    (flags & PackageManager.DELETE_ALL_USERS) != 0
-                            ? UserHandle.ALL : new UserHandle(userId),
+            res = deletePackageLI(packageName, removeForUser,
                     true, allUsers, perUserInstalled,
                     flags | REMOVE_CHATTY, info, true);
             systemUpdate = info.isRemovedPackageSystemUpdate;