Merge "Zen: Remove suppression of untagged vibrations in zen mode." into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index a1f2acf..a309fe6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5526,8 +5526,8 @@
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
-    field public static int FLAG_MANAGED_CAN_ACCESS_PARENT;
-    field public static int FLAG_PARENT_CAN_ACCESS_MANAGED;
+    field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
+    field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
     field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
     field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
     field public static final int KEYGUARD_DISABLE_FINGERPRINT = 32; // 0x20
@@ -28222,7 +28222,6 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int ROUTE_ALL = 15; // 0xf
     field public static final int ROUTE_BLUETOOTH = 2; // 0x2
     field public static final int ROUTE_EARPIECE = 1; // 0x1
     field public static final int ROUTE_SPEAKER = 8; // 0x8
@@ -28239,7 +28238,7 @@
     method public final void destroy();
     method public final int getCapabilities();
     method public final java.util.List<android.telecomm.Connection> getConnections();
-    method public final android.telecomm.PhoneAccountHandle getPhoneAccount();
+    method public final android.telecomm.PhoneAccountHandle getPhoneAccountHandle();
     method public final int getState();
     method public void onDisconnect();
     method public void onHold();
@@ -28314,12 +28313,11 @@
   }
 
   public final class ConnectionRequest implements android.os.Parcelable {
-    ctor public ConnectionRequest(android.telecomm.PhoneAccountHandle, android.net.Uri, int, android.os.Bundle);
+    ctor public ConnectionRequest(android.telecomm.PhoneAccountHandle, android.net.Uri, android.os.Bundle);
     method public int describeContents();
     method public android.telecomm.PhoneAccountHandle getAccountHandle();
+    method public android.net.Uri getAddress();
     method public android.os.Bundle getExtras();
-    method public android.net.Uri getHandle();
-    method public int getHandlePresentation();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -28497,11 +28495,11 @@
   public final class StatusHints implements android.os.Parcelable {
     ctor public StatusHints(android.content.ComponentName, java.lang.CharSequence, int, android.os.Bundle);
     method public int describeContents();
-    method public android.content.ComponentName getComponentName();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Drawable getIcon(android.content.Context);
     method public int getIconResId();
     method public java.lang.CharSequence getLabel();
+    method public android.content.ComponentName getPackageName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 5f7a17d..27a03b6 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -54,6 +54,10 @@
         int action, in Bundle arguments, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, long threadId);
 
+    boolean computeClickPointInScreen(int accessibilityWindowId, long accessibilityNodeId,
+        int interactionId, IAccessibilityInteractionConnectionCallback callback,
+        long threadId);
+
     AccessibilityWindowInfo getWindow(int windowId);
 
     List<AccessibilityWindowInfo> getWindows();
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 9e80a4b..9f49194 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -205,6 +205,7 @@
     private boolean mIsStartingTransition;
     private ArrayList<GhostViewListeners> mGhostViewListeners =
             new ArrayList<GhostViewListeners>();
+    private ArrayMap<View, Float> mOriginalAlphas = new ArrayMap<View, Float>();
 
     public ActivityTransitionCoordinator(Window window,
             ArrayList<String> allSharedElementNames,
@@ -580,6 +581,7 @@
         mWindow = null;
         mSharedElements.clear();
         mTransitioningViews.clear();
+        mOriginalAlphas.clear();
         mResultReceiver = null;
         mPendingTransition = null;
         mListener = null;
@@ -589,10 +591,27 @@
         return getWindow().getTransitionBackgroundFadeDuration();
     }
 
-    protected static void setTransitionAlpha(ArrayList<View> views, float alpha) {
+    protected void hideViews(ArrayList<View> views) {
         int count = views.size();
         for (int i = 0; i < count; i++) {
-            views.get(i).setTransitionAlpha(alpha);
+            View view = views.get(i);
+            if (!mOriginalAlphas.containsKey(view)) {
+                mOriginalAlphas.put(view, view.getAlpha());
+            }
+            view.setAlpha(0f);
+            view.setTransitionAlpha(0f);
+        }
+    }
+
+    protected void showViews(ArrayList<View> views) {
+        int count = views.size();
+        for (int i = 0; i < count; i++) {
+            View view = views.get(i);
+            Float alpha = mOriginalAlphas.remove(view);
+            if (alpha != null) {
+                view.setAlpha(alpha);
+                view.setTransitionAlpha(1f);
+            }
         }
     }
 
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index f432c49..f38c108 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -112,9 +112,9 @@
     protected void viewsReady(ArrayMap<String, View> sharedElements) {
         super.viewsReady(sharedElements);
         mIsReadyForTransition = true;
-        setTransitionAlpha(mSharedElements, 0);
+        hideViews(mSharedElements);
         if (getViewsTransition() != null) {
-            setTransitionAlpha(mTransitioningViews, 0);
+            hideViews(mTransitioningViews);
         }
         if (mIsReturning) {
             sendSharedElementDestination();
@@ -240,7 +240,7 @@
         if (!mIsCanceled) {
             mIsCanceled = true;
             if (getViewsTransition() == null || mIsViewsTransitionStarted) {
-                setTransitionAlpha(mSharedElements, 1);
+                showViews(mSharedElements);
             } else {
                 mTransitioningViews.addAll(mSharedElements);
             }
@@ -300,7 +300,7 @@
         // Now start shared element transition
         ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
                 mSharedElementNames);
-        setTransitionAlpha(mSharedElements, 1);
+        showViews(mSharedElements);
         scheduleSetSharedElementEnd(sharedElementSnapshots);
         ArrayList<SharedElementOriginalState> originalImageViewState =
                 setSharedElementState(sharedElementState, sharedElementSnapshots);
@@ -411,7 +411,7 @@
                     @Override
                     public void onTransitionStart(Transition transition) {
                         mEnterViewsTransition = transition;
-                        setTransitionAlpha(mTransitioningViews, 1);
+                        showViews(mTransitioningViews);
                         super.onTransitionStart(transition);
                     }
 
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index a59a927..982bbc4 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -126,8 +126,8 @@
     }
 
     public void resetViews() {
-        setTransitionAlpha(mTransitioningViews, 1);
-        setTransitionAlpha(mSharedElements, 1);
+        showViews(mTransitioningViews);
+        showViews(mSharedElements);
         mIsHidden = true;
         if (!mIsReturning && getDecor() != null) {
             getDecor().suppressLayout(false);
@@ -187,7 +187,7 @@
     private void hideSharedElements() {
         moveSharedElementsFromOverlay();
         if (!mIsHidden) {
-            setTransitionAlpha(mSharedElements, 0);
+            hideViews(mSharedElements);
         }
         mSharedElementsHidden = true;
         finishIfNecessary();
@@ -296,7 +296,7 @@
                     transition.removeListener(this);
                     exitTransitionComplete();
                     if (mIsHidden) {
-                        setTransitionAlpha(mTransitioningViews, 1);
+                        showViews(mTransitioningViews);
                     }
                     if (mSharedElementBundle != null) {
                         delayCancel();
@@ -323,7 +323,7 @@
                     transition.removeListener(this);
                     sharedElementTransitionComplete();
                     if (mIsHidden) {
-                        setTransitionAlpha(mSharedElements, 1);
+                        showViews(mSharedElements);
                     }
                 }
             });
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1083943..c831c25 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3386,8 +3386,16 @@
      */
     public static abstract class Style {
         private CharSequence mBigContentTitle;
-        private CharSequence mSummaryText = null;
-        private boolean mSummaryTextSet = false;
+
+        /**
+         * @hide
+         */
+        protected CharSequence mSummaryText = null;
+
+        /**
+         * @hide
+         */
+        protected boolean mSummaryTextSet = false;
 
         protected Builder mBuilder;
 
@@ -3679,6 +3687,11 @@
      * @see Notification#bigContentView
      */
     public static class BigTextStyle extends Style {
+
+        private static final int MAX_LINES = 13;
+        private static final int LINES_CONSUMED_BY_ACTIONS = 3;
+        private static final int LINES_CONSUMED_BY_SUMMARY = 2;
+
         private CharSequence mBigText;
 
         public BigTextStyle() {
@@ -3745,6 +3758,7 @@
 
             contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
+            contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines());
             contentView.setViewVisibility(R.id.text2, View.GONE);
 
             applyTopPadding(contentView);
@@ -3756,6 +3770,24 @@
             return contentView;
         }
 
+        private int calculateMaxLines() {
+            int lineCount = MAX_LINES;
+            boolean hasActions = mBuilder.mActions.size() > 0;
+            boolean hasSummary = (mSummaryTextSet ? mSummaryText : mBuilder.mSubText) != null;
+            if (hasActions) {
+                lineCount -= LINES_CONSUMED_BY_ACTIONS;
+            }
+            if (hasSummary) {
+                lineCount -= LINES_CONSUMED_BY_SUMMARY;
+            }
+
+            // If we have less top padding at the top, we can fit less lines.
+            if (!mBuilder.mHasThreeLines) {
+                lineCount--;
+            }
+            return lineCount;
+        }
+
         /**
          * @hide
          */
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 112fc82..926a348 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -441,13 +441,13 @@
      * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from a
      * managed profile to its parent.
      */
-    public static int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
+    public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
 
     /**
      * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from the
      * parent to its managed profile.
      */
-    public static int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
+    public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
 
     /**
      * Return true if the given administrator component is currently
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0a211cf..06d4c4a 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -285,6 +285,9 @@
      *
      * @throws IOException if parameters were unsatisfiable, such as lack of
      *             disk space or unavailable media.
+     * @throws SecurityException when installation services are unavailable,
+     *             such as when called from a restricted user.
+     * @throws IllegalArgumentException when {@link SessionParams} is invalid.
      * @return positive, non-zero unique ID that represents the created session.
      *         This ID remains consistent across device reboots until the
      *         session is finalized. IDs are not reused during a given boot.
@@ -303,6 +306,11 @@
     /**
      * Open an existing session to actively perform work. To succeed, the caller
      * must be the owner of the install session.
+     *
+     * @throws IOException if parameters were unsatisfiable, such as lack of
+     *             disk space or unavailable media.
+     * @throws SecurityException when the caller does not own the session, or
+     *             the session is invalid.
      */
     public @NonNull Session openSession(int sessionId) throws IOException {
         try {
@@ -319,6 +327,9 @@
      * Update the icon representing the app being installed in a specific
      * session. This should be roughly
      * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
+     *
+     * @throws SecurityException when the caller does not own the session, or
+     *             the session is invalid.
      */
     public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
         try {
@@ -331,6 +342,9 @@
     /**
      * Update the label representing the app being installed in a specific
      * session.
+     *
+     * @throws SecurityException when the caller does not own the session, or
+     *             the session is invalid.
      */
     public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
         try {
@@ -341,6 +355,15 @@
         }
     }
 
+    /**
+     * Completely abandon the given session, destroying all staged data and
+     * rendering it invalid. Abandoned sessions will be reported to
+     * {@link SessionCallback} listeners as failures. This is equivalent to
+     * opening the session and calling {@link Session#abandon()}.
+     *
+     * @throws SecurityException when the caller does not own the session, or
+     *             the session is invalid.
+     */
     public void abandonSession(int sessionId) {
         try {
             mInstaller.abandonSession(sessionId);
@@ -350,7 +373,11 @@
     }
 
     /**
-     * Return details for a specific session.
+     * Return details for a specific session. No special permissions are
+     * required to retrieve these details.
+     *
+     * @return details for the requested session, or {@code null} if the session
+     *         does not exist.
      */
     public @Nullable SessionInfo getSessionInfo(int sessionId) {
         try {
@@ -361,7 +388,7 @@
     }
 
     /**
-     * Return list of all active install sessions, regardless of the installer.
+     * Return list of all known install sessions, regardless of the installer.
      */
     public @NonNull List<SessionInfo> getAllSessions() {
         final ApplicationInfo info = mContext.getApplicationInfo();
@@ -379,7 +406,7 @@
     }
 
     /**
-     * Return list of all install sessions owned by the calling app.
+     * Return list of all known install sessions owned by the calling app.
      */
     public @NonNull List<SessionInfo> getMySessions() {
         try {
@@ -547,7 +574,8 @@
     }
 
     /**
-     * Register to watch for session lifecycle events.
+     * Register to watch for session lifecycle events. No special permissions
+     * are required to watch for these events.
      */
     public void registerSessionCallback(@NonNull SessionCallback callback) {
         registerSessionCallback(callback, new Handler());
@@ -560,7 +588,8 @@
     }
 
     /**
-     * Register to watch for session lifecycle events.
+     * Register to watch for session lifecycle events. No special permissions
+     * are required to watch for these events.
      *
      * @param handler to dispatch callback events through, otherwise uses
      *            calling thread.
@@ -593,7 +622,7 @@
     }
 
     /**
-     * Unregister an existing callback.
+     * Unregister a previously registered callback.
      */
     public void unregisterSessionCallback(@NonNull SessionCallback callback) {
         synchronized (mDelegates) {
@@ -686,6 +715,12 @@
          *            start at the beginning of the file.
          * @param lengthBytes total size of the file being written, used to
          *            preallocate the underlying disk space, or -1 if unknown.
+         *            The system may clear various caches as needed to allocate
+         *            this space.
+         * @throws IOException if trouble opening the file for writing, such as
+         *             lack of disk space or unavailable media.
+         * @throws SecurityException if called after the session has been
+         *             committed or abandoned.
          */
         public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
                 long lengthBytes) throws IOException {
@@ -719,6 +754,9 @@
          * <p>
          * This returns all names which have been previously written through
          * {@link #openWrite(String, long, long)} as part of this session.
+         *
+         * @throws SecurityException if called after the session has been
+         *             committed or abandoned.
          */
         public @NonNull String[] getNames() throws IOException {
             try {
@@ -738,6 +776,9 @@
          * through {@link #openWrite(String, long, long)} as part of this
          * session. For example, this stream may be used to calculate a
          * {@link MessageDigest} of a written APK before committing.
+         *
+         * @throws SecurityException if called after the session has been
+         *             committed or abandoned.
          */
         public @NonNull InputStream openRead(@NonNull String name) throws IOException {
             try {
@@ -759,6 +800,9 @@
          * Once this method is called, no additional mutations may be performed
          * on the session. If the device reboots before the session has been
          * finalized, you may commit the session again.
+         *
+         * @throws SecurityException if streams opened through
+         *             {@link #openWrite(String, long, long)} are still open.
          */
         public void commit(@NonNull IntentSender statusReceiver) {
             try {
@@ -783,7 +827,9 @@
 
         /**
          * Completely abandon this session, destroying all staged data and
-         * rendering it invalid.
+         * rendering it invalid. Abandoned sessions will be reported to
+         * {@link SessionCallback} listeners as failures. This is equivalent to
+         * opening the session and calling {@link Session#abandon()}.
          */
         public void abandon() {
             try {
@@ -937,6 +983,18 @@
         }
 
         /** {@hide} */
+        public void setInstallFlagsInternal() {
+            installFlags |= PackageManager.INSTALL_INTERNAL;
+            installFlags &= ~PackageManager.INSTALL_EXTERNAL;
+        }
+
+        /** {@hide} */
+        public void setInstallFlagsExternal() {
+            installFlags |= PackageManager.INSTALL_EXTERNAL;
+            installFlags &= ~PackageManager.INSTALL_INTERNAL;
+        }
+
+        /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
             pw.printHexPair("installFlags", installFlags);
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index 022a106..0acf24b 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -75,6 +75,13 @@
         return mClosed;
     }
 
+    public void forceClose() {
+        IoUtils.closeQuietly(mTarget);
+        IoUtils.closeQuietly(mServer);
+        IoUtils.closeQuietly(mClient);
+        mClosed = true;
+    }
+
     public void setTargetFile(FileDescriptor target) {
         mTarget = target;
     }
@@ -89,7 +96,6 @@
         try {
             while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) {
                 final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN);
-
                 if (cmd == CMD_WRITE) {
                     // Shuttle data into local file
                     int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
@@ -118,15 +124,10 @@
                 }
             }
 
-        } catch (ErrnoException e) {
-            Log.wtf(TAG, "Failed during bridge", e);
-        } catch (IOException e) {
+        } catch (ErrnoException | IOException e) {
             Log.wtf(TAG, "Failed during bridge", e);
         } finally {
-            IoUtils.closeQuietly(mTarget);
-            IoUtils.closeQuietly(mServer);
-            IoUtils.closeQuietly(mClient);
-            mClosed = true;
+            forceClose();
         }
     }
 
@@ -151,6 +152,7 @@
                 writeCommandAndBlock(CMD_CLOSE, "close()");
             } finally {
                 IoBridge.closeAndSignalBlockedThreads(mClient);
+                IoUtils.closeQuietly(mClientPfd);
             }
         }
 
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 4de5f41..8aa2689 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -468,19 +468,6 @@
     }
 
     /**
-     * FIXME: Remove once the prebuilts are updated.
-     *
-     * @hide
-     */
-    @Deprecated
-    public Intent createIntentToEnroll() {
-        if (DBG) Slog.d(TAG, "createIntentToEnroll");
-        synchronized (mLock) {
-            return getManageIntentLocked(MANAGE_ACTION_ENROLL);
-        }
-    }
-
-    /**
      * Creates an intent to start the un-enrollment for the associated keyphrase.
      * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
      * Starting re-enrollment is only valid if the keyphrase is already enrolled,
@@ -502,19 +489,6 @@
     }
 
     /**
-     * FIXME: Remove once the prebuilts are updated.
-     *
-     * @hide
-     */
-    @Deprecated
-    public Intent createIntentToUnEnroll() {
-        if (DBG) Slog.d(TAG, "createIntentToUnEnroll");
-        synchronized (mLock) {
-            return getManageIntentLocked(MANAGE_ACTION_UN_ENROLL);
-        }
-    }
-
-    /**
      * Creates an intent to start the re-enrollment for the associated keyphrase.
      * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
      * Starting re-enrollment is only valid if the keyphrase is already enrolled,
@@ -535,19 +509,6 @@
         }
     }
 
-    /**
-     * FIXME: Remove once the prebuilts are updated.
-     *
-     * @hide
-     */
-    @Deprecated
-    public Intent createIntentToReEnroll() {
-        if (DBG) Slog.d(TAG, "createIntentToReEnroll");
-        synchronized (mLock) {
-            return getManageIntentLocked(MANAGE_ACTION_RE_ENROLL);
-        }
-    }
-
     private Intent getManageIntentLocked(int action) {
         if (mAvailability == STATE_INVALID) {
             throw new IllegalStateException("getManageIntent called on an invalid detector");
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 0d1b568..40bb6ec 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1417,9 +1417,9 @@
                     }
                     capturePropagationValues(values);
                     if (start) {
-                        addViewValues(mStartValues, view, values);
+                        addViewValues(mStartValues, view, values, true);
                     } else {
-                        addViewValues(mEndValues, view, values);
+                        addViewValues(mEndValues, view, values, true);
                     }
                 }
             }
@@ -1460,7 +1460,7 @@
     }
 
     static void addViewValues(TransitionValuesMaps transitionValuesMaps,
-            View view, TransitionValues transitionValues) {
+            View view, TransitionValues transitionValues, boolean setTransientState) {
         transitionValuesMaps.viewValues.put(view, transitionValues);
         int id = view.getId();
         if (id >= 0) {
@@ -1489,11 +1489,15 @@
                     // Duplicate item IDs: cannot match by item ID.
                     View alreadyMatched = transitionValuesMaps.itemIdValues.get(itemId);
                     if (alreadyMatched != null) {
-                        alreadyMatched.setHasTransientState(false);
+                        if (setTransientState) {
+                            alreadyMatched.setHasTransientState(false);
+                        }
                         transitionValuesMaps.itemIdValues.put(itemId, null);
                     }
                 } else {
-                    view.setHasTransientState(true);
+                    if (setTransientState) {
+                        view.setHasTransientState(true);
+                    }
                     transitionValuesMaps.itemIdValues.put(itemId, view);
                 }
             }
@@ -1560,9 +1564,9 @@
             }
             capturePropagationValues(values);
             if (start) {
-                addViewValues(mStartValues, view, values);
+                addViewValues(mStartValues, view, values, true);
             } else {
-                addViewValues(mEndValues, view, values);
+                addViewValues(mEndValues, view, values, true);
             }
         }
         if (view instanceof ViewGroup) {
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index f6499ae..56db674 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -408,7 +408,7 @@
         for (int i = 0; i < numValues; i++) {
             View view = values.viewValues.keyAt(i);
             if (isValidTarget(view)) {
-                addViewValues(included, view, values.viewValues.valueAt(i));
+                addViewValues(included, view, values.viewValues.valueAt(i), false);
             }
         }
         return included;
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 0b02552..d648ca6 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -358,12 +358,16 @@
                     overlayView = startView;
                 } else if (startView.getParent() instanceof View) {
                     View startParent = (View) startView.getParent();
-                    if (!isValidTarget(startParent)) {
-                        if (startView.isAttachedToWindow()) {
-                            overlayView = copyViewImage(startView);
-                        } else {
-                            overlayView = startView;
-                        }
+                    VisibilityInfo parentVisibilityInfo = null;
+                    TransitionValues endParentValues = getMatchedTransitionValues(startParent,
+                            true);
+                    if (endParentValues != null) {
+                        TransitionValues startParentValues = getTransitionValues(startParent, true);
+                        parentVisibilityInfo =
+                                getVisibilityChangeInfo(startParentValues, endParentValues);
+                    }
+                    if (parentVisibilityInfo == null || !parentVisibilityInfo.visibilityChange) {
+                        overlayView = copyViewImage(startView);
                     } else if (startParent.getParent() == null) {
                         int id = startParent.getId();
                         if (id != View.NO_ID && sceneRoot.findViewById(id) != null
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index a10dda3..a283b91 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -19,7 +19,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -101,7 +100,7 @@
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
             long interrogatingTid, MagnificationSpec spec) {
         Message message = mHandler.obtainMessage();
-        message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+        message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID;
         message.arg1 = flags;
 
         SomeArgs args = SomeArgs.obtain();
@@ -176,7 +175,7 @@
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
             long interrogatingTid, MagnificationSpec spec) {
         Message message = mHandler.obtainMessage();
-        message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID;
+        message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID;
         message.arg1 = flags;
         message.arg2 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
 
@@ -261,7 +260,7 @@
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
             long interrogatingTid, MagnificationSpec spec) {
         Message message = mHandler.obtainMessage();
-        message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
+        message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT;
         message.arg1 = flags;
 
         SomeArgs args = SomeArgs.obtain();
@@ -637,6 +636,95 @@
         }
     }
 
+    public void computeClickPointInScreenClientThread(long accessibilityNodeId,
+            Region interactiveRegion, int interactionId,
+            IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+            long interrogatingTid, MagnificationSpec spec) {
+        Message message = mHandler.obtainMessage();
+        message.what = PrivateHandler.MSG_COMPUTE_CLICK_POINT_IN_SCREEN;
+
+        SomeArgs args = SomeArgs.obtain();
+        args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+        args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
+        args.argi3 = interactionId;
+        args.arg1 = callback;
+        args.arg2 = spec;
+        args.arg3 = interactiveRegion;
+
+        message.obj = args;
+
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
+    private void computeClickPointInScreenUiThread(Message message) {
+        SomeArgs args = (SomeArgs) message.obj;
+        final int accessibilityViewId = args.argi1;
+        final int virtualDescendantId = args.argi2;
+        final int interactionId = args.argi3;
+        final IAccessibilityInteractionConnectionCallback callback =
+                (IAccessibilityInteractionConnectionCallback) args.arg1;
+        final MagnificationSpec spec = (MagnificationSpec) args.arg2;
+        final Region interactiveRegion = (Region) args.arg3;
+        args.recycle();
+
+        boolean succeeded = false;
+        Point point = mTempPoint;
+        try {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+                return;
+            }
+            View target = null;
+            if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+                target = findViewByAccessibilityId(accessibilityViewId);
+            } else {
+                target = mViewRootImpl.mView;
+            }
+            if (target != null && isShown(target)) {
+                AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
+                if (provider != null) {
+                    // For virtual views just use the center of the bounds in screen.
+                    AccessibilityNodeInfo node = null;
+                    if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+                        node = provider.createAccessibilityNodeInfo(virtualDescendantId);
+                    } else {
+                        node = provider.createAccessibilityNodeInfo(
+                                AccessibilityNodeProvider.HOST_VIEW_ID);
+                    }
+                    if (node != null) {
+                        succeeded = true;
+                        Rect boundsInScreen = mTempRect;
+                        node.getBoundsInScreen(boundsInScreen);
+                        point.set(boundsInScreen.centerX(), boundsInScreen.centerY());
+                    }
+                } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+                    // For a real view, ask the view to compute the click point.
+                    succeeded = target.computeClickPointInScreenForAccessibility(
+                            interactiveRegion, point);
+                }
+            }
+        } finally {
+            try {
+                Point result = null;
+                if (succeeded) {
+                    applyAppScaleAndMagnificationSpecIfNeeded(point, spec);
+                    result = point;
+                }
+                callback.setComputeClickPointInScreenActionResult(result, interactionId);
+            } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+            }
+        }
+    }
+
     private View findViewByAccessibilityId(int accessibilityId) {
         View root = mViewRootImpl.mView;
         if (root == null) {
@@ -688,6 +776,26 @@
         }
     }
 
+    private void applyAppScaleAndMagnificationSpecIfNeeded(Point point,
+            MagnificationSpec spec) {
+        final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
+        if (!shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
+            return;
+        }
+
+        if (applicationScale != 1.0f) {
+            point.x *= applicationScale;
+            point.y *= applicationScale;
+        }
+
+        if (spec != null) {
+            point.x *= spec.scale;
+            point.y *= spec.scale;
+            point.x += (int) spec.offsetX;
+            point.y += (int) spec.offsetY;
+        }
+    }
+
     private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info,
             MagnificationSpec spec) {
         if (info == null) {
@@ -1080,11 +1188,12 @@
 
     private class PrivateHandler extends Handler {
         private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 1;
-        private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
-        private final static int MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID = 3;
-        private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 4;
+        private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
+        private final static int MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID = 3;
+        private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4;
         private final static int MSG_FIND_FOCUS = 5;
         private final static int MSG_FOCUS_SEARCH = 6;
+        private final static int MSG_COMPUTE_CLICK_POINT_IN_SCREEN = 7;
 
         public PrivateHandler(Looper looper) {
             super(looper);
@@ -1096,16 +1205,18 @@
             switch (type) {
                 case MSG_PERFORM_ACCESSIBILITY_ACTION:
                     return "MSG_PERFORM_ACCESSIBILITY_ACTION";
-                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
-                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
-                case MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID:
-                    return "MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID";
-                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
-                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
+                case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID:
+                    return "MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID";
+                case MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID:
+                    return "MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID";
+                case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT:
+                    return "MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT";
                 case MSG_FIND_FOCUS:
                     return "MSG_FIND_FOCUS";
                 case MSG_FOCUS_SEARCH:
                     return "MSG_FOCUS_SEARCH";
+                case MSG_COMPUTE_CLICK_POINT_IN_SCREEN:
+                    return "MSG_COMPUTE_CLICK_POINT_IN_SCREEN";
                 default:
                     throw new IllegalArgumentException("Unknown message type: " + type);
             }
@@ -1115,16 +1226,16 @@
         public void handleMessage(Message message) {
             final int type = message.what;
             switch (type) {
-                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
+                case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
                     findAccessibilityNodeInfoByAccessibilityIdUiThread(message);
                 } break;
                 case MSG_PERFORM_ACCESSIBILITY_ACTION: {
                     perfromAccessibilityActionUiThread(message);
                 } break;
-                case MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID: {
+                case MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID: {
                     findAccessibilityNodeInfosByViewIdUiThread(message);
                 } break;
-                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
+                case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT: {
                     findAccessibilityNodeInfosByTextUiThread(message);
                 } break;
                 case MSG_FIND_FOCUS: {
@@ -1133,6 +1244,9 @@
                 case MSG_FOCUS_SEARCH: {
                     focusSearchUiThread(message);
                 } break;
+                case MSG_COMPUTE_CLICK_POINT_IN_SCREEN: {
+                    computeClickPointInScreenUiThread(message);
+                } break;
                 default:
                     throw new IllegalArgumentException("Unknown message type: " + type);
             }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 770e78c..82c5425 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -35,6 +35,8 @@
 import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PorterDuff;
@@ -5731,6 +5733,136 @@
     }
 
     /**
+     * Computes a point on which a sequence of a down/up event can be sent to
+     * trigger clicking this view. This method is for the exclusive use by the
+     * accessibility layer to determine where to send a click event in explore
+     * by touch mode.
+     *
+     * @param interactiveRegion The interactive portion of this window.
+     * @param outPoint The point to populate.
+     * @return True of such a point exists.
+     */
+    boolean computeClickPointInScreenForAccessibility(Region interactiveRegion,
+            Point outPoint) {
+        // Since the interactive portion of the view is a region but as a view
+        // may have a transformation matrix which cannot be applied to a
+        // region we compute the view bounds rectangle and all interactive
+        // predecessor's and sibling's (siblings of predecessors included)
+        // rectangles that intersect the view bounds. At the
+        // end if the view was partially covered by another interactive
+        // view we compute the view's interactive region and pick a point
+        // on its boundary path as regions do not offer APIs to get inner
+        // points. Note that the the code is optimized to fail early and
+        // avoid unnecessary allocations plus computations.
+
+        // The current approach has edge cases that may produce false
+        // positives or false negatives. For example, a portion of the
+        // view may be covered by an interactive descendant of a
+        // predecessor, which we do not compute. Also a view may be handling
+        // raw touch events instead registering click listeners, which
+        // we cannot compute. Despite these limitations this approach will
+        // work most of the time and it is a huge improvement over just
+        // blindly sending the down and up events in the center of the
+        // view.
+
+        // Cannot click on an unattached view.
+        if (mAttachInfo == null) {
+            return false;
+        }
+
+        // Attached to an invisible window means this view is not visible.
+        if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
+            return false;
+        }
+
+        RectF bounds = mAttachInfo.mTmpTransformRect;
+        bounds.set(0, 0, getWidth(), getHeight());
+        List<RectF> intersections = mAttachInfo.mTmpRectList;
+        intersections.clear();
+
+        if (mParent instanceof ViewGroup) {
+            ViewGroup parentGroup = (ViewGroup) mParent;
+            if (!parentGroup.translateBoundsAndIntersectionsInWindowCoordinates(
+                    this, bounds, intersections)) {
+                intersections.clear();
+                return false;
+            }
+        }
+
+        // Take into account the window location.
+        final int dx = mAttachInfo.mWindowLeft;
+        final int dy = mAttachInfo.mWindowTop;
+        bounds.offset(dx, dy);
+        offsetRects(intersections, dx, dy);
+
+        if (intersections.isEmpty() && interactiveRegion == null) {
+            outPoint.set((int) bounds.centerX(), (int) bounds.centerY());
+        } else {
+            // This view is partially covered by other views, then compute
+            // the not covered region and pick a point on its boundary.
+            Region region = new Region();
+            region.set((int) bounds.left, (int) bounds.top,
+                    (int) bounds.right, (int) bounds.bottom);
+
+            final int intersectionCount = intersections.size();
+            for (int i = intersectionCount - 1; i >= 0; i--) {
+                RectF intersection = intersections.remove(i);
+                region.op((int) intersection.left, (int) intersection.top,
+                        (int) intersection.right, (int) intersection.bottom,
+                        Region.Op.DIFFERENCE);
+            }
+
+            // If the view is completely covered, done.
+            if (region.isEmpty()) {
+                return false;
+            }
+
+            // Take into account the interactive portion of the window
+            // as the rest is covered by other windows. If no such a region
+            // then the whole window is interactive.
+            if (interactiveRegion != null) {
+                region.op(interactiveRegion, Region.Op.INTERSECT);
+            }
+
+            // If the view is completely covered, done.
+            if (region.isEmpty()) {
+                return false;
+            }
+
+            // Try a shortcut here.
+            if (region.isRect()) {
+                Rect regionBounds = mAttachInfo.mTmpInvalRect;
+                region.getBounds(regionBounds);
+                outPoint.set(regionBounds.centerX(), regionBounds.centerY());
+                return true;
+            }
+
+            // Get the a point on the region boundary path.
+            Path path = region.getBoundaryPath();
+            PathMeasure pathMeasure = new PathMeasure(path, false);
+            final float[] coordinates = mAttachInfo.mTmpTransformLocation;
+
+            // Without loss of generality pick a point.
+            final float point = pathMeasure.getLength() * 0.01f;
+            if (!pathMeasure.getPosTan(point, coordinates, null)) {
+                return false;
+            }
+
+            outPoint.set(Math.round(coordinates[0]), Math.round(coordinates[1]));
+        }
+
+        return true;
+    }
+
+    static void offsetRects(List<RectF> rects, float offsetX, float offsetY) {
+        final int rectCount = rects.size();
+        for (int i = 0; i < rectCount; i++) {
+            RectF intersection = rects.get(i);
+            intersection.offset(offsetX, offsetY);
+        }
+    }
+
+    /**
      * Returns the delegate for implementing accessibility support via
      * composition. For more details see {@link AccessibilityDelegate}.
      *
@@ -20154,6 +20286,16 @@
         final RectF mTmpTransformRect = new RectF();
 
         /**
+         * Temporary for use in computing hit areas with transformed views
+         */
+        final RectF mTmpTransformRect1 = new RectF();
+
+        /**
+         * Temporary list of rectanges.
+         */
+        final List<RectF> mTmpRectList = new ArrayList<>();
+
+        /**
          * Temporary for use in transforming invalidation rect
          */
         final Matrix mTmpMatrix = new Matrix();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c1e66de..4e1db90 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -771,6 +771,112 @@
     }
 
     /**
+     * Translates the given bounds and intersections from child coordinates to
+     * local coordinates. In case any interactive sibling of the calling child
+     * covers the latter, a new intersections is added to the intersection list.
+     * This method is for the exclusive use by the accessibility layer to compute
+     * a point where a sequence of down and up events would click on a view.
+     *
+     * @param child The child making the call.
+     * @param bounds The bounds to translate in child coordinates.
+     * @param intersections The intersections of interactive views covering the child.
+     * @return True if the bounds and intersections were computed, false otherwise.
+     */
+    boolean translateBoundsAndIntersectionsInWindowCoordinates(View child,
+            RectF bounds, List<RectF> intersections) {
+        // Not attached, done.
+        if (mAttachInfo == null) {
+            return false;
+        }
+
+        if (getAlpha() <= 0 || getTransitionAlpha() <= 0 ||
+                getVisibility() != VISIBLE) {
+            // Cannot click on a view with an invisible predecessor.
+            return false;
+        }
+
+        // Compensate for the child transformation.
+        if (!child.hasIdentityMatrix()) {
+            Matrix matrix = child.getMatrix();
+            matrix.mapRect(bounds);
+            final int intersectionCount = intersections.size();
+            for (int i = 0; i < intersectionCount; i++) {
+                RectF intersection = intersections.get(i);
+                matrix.mapRect(intersection);
+            }
+        }
+
+        // Translate the bounds from child to parent coordinates.
+        final int dx = child.mLeft - mScrollX;
+        final int dy = child.mTop - mScrollY;
+        bounds.offset(dx, dy);
+        offsetRects(intersections, dx, dy);
+
+        // If the bounds do not intersect our bounds, done.
+        if (!bounds.intersects(0, 0, getWidth(), getHeight())) {
+            return false;
+        }
+
+        // Check whether any clickable siblings cover the child
+        // view and if so keep track of the intersections. Also
+        // respect Z ordering when iterating over children.
+        ArrayList<View> orderedList = buildOrderedChildList();
+        final boolean useCustomOrder = orderedList == null
+                && isChildrenDrawingOrderEnabled();
+
+        final int childCount = mChildrenCount;
+        for (int i = childCount - 1; i >= 0; i--) {
+            final int childIndex = useCustomOrder
+                    ? getChildDrawingOrder(childCount, i) : i;
+            final View sibling = (orderedList == null)
+                    ? mChildren[childIndex] : orderedList.get(childIndex);
+
+            // We care only about siblings over the child.
+            if (sibling == child) {
+                break;
+            }
+
+            // If sibling is not interactive we do not care.
+            if (!sibling.isClickable() && !sibling.isLongClickable()) {
+                continue;
+            }
+
+            // Compute the sibling bounds in its coordinates.
+            RectF siblingBounds = mAttachInfo.mTmpTransformRect1;
+            siblingBounds.set(0, 0, sibling.getWidth(), sibling.getHeight());
+
+            // Take into account the sibling transformation matrix.
+            if (!sibling.hasIdentityMatrix()) {
+                sibling.getMatrix().mapRect(siblingBounds);
+            }
+
+            // Offset the sibling to our coordinates.
+            final int siblingDx = sibling.mLeft - mScrollX;
+            final int siblingDy = sibling.mTop - mScrollY;
+            siblingBounds.offset(siblingDx, siblingDy);
+
+            // Compute the intersection between the child and the sibling.
+            if (siblingBounds.intersect(bounds)) {
+                // If an interactive sibling completely covers the child, done.
+                if (siblingBounds.equals(bounds)) {
+                    return false;
+                }
+                // Keep track of the intersection rectangle.
+                RectF intersection = new RectF(siblingBounds);
+                intersections.add(intersection);
+            }
+        }
+
+        if (mParent instanceof ViewGroup) {
+            ViewGroup parentGroup = (ViewGroup) mParent;
+            return parentGroup.translateBoundsAndIntersectionsInWindowCoordinates(
+                    this, bounds, intersections);
+        }
+
+        return true;
+    }
+
+    /**
      * Called when a child view has changed whether or not it is tracking transient state.
      */
     public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4299e2e..80b9ade 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6679,12 +6679,12 @@
         public void performAccessibilityAction(long accessibilityNodeId, int action,
                 Bundle arguments, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interogatingPid, long interrogatingTid) {
+                int interrogatingPid, long interrogatingTid) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
-                            interactionId, callback, flags, interogatingPid, interrogatingTid);
+                            interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
@@ -6696,6 +6696,26 @@
         }
 
         @Override
+        public void computeClickPointInScreen(long accessibilityNodeId, Region interactiveRegion,
+                int interactionId, IAccessibilityInteractionConnectionCallback callback,
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+            ViewRootImpl viewRootImpl = mViewRootImpl.get();
+            if (viewRootImpl != null && viewRootImpl.mView != null) {
+                viewRootImpl.getAccessibilityInteractionController()
+                        .computeClickPointInScreenClientThread(accessibilityNodeId,
+                                interactiveRegion, interactionId, callback, interrogatingPid,
+                                interrogatingTid, spec);
+            } else {
+                // We cannot make the call and notify the caller so it does not wait.
+                try {
+                    callback.setComputeClickPointInScreenActionResult(null, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
+            }
+        }
+
+        @Override
         public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
                 String viewId, Region interactiveRegion, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index db78ec5..374f7e0 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -17,6 +17,7 @@
 package android.view.accessibility;
 
 import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.graphics.Point;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -98,6 +99,8 @@
 
     private boolean mPerformAccessibilityActionResult;
 
+    private Point mComputeClickPointResult;
+
     private Message mSameThreadMessage;
 
     private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
@@ -519,6 +522,43 @@
         return false;
     }
 
+    /**
+     * Computes a point in screen coordinates where sending a down/up events would
+     * perform a click on an {@link AccessibilityNodeInfo}.
+     *
+     * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
+     * @return Point the click point of null if no such point.
+     */
+    public Point computeClickPointInScreen(int connectionId, int accessibilityWindowId,
+            long accessibilityNodeId) {
+        try {
+            IAccessibilityServiceConnection connection = getConnection(connectionId);
+            if (connection != null) {
+                final int interactionId = mInteractionIdCounter.getAndIncrement();
+                final boolean success = connection.computeClickPointInScreen(
+                        accessibilityWindowId, accessibilityNodeId,
+                        interactionId, this, Thread.currentThread().getId());
+                if (success) {
+                    return getComputeClickPointInScreenResultAndClear(interactionId);
+                }
+            } else {
+                if (DEBUG) {
+                    Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+                }
+            }
+        } catch (RemoteException re) {
+            Log.w(LOG_TAG, "Error while calling remote computeClickPointInScreen", re);
+        }
+        return null;
+    }
+
     public void clearCache() {
         sAccessibilityCache.clear();
     }
@@ -634,6 +674,34 @@
     }
 
     /**
+     * Gets the result of a request to compute a point in screen for clicking on a node.
+     *
+     * @param interactionId The interaction id to match the result with the request.
+     * @return The point or null if no such point.
+     */
+    private Point getComputeClickPointInScreenResultAndClear(int interactionId) {
+        synchronized (mInstanceLock) {
+            final boolean success = waitForResultTimedLocked(interactionId);
+            Point result = success ? mComputeClickPointResult : null;
+            clearResultLocked();
+            return result;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setComputeClickPointInScreenActionResult(Point point, int interactionId) {
+        synchronized (mInstanceLock) {
+            if (interactionId > mInteractionId) {
+                mComputeClickPointResult = point;
+                mInteractionId = interactionId;
+            }
+            mInstanceLock.notifyAll();
+        }
+    }
+
+    /**
      * Clears the result state.
      */
     private void clearResultLocked() {
@@ -641,6 +709,7 @@
         mFindAccessibilityNodeInfoResult = null;
         mFindAccessibilityNodeInfosResult = null;
         mPerformAccessibilityActionResult = false;
+        mComputeClickPointResult = null;
     }
 
     /**
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index faf7789..66a3f46 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -17,6 +17,7 @@
 package android.view.accessibility;
 
 import android.graphics.Region;
+import android.graphics.Point;
 import android.os.Bundle;
 import android.view.MagnificationSpec;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -53,4 +54,8 @@
     void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
         int interrogatingPid, long interrogatingTid);
+
+    void computeClickPointInScreen(long accessibilityNodeId, in Region bounds, int interactionId,
+        IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+        long interrogatingTid, in MagnificationSpec spec);
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index c1a3ab7..f480216 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -16,6 +16,7 @@
 
 package android.view.accessibility;
 
+import android.graphics.Point;
 import android.view.accessibility.AccessibilityNodeInfo;
 import java.util.List;
 
@@ -51,4 +52,12 @@
      * @param interactionId The interaction id to match the result with the request.
      */
     void setPerformAccessibilityActionResult(boolean succeeded, int interactionId);
+
+    /**
+     * Sets the result of a request to compute a point for clicking in a view.
+     *
+     * @param point The point of null if no such point.
+     * @param interactionId The interaction id to match the result with the request.
+     */
+    void setComputeClickPointInScreenActionResult(in Point point, int interactionId);
 }
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index c17f4ee..7bdb4be 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -390,7 +390,10 @@
         if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) {
             final File target = new UserEnvironment(UserHandle.USER_OWNER)
                     .getExternalStorageDirectory();
-            fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
+            // External is only an option when size is known
+            if (sizeBytes > 0) {
+                fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
+            }
         }
 
         if (prefer == RECOMMEND_INSTALL_INTERNAL) {
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 7db70ba..45d790b 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -1440,6 +1440,16 @@
         return Boolean.parseBoolean(value);
     }
 
+    public static boolean readBooleanAttribute(XmlPullParser in, String name,
+            boolean defaultValue) {
+        final String value = in.getAttributeValue(null, name);
+        if (value == null) {
+            return defaultValue;
+        } else {
+            return Boolean.parseBoolean(value);
+        }
+    }
+
     public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
             throws IOException {
         out.attribute(null, name, Boolean.toString(value));
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 2382d18..8a66c3f 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -44,6 +44,7 @@
             android:layout_width="match_parent"
             android:layout_weight="1"
             android:layout_height="0dp"
+            android:layout_marginEnd="8dp"
             android:orientation="horizontal"
             >
             <TextView android:id="@+id/inbox_text0"
@@ -60,7 +61,6 @@
                 android:layout_height="@dimen/notification_badge_size"
                 android:layout_weight="0"
                 android:layout_marginStart="4dp"
-                android:layout_marginEnd="8dp"
                 android:scaleType="fitCenter"
                 android:visibility="gone"
                 />
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index a10e70f..254492f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -872,6 +872,8 @@
             handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
                     renderer.getSaveCount() - 1, properties().getClipToBounds());
         } else {
+            const int saveCountOffset = renderer.getSaveCount() - 1;
+            const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
             DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
             for (size_t chunkIndex = 0; chunkIndex < mDisplayListData->getChunks().size(); chunkIndex++) {
                 const DisplayListData::Chunk& chunk = mDisplayListData->getChunks()[chunkIndex];
@@ -882,8 +884,6 @@
                 issueOperationsOf3dChildren(kNegativeZChildren,
                         initialTransform, zTranslatedNodes, renderer, handler);
 
-                const int saveCountOffset = renderer.getSaveCount() - 1;
-                const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
 
                 for (int opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
                     DisplayListOp *op = mDisplayListData->displayListOps[opIndex];
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 082a158..2c805bb 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1109,9 +1109,9 @@
      * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
      *
      * <p>
-     * Before API version 20, this method would throw {@link SecurityException}
-     * if the location permissions were not sufficient to use the specified
-     * provider.
+     * Before API version {@link android.os.Build.VERSION_CODES#L}, this
+     * method would throw {@link SecurityException} if the location permissions
+     * were not sufficient to use the specified provider.
      *
      * @param provider the name of the provider
      * @return true if the provider exists and is enabled
@@ -1119,7 +1119,6 @@
      * @throws IllegalArgumentException if provider is null
      */
     public boolean isProviderEnabled(String provider) {
-        // STOPSHIP: finalize API version number in javadoc
         checkProvider(provider);
 
         try {
diff --git a/packages/SystemUI/res/drawable/stat_sys_vpn_ic.xml b/packages/SystemUI/res/drawable/stat_sys_vpn_ic.xml
new file mode 100644
index 0000000..7ca8c40
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_vpn_ic.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17.0dp"
+        android:height="17.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12.700000,10.000000c-0.800000,-2.300000 -3.000000,-4.000000 -5.700000,-4.000000c-3.300000,0.000000 -6.000000,2.700000 -6.000000,6.000000s2.700000,6.000000 6.000000,6.000000c2.600000,0.000000 4.800000,-1.700000 5.700000,-4.000000L17.000000,14.000000l0.000000,4.000000l4.000000,0.000000l0.000000,-4.000000l2.000000,0.000000l0.000000,-4.000000L12.700000,10.000000zM7.000000,14.000000c-1.100000,0.000000 -2.000000,-0.900000 -2.000000,-2.000000c0.000000,-1.100000 0.900000,-2.000000 2.000000,-2.000000s2.000000,0.900000 2.000000,2.000000C9.000000,13.100000 8.100000,14.000000 7.000000,14.000000z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml
index 1ef9cad..4b68e77 100644
--- a/packages/SystemUI/res/layout/recents_empty.xml
+++ b/packages/SystemUI/res/layout/recents_empty.xml
@@ -23,6 +23,6 @@
     android:textSize="16sp"
     android:textColor="#ffffffff"
     android:text="@string/recents_empty_message"
-    android:fontFamily="sans-serif-light"
+    android:fontFamily="sans-serif"
     android:background="#80000000"
     android:visibility="gone" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 347c8a9..3a8a17d 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -25,6 +25,13 @@
     android:gravity="center_vertical"
     android:orientation="horizontal"
     >
+    <ImageView
+        android:id="@+id/vpn"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:paddingEnd="6dp"
+        android:src="@drawable/stat_sys_vpn_ic"
+        />
     <FrameLayout
         android:id="@+id/wifi_combo"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0e18979..c0e2b10 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -134,10 +134,13 @@
     <integer name="recents_animate_task_exit_to_home_duration">225</integer>
     <!-- The min animation duration for animating the task bar out. -->
     <integer name="recents_animate_task_bar_exit_duration">125</integer>
+    <!-- The animation delay for animating the first task in. This should roughly be the animation
+     duration of the transition in to recents from home. -->
+    <integer name="recents_animate_task_enter_from_home_delay">150</integer>
     <!-- The min animation duration for animating the task in when transitioning from home. -->
     <integer name="recents_animate_task_enter_from_home_duration">275</integer>
     <!-- The animation stagger to apply to each task animation when transitioning from home. -->
-    <integer name="recents_animate_task_enter_from_home_delay">10</integer>
+    <integer name="recents_animate_task_enter_from_home_stagger_delay">10</integer>
     <!-- The short duration when animating in/out the lock to app button. -->
     <integer name="recents_animate_lock_to_app_button_short_duration">150</integer>
     <!-- The long duration when animating in/out the lock to app button. -->
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 5d8181c..396be3b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -74,8 +74,9 @@
     public float taskStackOverscrollPct;
 
     /** Task view animation and styles */
-    public int taskViewEnterFromHomeDuration;
     public int taskViewEnterFromHomeDelay;
+    public int taskViewEnterFromHomeDuration;
+    public int taskViewEnterFromHomeStaggerDelay;
     public int taskViewExitToHomeDuration;
     public int taskViewRemoveAnimDuration;
     public int taskViewRemoveAnimTranslationXPx;
@@ -209,10 +210,12 @@
         taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
 
         // Task view animation and styles
-        taskViewEnterFromHomeDuration =
-                res.getInteger(R.integer.recents_animate_task_enter_from_home_duration);
         taskViewEnterFromHomeDelay =
                 res.getInteger(R.integer.recents_animate_task_enter_from_home_delay);
+        taskViewEnterFromHomeDuration =
+                res.getInteger(R.integer.recents_animate_task_enter_from_home_duration);
+        taskViewEnterFromHomeStaggerDelay =
+                res.getInteger(R.integer.recents_animate_task_enter_from_home_stagger_delay);
         taskViewExitToHomeDuration =
                 res.getInteger(R.integer.recents_animate_task_exit_to_home_duration);
         taskViewRemoveAnimDuration =
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 49aa52b..6fe86be 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -284,7 +284,7 @@
                 float scaledWindowInsetTop = (int) (taskScale * windowInsetTop);
                 float scaledTranslationY = taskRect.top + transform.translationY -
                         (scaledWindowInsetTop + scaledYOffset);
-                startDelay = mConfig.taskViewEnterFromHomeDelay;
+                startDelay = mConfig.taskViewEnterFromHomeStaggerDelay;
 
                 // Animate the top clip
                 mViewBounds.animateClipTop(windowInsetTop, duration,
@@ -410,8 +410,8 @@
         } else if (mConfig.launchedFromHome) {
             // Animate the tasks up
             int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
-            int delay = mConfig.taskBarEnterAnimDelay +
-                    frontIndex * mConfig.taskViewEnterFromHomeDelay;
+            int delay = mConfig.taskViewEnterFromHomeDelay +
+                    frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay;
             if (Constants.DebugFlags.App.EnableShadows) {
                 animate().translationZ(transform.translationZ);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1c4556f..4dabe0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -91,6 +91,7 @@
 import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
+import com.android.systemui.statusbar.policy.PreviewInflater;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
@@ -260,10 +261,12 @@
             final boolean isActivity = pendingIntent.isActivity();
             if (isActivity) {
                 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+                final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
+                        mContext, pendingIntent.getIntent(), mCurrentUserId);
                 dismissKeyguardThenExecute(new OnDismissAction() {
                     @Override
                     public boolean onDismiss() {
-                        if (keyguardShowing) {
+                        if (keyguardShowing && !afterKeyguardGone) {
                             try {
                                 ActivityManagerNative.getDefault()
                                         .keyguardWaitingForActivityDrawn();
@@ -277,7 +280,7 @@
                         }
 
                         boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
-                        overrideActivityPendingAppTransition(keyguardShowing);
+                        overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
 
                         // close the shade if it was open
                         if (handled) {
@@ -287,7 +290,7 @@
                         // Wait for activity start.
                         return handled;
                     }
-                }, false /* afterKeyguardGone */);
+                }, afterKeyguardGone);
                 return true;
             } else {
                 return super.onClickHandler(view, pendingIntent, fillInIntent);
@@ -1440,6 +1443,9 @@
 
         public void onClick(final View v) {
             final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+            final boolean afterKeyguardGone = mIntent.isActivity()
+                    && PreviewInflater.wouldLaunchResolverActivity(mContext, mIntent.getIntent(),
+                            mCurrentUserId);
             dismissKeyguardThenExecute(new OnDismissAction() {
                 public boolean onDismiss() {
                     if (mIsHeadsUp) {
@@ -1448,7 +1454,7 @@
                     AsyncTask.execute(new Runnable() {
                         @Override
                         public void run() {
-                            if (keyguardShowing) {
+                            if (keyguardShowing && !afterKeyguardGone) {
                                 try {
                                     ActivityManagerNative.getDefault()
                                             .keyguardWaitingForActivityDrawn();
@@ -1472,7 +1478,8 @@
                                     // TODO: Dismiss Keyguard.
                                 }
                                 if (mIntent.isActivity()) {
-                                    overrideActivityPendingAppTransition(keyguardShowing);
+                                    overrideActivityPendingAppTransition(keyguardShowing
+                                            && !afterKeyguardGone);
                                 }
                             }
 
@@ -1490,7 +1497,7 @@
 
                     return mIntent != null && mIntent.isActivity();
                 }
-            }, false /* afterKeyguardGone */);
+            }, afterKeyguardGone);
         }
     }
 
@@ -1625,7 +1632,7 @@
                 }
             }
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
-            if ((isLockscreenPublicMode() && !showOnKeyguard) ||
+            if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
                     (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
                             || !showOnKeyguard))) {
                 entry.row.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 5883c26..740211f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -27,17 +27,21 @@
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.SecurityController;
 
 // Intimately tied to the design of res/layout/signal_cluster_view.xml
 public class SignalClusterView
         extends LinearLayout
-        implements NetworkControllerImpl.SignalCluster {
+        implements NetworkControllerImpl.SignalCluster,
+        SecurityController.SecurityControllerCallback {
 
     static final String TAG = "SignalClusterView";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     NetworkControllerImpl mNC;
+    SecurityController mSC;
 
+    private boolean mVpnVisible = false;
     private boolean mWifiVisible = false;
     private int mWifiStrengthId = 0;
     private boolean mMobileVisible = false;
@@ -48,7 +52,7 @@
     private boolean mRoaming;
 
     ViewGroup mWifiGroup, mMobileGroup;
-    ImageView mWifi, mMobile, mMobileType, mAirplane;
+    ImageView mVpn, mWifi, mMobile, mMobileType, mAirplane;
     View mWifiAirplaneSpacer;
 
     public SignalClusterView(Context context) {
@@ -68,10 +72,18 @@
         mNC = nc;
     }
 
+    public void setSecurityController(SecurityController sc) {
+        if (DEBUG) Log.d(TAG, "SecurityController=" + sc);
+        mSC = sc;
+        mSC.addCallback(this);
+        mVpnVisible = mSC.isVpnEnabled();
+    }
+
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
+        mVpn            = (ImageView) findViewById(R.id.vpn);
         mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
         mWifi           = (ImageView) findViewById(R.id.wifi_signal);
         mMobileGroup    = (ViewGroup) findViewById(R.id.mobile_combo);
@@ -85,6 +97,7 @@
 
     @Override
     protected void onDetachedFromWindow() {
+        mVpn            = null;
         mWifiGroup      = null;
         mWifi           = null;
         mMobileGroup    = null;
@@ -95,6 +108,18 @@
         super.onDetachedFromWindow();
     }
 
+    // From SecurityController.
+    @Override
+    public void onStateChanged() {
+        post(new Runnable() {
+            @Override
+            public void run() {
+                mVpnVisible = mSC.isVpnEnabled();
+                apply();
+            }
+        });
+    }
+
     @Override
     public void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription) {
         mWifiVisible = visible;
@@ -168,6 +193,8 @@
     private void apply() {
         if (mWifiGroup == null) return;
 
+        mVpn.setVisibility(mVpnVisible ? View.VISIBLE : View.GONE);
+        if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
         if (mWifiVisible) {
             mWifi.setImageResource(mWifiStrengthId);
             mWifiGroup.setContentDescription(mWifiDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
index 9dfbb27..23810f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
@@ -24,5 +24,5 @@
  * Keyguard.
  */
 public interface ActivityStarter {
-    public void startActivity(Intent intent, boolean dismissShade, boolean afterKeyguardGone);
+    public void startActivity(Intent intent, boolean dismissShade);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index f9da30f..e84ca52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -315,15 +315,15 @@
     public void launchCamera() {
         mFlashlightController.killFlashlight();
         Intent intent = getCameraIntent();
-        boolean wouldLaunchResolverActivity = mPreviewInflater.wouldLaunchResolverActivity(intent);
+        boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
+                mContext, intent, mLockPatternUtils.getCurrentUser());
         if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
             mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         } else {
 
             // We need to delay starting the activity because ResolverActivity finishes itself if
             // launched behind lockscreen.
-            mActivityStarter.startActivity(intent, false /* dismissShade */,
-                    wouldLaunchResolverActivity /* afterKeyguardGone */);
+            mActivityStarter.startActivity(intent, false /* dismissShade */);
         }
     }
 
@@ -337,8 +337,7 @@
                 }
             });
         } else {
-            mActivityStarter.startActivity(PHONE_INTENT, false /* dismissShade */,
-                    mPreviewInflater.wouldLaunchResolverActivity(PHONE_INTENT));
+            mActivityStarter.startActivity(PHONE_INTENT, false /* dismissShade */);
         }
     }
 
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 861bf4a..128c687 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -149,6 +149,7 @@
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.PreviewInflater;
 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
 import com.android.systemui.statusbar.policy.SecurityControllerImpl;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -786,8 +787,11 @@
         mNetworkController.addSignalCluster(signalCluster);
         mNetworkController.addSignalCluster(signalClusterKeyguard);
         mNetworkController.addSignalCluster(signalClusterQs);
+        signalCluster.setSecurityController(mSecurityController);
         signalCluster.setNetworkController(mNetworkController);
+        signalClusterKeyguard.setSecurityController(mSecurityController);
         signalClusterKeyguard.setNetworkController(mNetworkController);
+        signalClusterQs.setSecurityController(mSecurityController);
         signalClusterQs.setNetworkController(mNetworkController);
         final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
         if (isAPhone) {
@@ -2067,8 +2071,8 @@
     }
 
     @Override
-    public void startActivity(Intent intent, boolean dismissShade, boolean afterKeyguardGone) {
-        startActivityDismissingKeyguard(intent, false, dismissShade, afterKeyguardGone);
+    public void startActivity(Intent intent, boolean dismissShade) {
+        startActivityDismissingKeyguard(intent, false, dismissShade);
     }
 
     public ScrimController getScrimController() {
@@ -2957,9 +2961,11 @@
     }
 
     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
-            final boolean dismissShade, final boolean afterKeyguardGone) {
+            final boolean dismissShade) {
         if (onlyProvisioned && !isDeviceProvisioned()) return;
 
+        final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
+                mContext, intent, mCurrentUserId);
         final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
         dismissKeyguardThenExecute(new OnDismissAction() {
             @Override
@@ -3308,8 +3314,7 @@
     }
 
     private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
-        startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */,
-                false /* afterKeyguardGone */);
+        startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
     }
 
     private static class FastColorDrawable extends Drawable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index eeb97e3..15a7229 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -497,20 +497,19 @@
         } else if (v == mAlarmStatus && mNextAlarm != null) {
             PendingIntent showIntent = mNextAlarm.getShowIntent();
             if (showIntent != null && showIntent.isActivity()) {
-                mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */,
-                        false /* afterKeyguardGone */);
+                mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */);
             }
         }
     }
 
     private void startSettingsActivity() {
         mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
-                true /* dismissShade */, false /* afterKeyguardGone */);
+                true /* dismissShade */);
     }
 
     private void startBatteryActivity() {
         mActivityStarter.startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY),
-                true /* dismissShade */, false /* afterKeyguardGone */);
+                true /* dismissShade */);
     }
 
     public void setQSPanel(QSPanel qsp) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 4a6f1a8..f04d6a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -928,8 +928,8 @@
                     intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
             boolean wasConnected = mWifiConnected;
             mWifiConnected = networkInfo != null && networkInfo.isConnected();
-            // If we just connected, grab the inintial signal strength and ssid
-            if (mWifiConnected && !wasConnected) {
+            // If Connected grab the signal strength and ssid
+            if (mWifiConnected) {
                 // try getting it out of the intent first
                 WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
                 if (info == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index cdbe494..030cd6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -20,14 +20,12 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardActivityLauncher;
 import com.android.systemui.statusbar.phone.KeyguardPreviewContainer;
 
 import java.util.List;
@@ -107,20 +105,21 @@
         return info;
     }
 
-    public boolean wouldLaunchResolverActivity(Intent intent) {
-        PackageManager packageManager = mContext.getPackageManager();
+    public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent,
+            int currentUserId) {
+        PackageManager packageManager = ctx.getPackageManager();
         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+                intent, PackageManager.MATCH_DEFAULT_ONLY, currentUserId);
         if (appList.size() == 0) {
             return false;
         }
         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
-                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
-                mLockPatternUtils.getCurrentUser());
+                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA, currentUserId);
         return wouldLaunchResolverActivity(resolved, appList);
     }
 
-    private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
+    private static boolean wouldLaunchResolverActivity(
+            ResolveInfo resolved, List<ResolveInfo> appList) {
         // If the list contains the above resolved activity, then it can't be
         // ResolverActivity itself.
         for (int i = 0; i < appList.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index a15ddaf..2fbb812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -139,14 +139,14 @@
     }
 
     @Override
-    public void addCallback(SecurityControllerCallback callback) {
+    public void removeCallback(SecurityControllerCallback callback) {
         if (callback == null) return;
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
         mCallbacks.remove(callback);
     }
 
     @Override
-    public void removeCallback(SecurityControllerCallback callback) {
+    public void addCallback(SecurityControllerCallback callback) {
         if (callback == null || mCallbacks.contains(callback)) return;
         if (DEBUG) Log.d(TAG, "addCallback " + callback);
         mCallbacks.add(callback);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index acb4827..0586a83 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -140,8 +140,7 @@
         @Override
         public void run() {
             getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
-                    ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */,
-                    false /* afterKeyguardGone */);
+                    ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
             mPanel.postDismiss(mDismissDelay);
         }
     };
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index a43a2a6..ebe21ff 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -746,14 +746,16 @@
     }
 
     /**
-     * Gets the bounds of the accessibility focus in the active window.
+     * Gets a point within the accessibility focused node where we can send down
+     * and up events to perform a click.
      *
-     * @param outBounds The output to which to write the focus bounds.
-     * @return Whether accessibility focus was found and the bounds are populated.
+     * @param outPoint The click point to populate.
+     * @return Whether accessibility a click point was found and set.
      */
     // TODO: (multi-display) Make sure this works for multiple displays.
-    boolean getAccessibilityFocusBounds(Rect outBounds) {
-        return getInteractionBridgeLocked().getAccessibilityFocusBoundsNotLocked(outBounds);
+    boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
+        return getInteractionBridgeLocked()
+                .getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
     }
 
     /**
@@ -2196,8 +2198,8 @@
             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName,
-                        partialInteractiveRegion, interactionId, callback, mFetchFlags, interrogatingPid,
-                        interrogatingTid, spec);
+                        partialInteractiveRegion, interactionId, callback, mFetchFlags,
+                        interrogatingPid, interrogatingTid, spec);
                 return true;
             } catch (RemoteException re) {
                 if (DEBUG) {
@@ -2248,8 +2250,8 @@
             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
-                        partialInteractiveRegion, interactionId, callback, mFetchFlags, interrogatingPid,
-                        interrogatingTid, spec);
+                        partialInteractiveRegion, interactionId, callback, mFetchFlags,
+                        interrogatingPid, interrogatingTid, spec);
                 return true;
             } catch (RemoteException re) {
                 if (DEBUG) {
@@ -2352,8 +2354,9 @@
             final long identityToken = Binder.clearCallingIdentity();
             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
-                connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion, interactionId,
-                        callback, mFetchFlags, interrogatingPid, interrogatingTid, spec);
+                connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion,
+                        interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
+                        spec);
                 return true;
             } catch (RemoteException re) {
                 if (DEBUG) {
@@ -2403,8 +2406,9 @@
             final long identityToken = Binder.clearCallingIdentity();
             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
-                connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion, interactionId,
-                        callback, mFetchFlags, interrogatingPid, interrogatingTid, spec);
+                connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion,
+                        interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
+                        spec);
                 return true;
             } catch (RemoteException re) {
                 if (DEBUG) {
@@ -2460,6 +2464,7 @@
             return true;
         }
 
+        @Override
         public boolean performGlobalAction(int action) {
             synchronized (mLock) {
                 // We treat calls from a profile as if made by its parent as profiles
@@ -2501,6 +2506,57 @@
         }
 
         @Override
+        public  boolean computeClickPointInScreen(int accessibilityWindowId,
+                long accessibilityNodeId, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
+                throws RemoteException {
+            final int resolvedWindowId;
+            IAccessibilityInteractionConnection connection = null;
+            Region partialInteractiveRegion = mTempRegion;
+            synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
+                final int resolvedUserId = mSecurityPolicy
+                        .resolveCallingUserIdEnforcingPermissionsLocked(
+                                UserHandle.getCallingUserId());
+                if (resolvedUserId != mCurrentUserId) {
+                    return false;
+                }
+                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
+                final boolean permissionGranted =
+                        mSecurityPolicy.canRetrieveWindowContentLocked(this);
+                if (!permissionGranted) {
+                    return false;
+                } else {
+                    connection = getConnectionLocked(resolvedWindowId);
+                    if (connection == null) {
+                        return false;
+                    }
+                }
+                if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
+                        resolvedWindowId, partialInteractiveRegion)) {
+                    partialInteractiveRegion = null;
+                }
+            }
+            final int interrogatingPid = Binder.getCallingPid();
+            final long identityToken = Binder.clearCallingIdentity();
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
+            try {
+                connection.computeClickPointInScreen(accessibilityNodeId, partialInteractiveRegion,
+                        interactionId, callback, interrogatingPid, interrogatingTid, spec);
+                return true;
+            } catch (RemoteException re) {
+                if (DEBUG) {
+                    Slog.e(LOG_TAG, "Error computeClickPointInScreen().");
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+            return false;
+        }
+
+        @Override
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
             synchronized (mLock) {
@@ -3119,30 +3175,43 @@
             }
         }
 
-        public boolean getAccessibilityFocusBoundsNotLocked(Rect outBounds) {
+        public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) {
             AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
             if (focus == null) {
                 return false;
             }
 
             synchronized (mLock) {
-                focus.getBoundsInScreen(outBounds);
+                Point point = mClient.computeClickPointInScreen(mConnectionId,
+                        focus.getWindowId(), focus.getSourceNodeId());
+
+                if (point == null) {
+                    return false;
+                }
 
                 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
                 if (spec != null && !spec.isNop()) {
-                    outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
-                    outBounds.scale(1 / spec.scale);
+                    point.offset((int) -spec.offsetX, (int) -spec.offsetY);
+                    point.x = (int) (point.x * (1 / spec.scale));
+                    point.y = (int) (point.y * (1 / spec.scale));
                 }
 
-                // Clip to the window rectangle.
+                // Make sure the point is within the window.
                 Rect windowBounds = mTempRect;
                 getActiveWindowBounds(windowBounds);
-                outBounds.intersect(windowBounds);
+                if (!windowBounds.contains(point.x, point.y)) {
+                    return false;
+                }
 
-                // Clip to the screen rectangle.
-                mDefaultDisplay.getRealSize(mTempPoint);
-                outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y);
+                // Make sure the point is within the screen.
+                Point screenSize = mTempPoint;
+                mDefaultDisplay.getRealSize(screenSize);
+                if (point.x < 0 || point.x > screenSize.x
+                        || point.y < 0 || point.y > screenSize.y) {
+                    return false;
+                }
 
+                outPoint.set(point.x, point.y);
                 return true;
             }
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index ac0ca0a..9e63433 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -24,6 +24,7 @@
 import android.gesture.GestureStore;
 import android.gesture.GestureStroke;
 import android.gesture.Prediction;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.SystemClock;
@@ -171,6 +172,9 @@
     // Temporary rectangle to avoid instantiation.
     private final Rect mTempRect = new Rect();
 
+    // Temporary point to avoid instantiation.
+    private final Point mTempPoint = new Point();
+
     // Context in which this explorer operates.
     private final Context mContext;
 
@@ -1157,18 +1161,18 @@
                 mInjectedPointerTracker.getLastInjectedHoverEventForClick();
             if (lastExploreEvent == null) {
                 // No last touch explored event but there is accessibility focus in
-                // the active window. We click in the middle of the focus bounds.
-                Rect focusBounds = mTempRect;
-                if (mAms.getAccessibilityFocusBounds(focusBounds)) {
-                    clickLocationX = focusBounds.centerX();
-                    clickLocationY = focusBounds.centerY();
+                // the active window. We click in the focus bounds.
+                Point point = mTempPoint;
+                if (mAms.getAccessibilityFocusClickPointInScreen(point)) {
+                    clickLocationX = point.x;
+                    clickLocationY = point.y;
                 } else {
                     // Out of luck - do nothing.
                     return;
                 }
             } else {
                 // If the click is within the active window but not within the
-                // accessibility focus bounds we click in the focus center.
+                // accessibility focus bounds we click in the focus bounds.
                 final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
                 clickLocationX = (int) lastExploreEvent.getX(lastExplorePointerIndex);
                 clickLocationY = (int) lastExploreEvent.getY(lastExplorePointerIndex);
@@ -1176,12 +1180,10 @@
                 if (mLastTouchedWindowId == mAms.getActiveWindowId()) {
                     mAms.getActiveWindowBounds(activeWindowBounds);
                     if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
-                        Rect focusBounds = mTempRect;
-                        if (mAms.getAccessibilityFocusBounds(focusBounds)) {
-                            if (!focusBounds.contains(clickLocationX, clickLocationY)) {
-                                clickLocationX = focusBounds.centerX();
-                                clickLocationY = focusBounds.centerY();
-                            }
+                        Point point = mTempPoint;
+                        if (mAms.getAccessibilityFocusClickPointInScreen(point)) {
+                            clickLocationX = point.x;
+                            clickLocationY = point.y;
                         }
                     }
                 }
@@ -1330,18 +1332,18 @@
                 mInjectedPointerTracker.getLastInjectedHoverEventForClick();
             if (lastExploreEvent == null) {
                 // No last touch explored event but there is accessibility focus in
-                // the active window. We click in the middle of the focus bounds.
-                Rect focusBounds = mTempRect;
-                if (mAms.getAccessibilityFocusBounds(focusBounds)) {
-                    clickLocationX = focusBounds.centerX();
-                    clickLocationY = focusBounds.centerY();
+                // the active window. We click in the focus bounds.
+                Point point = mTempPoint;
+                if (mAms.getAccessibilityFocusClickPointInScreen(point)) {
+                    clickLocationX = point.x;
+                    clickLocationY = point.y;
                 } else {
                     // Out of luck - do nothing.
                     return;
                 }
             } else {
                 // If the click is within the active window but not within the
-                // accessibility focus bounds we click in the focus center.
+                // accessibility focus bounds we click in the focus bounds.
                 final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
                 clickLocationX = (int) lastExploreEvent.getX(lastExplorePointerIndex);
                 clickLocationY = (int) lastExploreEvent.getY(lastExplorePointerIndex);
@@ -1349,12 +1351,10 @@
                 if (mLastTouchedWindowId == mAms.getActiveWindowId()) {
                     mAms.getActiveWindowBounds(activeWindowBounds);
                     if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
-                        Rect focusBounds = mTempRect;
-                        if (mAms.getAccessibilityFocusBounds(focusBounds)) {
-                            if (!focusBounds.contains(clickLocationX, clickLocationY)) {
-                                clickLocationX = focusBounds.centerX();
-                                clickLocationY = focusBounds.centerY();
-                            }
+                        Point point = mTempPoint;
+                        if (mAms.getAccessibilityFocusClickPointInScreen(point)) {
+                            clickLocationX = point.x;
+                            clickLocationY = point.y;
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6168546..bcf3b17 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -425,13 +425,13 @@
     }
 
     final ActivityRecord topActivity() {
-        // Iterate to find the first non-empty task stack. Note that this code can
-        // be simplified once we stop storing tasks with empty mActivities lists.
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
-            final int topActivityNdx = activities.size() - 1;
-            if (topActivityNdx >= 0) {
-                return activities.get(topActivityNdx);
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (!r.finishing) {
+                    return r;
+                }
             }
         }
         return null;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f821daf..b8261a4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1772,7 +1772,7 @@
                 if (intentActivity != null) {
                     if (isLockTaskModeViolation(intentActivity.task)) {
                         showLockTaskToast();
-                        Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode");
+                        Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                         return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
                     }
                     if (r.task == null) {
@@ -2783,9 +2783,8 @@
         }
 
         // A non-top activity is reporting a visibility change.
-        if ((visible && (top.fullscreen || top.state != ActivityState.RESUMED)) ||
-                top.app == null || top.app.thread == null) {
-            // Can't carry out this request.
+        if (visible && top.fullscreen) {
+            // Let the caller know that it can't be seen.
             if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG, "requestVisibleBehind: returning top.fullscreen="
                     + top.fullscreen + " top.state=" + top.state + " top.app=" + top.app +
                     " top.app.thread=" + top.app.thread);
@@ -2807,9 +2806,12 @@
                 mService.convertFromTranslucent(next.appToken);
             }
         }
-        try {
-            top.app.thread.scheduleBackgroundVisibleBehindChanged(top.appToken, visible);
-        } catch (RemoteException e) {
+        if (top.app != null && top.app.thread != null) {
+            // Notify the top app of the change.
+            try {
+                top.app.thread.scheduleBackgroundVisibleBehindChanged(top.appToken, visible);
+            } catch (RemoteException e) {
+            }
         }
         return true;
     }
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
index 317ebef..b71bad8 100644
--- a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
+++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
@@ -43,6 +43,7 @@
 import java.util.Date;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.TimeZone;
 
 /** Built-in zen condition provider for managing downtime */
 public class DowntimeConditionProvider extends ConditionProviderService {
@@ -275,6 +276,9 @@
                 final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
                 if (DEBUG) Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
                         action, ts(schTime), ts(now), now - schTime));
+            } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+                if (DEBUG) Slog.d(TAG, "timezone changed to " + TimeZone.getDefault());
+                mCalendar.setTimeZone(TimeZone.getDefault());
             } else {
                 if (DEBUG) Slog.d(TAG, action + " fired at " + now);
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 89ea905..496c136 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -42,7 +42,6 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
@@ -50,15 +49,11 @@
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageLite;
-import android.content.pm.PackageParser.PackageParserException;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -70,7 +65,6 @@
 import android.os.SELinux;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -126,6 +120,7 @@
     private static final String ATTR_CREATED_MILLIS = "createdMillis";
     private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
     private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
+    private static final String ATTR_PREPARED = "prepared";
     private static final String ATTR_SEALED = "sealed";
     private static final String ATTR_MODE = "mode";
     private static final String ATTR_INSTALL_FLAGS = "installFlags";
@@ -148,7 +143,6 @@
     private final Context mContext;
     private final PackageManagerService mPm;
     private final AppOpsManager mAppOps;
-    private final StorageManager mStorage;
 
     private final File mStagingDir;
     private final HandlerThread mInstallThread;
@@ -190,7 +184,6 @@
         mContext = context;
         mPm = pm;
         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-        mStorage = StorageManager.from(mContext);
 
         mStagingDir = stagingDir;
 
@@ -266,7 +259,9 @@
             try {
                 final int sessionId = allocateSessionIdLocked();
                 mLegacySessions.put(sessionId, true);
-                return prepareInternalStageDir(sessionId);
+                final File stageDir = buildInternalStageDir(sessionId);
+                prepareInternalStageDir(stageDir);
+                return stageDir;
             } catch (IllegalStateException e) {
                 throw new IOException(e);
             }
@@ -345,6 +340,7 @@
         final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
         final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
         final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
+        final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
         final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
 
         final SessionParams params = new SessionParams(
@@ -362,7 +358,7 @@
 
         return new PackageInstallerSession(mInternalCallback, mContext, mPm,
                 mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
-                createdMillis, stageDir, stageCid, sealed);
+                createdMillis, stageDir, stageCid, prepared, sealed);
     }
 
     private void writeSessionsLocked() {
@@ -410,6 +406,7 @@
         if (session.stageCid != null) {
             writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid);
         }
+        writeBooleanAttribute(out, ATTR_PREPARED, session.isPrepared());
         writeBooleanAttribute(out, ATTR_SEALED, session.isSealed());
 
         writeIntAttribute(out, ATTR_MODE, params.mode);
@@ -483,14 +480,10 @@
             }
         }
 
-        // TODO: treat INHERIT_EXISTING as install for user
-
-        // Figure out where we're going to be staging session data
-        final boolean stageInternal;
-
-        if (params.mode == SessionParams.MODE_FULL_INSTALL) {
-            // Brand new install, use best resolved location. This also verifies
-            // that target has enough free space for the install.
+        if (params.mode == SessionParams.MODE_FULL_INSTALL
+                || params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+            // Resolve best location for install, based on combination of
+            // requested install flags, delta size, and manifest settings.
             final long ident = Binder.clearCallingIdentity();
             try {
                 final int resolved = PackageHelper.resolveInstallLocation(mContext,
@@ -498,46 +491,15 @@
                         params.installFlags);
 
                 if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
-                    stageInternal = true;
+                    params.setInstallFlagsInternal();
                 } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
-                    stageInternal = false;
+                    params.setInstallFlagsExternal();
                 } else {
                     throw new IOException("No storage with enough free space; res=" + resolved);
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
-        } else if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
-            // Inheriting existing install, so stay on the same storage medium.
-            final ApplicationInfo existingApp = mPm.getApplicationInfo(params.appPackageName, 0,
-                    userId);
-            if (existingApp == null) {
-                throw new IllegalStateException(
-                        "Missing existing app " + params.appPackageName);
-            }
-
-            final long existingSize;
-            try {
-                final PackageLite existingPkg = PackageParser.parsePackageLite(
-                        new File(existingApp.getCodePath()), 0);
-                existingSize = PackageHelper.calculateInstalledSize(existingPkg, false,
-                        params.abiOverride);
-            } catch (PackageParserException e) {
-                throw new IllegalStateException(
-                        "Failed to calculate size of " + params.appPackageName);
-            }
-
-            if ((existingApp.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0) {
-                // Internal we can link existing install into place, so we only
-                // need enough space for the new data.
-                checkInternalStorage(params.sizeBytes);
-                stageInternal = true;
-            } else {
-                // External we're going to copy existing install into our
-                // container, so we need footprint of both.
-                checkExternalStorage(params.sizeBytes + existingSize);
-                stageInternal = false;
-            }
         } else {
             throw new IllegalArgumentException("Invalid install mode: " + params.mode);
         }
@@ -563,15 +525,15 @@
             // We're staging to exactly one location
             File stageDir = null;
             String stageCid = null;
-            if (stageInternal) {
-                stageDir = prepareInternalStageDir(sessionId);
+            if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+                stageDir = buildInternalStageDir(sessionId);
             } else {
-                stageCid = prepareExternalStageCid(sessionId, params.sizeBytes);
+                stageCid = buildExternalStageCid(sessionId);
             }
 
             session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
                     mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
-                    createdMillis, stageDir, stageCid, false);
+                    createdMillis, stageDir, stageCid, false, false);
             mSessions.put(sessionId, session);
         }
 
@@ -615,32 +577,16 @@
         }
     }
 
-    private void checkInternalStorage(long sizeBytes) throws IOException {
-        if (sizeBytes <= 0) return;
-
-        final File target = Environment.getDataDirectory();
-        final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target);
-
-        mPm.freeStorage(targetBytes);
-        if (target.getUsableSpace() < targetBytes) {
-            throw new IOException("Not enough internal space to write " + sizeBytes + " bytes");
-        }
-    }
-
-    private void checkExternalStorage(long sizeBytes) throws IOException {
-        if (sizeBytes <= 0) return;
-
-        final File target = new UserEnvironment(UserHandle.USER_OWNER)
-                .getExternalStorageDirectory();
-        final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target);
-
-        if (target.getUsableSpace() < targetBytes) {
-            throw new IOException("Not enough external space to write " + sizeBytes + " bytes");
-        }
-    }
-
     @Override
     public IPackageInstallerSession openSession(int sessionId) {
+        try {
+            return openSessionInternal(sessionId);
+        } catch (IOException e) {
+            throw ExceptionUtils.wrap(e);
+        }
+    }
+
+    private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
         synchronized (mSessions) {
             final PackageInstallerSession session = mSessions.get(sessionId);
             if (session == null || !isCallingUidOwner(session)) {
@@ -665,40 +611,37 @@
         throw new IllegalStateException("Failed to allocate session ID");
     }
 
-    private File prepareInternalStageDir(int sessionId) throws IOException {
-        final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp");
+    private File buildInternalStageDir(int sessionId) {
+        return new File(mStagingDir, "vmdl" + sessionId + ".tmp");
+    }
 
-        if (file.exists()) {
-            throw new IOException("Session dir already exists: " + file);
+    static void prepareInternalStageDir(File stageDir) throws IOException {
+        if (stageDir.exists()) {
+            throw new IOException("Session dir already exists: " + stageDir);
         }
 
         try {
-            Os.mkdir(file.getAbsolutePath(), 0755);
-            Os.chmod(file.getAbsolutePath(), 0755);
+            Os.mkdir(stageDir.getAbsolutePath(), 0755);
+            Os.chmod(stageDir.getAbsolutePath(), 0755);
         } catch (ErrnoException e) {
             // This purposefully throws if directory already exists
-            throw new IOException("Failed to prepare session dir", e);
+            throw new IOException("Failed to prepare session dir: " + stageDir, e);
         }
 
-        if (!SELinux.restorecon(file)) {
-            throw new IOException("Failed to restorecon session dir");
+        if (!SELinux.restorecon(stageDir)) {
+            throw new IOException("Failed to restorecon session dir: " + stageDir);
         }
-
-        return file;
     }
 
-    private String prepareExternalStageCid(int sessionId, long sizeBytes) throws IOException {
-        if (sizeBytes <= 0) {
-            throw new IOException("Session must provide valid size for ASEC");
-        }
+    private String buildExternalStageCid(int sessionId) {
+        return "smdl" + sessionId + ".tmp";
+    }
 
-        final String cid = "smdl" + sessionId + ".tmp";
-        if (PackageHelper.createSdDir(sizeBytes, cid, PackageManagerService.getEncryptKey(),
+    static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException {
+        if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(),
                 Process.SYSTEM_UID, true) == null) {
-            throw new IOException("Failed to create ASEC");
+            throw new IOException("Failed to create session cid: " + stageCid);
         }
-
-        return cid;
     }
 
     @Override
@@ -1031,6 +974,12 @@
             writeSessionsAsync();
         }
 
+        public void onSessionPrepared(PackageInstallerSession session) {
+            // We prepared the destination to write into; we want to persist
+            // this, but it's not critical enough to block for.
+            writeSessionsAsync();
+        }
+
         public void onSessionSealed(PackageInstallerSession session) {
             // It's very important that we block until we've recorded the
             // session as being sealed, since we never want to allow mutation
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index f8273c0..adca46a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -17,15 +17,15 @@
 package com.android.server.pm;
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
-import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
-import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
+import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
+import static com.android.server.pm.PackageInstallerService.prepareInternalStageDir;
 
 import android.content.Context;
 import android.content.Intent;
@@ -88,8 +88,6 @@
     // TODO: enforce INSTALL_ALLOW_TEST
     // TODO: enforce INSTALL_ALLOW_DOWNGRADE
 
-    // TODO: treat INHERIT_EXISTING as installExistingPackage()
-
     private final PackageInstallerService.InternalCallback mCallback;
     private final Context mContext;
     private final PackageManagerService mPm;
@@ -108,18 +106,23 @@
     /** Note that UID is not persisted; it's always derived at runtime. */
     final int installerUid;
 
-    private final AtomicInteger mOpenCount = new AtomicInteger();
+    private final AtomicInteger mActiveCount = new AtomicInteger();
 
     private final Object mLock = new Object();
 
     @GuardedBy("mLock")
     private float mClientProgress = 0;
     @GuardedBy("mLock")
+    private float mInternalProgress = 0;
+
+    @GuardedBy("mLock")
     private float mProgress = 0;
     @GuardedBy("mLock")
     private float mReportedProgress = -1;
 
     @GuardedBy("mLock")
+    private boolean mPrepared = false;
+    @GuardedBy("mLock")
     private boolean mSealed = false;
     @GuardedBy("mLock")
     private boolean mPermissionsAccepted = false;
@@ -184,7 +187,7 @@
     public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
             Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
             String installerPackageName, SessionParams params, long createdMillis,
-            File stageDir, String stageCid, boolean sealed) {
+            File stageDir, String stageCid, boolean prepared, boolean sealed) {
         mCallback = callback;
         mContext = context;
         mPm = pm;
@@ -203,6 +206,7 @@
                     "Exactly one of stageDir or stageCid stage must be set");
         }
 
+        mPrepared = prepared;
         mSealed = sealed;
 
         // Always derived at runtime
@@ -214,8 +218,6 @@
         } else {
             mPermissionsAccepted = false;
         }
-
-        computeProgressLocked();
     }
 
     public SessionInfo generateInfo() {
@@ -227,7 +229,7 @@
                     mResolvedBaseFile.getAbsolutePath() : null;
             info.progress = mProgress;
             info.sealed = mSealed;
-            info.active = mOpenCount.get() > 0;
+            info.active = mActiveCount.get() > 0;
 
             info.mode = params.mode;
             info.sizeBytes = params.sizeBytes;
@@ -238,14 +240,23 @@
         return info;
     }
 
+    public boolean isPrepared() {
+        synchronized (mLock) {
+            return mPrepared;
+        }
+    }
+
     public boolean isSealed() {
         synchronized (mLock) {
             return mSealed;
         }
     }
 
-    private void assertNotSealed(String cookie) {
+    private void assertPreparedAndNotSealed(String cookie) {
         synchronized (mLock) {
+            if (!mPrepared) {
+                throw new IllegalStateException(cookie + " before prepared");
+            }
             if (mSealed) {
                 throw new SecurityException(cookie + " not allowed after commit");
             }
@@ -278,30 +289,26 @@
     @Override
     public void setClientProgress(float progress) {
         synchronized (mLock) {
+            // Always publish first staging movement
+            final boolean forcePublish = (mClientProgress == 0);
             mClientProgress = progress;
-            computeProgressLocked();
+            computeProgressLocked(forcePublish);
         }
-        maybePublishProgress();
     }
 
     @Override
     public void addClientProgress(float progress) {
         synchronized (mLock) {
-            mClientProgress += progress;
-            computeProgressLocked();
-        }
-        maybePublishProgress();
-    }
-
-    private void computeProgressLocked() {
-        if (mProgress <= 0.8f) {
-            mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f);
+            setClientProgress(mClientProgress + progress);
         }
     }
 
-    private void maybePublishProgress() {
+    private void computeProgressLocked(boolean forcePublish) {
+        mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
+                + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
+
         // Only publish when meaningful change
-        if (Math.abs(mProgress - mReportedProgress) > 0.01) {
+        if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
             mReportedProgress = mProgress;
             mCallback.onSessionProgressChanged(this, mProgress);
         }
@@ -309,7 +316,7 @@
 
     @Override
     public String[] getNames() {
-        assertNotSealed("getNames");
+        assertPreparedAndNotSealed("getNames");
         try {
             return resolveStageDir().list();
         } catch (IOException e) {
@@ -333,7 +340,7 @@
         // will block any attempted install transitions.
         final FileBridge bridge;
         synchronized (mLock) {
-            assertNotSealed("openWrite");
+            assertPreparedAndNotSealed("openWrite");
 
             bridge = new FileBridge();
             mBridges.add(bridge);
@@ -387,7 +394,7 @@
     }
 
     private ParcelFileDescriptor openReadInternal(String name) throws IOException {
-        assertNotSealed("openRead");
+        assertPreparedAndNotSealed("openRead");
 
         try {
             if (!FileUtils.isValidExtFilename(name)) {
@@ -407,6 +414,30 @@
     public void commit(IntentSender statusReceiver) {
         Preconditions.checkNotNull(statusReceiver);
 
+        synchronized (mLock) {
+            if (!mSealed) {
+                // Verify that all writers are hands-off
+                for (FileBridge bridge : mBridges) {
+                    if (!bridge.isClosed()) {
+                        throw new SecurityException("Files still open");
+                    }
+                }
+
+                // Persist the fact that we've sealed ourselves to prevent
+                // mutations of any hard links we create.
+                mSealed = true;
+                mCallback.onSessionSealed(this);
+            }
+        }
+
+        // Client staging is fully done at this point
+        mClientProgress = 1f;
+        computeProgressLocked(true);
+
+        // This ongoing commit should keep session active, even though client
+        // will probably close their end.
+        mActiveCount.incrementAndGet();
+
         final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
                 statusReceiver, sessionId);
         mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
@@ -414,22 +445,10 @@
 
     private void commitLocked() throws PackageManagerException {
         if (mDestroyed) {
-            throw new PackageManagerException(INSTALL_FAILED_ALREADY_EXISTS, "Invalid session");
+            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
         }
-
-        // Verify that all writers are hands-off
         if (!mSealed) {
-            for (FileBridge bridge : mBridges) {
-                if (!bridge.isClosed()) {
-                    throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
-                            "Files still open");
-                }
-            }
-            mSealed = true;
-
-            // Persist the fact that we've sealed ourselves to prevent mutations
-            // of any hard links we create below.
-            mCallback.onSessionSealed(this);
+            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
         }
 
         try {
@@ -458,6 +477,10 @@
                 mRemoteObserver.onUserActionRequired(intent);
             } catch (RemoteException ignored) {
             }
+
+            // Commit was keeping session marked as active until now; release
+            // that extra refcount so session appears idle.
+            close();
             return;
         }
 
@@ -487,8 +510,8 @@
         }
 
         // TODO: surface more granular state from dexopt
-        mProgress = 0.9f;
-        maybePublishProgress();
+        mInternalProgress = 0.5f;
+        computeProgressLocked(true);
 
         // Unpack native libraries
         extractNativeLibraries(mResolvedStageDir, params.abiOverride);
@@ -831,15 +854,35 @@
         }
     }
 
-    public void open() {
-        if (mOpenCount.getAndIncrement() == 0) {
+    public void open() throws IOException {
+        if (mActiveCount.getAndIncrement() == 0) {
             mCallback.onSessionActiveChanged(this, true);
         }
+
+        synchronized (mLock) {
+            if (!mPrepared) {
+                if (stageDir != null) {
+                    prepareInternalStageDir(stageDir);
+                } else if (stageCid != null) {
+                    prepareExternalStageCid(stageCid, params.sizeBytes);
+
+                    // TODO: deliver more granular progress for ASEC allocation
+                    mInternalProgress = 0.25f;
+                    computeProgressLocked(true);
+                } else {
+                    throw new IllegalArgumentException(
+                            "Exactly one of stageDir or stageCid stage must be set");
+                }
+
+                mPrepared = true;
+                mCallback.onSessionPrepared(this);
+            }
+        }
     }
 
     @Override
     public void close() {
-        if (mOpenCount.decrementAndGet() == 0) {
+        if (mActiveCount.decrementAndGet() == 0) {
             mCallback.onSessionActiveChanged(this, false);
         }
     }
@@ -869,6 +912,11 @@
         synchronized (mLock) {
             mSealed = true;
             mDestroyed = true;
+
+            // Force shut down all bridges
+            for (FileBridge bridge : mBridges) {
+                bridge.forceClose();
+            }
         }
         if (stageDir != null) {
             FileUtils.deleteContents(stageDir);
diff --git a/telecomm/java/android/telecomm/AudioState.java b/telecomm/java/android/telecomm/AudioState.java
index a5fda79..314704b 100644
--- a/telecomm/java/android/telecomm/AudioState.java
+++ b/telecomm/java/android/telecomm/AudioState.java
@@ -34,7 +34,7 @@
     /** Direct the audio stream through a wired headset. */
     public static final int ROUTE_WIRED_HEADSET = 0x00000004;
 
-    /** Direct the audio stream through the device's spakerphone. */
+    /** Direct the audio stream through the device's speakerphone. */
     public static final int ROUTE_SPEAKER       = 0x00000008;
 
     /**
@@ -43,7 +43,10 @@
      */
     public static final int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
 
-    /** Bit mask of all possible audio routes. */
+    /** Bit mask of all possible audio routes.
+     *
+     * @hide
+     */
     public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
             ROUTE_SPEAKER;
 
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
index c838b48..f9c3ac3 100644
--- a/telecomm/java/android/telecomm/Conference.java
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -54,7 +54,7 @@
         mPhoneAccount = phoneAccount;
     }
 
-    public final PhoneAccountHandle getPhoneAccount() {
+    public final PhoneAccountHandle getPhoneAccountHandle() {
         return mPhoneAccount;
     }
 
@@ -183,7 +183,7 @@
     }
 
     /**
-     * Tears down the conference object and any of it's current connections.
+     * Tears down the conference object and any of its current connections.
      */
     public final void destroy() {
         Log.d(this, "destroying conference : %s", this);
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
index 39ae59a..d5a6aa5 100644
--- a/telecomm/java/android/telecomm/ConnectionRequest.java
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -29,31 +29,25 @@
 
     // TODO: Token to limit recursive invocations
     private final PhoneAccountHandle mAccountHandle;
-    private final Uri mHandle;
-    private final int mHandlePresentation;
+    private final Uri mAddress;
     private final Bundle mExtras;
     private final int mVideoState;
 
     /**
      * @param accountHandle The accountHandle which should be used to place the call.
      * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect.
-     * @param handlePresentation The {@link PropertyPresentation} which controls how the handle
-     *         is shown.
      * @param extras Application-specific extra data.
      */
     public ConnectionRequest(
             PhoneAccountHandle accountHandle,
             Uri handle,
-            int handlePresentation,
             Bundle extras) {
-        this(accountHandle, handle, handlePresentation, extras, VideoProfile.VideoState.AUDIO_ONLY);
+        this(accountHandle, handle, extras, VideoProfile.VideoState.AUDIO_ONLY);
     }
 
     /**
      * @param accountHandle The accountHandle which should be used to place the call.
      * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect.
-     * @param handlePresentation The {@link PropertyPresentation} which controls how the handle
-     *         is shown.
      * @param extras Application-specific extra data.
      * @param videoState Determines the video state for the connection.
      * @hide
@@ -61,20 +55,17 @@
     public ConnectionRequest(
             PhoneAccountHandle accountHandle,
             Uri handle,
-            int handlePresentation,
             Bundle extras,
             int videoState) {
         mAccountHandle = accountHandle;
-        mHandle = handle;
-        mHandlePresentation = handlePresentation;
+        mAddress = handle;
         mExtras = extras;
         mVideoState = videoState;
     }
 
     private ConnectionRequest(Parcel in) {
         mAccountHandle = in.readParcelable(getClass().getClassLoader());
-        mHandle = in.readParcelable(getClass().getClassLoader());
-        mHandlePresentation = in.readInt();
+        mAddress = in.readParcelable(getClass().getClassLoader());
         mExtras = in.readParcelable(getClass().getClassLoader());
         mVideoState = in.readInt();
     }
@@ -87,12 +78,7 @@
     /**
      * The handle (e.g., phone number) to which the {@link Connection} is to connect.
      */
-    public Uri getHandle() { return mHandle; }
-
-    /**
-     * The {@link PropertyPresentation} which controls how the handle is shown.
-     */
-    public int getHandlePresentation() { return mHandlePresentation; }
+    public Uri getAddress() { return mAddress; }
 
     /**
      * Application-specific extra data. Used for passing back information from an incoming
@@ -118,9 +104,9 @@
     @Override
     public String toString() {
         return String.format("ConnectionRequest %s %s",
-                mHandle == null
+                mAddress == null
                         ? Uri.EMPTY
-                        : Connection.toLogSafePhoneNumber(mHandle.toString()),
+                        : Connection.toLogSafePhoneNumber(mAddress.toString()),
                 mExtras == null ? "" : mExtras);
     }
 
@@ -147,8 +133,7 @@
     @Override
     public void writeToParcel(Parcel destination, int flags) {
         destination.writeParcelable(mAccountHandle, 0);
-        destination.writeParcelable(mHandle, 0);
-        destination.writeInt(mHandlePresentation);
+        destination.writeParcelable(mAddress, 0);
         destination.writeParcelable(mExtras, 0);
         destination.writeInt(mVideoState);
     }
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 833aa26..39365b6 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -781,7 +781,7 @@
                 }
             }
             ParcelableConference parcelableConference = new ParcelableConference(
-                    conference.getPhoneAccount(),
+                    conference.getPhoneAccountHandle(),
                     conference.getState(),
                     conference.getCapabilities(),
                     connectionIds);
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 79193c2..8ad0ad0 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -325,8 +325,7 @@
         final String id = UUID.randomUUID().toString();
         final ConnectionRequest newRequest = new ConnectionRequest(
                 request.getAccountHandle(),
-                request.getHandle(),
-                request.getHandlePresentation(),
+                request.getAddress(),
                 request.getExtras(),
                 request.getVideoState());
         try {
diff --git a/telecomm/java/android/telecomm/StatusHints.java b/telecomm/java/android/telecomm/StatusHints.java
index f7c4f2f..ff96a5b 100644
--- a/telecomm/java/android/telecomm/StatusHints.java
+++ b/telecomm/java/android/telecomm/StatusHints.java
@@ -32,23 +32,24 @@
  */
 public final class StatusHints implements Parcelable {
 
-    private final ComponentName mComponentName;
+    private final ComponentName mPackageName;
     private final CharSequence mLabel;
     private final int mIconResId;
     private final Bundle mExtras;
 
-    public StatusHints(ComponentName componentName, CharSequence label, int iconResId, Bundle extras) {
-        mComponentName = componentName;
+    public StatusHints(ComponentName packageName, CharSequence label, int iconResId,
+            Bundle extras) {
+        mPackageName = packageName;
         mLabel = label;
         mIconResId = iconResId;
         mExtras = extras;
     }
 
     /**
-     * @return A component used to load the icon.
+     * @return A package used to load the icon.
      */
-    public ComponentName getComponentName() {
-        return mComponentName;
+    public ComponentName getPackageName() {
+        return mPackageName;
     }
 
     /**
@@ -88,7 +89,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeParcelable(mComponentName, flags);
+        out.writeParcelable(mPackageName, flags);
         out.writeCharSequence(mLabel);
         out.writeInt(mIconResId);
         out.writeParcelable(mExtras, 0);
@@ -106,7 +107,7 @@
     };
 
     private StatusHints(Parcel in) {
-        mComponentName = in.readParcelable(getClass().getClassLoader());
+        mPackageName = in.readParcelable(getClass().getClassLoader());
         mLabel = in.readCharSequence();
         mIconResId = in.readInt();
         mExtras = in.readParcelable(getClass().getClassLoader());
@@ -115,16 +116,16 @@
     private Drawable getIcon(Context context, int resId) {
         Context packageContext;
         try {
-            packageContext = context.createPackageContext(mComponentName.getPackageName(), 0);
+            packageContext = context.createPackageContext(mPackageName.getPackageName(), 0);
         } catch (PackageManager.NameNotFoundException e) {
-            Log.e(this, e, "Cannot find package %s", mComponentName.getPackageName());
+            Log.e(this, e, "Cannot find package %s", mPackageName.getPackageName());
             return null;
         }
         try {
             return packageContext.getDrawable(resId);
         } catch (MissingResourceException e) {
             Log.e(this, e, "Cannot find icon %d in package %s",
-                    resId, mComponentName.getPackageName());
+                    resId, mPackageName.getPackageName());
             return null;
         }
     }
@@ -133,7 +134,7 @@
     public boolean equals(Object other) {
         if (other != null && other instanceof StatusHints) {
             StatusHints otherHints = (StatusHints) other;
-            return Objects.equals(otherHints.getComponentName(), getComponentName()) &&
+            return Objects.equals(otherHints.getPackageName(), getPackageName()) &&
                     Objects.equals(otherHints.getLabel(), getLabel()) &&
                     otherHints.getIconResId() == getIconResId() &&
                     Objects.equals(otherHints.getExtras(), getExtras());
@@ -143,7 +144,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(mComponentName) + Objects.hashCode(mLabel) + mIconResId +
+        return Objects.hashCode(mPackageName) + Objects.hashCode(mLabel) + mIconResId +
                 Objects.hashCode(mExtras);
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ac2a176..21f200f 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -341,6 +341,12 @@
 
     /**
      * @hide
+     * last time we connected, this configuration had no internet access
+     */
+    public boolean noInternetAccess;
+
+    /**
+     * @hide
      * Uid of app creating the configuration
      */
     @SystemApi
@@ -673,6 +679,49 @@
     @SystemApi
     public int numAssociation;
 
+    /**
+     * @hide
+     * Number of time user disabled WiFi while associated to this configuration with Low RSSI.
+     */
+    public int numUserTriggeredWifiDisableLowRSSI;
+
+    /**
+     * @hide
+     * Number of time user disabled WiFi while associated to this configuration with Bad RSSI.
+     */
+    public int numUserTriggeredWifiDisableBadRSSI;
+
+    /**
+     * @hide
+     * Number of time user disabled WiFi while associated to this configuration
+     * and RSSI was not HIGH.
+     */
+    public int numUserTriggeredWifiDisableNotHighRSSI;
+
+    /**
+     * @hide
+     * Number of ticks associated to this configuration with Low RSSI.
+     */
+    public int numTicksAtLowRSSI;
+
+    /**
+     * @hide
+     * Number of ticks associated to this configuration with Bad RSSI.
+     */
+    public int numTicksAtBadRSSI;
+
+    /**
+     * @hide
+     * Number of ticks associated to this configuration
+     * and RSSI was not HIGH.
+     */
+    public int numTicksAtNotHighRSSI;
+    /**
+     * @hide
+     * Number of time user (WifiManager) triggered association to this configuration.
+     * TODO: count this only for Wifi Settings uuid, so as to not count 3rd party apps
+     */
+    public int numUserTriggeredJoinAttempts;
 
     /**
      * @hide
@@ -725,6 +774,7 @@
         selfAdded = false;
         didSelfAdd = false;
         ephemeral = false;
+        noInternetAccess = false;
         mIpConfiguration = new IpConfiguration();
     }
 
@@ -824,8 +874,10 @@
             sbuf.append(" autoJoinStatus ").append(this.numConnectionFailures).append("\n");
         }
         if (this.didSelfAdd || this.selfAdded) {
-            if (this.didSelfAdd) sbuf.append(" didSelfAdd ");
-            if (this.selfAdded) sbuf.append(" selfAdded ");
+            if (this.didSelfAdd) sbuf.append(" didSelfAdd");
+            if (this.selfAdded) sbuf.append(" selfAdded");
+            if (this.noInternetAccess) sbuf.append(" noInternetAccess");
+
             sbuf.append("\n");
         }
         sbuf.append(" KeyMgmt:");
@@ -896,18 +948,44 @@
 
         sbuf.append(mIpConfiguration.toString());
 
-        if (selfAdded)  sbuf.append("selfAdded");
-        if (creatorUid != 0)  sbuf.append("uid=" + Integer.toString(creatorUid));
+        if (this.creatorUid != 0)  sbuf.append("uid=" + Integer.toString(creatorUid));
 
-        if (blackListTimestamp != 0) {
+        if (this.blackListTimestamp != 0) {
             long now_ms = System.currentTimeMillis();
-            long diff = now_ms - blackListTimestamp;
+            long diff = now_ms - this.blackListTimestamp;
             if (diff <= 0) {
                 sbuf.append("blackListed since <incorrect>");
             } else {
                 sbuf.append("blackListed since ").append(Long.toString(diff/1000)).append( "sec");
             }
         }
+        sbuf.append('\n');
+        if (this.linkedConfigurations != null) {
+            for(String key : this.linkedConfigurations.keySet()) {
+                sbuf.append(" linked: ").append(key);
+                sbuf.append('\n');
+            }
+        }
+        if (this.connectChoices != null) {
+            for(String key : this.connectChoices.keySet()) {
+                Integer choice = this.connectChoices.get(key);
+                if (choice != null) {
+                    sbuf.append(" choice: ").append(key);
+                    sbuf.append(" = ").append(choice);
+                    sbuf.append('\n');
+                }
+            }
+        }
+        sbuf.append(" triggeredLow: ").append(numUserTriggeredWifiDisableLowRSSI);
+        sbuf.append(" triggeredBad: ").append(numUserTriggeredWifiDisableBadRSSI);
+        sbuf.append(" triggeredNotHigh: ").append(numUserTriggeredWifiDisableNotHighRSSI);
+        sbuf.append('\n');
+        sbuf.append(" ticksLow: ").append(numTicksAtLowRSSI);
+        sbuf.append(" ticksBad: ").append(numTicksAtBadRSSI);
+        sbuf.append(" ticksNotHigh: ").append(numTicksAtNotHighRSSI);
+        sbuf.append('\n');
+        sbuf.append(" triggeredJoin: ").append(numUserTriggeredJoinAttempts);
+        sbuf.append('\n');
 
         return sbuf.toString();
     }
@@ -1197,7 +1275,7 @@
             mCachedConfigKey = null; //force null configKey
             autoJoinStatus = source.autoJoinStatus;
             selfAdded = source.selfAdded;
-
+            noInternetAccess = source.noInternetAccess;
             if (source.visibility != null) {
                 visibility = new Visibility(source.visibility);
             }
@@ -1217,6 +1295,13 @@
             numScorerOverride = source.numScorerOverride;
             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
             numAssociation = source.numAssociation;
+            numUserTriggeredWifiDisableLowRSSI = source.numUserTriggeredWifiDisableLowRSSI;
+            numUserTriggeredWifiDisableBadRSSI = source.numUserTriggeredWifiDisableBadRSSI;
+            numUserTriggeredWifiDisableNotHighRSSI = source.numUserTriggeredWifiDisableNotHighRSSI;
+            numTicksAtLowRSSI = source.numTicksAtLowRSSI;
+            numTicksAtBadRSSI = source.numTicksAtBadRSSI;
+            numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
+            numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
         }
     }
 
@@ -1259,6 +1344,7 @@
         dest.writeInt(autoJoinStatus);
         dest.writeInt(selfAdded ? 1 : 0);
         dest.writeInt(didSelfAdd ? 1 : 0);
+        dest.writeInt(noInternetAccess ? 1 : 0);
         dest.writeInt(creatorUid);
         dest.writeInt(lastConnectUid);
         dest.writeInt(lastUpdateUid);
@@ -1269,6 +1355,14 @@
         dest.writeInt(numScorerOverride);
         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
         dest.writeInt(numAssociation);
+        dest.writeInt(numUserTriggeredWifiDisableLowRSSI);
+        dest.writeInt(numUserTriggeredWifiDisableBadRSSI);
+        dest.writeInt(numUserTriggeredWifiDisableNotHighRSSI);
+        dest.writeInt(numTicksAtLowRSSI);
+        dest.writeInt(numTicksAtBadRSSI);
+        dest.writeInt(numTicksAtNotHighRSSI);
+        dest.writeInt(numUserTriggeredJoinAttempts);
+
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -1307,6 +1401,7 @@
                 config.autoJoinStatus = in.readInt();
                 config.selfAdded = in.readInt() != 0;
                 config.didSelfAdd = in.readInt() != 0;
+                config.noInternetAccess = in.readInt() != 0;
                 config.creatorUid = in.readInt();
                 config.lastConnectUid = in.readInt();
                 config.lastUpdateUid = in.readInt();
@@ -1317,6 +1412,13 @@
                 config.numScorerOverride = in.readInt();
                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
                 config.numAssociation = in.readInt();
+                config.numUserTriggeredWifiDisableLowRSSI = in.readInt();
+                config.numUserTriggeredWifiDisableBadRSSI = in.readInt();
+                config.numUserTriggeredWifiDisableNotHighRSSI = in.readInt();
+                config.numTicksAtLowRSSI = in.readInt();
+                config.numTicksAtBadRSSI = in.readInt();
+                config.numTicksAtNotHighRSSI = in.readInt();
+                config.numUserTriggeredJoinAttempts = in.readInt();
                 return config;
             }