Merge "Allow array of required permissions in sendBroadcast" into mnc-dev
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 7a20929..dd3d3a8 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2359,7 +2359,7 @@
         intent.setClassName(componentName.getPackageName(),
                 componentName.getClassName());
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST,
-                new ArrayList<Account>(allowableAccounts));
+                allowableAccounts == null ? null : new ArrayList<Account>(allowableAccounts));
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
                 allowableAccountTypes);
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 242986c..71cada3 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1954,13 +1954,14 @@
                         // enough permissions; ask vold to create on our behalf.
                         final IMountService mount = IMountService.Stub.asInterface(
                                 ServiceManager.getService("mount"));
-                        int res = -1;
                         try {
-                            res = mount.mkdirs(getPackageName(), dir.getAbsolutePath());
-                        } catch (Exception ignored) {
-                        }
-                        if (res != 0) {
-                            Log.w(TAG, "Failed to ensure directory: " + dir);
+                            final int res = mount.mkdirs(getPackageName(), dir.getAbsolutePath());
+                            if (res != 0) {
+                                Log.w(TAG, "Failed to ensure " + dir + ": " + res);
+                                dir = null;
+                            }
+                        } catch (Exception e) {
+                            Log.w(TAG, "Failed to ensure " + dir + ": " + e);
                             dir = null;
                         }
                     }
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 6302521..fb81fd1 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -240,6 +240,8 @@
             as.close();
             throw new IOException("bt socket acept failed");
         }
+
+        as.mPfd = new ParcelFileDescriptor(fds[0]);
         as.mSocket = new LocalSocket(fds[0]);
         as.mSocketIS = as.mSocket.getInputStream();
         as.mSocketOS = as.mSocket.getOutputStream();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 103ee29..ceb610a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -502,9 +502,6 @@
 
     void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
     void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
-
-    int getMountExternalMode(int uid);
-
     void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
 
     boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index 96000dd..4dbac05 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -26,7 +26,9 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
+
 import com.android.internal.util.XmlUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -181,14 +183,28 @@
         return getStatusStringFromValue(mMainStatus);
     }
 
-    public static String getStatusStringFromValue(int val) {
-        switch (val) {
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK       : return "ask";
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS    : return "always";
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER     : return "never";
+    public static String getStatusStringFromValue(long val) {
+        StringBuilder sb = new StringBuilder();
+        switch ((int)(val >> 32)) {
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
+                sb.append("always : ");
+                sb.append(Long.toHexString(val & 0x00000000FFFFFFFF));
+                break;
+
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
+                sb.append("ask");
+                break;
+
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER:
+                sb.append("never");
+                break;
+
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
             default:
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED : return "undefined";
+                sb.append("undefined");
+                break;
         }
+        return sb.toString();
     }
 
     @Override
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 92b8055..9b28401 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -38,6 +38,7 @@
     public ArraySet<String> enabledComponents;
 
     public int domainVerificationStatus;
+    public int appLinkGeneration;
 
     public PackageUserState() {
         installed = true;
@@ -60,5 +61,6 @@
                 ? new ArraySet<>(o.enabledComponents) : null;
         blockUninstall = o.blockUninstall;
         domainVerificationStatus = o.domainVerificationStatus;
+        appLinkGeneration = o.appLinkGeneration;
     }
 }
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 579634f..19921b5 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -603,7 +603,7 @@
      * @hide only for resource preloading
      */
     public ConstantState<ColorStateList> getConstantState() {
-        if (mFactory != null) {
+        if (mFactory == null) {
             mFactory = new ColorStateListFactory(this);
         }
         return mFactory;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 9a99a46..731903c 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1918,6 +1918,7 @@
             other.mResId = mResId;
             other.mForce = mForce;
             other.mCount = mCount;
+            other.mHashCode = mHashCode;
             return other;
         }
     }
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 0fb6889..2e4f628 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -723,6 +723,8 @@
         private static final String TAG = "CameraManagerGlobal";
         private final boolean DEBUG = false;
 
+        private final int CAMERA_SERVICE_RECONNECT_DELAY_MS = 1000;
+
         // Singleton instance
         private static final CameraManagerGlobal gCameraManager =
             new CameraManagerGlobal();
@@ -1158,6 +1160,45 @@
         }
 
         /**
+         * Try to connect to camera service after some delay if any client registered camera
+         * availability callback or torch status callback.
+         */
+        private void scheduleCameraServiceReconnectionLocked() {
+            final Handler handler;
+
+            if (mCallbackMap.size() > 0) {
+                handler = mCallbackMap.valueAt(0);
+            } else if (mTorchCallbackMap.size() > 0) {
+                handler = mTorchCallbackMap.valueAt(0);
+            } else {
+                // Not necessary to reconnect camera service if no client registers a callback.
+                return;
+            }
+
+            if (DEBUG) {
+                Log.v(TAG, "Reconnecting Camera Service in " + CAMERA_SERVICE_RECONNECT_DELAY_MS +
+                        " ms");
+            }
+
+            handler.postDelayed(
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            ICameraService cameraService = getCameraService();
+                            if (cameraService == null) {
+                                synchronized(mLock) {
+                                    if (DEBUG) {
+                                        Log.v(TAG, "Reconnecting Camera Service failed.");
+                                    }
+                                    scheduleCameraServiceReconnectionLocked();
+                                }
+                            }
+                        }
+                    },
+                    CAMERA_SERVICE_RECONNECT_DELAY_MS);
+        }
+
+        /**
          * Listener for camera service death.
          *
          * <p>The camera service isn't supposed to die under any normal circumstances, but can be
@@ -1171,21 +1212,19 @@
 
                 mCameraService = null;
 
-                // Tell listeners that the cameras and torch modes are _available_, because any
-                // existing clients will have gotten disconnected. This is optimistic under the
-                // assumption that the service will be back shortly.
-                //
-                // Without this, a camera service crash while a camera is open will never signal
-                // to listeners that previously in-use cameras are now available.
+                // Tell listeners that the cameras and torch modes are unavailable and schedule a
+                // reconnection to camera service. When camera service is reconnected, the camera
+                // and torch statuses will be updated.
                 for (int i = 0; i < mDeviceStatus.size(); i++) {
                     String cameraId = mDeviceStatus.keyAt(i);
-                    onStatusChangedLocked(STATUS_PRESENT, cameraId);
+                    onStatusChangedLocked(STATUS_NOT_PRESENT, cameraId);
                 }
                 for (int i = 0; i < mTorchStatus.size(); i++) {
                     String cameraId = mTorchStatus.keyAt(i);
-                    onTorchStatusChangedLocked(TORCH_STATUS_AVAILABLE_OFF, cameraId);
+                    onTorchStatusChangedLocked(TORCH_STATUS_NOT_AVAILABLE, cameraId);
                 }
 
+                scheduleCameraServiceReconnectionLocked();
             }
         }
 
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 8bc2876..b039fc7 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -29,7 +29,7 @@
 public class ExtractEditText extends EditText {
     private InputMethodService mIME;
     private int mSettingExtractedText;
-    
+
     public ExtractEditText(Context context) {
         super(context, null);
     }
@@ -45,11 +45,11 @@
     public ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
     }
-    
+
     void setIME(InputMethodService ime) {
         mIME = ime;
     }
-    
+
     /**
      * Start making changes that will not be reported to the client.  That
      * is, {@link #onSelectionChanged(int, int)} will not result in sending
@@ -58,7 +58,7 @@
     public void startInternalChanges() {
         mSettingExtractedText += 1;
     }
-    
+
     /**
      * Finish making changes that will not be reported to the client.  That
      * is, {@link #onSelectionChanged(int, int)} will not result in sending
@@ -67,7 +67,7 @@
     public void finishInternalChanges() {
         mSettingExtractedText -= 1;
     }
-    
+
     /**
      * Implement just to keep track of when we are setting text from the
      * client (vs. seeing changes in ourself from the user).
@@ -80,7 +80,7 @@
             mSettingExtractedText--;
         }
     }
-    
+
     /**
      * Report to the underlying text editor about selection changes.
      */
@@ -89,7 +89,7 @@
             mIME.onExtractedSelectionChanged(selStart, selEnd);
         }
     }
-    
+
     /**
      * Redirect clicks to the IME for handling there.  First allows any
      * on click handler to run, though.
@@ -101,17 +101,18 @@
         }
         return false;
     }
-    
+
     @Override public boolean onTextContextMenuItem(int id) {
-        if (mIME != null && mIME.onExtractTextContextMenuItem(id)) {
+        // Select all shouldn't be handled by the original edit text, but by the extracted one.
+        if (id != android.R.id.selectAll && mIME != null && mIME.onExtractTextContextMenuItem(id)) {
             // Mode was started on Extracted, needs to be stopped here.
-            // Cut and paste will change the text, which stops selection mode.
-            if (id == android.R.id.copy) stopTextActionMode();
+            // Cut will change the text, which stops selection mode.
+            if (id == android.R.id.copy || id == android.R.id.paste) stopTextActionMode();
             return true;
         }
         return super.onTextContextMenuItem(id);
     }
-    
+
     /**
      * We are always considered to be an input method target.
      */
@@ -119,14 +120,14 @@
     public boolean isInputMethodTarget() {
         return true;
     }
-    
+
     /**
      * Return true if the edit text is currently showing a scroll bar.
      */
     public boolean hasVerticalScrollBar() {
         return computeVerticalScrollRange() > computeVerticalScrollExtent();
     }
-    
+
     /**
      * Pretend like the window this view is in always has focus, so its
      * highlight and cursor will be displayed.
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 84a879c..c3b098b 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -758,13 +758,15 @@
                 return _result;
             }
 
-            public StorageVolume[] getVolumeList(int userId) throws RemoteException {
+            public StorageVolume[] getVolumeList(int uid, String packageName)
+                    throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 StorageVolume[] _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeInt(userId);
+                    _data.writeInt(uid);
+                    _data.writeString(packageName);
                     mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.createTypedArray(StorageVolume.CREATOR);
@@ -1177,21 +1179,6 @@
                     _data.recycle();
                 }
             }
-
-            @Override
-            public void remountUid(int uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeInt(uid);
-                    mRemote.transact(Stub.TRANSACTION_remountUid, _data, _reply, 0);
-                    _reply.readException();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-            }
         }
 
         private static final String DESCRIPTOR = "IMountService";
@@ -1307,8 +1294,6 @@
         static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
         static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
 
-        static final int TRANSACTION_remountUid = IBinder.FIRST_CALL_TRANSACTION + 61;
-
         /**
          * Cast an IBinder object into an IMountService interface, generating a
          * proxy if needed.
@@ -1622,8 +1607,9 @@
                 }
                 case TRANSACTION_getVolumeList: {
                     data.enforceInterface(DESCRIPTOR);
-                    int userId = data.readInt();
-                    StorageVolume[] result = getVolumeList(userId);
+                    int uid = data.readInt();
+                    String packageName = data.readString();
+                    StorageVolume[] result = getVolumeList(uid, packageName);
                     reply.writeNoException();
                     reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                     return true;
@@ -1862,13 +1848,6 @@
                     reply.writeNoException();
                     return true;
                 }
-                case TRANSACTION_remountUid: {
-                    data.enforceInterface(DESCRIPTOR);
-                    int uid = data.readInt();
-                    remountUid(uid);
-                    reply.writeNoException();
-                    return true;
-                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -2080,11 +2059,11 @@
     /**
      * Returns list of all mountable volumes.
      */
-    public StorageVolume[] getVolumeList(int userId) throws RemoteException;
+    public StorageVolume[] getVolumeList(int uid, String packageName) throws RemoteException;
 
     /**
      * Gets the path on the filesystem for the ASEC container itself.
-     * 
+     *
      * @param cid ASEC container ID
      * @return path to filesystem or {@code null} if it's not found
      * @throws RemoteException
@@ -2178,6 +2157,4 @@
     public String getPrimaryStorageUuid() throws RemoteException;
     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
             throws RemoteException;
-
-    public void remountUid(int uid) throws RemoteException;
 }
diff --git a/core/java/android/os/storage/MountServiceInternal.java b/core/java/android/os/storage/MountServiceInternal.java
new file mode 100644
index 0000000..17aaef9
--- /dev/null
+++ b/core/java/android/os/storage/MountServiceInternal.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+/**
+ * Mount service local interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class MountServiceInternal {
+
+    /**
+     * Policy that influences how external storage is mounted and reported.
+     */
+    public interface ExternalStorageMountPolicy {
+        /**
+         * Gets the external storage mount mode for the given uid.
+         *
+         * @param uid The UID for which to determine mount mode.
+         * @param packageName The package in the UID for making the call.
+         * @return The mount mode.
+         *
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_NONE
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_DEFAULT
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_READ
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_WRITE
+         */
+        public int getMountMode(int uid, String packageName);
+
+        /**
+         * Gets whether external storage should be reported to the given UID.
+         *
+         * @param uid The UID for which to determine whether it has external storage.
+         * @param packageName The package in the UID for making the call.
+         * @return Weather to report external storage.
+         * @return True to report the state of external storage, false to
+         *     report it as unmounted.
+         */
+        public boolean hasExternalStorage(int uid, String packageName);
+    }
+
+    /**
+     * Adds a policy for determining how external storage is mounted and reported.
+     * The mount mode is the most conservative result from querying all registered
+     * policies. Similarly, the reported state is the most conservative result from
+     * querying all registered policies.
+     *
+     * @param policy The policy to add.
+     */
+    public abstract void addExternalStoragePolicy(ExternalStorageMountPolicy policy);
+
+    /**
+     * Notify the mount service that the mount policy for a UID changed.
+     * @param uid The UID for which policy changed.
+     * @param packageName The package in the UID for making the call.
+     */
+    public abstract void onExternalStoragePolicyChanged(int uid, String packageName);
+
+    /**
+     * Gets the mount mode to use for a given UID as determined by consultin all
+     * policies.
+     *
+     * @param uid The UID for which to get mount mode.
+     * @param packageName The package in the UID for making the call.
+     * @return The mount mode.
+     */
+    public abstract int getExternalStorageMountMode(int uid, String packageName);
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index f03e04e..2b75f31 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityThread;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.IPackageMoveObserver;
@@ -816,17 +817,19 @@
 
     /** {@hide} */
     private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
-        File canonicalFile = null;
         try {
-            canonicalFile = file.getCanonicalFile();
+            file = file.getCanonicalFile();
         } catch (IOException ignored) {
-            canonicalFile = null;
+            return null;
         }
         for (StorageVolume volume : volumes) {
-            if (volume.getPathFile().equals(file)) {
-                return volume;
+            File volumeFile = volume.getPathFile();
+            try {
+                volumeFile = volumeFile.getCanonicalFile();
+            } catch (IOException ignored) {
+                continue;
             }
-            if (FileUtils.contains(volume.getPathFile(), canonicalFile)) {
+            if (FileUtils.contains(volumeFile, file)) {
                 return volume;
             }
         }
@@ -857,7 +860,9 @@
         final IMountService mountService = IMountService.Stub.asInterface(
                 ServiceManager.getService("mount"));
         try {
-            return mountService.getVolumeList(userId);
+            final String packageName = ActivityThread.currentOpPackageName();
+            final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId);
+            return mountService.getVolumeList(uid, packageName);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -894,15 +899,6 @@
     }
 
     /** {@hide} */
-    public void remountUid(int uid) {
-        try {
-            mMountService.remountUid(uid);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    /** {@hide} */
     private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
     private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
     private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
@@ -956,7 +952,7 @@
                         || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) {
                     final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(),
                             vol.getInternalPath(), path);
-                    if (internalPath != null) {
+                    if (internalPath != null && internalPath.exists()) {
                         return internalPath;
                     }
                 }
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 32f7bc9..8d603a1 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -298,14 +298,14 @@
         }
     }
 
-    public StorageVolume buildStorageVolume(Context context, int userId) {
+    public StorageVolume buildStorageVolume(Context context, int userId, boolean reportUnmounted) {
         final StorageManager storage = context.getSystemService(StorageManager.class);
 
         final boolean removable;
         final boolean emulated;
         final boolean allowMassStorage = false;
-        final String envState = getEnvironmentForState(state);
-
+        final String envState = reportUnmounted
+                ? Environment.MEDIA_UNMOUNTED : getEnvironmentForState(state);
         File userPath = getPathForUser(userId);
         if (userPath == null) {
             userPath = new File("/dev/null");
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 4862f01..39f66a5 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -55,6 +55,12 @@
         }
     }
 
+    public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        for (int i = mLog.size() - 1; i >= 0; i--) {
+            pw.println(mLog.get(i));
+        }
+    }
+
     public static class ReadOnlyLocalLog {
         private final LocalLog mLog;
         ReadOnlyLocalLog(LocalLog log) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index f45e750..e672fc3 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -62,7 +62,7 @@
  * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
  * setTypeface() methods control the typeface and style of label text, whereas the
  * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
- * the related seSwitchTypeface() methods control that of the thumb.
+ * the related setSwitchTypeface() methods control that of the thumb.
  *
  * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
  * guide.</p>
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 42ac599..131ba46 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6347,17 +6347,28 @@
         if (text.text != null) {
             if (content == null) {
                 setText(text.text, TextView.BufferType.EDITABLE);
-            } else if (text.partialStartOffset < 0) {
-                removeParcelableSpans(content, 0, content.length());
-                content.replace(0, content.length(), text.text);
             } else {
-                final int N = content.length();
-                int start = text.partialStartOffset;
-                if (start > N) start = N;
-                int end = text.partialEndOffset;
-                if (end > N) end = N;
+                int start = 0;
+                int end = content.length();
+
+                if (text.partialStartOffset >= 0) {
+                    final int N = content.length();
+                    start = text.partialStartOffset;
+                    if (start > N) start = N;
+                    end = text.partialEndOffset;
+                    if (end > N) end = N;
+                }
+
                 removeParcelableSpans(content, start, end);
-                content.replace(start, end, text.text);
+                if (TextUtils.equals(content.subSequence(start, end), text.text)) {
+                    if (text.text instanceof Spanned) {
+                        // OK to copy spans only.
+                        TextUtils.copySpansFrom((Spanned) text.text, start, end,
+                                Object.class, content, start);
+                    }
+                } else {
+                    content.replace(start, end, text.text);
+                }
             }
         }
 
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 45cc8b2..1a1e0b2 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -95,8 +95,7 @@
                         powerDeltaMaUs -= mLastPowerMaUs.valueAt(index);
 
                         final long timeDiffUs = nowUs - mLastTimeReadUs;
-                        if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0 || powerDeltaMaUs < 0 ||
-                                userTimeDeltaUs > timeDiffUs || systemTimeDeltaUs > timeDiffUs) {
+                        if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0 || powerDeltaMaUs < 0) {
                             StringBuilder sb = new StringBuilder("Malformed cpu data for UID=");
                             sb.append(uid).append("!\n");
                             sb.append("Time between reads: ");
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index ef2fef0..41628d0 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -41,13 +41,13 @@
     private final ActionMode.Callback2 mCallback;
     private final MenuBuilder mMenu;
     private final Rect mContentRect;
-    private final Rect mContentRectOnWindow;
-    private final Rect mPreviousContentRectOnWindow;
-    private final int[] mViewPosition;
-    private final int[] mPreviousViewPosition;
-    private final int[] mRootViewPosition;
-    private final Rect mViewRect;
-    private final Rect mPreviousViewRect;
+    private final Rect mContentRectOnScreen;
+    private final Rect mPreviousContentRectOnScreen;
+    private final int[] mViewPositionOnScreen;
+    private final int[] mPreviousViewPositionOnScreen;
+    private final int[] mRootViewPositionOnScreen;
+    private final Rect mViewRectOnScreen;
+    private final Rect mPreviousViewRectOnScreen;
     private final Rect mScreenRect;
     private final View mOriginatingView;
     private final int mBottomAllowance;
@@ -77,16 +77,16 @@
                 MenuItem.SHOW_AS_ACTION_IF_ROOM);
         setType(ActionMode.TYPE_FLOATING);
         mContentRect = new Rect();
-        mContentRectOnWindow = new Rect();
-        mPreviousContentRectOnWindow = new Rect();
-        mViewPosition = new int[2];
-        mPreviousViewPosition = new int[2];
-        mRootViewPosition = new int[2];
-        mViewRect = new Rect();
-        mPreviousViewRect = new Rect();
+        mContentRectOnScreen = new Rect();
+        mPreviousContentRectOnScreen = new Rect();
+        mViewPositionOnScreen = new int[2];
+        mPreviousViewPositionOnScreen = new int[2];
+        mRootViewPositionOnScreen = new int[2];
+        mViewRectOnScreen = new Rect();
+        mPreviousViewRectOnScreen = new Rect();
         mScreenRect = new Rect();
         mOriginatingView = Preconditions.checkNotNull(originatingView);
-        mOriginatingView.getLocationInWindow(mViewPosition);
+        mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
         // Allow the content rect to overshoot a little bit beyond the
         // bottom view bound if necessary.
         mBottomAllowance = context.getResources()
@@ -138,52 +138,53 @@
     public void updateViewLocationInWindow() {
         checkToolbarInitialized();
 
-        mOriginatingView.getLocationInWindow(mViewPosition);
-        mOriginatingView.getRootView().getLocationInWindow(mRootViewPosition);
-        mOriginatingView.getGlobalVisibleRect(mViewRect);
-        mViewRect.offset(mRootViewPosition[0], mRootViewPosition[1]);
+        mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
+        mOriginatingView.getRootView().getLocationOnScreen(mRootViewPositionOnScreen);
+        mOriginatingView.getGlobalVisibleRect(mViewRectOnScreen);
+        mViewRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);
 
-        if (!Arrays.equals(mViewPosition, mPreviousViewPosition)
-                || !mViewRect.equals(mPreviousViewRect)) {
+        if (!Arrays.equals(mViewPositionOnScreen, mPreviousViewPositionOnScreen)
+                || !mViewRectOnScreen.equals(mPreviousViewRectOnScreen)) {
             repositionToolbar();
-            mPreviousViewPosition[0] = mViewPosition[0];
-            mPreviousViewPosition[1] = mViewPosition[1];
-            mPreviousViewRect.set(mViewRect);
+            mPreviousViewPositionOnScreen[0] = mViewPositionOnScreen[0];
+            mPreviousViewPositionOnScreen[1] = mViewPositionOnScreen[1];
+            mPreviousViewRectOnScreen.set(mViewRectOnScreen);
         }
     }
 
     private void repositionToolbar() {
         checkToolbarInitialized();
 
-        mContentRectOnWindow.set(mContentRect);
-        mContentRectOnWindow.offset(mViewPosition[0], mViewPosition[1]);
+        mContentRectOnScreen.set(mContentRect);
+        mContentRectOnScreen.offset(mViewPositionOnScreen[0], mViewPositionOnScreen[1]);
 
         if (isContentRectWithinBounds()) {
             mFloatingToolbarVisibilityHelper.setOutOfBounds(false);
             // Make sure that content rect is not out of the view's visible bounds.
-            mContentRectOnWindow.set(
-                    Math.max(mContentRectOnWindow.left, mViewRect.left),
-                    Math.max(mContentRectOnWindow.top, mViewRect.top),
-                    Math.min(mContentRectOnWindow.right, mViewRect.right),
-                    Math.min(mContentRectOnWindow.bottom, mViewRect.bottom + mBottomAllowance));
+            mContentRectOnScreen.set(
+                    Math.max(mContentRectOnScreen.left, mViewRectOnScreen.left),
+                    Math.max(mContentRectOnScreen.top, mViewRectOnScreen.top),
+                    Math.min(mContentRectOnScreen.right, mViewRectOnScreen.right),
+                    Math.min(mContentRectOnScreen.bottom,
+                            mViewRectOnScreen.bottom + mBottomAllowance));
 
-            if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {
+            if (!mContentRectOnScreen.equals(mPreviousContentRectOnScreen)) {
                 // Content rect is moving.
                 mOriginatingView.removeCallbacks(mMovingOff);
                 mFloatingToolbarVisibilityHelper.setMoving(true);
                 mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
                 mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
 
-                mFloatingToolbar.setContentRect(mContentRectOnWindow);
+                mFloatingToolbar.setContentRect(mContentRectOnScreen);
                 mFloatingToolbar.updateLayout();
             }
         } else {
             mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
             mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
-            mContentRectOnWindow.setEmpty();
+            mContentRectOnScreen.setEmpty();
         }
 
-        mPreviousContentRectOnWindow.set(mContentRectOnWindow);
+        mPreviousContentRectOnScreen.set(mContentRectOnScreen);
     }
 
     private boolean isContentRectWithinBounds() {
@@ -193,8 +194,8 @@
             mContext.getResources().getDisplayMetrics().widthPixels,
             mContext.getResources().getDisplayMetrics().heightPixels);
 
-        return Rect.intersects(mContentRectOnWindow, mScreenRect)
-            && Rect.intersects(mContentRectOnWindow, mViewRect);
+        return Rect.intersects(mContentRectOnScreen, mScreenRect)
+            && Rect.intersects(mContentRectOnScreen, mViewRectOnScreen);
     }
 
     @Override
@@ -269,7 +270,6 @@
         mOriginatingView.removeCallbacks(mHideOff);
     }
 
-
     /**
      * A helper for showing/hiding the floating toolbar depending on certain states.
      */
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index a6e8034..b3f688b 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -285,6 +285,7 @@
 
         private final Context mContext;
         private final View mParent;
+        private final int[] mParentPositionOnScreen = new int[2];
         private final PopupWindow mPopupWindow;
         private final ViewGroup mContentContainer;
         private final int mMarginHorizontal;
@@ -337,8 +338,8 @@
             }
         };
 
-        private final Rect mViewPort = new Rect();
-        private final Point mCoords = new Point();
+        private final Rect mViewPortOnScreen = new Rect();
+        private final Point mCoordsOnScreen = new Point();
         private final Rect mTmpRect = new Rect();
 
         private final Region mTouchableRegion = new Region();
@@ -428,8 +429,8 @@
          * Shows this popup at the specified coordinates.
          * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
          */
-        public void show(Rect contentRect) {
-            Preconditions.checkNotNull(contentRect);
+        public void show(Rect contentRectOnScreen) {
+            Preconditions.checkNotNull(contentRectOnScreen);
 
             if (isShowing()) {
                 return;
@@ -447,9 +448,15 @@
                 // The "show" animation will make this visible.
                 mContentContainer.setAlpha(0);
             }
-            refreshCoordinatesAndOverflowDirection(contentRect);
+            refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
-            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y);
+            // We need to specify the offset relative to mParent.
+            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
+            // specify the popup poision in screen coordinates.
+            mParent.getLocationOnScreen(mParentPositionOnScreen);
+            final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
+            final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
+            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, relativeX, relativeY);
             setTouchableSurfaceInsetsComputer();
             runShowAnimation();
         }
@@ -502,17 +509,23 @@
          * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
          * This is a no-op if this popup is not showing.
          */
-        public void updateCoordinates(Rect contentRect) {
-            Preconditions.checkNotNull(contentRect);
+        public void updateCoordinates(Rect contentRectOnScreen) {
+            Preconditions.checkNotNull(contentRectOnScreen);
 
             if (!isShowing() || !mPopupWindow.isShowing()) {
                 return;
             }
 
             cancelOverflowAnimations();
-            refreshCoordinatesAndOverflowDirection(contentRect);
+            refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
-            mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight());
+            // We need to specify the offset relative to mParent.
+            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
+            // specify the popup poision in screen coordinates.
+            mParent.getLocationOnScreen(mParentPositionOnScreen);
+            final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
+            final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
+            mPopupWindow.update(relativeX, relativeY, getWidth(), getHeight());
         }
 
         /**
@@ -536,47 +549,47 @@
             return mContext;
         }
 
-        private void refreshCoordinatesAndOverflowDirection(Rect contentRect) {
+        private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) {
             refreshViewPort();
 
-            int x = contentRect.centerX() - getWidth() / 2;
+            int x = contentRectOnScreen.centerX() - getWidth() / 2;
             // Update x so that the toolbar isn't rendered behind the nav bar in landscape.
-            x = Math.max(0, Math.min(x, mViewPort.right - getWidth()));
+            x = Math.max(0, Math.min(x, mViewPortOnScreen.right - getWidth()));
 
             int y;
 
-            int availableHeightAboveContent = contentRect.top - mViewPort.top;
-            int availableHeightBelowContent = mViewPort.bottom - contentRect.bottom;
+            int availableHeightAboveContent = contentRectOnScreen.top - mViewPortOnScreen.top;
+            int availableHeightBelowContent = mViewPortOnScreen.bottom - contentRectOnScreen.bottom;
 
             if (mOverflowPanel == null) {  // There is no overflow.
                 if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()) {
                     // There is enough space at the top of the content.
-                    y = contentRect.top - getToolbarHeightWithVerticalMargin();
+                    y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin();
                 } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()) {
                     // There is enough space at the bottom of the content.
-                    y = contentRect.bottom;
+                    y = contentRectOnScreen.bottom;
                 } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(mContext)) {
                     // Just enough space to fit the toolbar with no vertical margins.
-                    y = contentRect.bottom - mMarginVertical;
+                    y = contentRectOnScreen.bottom - mMarginVertical;
                 } else {
                     // Not enough space. Prefer to position as high as possible.
                     y = Math.max(
-                            mViewPort.top,
-                            contentRect.top - getToolbarHeightWithVerticalMargin());
+                            mViewPortOnScreen.top,
+                            contentRectOnScreen.top - getToolbarHeightWithVerticalMargin());
                 }
             } else {  // There is an overflow.
                 int margin = 2 * mMarginVertical;
                 int minimumOverflowHeightWithMargin = mOverflowPanel.getMinimumHeight() + margin;
-                int availableHeightThroughContentDown =
-                        mViewPort.bottom - contentRect.top + getToolbarHeightWithVerticalMargin();
-                int availableHeightThroughContentUp =
-                        contentRect.bottom - mViewPort.top + getToolbarHeightWithVerticalMargin();
+                int availableHeightThroughContentDown = mViewPortOnScreen.bottom -
+                        contentRectOnScreen.top + getToolbarHeightWithVerticalMargin();
+                int availableHeightThroughContentUp = contentRectOnScreen.bottom -
+                        mViewPortOnScreen.top + getToolbarHeightWithVerticalMargin();
 
                 if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) {
                     // There is enough space at the top of the content rect for the overflow.
                     // Position above and open upwards.
                     updateOverflowHeight(availableHeightAboveContent - margin);
-                    y = contentRect.top - getHeight();
+                    y = contentRectOnScreen.top - getHeight();
                     mOverflowDirection = OVERFLOW_DIRECTION_UP;
                 } else if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()
                         && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) {
@@ -584,33 +597,34 @@
                     // but not the overflow.
                     // Position above but open downwards.
                     updateOverflowHeight(availableHeightThroughContentDown - margin);
-                    y = contentRect.top - getToolbarHeightWithVerticalMargin();
+                    y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin();
                     mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                 } else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) {
                     // There is enough space at the bottom of the content rect for the overflow.
                     // Position below and open downwards.
                     updateOverflowHeight(availableHeightBelowContent - margin);
-                    y = contentRect.bottom;
+                    y = contentRectOnScreen.bottom;
                     mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                 } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()
-                        && mViewPort.height() >= minimumOverflowHeightWithMargin) {
+                        && mViewPortOnScreen.height() >= minimumOverflowHeightWithMargin) {
                     // There is enough space at the bottom of the content rect for the main panel
                     // but not the overflow.
                     // Position below but open upwards.
                     updateOverflowHeight(availableHeightThroughContentUp - margin);
-                    y = contentRect.bottom + getToolbarHeightWithVerticalMargin() - getHeight();
+                    y = contentRectOnScreen.bottom + getToolbarHeightWithVerticalMargin() -
+                            getHeight();
                     mOverflowDirection = OVERFLOW_DIRECTION_UP;
                 } else {
                     // Not enough space.
                     // Position at the top of the view port and open downwards.
-                    updateOverflowHeight(mViewPort.height() - margin);
-                    y = mViewPort.top;
+                    updateOverflowHeight(mViewPortOnScreen.height() - margin);
+                    y = mViewPortOnScreen.top;
                     mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                 }
                 mOverflowPanel.setOverflowDirection(mOverflowDirection);
             }
 
-            mCoords.set(x, y);
+            mCoordsOnScreen.set(x, y);
         }
 
         private int getToolbarHeightWithVerticalMargin() {
@@ -913,18 +927,18 @@
 
 
         private void refreshViewPort() {
-            mParent.getWindowVisibleDisplayFrame(mViewPort);
+            mParent.getWindowVisibleDisplayFrame(mViewPortOnScreen);
         }
 
         private boolean viewPortHasChanged() {
             mParent.getWindowVisibleDisplayFrame(mTmpRect);
-            return !mTmpRect.equals(mViewPort);
+            return !mTmpRect.equals(mViewPortOnScreen);
         }
 
         private int getToolbarWidth(int suggestedWidth) {
             int width = suggestedWidth;
             refreshViewPort();
-            int maximumWidth = mViewPort.width() - 2 * mParent.getResources()
+            int maximumWidth = mViewPortOnScreen.width() - 2 * mParent.getResources()
                     .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
             if (width <= 0) {
                 width = mParent.getResources()
@@ -1443,6 +1457,9 @@
     private static PopupWindow createPopupWindow(View content) {
         ViewGroup popupContentHolder = new LinearLayout(content.getContext());
         PopupWindow popupWindow = new PopupWindow(popupContentHolder);
+        // TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false)
+        // unless FLAG_LAYOUT_IN_SCREEN has any unintentional side-effects.
+        popupWindow.setClippingEnabled(false);
         popupWindow.setWindowLayoutType(
                 WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
         popupWindow.setAnimationStyle(0);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ba51b23..d3117b9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1041,7 +1041,7 @@
     -->
     <permission android:name="android.permission.GET_ACCOUNTS"
         android:permissionGroup="android.permission-group.CONTACTS"
-        android:protectionLevel="normal"
+        android:protectionLevel="dangerous"
         android:description="@string/permdesc_getAccounts"
         android:label="@string/permlab_getAccounts" />
 
@@ -2436,7 +2436,7 @@
 
     <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
     <permission android:name="android.permission.MANAGE_FINGERPRINT"
-        android:protectionLevel="signature" />
+        android:protectionLevel="system|signature" />
 
     <!-- Allows an application to control keyguard.  Only allowed for system processes.
         @hide -->
diff --git a/docs/html/about/versions/android-5.0-changes.jd b/docs/html/about/versions/android-5.0-changes.jd
index f51af40..25d253f 100644
--- a/docs/html/about/versions/android-5.0-changes.jd
+++ b/docs/html/about/versions/android-5.0-changes.jd
@@ -598,3 +598,8 @@
 URI specifying where the photo should be stored. The camera app can write the
 image to the location specified by that URI, and the app that fired the intent
 would be able to read that file, even if the app is on the other profile. </p>
+
+<h3>Lockscreen widget support removed</h3>
+
+<p>Android 5.0 removes support for lockscreen widgets; it continues to support
+widgets on the home screen.</p>
\ No newline at end of file
diff --git a/docs/html/guide/components/bound-services.jd b/docs/html/guide/components/bound-services.jd
index 4215f0f2..c2ac607 100644
--- a/docs/html/guide/components/bound-services.jd
+++ b/docs/html/guide/components/bound-services.jd
@@ -649,8 +649,7 @@
 <p>Additionally, if your service is started and accepts binding, then when the system calls
 your {@link android.app.Service#onUnbind onUnbind()} method, you can optionally return
 {@code true} if you would like to receive a call to {@link android.app.Service#onRebind
-onRebind()} the next time a client binds to the service (instead of receiving a call to {@link
-android.app.Service#onBind onBind()}). {@link android.app.Service#onRebind
+onRebind()} the next time a client binds to the service. {@link android.app.Service#onRebind
 onRebind()} returns void, but the client still receives the {@link android.os.IBinder} in its
 {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback.
 Below, figure 1 illustrates the logic for this kind of lifecycle.</p>
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index a783ad1..c9575e0 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -26,12 +26,6 @@
         </ol>
       </li>
       <li><a href="#preview">Setting a Preview Image</a></li>
-      <li><a href="#lockscreen">Enabling App Widgets on the Lockscreen</a>
-        <ol>
-          <li><a href="#lockscreen-sizing">Sizing guidelines</a></li>
-        </ol>
-      </li>
-
       <li><a href="#collections">Using App Widgets with Collections</a>
         <ol>
           <li><a href="#collection_sample">Sample application</a></li>
@@ -175,8 +169,7 @@
     android:initialLayout="@layout/example_appwidget"
     android:configure="com.example.android.ExampleAppWidgetConfigure" 
     android:resizeMode="horizontal|vertical"
-    android:widgetCategory="home_screen|keyguard"
-    android:initialKeyguardLayout="@layout/example_keyguard">
+    android:widgetCategory="home_screen">
 &lt;/appwidget-provider>
 </pre>
 
@@ -281,17 +274,11 @@
 the widget can be resized. This field has no effect if it is greater than {@code minWidth} or if
 horizontal resizing isn't enabled (see <code>resizeMode</code>). Introduced in Android 4.0.</li>
 
-<li>The <code>widgetCategory</code> attribute declares whether your App Widget can be displayed on the home screen, 
-the lock screen (keyguard), or both. Values for this attribute include "home_screen" and "keyguard".  A widget that 
-is displayed on both needs to ensure that it follows the design guidelines for both widget classes. For more
-information, see <a href="#lockscreen">Enabling App Widgets on the Lockscreen</a>. The default value is "home_screen". Introduced in Android 4.2.
-</li>
-
-<li>The <code>initialKeyguardLayout</code> attribute points to the layout resource
-that defines the lock screen App Widget layout. This works the same way as the 
-{@link android.appwidget.AppWidgetProviderInfo#initialLayout android:initialLayout}, 
-in that it provides a layout that can appear immediately until your app widget is initialized and able to update 
-the layout. Introduced in Android 4.2.</li>
+<li>The <code>widgetCategory</code> attribute declares whether your App Widget
+can be displayed on the home screen ({@code home_screen}), the lock screen
+({@code keyguard}), or both. Only Android versions lower than 5.0 support
+lock-screen widgets. For Android 5.0 and higher, only {@code home_screen} is
+valid.</li>
 
 </ul>
 
@@ -737,66 +724,6 @@
 application and set it up how you'd like your preview image to appear, then save
 it and place it in your application's drawable resources.</p>
 
-<h2 id="lockscreen">Enabling App Widgets on the Lockscreen</h2>
-
-<p>Android 4.2 introduces the ability for users to add widgets to the lock screen. To indicate that your app widget is available for use on the lock screen, declare the {@link android.appwidget.AppWidgetProviderInfo#widgetCategory android:widgetCategory} attribute in the XML file that specifies your {@link android.appwidget.AppWidgetProviderInfo}. This attribute supports two values: "home_screen" and "keyguard". An app widget can declare support for one or both.</p>
-
-<p>By default, every app widget supports placement on the Home screen, so "home_screen" is the default value for the 
-{@link android.appwidget.AppWidgetProviderInfo#widgetCategory android:widgetCategory} attribute. If you want your app widget to be available for the lock screen, add the "keyguard" value:</p>
-<pre>
-&lt;appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
-   ...
-   android:widgetCategory="keyguard|home_screen">
-&lt;/appwidget-provider>
-</pre>
-
-<p>If you declare a widget to be displayable on both keyguard (lockscreen) and home, it's likely that you'll want to customize the widget depending on where it is displayed. For example, you might create a separate layout file for keyguard vs. home. The next step is to detect the widget category at runtime and respond accordingly. 
-
-You can detect whether your widget is on the lockscreen or home screen by calling 
-{@link android.appwidget.AppWidgetManager#getAppWidgetOptions getAppWidgetOptions()} 
-to get the widget's options as a {@link android.os.Bundle}. The returned bundle will include the key 
-{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_HOST_CATEGORY}, whose value will be one of {@link android.appwidget.AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or 
-{@link android.appwidget.AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD}. This value is determined by the host into which the widget is bound. In the {@link android.appwidget.AppWidgetProvider}, you can then check the widget's category, for example:</p>
-
-<pre>
-AppWidgetManager appWidgetManager;
-int widgetId;
-Bundle myOptions = appWidgetManager.getAppWidgetOptions (widgetId);
-
-// Get the value of OPTION_APPWIDGET_HOST_CATEGORY
-int category = myOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
-
-// If the value is WIDGET_CATEGORY_KEYGUARD, it's a lockscreen widget
-boolean isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
-</pre>
-
-<p>Once you know the widget's category, you can optionally load a different base layout, set different properties, and so on. For example:</p>
-
-<pre>
-int baseLayout = isKeyguard ? R.layout.keyguard_widget_layout : R.layout.widget_layout;
-</pre>
-
-
-<p>You should also specify an initial layout for your app widget when on the lock screen with the 
-{@link android.appwidget.AppWidgetProviderInfo#initialKeyguardLayout android:initialKeyguardLayout} attribute. This works the same way as the 
-{@link android.appwidget.AppWidgetProviderInfo#initialLayout android:initialLayout}, in that it provides a layout that can appear immediately until your app widget is initialized and able to update the layout.</p>
-
-<h3 id="lockscreen-sizing">Sizing guidelines</h3>
-
-<p>When a widget is hosted on the lockscreen, the framework ignores the {@code minWidth}, {@code minHeight}, {@code minResizeWidth}, and {@code minResizeHeight} fields. If a widget is also a home screen widget, these parameters are still needed as they're still used on home, but they will be ignored for purposes of the lockscreen.</p>
-
-<p>The width of a lockscreen widget always fills the provided space. For the height of a lockscreen widget, you have the following options:</p>
-
-<ul>
-    <li>If the widget does not mark itself as vertically resizable ({@code android:resizeMode="vertical"}), then the widget height will always be "small":
-      <ul>
-        <li>On a phone in portrait mode, "small" is defined as the space remaining when an unlock UI is being displayed.</li>
-        <li>On tablets and landscape phones, "small" is set on a per-device basis.</li>    
-      </ul>
-    </li>
-    <li>If the widget marks itself as vertically resizable, then the widget height shows up as "small" on portrait phones displaying an unlock UI. In all other cases, the widget sizes to fill the available height.</li>
-</ul>
-
 <h2 id="collections">Using App Widgets with Collections</h2>
 
 <p>Android 3.0 introduces app widgets with collections. These kinds of App
diff --git a/docs/html/guide/topics/ui/controls/togglebutton.jd b/docs/html/guide/topics/ui/controls/togglebutton.jd
index 09af516..e0549ec 100644
--- a/docs/html/guide/topics/ui/controls/togglebutton.jd
+++ b/docs/html/guide/topics/ui/controls/togglebutton.jd
@@ -6,16 +6,15 @@
 <div id="qv">
 <h2>In this document</h2>
 <ol>
-  <li><a href="#HandlingEvents">Responding to Click Events</a>
-    <ol>
-      <li><a href="#ClickListener">Using an OnCheckedChangeListener</a></li>
-    </ol>
+  <li>
+    <a href="#ClickListener">Responding to Button Presses</a>
   </li>
 </ol>
   <h2>Key classes</h2>
   <ol>
     <li>{@link android.widget.ToggleButton}</li>
     <li>{@link android.widget.Switch}</li>
+    <li>{@link android.widget.CompoundButton}</li>
   </ol>
 </div>
 </div>
@@ -26,6 +25,12 @@
 object. Android 4.0 (API level 14) introduces another kind of toggle button called a switch that
 provides a slider control, which you can add with a {@link android.widget.Switch} object.</p>
 
+<p>
+  If you need to change a button's state yourself, you can use the {@link
+  android.widget.CompoundButton#setChecked CompoundButton.setChecked()} or
+  {@link android.widget.CompoundButton#toggle CompoundButton.toggle()} methods.
+</p>
+
 <div style="float:left;width:200px">
 <img src="{@docRoot}images/ui/togglebutton.png" alt="" />
 <p class="img-caption"><em>Toggle buttons</em></p>
@@ -36,78 +41,15 @@
 <p class="img-caption"><em>Switches (in Android 4.0+)</em></p>
 </div>
 
-<p style="clear:left">The {@link android.widget.ToggleButton} and {@link android.widget.Switch}
-controls are subclasses of {@link android.widget.CompoundButton} and function in the same manner, so
-you can implement their behavior the same way.</p>
+<h2 id="ClickListener">Responding to Button Presses</h2>
 
-<h2 id="HandlingEvents">Responding to Click Events</h2>
-
-<p>When the user selects a {@link android.widget.ToggleButton} and {@link android.widget.Switch},
-the object receives an on-click event.</p>
-
-<p>To define the click event handler, add the <code><a
-href="/reference/android/R.attr.html#onClick">android:onClick</a></code> attribute to the
-<code>&lt;ToggleButton&gt;</code> or <code>&lt;Switch&gt;</code> element in your XML
-layout. The value for this attribute must be the name of the method you want to call in response
-to a click event. The {@link android.app.Activity} hosting the layout must then implement the
-corresponding method.</p>
-
-<p>For example, here's a {@link android.widget.ToggleButton} with the <code><a
-href="/reference/android/R.attr.html#onClick">android:onClick</a></code> attribute:</p>
-
-<pre>
-&lt;ToggleButton 
-    android:id="@+id/togglebutton"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:textOn="Vibrate on"
-    android:textOff="Vibrate off"
-    android:onClick="onToggleClicked"/>
-</pre>
-
-<p>Within the {@link android.app.Activity} that hosts this layout, the following method handles the
-click event:</p>
-
-<pre>
-public void onToggleClicked(View view) {
-    // Is the toggle on?
-    boolean on = ((ToggleButton) view).isChecked();
-    
-    if (on) {
-        // Enable vibrate
-    } else {
-        // Disable vibrate
-    }
-}
-</pre>
-
-<p>The method you declare in the {@link android.R.attr#onClick android:onClick} attribute
-must have a signature exactly as shown above. Specifically, the method must:</p>
-<ul>
-  <li>Be public</li>
-  <li>Return void</li>
-  <li>Define a {@link android.view.View} as its only parameter (this will be the {@link
-android.view.View} that was clicked)</li>
-</ul>
-
-<p class="note"><strong>Tip:</strong> If you need to change the state
-yourself,
-use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link
-android.widget.CompoundButton#toggle()} method to change the state.</p>
-
-
-
-<h3 id="ClickListener">Using an OnCheckedChangeListener</h3>
-
-<p>You can also declare a click event handler programmatically rather than in an XML layout. This
-might be necessary if you instantiate the {@link android.widget.ToggleButton} or {@link
-android.widget.Switch} at runtime or you need to
-declare the click behavior in a {@link android.app.Fragment} subclass.</p>
-
-<p>To declare the event handler programmatically, create an {@link
-android.widget.CompoundButton.OnCheckedChangeListener} object and assign it to the button by calling
-{@link
-android.widget.CompoundButton#setOnCheckedChangeListener}. For example:</p>
+<p>
+  To detect when the user activates the button or switch, create an {@link
+  android.widget.CompoundButton.OnCheckedChangeListener} object and assign it
+  to the button by calling {@link
+  android.widget.CompoundButton#setOnCheckedChangeListener
+  setOnCheckedChangeListener()}. For example:
+</p>
 
 <pre>
 ToggleButton toggle = (ToggleButton) findViewById(R.id.togglebutton);
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 75b3c52..4300b43 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -120,14 +120,16 @@
 &lt;uses-permission
         android:name="android.permission.USE_FINGERPRINT" /&gt;
 </pre>
-
 <img src="{@docRoot}preview/images/fingerprint-screen.png"
 srcset="{@docRoot}preview/images/fingerprint-screen.png 1x, {@docRoot}preview/images/fingerprint-screen_2x.png 2x"
 style="float:right; margin:0 0 10px 20px" width="282" height="476" />
 
 <p>To see an app implementation of fingerprint authentication, refer to the
 <a href="https://github.com/googlesamples/android-FingerprintDialog" class="external-link">
-  Fingerprint Dialog sample</a>.</p>
+  Fingerprint Dialog sample</a>. For a demonstration of how you can use these authentication
+  APIs in conjunction with other Android APIs, see the video
+  <a class="video-shadowbox-button" href="https://www.youtube.com/watch?v=VOn7VrTRlA4">
+  Fingerprint and Payment APIs</a>.</p>
 
 <p>If you are testing this feature, follow these steps:</p>
 <ol>
diff --git a/docs/html/tools/debugging/ddms.jd b/docs/html/tools/debugging/ddms.jd
index 28ad11e..becbdb1 100644
--- a/docs/html/tools/debugging/ddms.jd
+++ b/docs/html/tools/debugging/ddms.jd
@@ -22,28 +22,23 @@
                 <li><a href="#logcat">Using LogCat</a></li>
                 <li><a href="#ops-location">Emulating phone operations and location</a></li>
             </ol>
-        
+
         </li>
       </ol>
     </div>
   </div>
 
-  <p>Android ships with a debugging tool called the Dalvik Debug Monitor Server (DDMS), which
+  <p>Android Studio includes a debugging tool called the Dalvik Debug Monitor Server (DDMS), which
   provides port-forwarding services, screen capture on the device, thread and heap information on
   the device, logcat, process, and radio state information, incoming call and SMS spoofing,
   location data spoofing, and more. This page provides a modest discussion of DDMS features; it is
   not an exhaustive exploration of all the features and capabilities.</p>
-  
+
   <h2 id="running">Running DDMS</h2>
-  <p>DDMS is integrated into Eclipse and is also shipped in the <code>tools/</code> directory of the
-  SDK. DDMS works with both the emulator and a connected device. If both are connected and running simultaneously, 
-  DDMS defaults to the emulator.</p>
-  
-  <ul>
-    <li>From Eclipse: Click <strong>Window > Open Perspective > Other... > DDMS</strong>.</li>
-    <li>From the command line: Type <code>ddms</code> (or <code>./ddms</code> on Mac/Linux) from the <code>tools/</code>
-    directory. </li>
-  </ul>
+  <p>DDMS is integrated into Android Studio. To use it, launch the
+  <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a>, and click the
+  <strong>DDMS</strong> menu button. DDMS works with both the emulator and a
+  connected device. If both are connected and running simultaneously, DDMS defaults to the emulator.</p>
 
 
   <h2 id="how-ddms-works">How DDMS Interacts with a Debugger</h2>
@@ -70,7 +65,7 @@
   all the VMs on a device. The traffic that is forwarded is determined by the currently selected process
   in the DDMS Devices view.</p>
 
-  <p>The following screenshot shows a typical DDMS screen in Eclipse. If you are starting DDMS from
+  <p>The following screenshot shows a typical DDMS screen. If you are starting DDMS from
   the command line, the screen is slightly different, but much of the functionality is identical.
   Notice that the highlighted process, <code>com.android.email</code>, that is running in the emulator
   has the debugging port 8700 assigned to it as well as 8606. This signifies that DDMS is currently
@@ -78,10 +73,10 @@
 
   <img src="{@docRoot}images/debug-ddms.png"
        width="1024" />
-  <p class="img-caption"><strong>Figure 1.</strong> 
-  Screenshot of DDMS</p> 
+  <p class="img-caption"><strong>Figure 1.</strong>
+  Screenshot of DDMS</p>
 
-  <p>If you are not using Eclipse and ADT, read <a href=
+  <p>If you are using the command line, read <a href=
   "{@docRoot}tools/debugging/debugging-projects-cmdline.html#debuggingPort">Configuring
   your IDE to attach to the debugging port</a>, for more information on attaching your
   debugger.</p>
@@ -97,11 +92,11 @@
 
   <h2 id="using-ddms">Using DDMS</h2>
   The following sections describe how to use DDMS and the various tabs and panes that are part of the
-  DDMS GUI. The Eclipse version and the command line version have minor UI differences, but the 
-  same functionality. For information on running DDMS, see the previous section in this document,
+  DDMS GUI. The Android Studio version and the command line version have minor UI differences, but
+  the same functionality. For information on running DDMS, see the previous section in this document,
   <a href="#running">Running DDMS</a>.
-  
-  
+
+
   <h3 id="heap">Viewing heap usage for a process</h3>
 
   <p>DDMS allows you to view how much heap memory a process is using. This information is useful in
@@ -129,7 +124,7 @@
   objects are being allocated when you perform certain actions in your application. This
   information is valuable for assessing memory usage that can affect application performance.
   </p>
-  
+
   <p>To track memory allocation of objects:</p>
   <ol>
     <li>In the Devices tab, select the process that you want to enable allocation tracking
@@ -155,7 +150,7 @@
   <p>DDMS provides a File Explorer tab that allows you to view, copy, and delete files on the
   device. This feature is useful in examining files that are created by your application or if you
   want to transfer files to and from the device.</p>
-  
+
   <p>To work with an emulator or device's file system:</p>
   <ol>
     <li>In the Devices tab, select the emulator that you want to view the file system for.</li>
@@ -166,7 +161,7 @@
     <li>To copy a file to the device, click the <strong>Push file</strong> button on the File
     Explorer tab.</li>
   </ol>
-  
+
   <!-- Need to elaborate more on where things are stored in the file system,
    databases, apks, user info, files that are important to look at -->
 
@@ -189,7 +184,7 @@
   where profiling data is collected, use the {@link android.os.Debug#startMethodTracing()} and 
   {@link android.os.Debug#stopMethodTracing()} methods. For more information about generating trace logs, see 
   <a href="debugging-tracing.html">Profiling and Debugging UIs</a>.</p>
-  
+
   <p>Before you start method profiling in DDMS, be aware of the following restrictions:</p>
     <ul>
       <li>Android 2.1 and earlier devices must
@@ -197,7 +192,7 @@
       <li>Android 2.2 and later devices do not need an SD card. The trace log files are 
       streamed directly to your development machine.</li>
     </ul>
-  
+
   <p>To start method profiling:</p>
   <ol>
     <li>On the Devices tab, select the process that you want to enable method profiling for.</li>
@@ -218,7 +213,7 @@
   </ol>
 
    <h3 id="network">Using the Network Traffic tool</h3>
-   
+
    <p>In Android 4.0, the DDMS (Dalvik Debug Monitor Server) includes a Detailed
 Network Usage tab that makes it possible to track when your application is
 making network requests. Using this tool, you can monitor how and when your app
@@ -274,7 +269,7 @@
 
 <p>Socket tagging is supported in Android 4.0, but real-time stats will only be
 displayed on devices running Android 4.0.3 or higher.</p>
-   
+
   <h3 id="logcat">Using LogCat</h3>
 
   <p>LogCat is integrated into DDMS, and outputs the messages that you print out using the {@link android.util.Log}
@@ -296,7 +291,7 @@
 
     <li>Error</li>
   </ul>
-  
+
   <p>You can also setup your own custom filter to specify more details such as filtering messages
   with the log tags or with the process id that generated the log message. The add filter,
   edit filter, and delete filter buttons let you manage your custom filters.</p>
@@ -351,7 +346,7 @@
 
     <li>KML - Keyhole Markup Language file</li>
   </ul>
-  
+
   For more information about providing mock location data, see 
   <a href="{@docRoot}guide/topics/location/strategies.html#MockData">Location Strategies</a>.
   
diff --git a/docs/html/tools/debugging/debugging-tracing.jd b/docs/html/tools/debugging/debugging-tracing.jd
index fa5b4e1..829c82a 100644
--- a/docs/html/tools/debugging/debugging-tracing.jd
+++ b/docs/html/tools/debugging/debugging-tracing.jd
@@ -177,12 +177,15 @@
 
   <h2 id="runningtraceview">Viewing Trace Files in Traceview</h2>
 
-  <p>To run Traceview and view the trace files, enter <code>traceview
-  &lt;trace-base-name&gt;</code>. For example, to run Traceview on the example files copied in the
-  previous section, use:</p>
-  <pre>
-traceview /tmp/calc
-</pre>
+  <p>To run Traceview and view the trace files:</p>
+  <ul>
+    <li>start the
+    <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a>. </li>
+    <li>In the Android Device Monitor tool bar, click <strong>DDMS</strong> and select a process. </li>
+    <li>Click the <strong>Start Method Profiling</strong> icon to start method profiling. </li>
+    <li>After the profiling is complete, click the <strong>Stop Method Profiling</strong> icon to
+    display the traceview. </li>
+   </ul> 
 
   <p class="note"><strong>Note:</strong> If you are trying to view the trace logs of an application 
   that is built with ProGuard enabled (release mode build), some method and member names might be obfuscated.
diff --git a/docs/html/tools/help/monitor.jd b/docs/html/tools/help/monitor.jd
index 513eb10..5f7b5ce 100644
--- a/docs/html/tools/help/monitor.jd
+++ b/docs/html/tools/help/monitor.jd
@@ -15,8 +15,8 @@
 
 <p>Android Device Monitor is a stand-alone tool that provides a graphical user interface for
 several Android application debugging and analysis tools. The Monitor tool does not
-require installation of an integrated development environment, such as Eclipse, and encapsulates the
-following tools:</p>
+require installation of an integrated development environment, such as Android Studio, and
+encapsulates the following tools:</p>
 
 <ul>
   <li><a href="{@docRoot}tools/debugging/ddms.html">DDMS</a></li>
@@ -30,9 +30,19 @@
 
 <h2 id="usage">Usage</h2>
 
-<p>To start Device Monitor, enter the following command from the SDK <code>tools/</code>
-directory:</p>
+<p>To start Device Monitor:</p>
+
+<ul>
+  <li>From Android Studio, choose <strong>Tools &gt; Android Device Monitor</strong> or click
+    the Android Device Monitor icon
+    <img src="{@docRoot}images/tools/hierarchicalviewer-icon.png" alt=""/>.
+  </li>
+  <li>From the command line, in the SDK <code>tools/</code> directory, enter the following command:
   <pre>monitor</pre>
+  </li>
+</ul>
+
+
 
 <p>Start an Android emulator or connect an Android device via USB cable, and connect Device
 Monitor to the device by selecting it in the <strong>Devices</strong> window.</p>
diff --git a/docs/html/tools/help/traceview.jd b/docs/html/tools/help/traceview.jd
index 6555ac0..a268291 100644
--- a/docs/html/tools/help/traceview.jd
+++ b/docs/html/tools/help/traceview.jd
@@ -3,14 +3,26 @@
 parent.link=index.html
 @jd:body
 
-<p>Traceview is a graphical viewer for execution logs saved by your application. 
+<p>Traceview is a graphical viewer for execution logs saved by your application.
 Traceview can help you debug your application and profile its performance.</p>
 
-<p>To start Traceview, enter the following command from the SDK <code>tools/</code> directory:</p>
-  <pre>traceview</pre>
-</ol>
+<p>To start the Traceview tool:</p>
 
-<p>For more information on how to use Traceview, see 
-<a href="{@docRoot}tools/debugging/debugging-tracing.html">Profiling with Traceview and dmtracedump</a>
+<ul>
+ <li>Start the <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a>. </li>
+ <li>In the Android Device Monitor tool bar, click <strong>DDMS</strong> and select a process. </li>
+ <li>Click the <strong>Start Method Profiling</strong> icon to start method profiling. </li>
+ <li>After the profiling is complete, click the <strong>Stop Method Profiling</strong> icon to
+   display the traceview. </li>
+</ul>
+
+
+<p>For more information on how to use Traceview, see
+<a href="{@docRoot}tools/debugging/debugging-tracing.html">Profiling with Traceview and
+dmtracedump</a>.
 </p>
 
+<p class="note"><strong>Note:</strong> Running <code>traceview</code> from the command line
+has been deprecated. </p>
+
+
diff --git a/docs/html/training/tv/start/layouts.jd b/docs/html/training/tv/start/layouts.jd
index a378096..2b190b4 100644
--- a/docs/html/training/tv/start/layouts.jd
+++ b/docs/html/training/tv/start/layouts.jd
@@ -262,14 +262,16 @@
 
 <h2 id="advertising">Provide Effective Advertising</h2>
 
-<p>Advertising on Android TV must always be full-screen. Ads must not appear alongside or over
-content. The user must be able to dismiss an advertisement with the D-pad controller. Video ads must
-be dismissible within 30 seconds of their start time.</p>
+<p>For the living room environment, we recommend you use video ads solutions
+that are full-screen and dismissable within 30 seconds. Functionality for
+advertising on Android TV, such as dismiss buttons and clickthroughs, must be
+accessible using the D-pad rather than touch.</p>
 
-<p>Android TV does not provide a web browser. Your ads must not attempt to launch a web browser or
-redirect to the Google Play Store.</p>
+<p>Android TV does not provide a web browser. Your ads must not attempt to
+launch a web browser or redirect to Google Play Store content that is not
+approved for Android TV devices.</p>
 
 <p class="note">
-  <strong>Note:</strong> You can use the {@link android.webkit.WebView} class for logins to
-  services like Google+ and Facebook.
+  <strong>Note:</strong> You can use the {@link android.webkit.WebView} class
+  for logins to services like Google+ and Facebook.
 </p>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 7c9b30b..26232a9 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,6 +21,7 @@
 import android.content.res.ColorStateList;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -294,7 +295,13 @@
                     } else {
                         final PackageManager pm = context.getPackageManager();
                         try {
-                            mObj1 = pm.getResourcesForApplication(resPackage);
+                            ApplicationInfo ai = pm.getApplicationInfo(
+                                    resPackage, PackageManager.GET_UNINSTALLED_PACKAGES);
+                            if (ai != null) {
+                                mObj1 = pm.getResourcesForApplication(ai);
+                            } else {
+                                break;
+                            }
                         } catch (PackageManager.NameNotFoundException e) {
                             Log.e(TAG, String.format("Unable to find pkg=%s for icon %s",
                                     resPackage, this), e);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
index 515be1d..5ce4fd2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
@@ -124,22 +124,27 @@
 
     @Override
     protected PrivateKey engineGeneratePrivate(KeySpec spec) throws InvalidKeySpecException {
-        throw new UnsupportedOperationException(
-                "To generate a key pair in Android KeyStore, use KeyPairGenerator initialized with"
+        throw new InvalidKeySpecException(
+                "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
                 + " " + KeyGenParameterSpec.class.getName());
     }
 
     @Override
     protected PublicKey engineGeneratePublic(KeySpec spec) throws InvalidKeySpecException {
-        throw new UnsupportedOperationException(
-                "To generate a key pair in Android KeyStore, use KeyPairGenerator initialized with"
+        throw new InvalidKeySpecException(
+                "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
                 + " " + KeyGenParameterSpec.class.getName());
     }
 
     @Override
-    protected Key engineTranslateKey(Key arg0) throws InvalidKeyException {
-        throw new UnsupportedOperationException(
-                "To import a key into Android KeyStore, use KeyStore.setEntry with "
-                + KeyProtection.class.getName());
+    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+        if (key == null) {
+            throw new InvalidKeyException("key == null");
+        } else if ((!(key instanceof AndroidKeyStorePrivateKey))
+                && (!(key instanceof AndroidKeyStorePublicKey))) {
+            throw new InvalidKeyException(
+                    "To import a key into Android Keystore, use KeyStore.setEntry");
+        }
+        return key;
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 9a2f908..11c22a9 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -185,15 +185,20 @@
 
     @Override
     protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
-        throw new UnsupportedOperationException(
-                "To generate secret key in Android KeyStore, use KeyGenerator initialized with "
+        throw new InvalidKeySpecException(
+                "To generate secret key in Android Keystore, use KeyGenerator initialized with "
                         + KeyGenParameterSpec.class.getName());
     }
 
     @Override
     protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
-        throw new UnsupportedOperationException(
-                "To import a secret key into Android KeyStore, use KeyStore.setEntry with "
-                + KeyProtection.class.getName());
+        if (key == null) {
+            throw new InvalidKeyException("key == null");
+        } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
+            throw new InvalidKeyException(
+                    "To import a secret key into Android Keystore, use KeyStore.setEntry");
+        }
+
+        return key;
     }
 }
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 2cfb9e1..a2aa2d1 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -370,7 +370,11 @@
     if (tryStoreLayer(caches, shader, modelViewMatrix,
             textureUnit, description, &outData->layerData)) {
         outData->skiaShaderType = kLayer_SkiaShaderType;
+        return;
     }
+
+    // Unknown/unsupported type, so explicitly ignore shader
+    outData->skiaShaderType = kNone_SkiaShaderType;
 }
 
 void SkiaShader::apply(Caches& caches, const SkiaShaderData& data) {
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index a211de7..987d4cd 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -22,7 +22,8 @@
 const GLenum kTextureUnits[] = {
     GL_TEXTURE0,
     GL_TEXTURE1,
-    GL_TEXTURE2
+    GL_TEXTURE2,
+    GL_TEXTURE3
 };
 
 TextureState::TextureState()
@@ -33,10 +34,13 @@
     GLint maxTextureUnits;
     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
     LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
-        "At least %d texture units are required!", kTextureUnitsCount);
+            "At least %d texture units are required!", kTextureUnitsCount);
 }
 
 void TextureState::activateTexture(GLuint textureUnit) {
+    LOG_ALWAYS_FATAL_IF(textureUnit >= kTextureUnitsCount,
+            "Tried to use texture unit index %d, only %d exist",
+            textureUnit, kTextureUnitsCount);
     if (mTextureUnit != textureUnit) {
         glActiveTexture(kTextureUnits[textureUnit]);
         mTextureUnit = textureUnit;
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index 5a57b9f..d3c014c 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -73,7 +73,7 @@
     void unbindTexture(GLuint texture);
 private:
     // total number of texture units available for use
-    static const int kTextureUnitsCount = 3;
+    static const int kTextureUnitsCount = 4;
 
     TextureState();
     GLuint mTextureUnit;
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index f42fab7..76d36a0 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
@@ -1003,6 +1005,7 @@
         private Range<Rational> mAspectRatioRange;
         private Range<Rational> mBlockAspectRatioRange;
         private Range<Long> mBlocksPerSecondRange;
+        private Map<Size, Range<Long>> mMeasuredFrameRates;
         private Range<Integer> mFrameRateRange;
 
         private int mBlockWidth;
@@ -1195,6 +1198,28 @@
                             (double) mFrameRateRange.getUpper()));
         }
 
+        @NonNull
+        private Size findClosestSize(int width, int height) {
+            int targetPixels = width * height;
+            Size closestSize = null;
+            int mimPixelsDiff = Integer.MAX_VALUE;
+            for (Size size : mMeasuredFrameRates.keySet()) {
+                int pixelsDiff = Math.abs(targetPixels - size.getWidth() * size.getHeight());
+                if (pixelsDiff < mimPixelsDiff) {
+                    mimPixelsDiff = pixelsDiff;
+                    closestSize = size;
+                }
+            }
+            return closestSize;
+        }
+
+        private Range<Double> estimateFrameRatesFor(int width, int height) {
+            Size size = findClosestSize(width, height);
+            Range<Long> range = mMeasuredFrameRates.get(size);
+            Double ratio = (double)(width * height) / (size.getWidth() * size.getHeight());
+            return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
+        }
+
         /**
          * Returns the range of achievable video frame rates for a video size.
          * May return {@code null}, if the codec did not publish any measurement
@@ -1208,12 +1233,18 @@
          *
          * @throws IllegalArgumentException if the video size is not supported.
          */
+        @Nullable
         public Range<Double> getAchievableFrameRatesFor(int width, int height) {
             if (!supports(width, height, null)) {
                 throw new IllegalArgumentException("unsupported size");
             }
-            // TODO: get this data from the codec
-            return null;
+
+            if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
+                Log.w(TAG, "Codec did not publish any measurement data.");
+                return null;
+            }
+
+            return estimateFrameRatesFor(width, height);
         }
 
         /**
@@ -1346,6 +1377,34 @@
             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
         }
 
+        private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
+            Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
+            final String prefix = "measured-frame-rate-";
+            Set<String> keys = map.keySet();
+            for (String key : keys) {
+                // looking for: measured-frame-rate-WIDTHxHEIGHT-range
+                if (!key.startsWith(prefix)) {
+                    continue;
+                }
+                String subKey = key.substring(prefix.length());
+                String[] temp = key.split("-");
+                if (temp.length != 5) {
+                    continue;
+                }
+                String sizeStr = temp[3];
+                Size size = Utils.parseSize(sizeStr, null);
+                if (size == null || size.getWidth() * size.getHeight() <= 0) {
+                    continue;
+                }
+                Range<Long> range = Utils.parseLongRange(map.get(key), null);
+                if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
+                    continue;
+                }
+                ret.put(size, range);
+            }
+            return ret;
+        }
+
         private void parseFromInfo(MediaFormat info) {
             final Map<String, Object> map = info.getMap();
             Size blockSize = new Size(mBlockWidth, mBlockHeight);
@@ -1360,6 +1419,7 @@
             counts = Utils.parseIntRange(map.get("block-count-range"), null);
             blockRates =
                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
+            mMeasuredFrameRates = getMeasuredFrameRates(map);
             {
                 Object o = map.get("size-range");
                 Pair<Size, Size> sizeRange = Utils.parseSizeRange(o);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 581c15b..6574e4e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -67,6 +67,8 @@
 
 import com.google.android.collect.Lists;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -1397,4 +1399,22 @@
         }
         return null; // not found
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("KeyguardUpdateMonitor state:");
+        pw.println("  SIM States:");
+        for (SimData data : mSimDatas.values()) {
+            pw.println("    " + data.toString());
+        }
+        pw.println("  Subs:");
+        if (mSubscriptionInfo != null) {
+            for (int i = 0; i < mSubscriptionInfo.size(); i++) {
+                pw.println("    " + mSubscriptionInfo.get(i));
+            }
+        }
+        pw.println("  Service states:");
+        for (int subId : mServiceStates.keySet()) {
+            pw.println("    " + subId + "=" + mServiceStates.get(subId));
+        }
+    }
 }
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 377a9a4..b03f100 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -182,4 +182,17 @@
     <!-- Message for the error dialog when BT pairing fails because the other device rejected the pairing. -->
     <string name="bluetooth_pairing_rejected_error_message">Pairing rejected by <xliff:g id="device_name">%1$s</xliff:g>.</string>
 
+    <!-- Content description of the WIFI signal when WIFI is disabled for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_off">Wifi off.</string>
+    <!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_no_wifi">Wifi disconnected.</string>
+    <!-- Content description of the WIFI signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_one_bar">Wifi one bar.</string>
+    <!-- Content description of the WIFI signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_two_bars">Wifi two bars.</string>
+    <!-- Content description of the WIFI signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_three_bars">Wifi three bars.</string>
+    <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_signal_full">Wifi signal full.</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 048fb9a..348d0ec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -625,9 +625,13 @@
                 mNetworkInfo != null && mNetworkInfo.getState() != State.DISCONNECTED;
     }
 
+    public boolean isPasspoint() {
+        return mConfig != null && mConfig.isPasspoint();
+    }
+
     /** Return whether the given {@link WifiInfo} is for this access point. */
     private boolean isInfoForThisAccessPoint(WifiInfo info) {
-        if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+        if (isPasspoint() == false && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
             return networkId == info.getNetworkId();
         } else {
             // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b41e1ac..6e5dc3f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -51,7 +51,6 @@
     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d32ce55..fcf7e3e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -276,19 +276,6 @@
     <!-- Content description of the data signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_data_signal_full">Data signal full.</string>
 
-    <!-- Content description of the WIFI signal when WIFI is disabled for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_wifi_off">Wifi off.</string>
-    <!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_no_wifi">Wifi disconnected.</string>
-    <!-- Content description of the WIFI signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_wifi_one_bar">Wifi one bar.</string>
-    <!-- Content description of the WIFI signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_wifi_two_bars">Wifi two bars.</string>
-    <!-- Content description of the WIFI signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_wifi_three_bars">Wifi three bars.</string>
-    <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_wifi_signal_full">Wifi signal full.</string>
-
     <!-- Content description of the wifi label showing what we are connected to. [CHAR LIMIT=NONE] -->
     <string name="accessibility_wifi_name">Connected to <xliff:g id="wifi" example="Home Network">%s</xliff:g>.</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 2ded919..94d5170 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -158,6 +158,9 @@
             mColumns = columns;
             postInvalidate();
         }
+        for (TileRecord r : mRecords) {
+            r.tile.clearState();
+        }
         if (mListening) {
             refreshAllTiles();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 38fade2..b330582 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -61,8 +61,8 @@
     protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
 
     private Callback mCallback;
-    protected final TState mState = newTileState();
-    private final TState mTmpState = newTileState();
+    protected TState mState = newTileState();
+    private TState mTmpState = newTileState();
     private boolean mAnnounceNextStateChange;
 
     abstract protected TState newTileState();
@@ -139,6 +139,10 @@
         mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
     }
 
+    public final void clearState() {
+        mHandler.sendEmptyMessage(H.CLEAR_STATE);
+    }
+
     public void userSwitch(int newUserId) {
         mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
     }
@@ -178,6 +182,11 @@
         // optional
     }
 
+    protected void handleClearState() {
+        mTmpState = newTileState();
+        mState = newTileState();
+    }
+
     protected void handleRefreshState(Object arg) {
         handleUpdateState(mTmpState, arg);
         final boolean changed = mTmpState.copyTo(mState);
@@ -246,6 +255,7 @@
         private static final int TOGGLE_STATE_CHANGED = 8;
         private static final int SCAN_STATE_CHANGED = 9;
         private static final int DESTROY = 10;
+        private static final int CLEAR_STATE = 11;
 
         private H(Looper looper) {
             super(looper);
@@ -286,6 +296,9 @@
                 } else if (msg.what == DESTROY) {
                     name = "handleDestroy";
                     handleDestroy();
+                } else if (msg.what == CLEAR_STATE) {
+                    name = "handleClearState";
+                    handleClearState();
                 } else {
                     throw new IllegalArgumentException("Unknown msg: " + msg.what);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index f28a24b..ddde106 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -94,7 +94,11 @@
         state.visible = mController.isHotspotSupported() && mUsageTracker.isRecentlyUsed();
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
-        state.value = mController.isHotspotEnabled();
+        if (arg instanceof Boolean) {
+            state.value = (boolean) arg;
+        } else {
+            mController.isHotspotEnabled();
+        }
         state.icon = state.visible && state.value ? mEnable : mDisable;
     }
 
@@ -120,7 +124,7 @@
     private final class Callback implements HotspotController.Callback {
         @Override
         public void onHotspotChanged(boolean enabled) {
-            refreshState();
+            refreshState(enabled);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 9343172..889160d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -658,11 +658,6 @@
                         (animator.getDuration() * getCannedFlingDurationFactor()
                                 / collapseSpeedUpFactor));
             }
-            if (PhoneStatusBar.DEBUG_EMPTY_KEYGUARD
-                    && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
-                Log.i(PhoneStatusBar.TAG, "Panel collapsed! Stacktrace: "
-                        + Log.getStackTraceString(new Throwable()));
-            }
         }
         animator.addListener(new AnimatorListenerAdapter() {
             private boolean mCancelled;
@@ -777,15 +772,6 @@
 
     public void setExpandedFraction(float frac) {
         setExpandedHeight(getMaxPanelHeight() * frac);
-        if (PhoneStatusBar.DEBUG_EMPTY_KEYGUARD
-                && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
-            if (frac == 0.0f) {
-                Log.i(PhoneStatusBar.TAG, "Panel collapsed! Stacktrace: "
-                        + Log.getStackTraceString(new Throwable()));
-            } else if (frac == 1.0f) {
-                mStatusBar.endWindowManagerLogging();
-            }
-        }
     }
 
     public float getExpandedHeight() {
@@ -817,11 +803,6 @@
     }
 
     public void collapse(boolean delayed, float speedUpFactor) {
-        if (PhoneStatusBar.DEBUG_EMPTY_KEYGUARD
-                && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
-            Log.i(PhoneStatusBar.TAG, "Panel collapsed! Stacktrace: "
-                    + Log.getStackTraceString(new Throwable()));
-        }
         if (DEBUG) logf("collapse: " + this);
         if (mPeekPending || mPeekAnimator != null) {
             mCollapseAfterPeek = true;
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 891cc73..88aa071 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -98,6 +98,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
@@ -184,7 +185,6 @@
         HeadsUpManager.OnHeadsUpChangedListener {
     static final String TAG = "PhoneStatusBar";
     public static final boolean DEBUG = BaseStatusBar.DEBUG;
-    public static final boolean DEBUG_EMPTY_KEYGUARD = true;
     public static final boolean SPEW = false;
     public static final boolean DUMPTRUCK = true; // extra dumpsys info
     public static final boolean DEBUG_GESTURES = false;
@@ -2008,10 +2008,6 @@
         mStatusBarWindowManager.setPanelExpanded(isExpanded);
     }
 
-    public void endWindowManagerLogging() {
-        mStatusBarWindowManager.setLogState(false);
-    }
-
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -2674,7 +2670,9 @@
             pw.print("  status bar gestures: ");
             mGestureRec.dump(fd, pw, args);
         }
-
+        if (mStatusBarWindowManager != null) {
+            mStatusBarWindowManager.dump(fd, pw, args);
+        }
         if (mNetworkController != null) {
             mNetworkController.dump(fd, pw, args);
         }
@@ -2704,6 +2702,9 @@
         } else {
             pw.println("  mHeadsUpManager: null");
         }
+        if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
+            KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
+        }
 
         pw.println("SharedPreferences:");
         for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
@@ -3588,9 +3589,6 @@
         // Make our window larger and the panel expanded.
         makeExpandedVisible(true);
         mNotificationPanel.instantExpand();
-        if (DEBUG_EMPTY_KEYGUARD) {
-            mStatusBarWindowManager.setLogState(true);
-        }
     }
 
     private void instantCollapseNotificationPanel() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 59e1bba..b2a67bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -275,7 +275,7 @@
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         int iconId = R.drawable.stat_sys_data_bluetooth;
         String contentDescription =
-                mContext.getString(R.string.accessibility_bluetooth_disconnected);
+                mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
         if (adapter != null) {
             mBluetoothEnabled = (adapter.getState() == BluetoothAdapter.STATE_ON);
             if (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 6a46924..6d04b28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -20,14 +20,12 @@
 import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.util.EventLog;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarState;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
@@ -118,11 +116,6 @@
     @Override
     public void onAllPanelsCollapsed() {
         super.onAllPanelsCollapsed();
-        if (PhoneStatusBar.DEBUG_EMPTY_KEYGUARD
-                && mBar.getBarState() == StatusBarState.KEYGUARD) {
-            Log.i(PhoneStatusBar.TAG, "Panel collapsed! Stacktrace: "
-                    + Log.getStackTraceString(new Throwable()));
-        }
         // Close the status bar in the next frame so we can show the end of the animation.
         postOnAnimation(mHideExpandedRunnable);
         mLastFullyOpenedPanel = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 0d816dd..038fefb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -21,7 +21,6 @@
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.SystemProperties;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -32,6 +31,8 @@
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.StatusBarState;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.lang.reflect.Field;
 
 /**
@@ -48,7 +49,6 @@
     private final boolean mKeyguardScreenRotation;
 
     private final State mCurrentState = new State();
-    private boolean mLogState;
 
     public StatusBarWindowManager(Context context) {
         mContext = context;
@@ -183,9 +183,6 @@
         applyFitsSystemWindows(state);
         applyModalFlag(state);
         if (mLp.copyFrom(mLpChanged) != 0) {
-            if (PhoneStatusBar.DEBUG_EMPTY_KEYGUARD && mLogState) {
-                logCurrentState();
-            }
             mWindowManager.updateViewLayout(mStatusBarView, mLp);
         }
     }
@@ -282,19 +279,9 @@
         apply(mCurrentState);
     }
 
-    public void setLogState(boolean logState) {
-        mLogState = logState;
-        if (logState) {
-            Log.w(PhoneStatusBar.TAG, "===== Started logging WM state changes =====");
-            logCurrentState();
-        } else {
-            Log.w(PhoneStatusBar.TAG, "===== Finished logging WM state changes =====");
-        }
-    }
-
-    private void logCurrentState() {
-        Log.i(PhoneStatusBar.TAG, mCurrentState.toString()
-                + "\n  Expanded: " + isExpanded(mCurrentState));
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("StatusBarWindowManager state:");
+        pw.println(mCurrentState);
     }
 
     private static class State {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 4bfd528..1e3bc4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -111,7 +111,9 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
-            fireCallback(isHotspotEnabled());
+            int state = intent.getIntExtra(
+                    WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
+            fireCallback(WifiManager.WIFI_AP_STATE_ENABLED == state);
         }
     }
 }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index f0fc399..417f18d 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -48,6 +48,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.storage.MountServiceInternal;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -60,6 +61,7 @@
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
@@ -245,6 +247,34 @@
                 scheduleFastWriteLocked();
             }
         }
+
+        MountServiceInternal mountServiceInternal = LocalServices.getService(
+                MountServiceInternal.class);
+        mountServiceInternal.addExternalStoragePolicy(
+                new MountServiceInternal.ExternalStorageMountPolicy() {
+                    @Override
+                    public int getMountMode(int uid, String packageName) {
+                        if (Process.isIsolated(uid)) {
+                            return Zygote.MOUNT_EXTERNAL_NONE;
+                        }
+                        if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
+                                packageName) != AppOpsManager.MODE_ALLOWED) {
+                            return Zygote.MOUNT_EXTERNAL_NONE;
+                        }
+                        if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
+                                packageName) != AppOpsManager.MODE_ALLOWED) {
+                            return Zygote.MOUNT_EXTERNAL_READ;
+                        }
+                        return Zygote.MOUNT_EXTERNAL_WRITE;
+                    }
+
+                    @Override
+                    public boolean hasExternalStorage(int uid, String packageName) {
+                        final int mountMode = getMountMode(uid, packageName);
+                        return mountMode == Zygote.MOUNT_EXTERNAL_READ
+                                || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
+                    }
+                });
     }
 
     public void packageRemoved(int uid, String packageName) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index daac521..eb74ab0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -407,6 +407,10 @@
     // sequence number of NetworkRequests
     private int mNextNetworkRequestId = 1;
 
+    // NetworkRequest activity String log entries.
+    private static final int MAX_NETWORK_REQUEST_LOGS = 20;
+    private final LocalLog mNetworkRequestInfoLogs = new LocalLog(MAX_NETWORK_REQUEST_LOGS);
+
     // Array of <Network,ReadOnlyLocalLogs> tracking network validation and results
     private static final int MAX_VALIDATION_LOGS = 10;
     private final ArrayDeque<Pair<Network,ReadOnlyLocalLog>> mValidationLogs =
@@ -610,8 +614,10 @@
         if (DBG) log("ConnectivityService starting up");
 
         mDefaultRequest = createInternetRequestForTransport(-1);
-        mNetworkRequests.put(mDefaultRequest, new NetworkRequestInfo(
-                null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST));
+        NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest,
+                new Binder(), NetworkRequestInfo.REQUEST);
+        mNetworkRequests.put(mDefaultRequest, defaultNRI);
+        mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
 
         mDefaultMobileDataRequest = createInternetRequestForTransport(
                 NetworkCapabilities.TRANSPORT_CELLULAR);
@@ -1859,6 +1865,12 @@
                     pw.decreaseIndent();
                 }
             }
+
+            pw.println();
+            pw.println("mNetworkRequestInfoLogs (most recent first):");
+            pw.increaseIndent();
+            mNetworkRequestInfoLogs.reverseDump(fd, pw, args);
+            pw.decreaseIndent();
         }
     }
 
@@ -2208,6 +2220,7 @@
 
     private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
         mNetworkRequests.put(nri.request, nri);
+        mNetworkRequestInfoLogs.log("REGISTER " + nri);
         rematchAllNetworksAndRequests(null, 0);
         if (nri.isRequest && mNetworkForRequestId.get(nri.request.requestId) == null) {
             sendUpdatedScoreToFactories(nri.request, 0);
@@ -2257,6 +2270,7 @@
             if (DBG) log("releasing NetworkRequest " + request);
             nri.unlinkDeathRecipient();
             mNetworkRequests.remove(request);
+            mNetworkRequestInfoLogs.log("RELEASE " + nri);
             if (nri.isRequest) {
                 // Find all networks that are satisfying this request and remove the request
                 // from their request lists.
@@ -3529,8 +3543,9 @@
         }
 
         public String toString() {
-            return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" +
-                    mPid + " for " + request +
+            return (isRequest ? "Request" : "Listen") +
+                    " from uid/pid:" + mUid + "/" + mPid +
+                    " for " + request +
                     (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
         }
     }
@@ -3560,9 +3575,9 @@
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId());
-        if (DBG) log("requestNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.REQUEST);
+        if (DBG) log("requestNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
         if (timeoutMs > 0) {
@@ -3625,9 +3640,9 @@
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
                 nextNetworkRequestId());
-        if (DBG) log("pendingRequest for " + networkRequest + " to trigger " + operation);
         NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation,
                 NetworkRequestInfo.REQUEST);
+        if (DBG) log("pendingRequest for " + nri);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
                 nri));
         return networkRequest;
@@ -3675,11 +3690,11 @@
             enforceAccessPermission();
         }
 
-        NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities), TYPE_NONE, nextNetworkRequestId());
-        if (DBG) log("listenForNetwork for " + networkRequest);
+        NetworkRequest networkRequest = new NetworkRequest(
+                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.LISTEN);
+        if (DBG) log("listenForNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
         return networkRequest;
@@ -3693,11 +3708,11 @@
             enforceAccessPermission();
         }
 
-        NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities), TYPE_NONE, nextNetworkRequestId());
-        if (DBG) log("pendingListenForNetwork for " + networkRequest + " to trigger " + operation);
+        NetworkRequest networkRequest = new NetworkRequest(
+                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation,
                 NetworkRequestInfo.LISTEN);
+        if (DBG) log("pendingListenForNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
     }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index da552dd..0e158a2 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -68,6 +68,8 @@
 import android.os.storage.IMountServiceListener;
 import android.os.storage.IMountShutdownObserver;
 import android.os.storage.IObbActionListener;
+import android.os.storage.MountServiceInternal;
+import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy;
 import android.os.storage.OnObbStateChangeListener;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageResultCode;
@@ -127,6 +129,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -307,16 +310,6 @@
     @GuardedBy("mLock")
     private String mMoveTargetUuid;
 
-    private DiskInfo findDiskById(String id) {
-        synchronized (mLock) {
-            final DiskInfo disk = mDisks.get(id);
-            if (disk != null) {
-                return disk;
-            }
-        }
-        throw new IllegalArgumentException("No disk found for ID " + id);
-    }
-
     private VolumeInfo findVolumeByIdOrThrow(String id) {
         synchronized (mLock) {
             final VolumeInfo vol = mVolumes.get(id);
@@ -456,6 +449,9 @@
     /** Map from raw paths to {@link ObbState}. */
     final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
 
+    // Not guarded by a lock.
+    private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
+
     class ObbState implements IBinder.DeathRecipient {
         public ObbState(String rawPath, String canonicalPath, int callingUid,
                 IObbActionListener token, int nonce) {
@@ -807,7 +803,7 @@
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) {
-                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
                     mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
 
                     final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
@@ -1250,7 +1246,7 @@
             // user-specific broadcasts.
             for (int userId : mStartedUsers) {
                 if (vol.isVisibleToUser(userId)) {
-                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
                     mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
 
                     mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
@@ -1370,6 +1366,8 @@
             readSettingsLocked();
         }
 
+        LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
+
         /*
          * Create the connection to vold with a maximum queue of twice the
          * amount of containers we'd ever expect to have. This keeps an
@@ -1787,27 +1785,28 @@
         }
     }
 
-    @Override
-    public void remountUid(int uid) {
-        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+    private void remountUidExternalStorage(int uid, int mode) {
         waitForReady();
 
-        final int mountExternal = mPms.getMountExternalMode(uid);
-        final String mode;
-        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
-            mode = "default";
-        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
-            mode = "read";
-        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
-            mode = "write";
-        } else {
-            mode = "none";
+        String modeName = "none";
+        switch (mode) {
+            case Zygote.MOUNT_EXTERNAL_DEFAULT: {
+                modeName = "default";
+            } break;
+
+            case Zygote.MOUNT_EXTERNAL_READ: {
+                modeName = "read";
+            } break;
+
+            case Zygote.MOUNT_EXTERNAL_WRITE: {
+                modeName = "write";
+            } break;
         }
 
         try {
-            mConnector.execute("volume", "remount_uid", uid, mode);
+            mConnector.execute("volume", "remount_uid", uid, modeName);
         } catch (NativeDaemonConnectorException e) {
-            Slog.w(TAG, "Failed to remount UID " + uid + " as " + mode + ": " + e);
+            Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
         }
     }
 
@@ -2598,15 +2597,27 @@
     }
 
     @Override
-    public StorageVolume[] getVolumeList(int userId) {
+    public StorageVolume[] getVolumeList(int uid, String packageName) {
         final ArrayList<StorageVolume> res = new ArrayList<>();
         boolean foundPrimary = false;
 
+        final int userId = UserHandle.getUserId(uid);
+        final boolean reportUnmounted;
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            reportUnmounted = !mMountServiceInternal.hasExternalStorage(
+                    uid, packageName);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
         synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 if (vol.isVisibleToUser(userId)) {
-                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
+                            reportUnmounted);
                     if (vol.isPrimary()) {
                         res.add(0, userVol);
                         foundPrimary = true;
@@ -3379,4 +3390,50 @@
             mCryptConnector.monitor();
         }
     }
+
+    private final class MountServiceInternalImpl extends MountServiceInternal {
+        // Not guarded by a lock.
+        private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
+                new CopyOnWriteArrayList<>();
+
+        @Override
+        public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
+            // No locking - CopyOnWriteArrayList
+            mPolicies.add(policy);
+        }
+
+        @Override
+        public void onExternalStoragePolicyChanged(int uid, String packageName) {
+            final int mountMode = getExternalStorageMountMode(uid, packageName);
+            remountUidExternalStorage(uid, mountMode);
+        }
+
+        @Override
+        public int getExternalStorageMountMode(int uid, String packageName) {
+            // No locking - CopyOnWriteArrayList
+            int mountMode = Integer.MAX_VALUE;
+            for (ExternalStorageMountPolicy policy : mPolicies) {
+                final int policyMode = policy.getMountMode(uid, packageName);
+                if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
+                    return Zygote.MOUNT_EXTERNAL_NONE;
+                }
+                mountMode = Math.min(mountMode, policyMode);
+            }
+            if (mountMode == Integer.MAX_VALUE) {
+                return Zygote.MOUNT_EXTERNAL_NONE;
+            }
+            return mountMode;
+        }
+
+        public boolean hasExternalStorage(int uid, String packageName) {
+            // No locking - CopyOnWriteArrayList
+            for (ExternalStorageMountPolicy policy : mPolicies) {
+                final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
+                if (!policyHasStorage) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 36d64aa..a06bb30 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
@@ -360,12 +361,20 @@
                 + " callback.asBinder=" + callback.asBinder());
         }
 
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.READ_PHONE_STATE, null);
+        try {
+            mContext.enforceCallingPermission(
+                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+                    "addOnSubscriptionsChangedListener");
+            // SKIP checking for run-time permission since obtained PRIVILEGED
+        } catch (SecurityException e) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_PHONE_STATE,
+                    "addOnSubscriptionsChangedListener");
 
-        if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
-                callingPackage) != AppOpsManager.MODE_ALLOWED) {
-            return;
+            if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
         }
 
         Record r;
@@ -471,9 +480,15 @@
             checkListenerPermission(events);
 
             if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
-                if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
-                        callingPackage) != AppOpsManager.MODE_ALLOWED) {
-                    return;
+                try {
+                    mContext.enforceCallingPermission(
+                            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+                    // SKIP checking for run-time permission since obtained PRIVILEGED
+                } catch (SecurityException e) {
+                    if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+                            callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                        return;
+                    }
                 }
             }
 
@@ -646,6 +661,12 @@
     }
 
     private boolean canReadPhoneState(String callingPackage) {
+        if (mContext.checkCallingPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) ==
+                PackageManager.PERMISSION_GRANTED) {
+            // SKIP checking for run-time permission since obtained PRIVILEGED
+            return true;
+        }
         boolean canReadPhoneState = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED;
         if (canReadPhoneState &&
@@ -1432,6 +1453,10 @@
             intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         }
 
+        // Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
+        // that have the runtime one
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                 android.Manifest.permission.READ_PHONE_STATE,
                 AppOpsManager.OP_READ_PHONE_STATE);
@@ -1563,8 +1588,14 @@
         }
 
         if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.READ_PHONE_STATE, null);
+            try {
+                mContext.enforceCallingPermission(
+                        android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+                // SKIP checking for run-time permission since obtained PRIVILEGED
+            } catch (SecurityException e) {
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.READ_PHONE_STATE, null);
+            }
         }
 
         if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9651067..37aa408 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,10 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -62,6 +65,7 @@
 import android.os.TransactionTooLargeException;
 import android.os.WorkSource;
 import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
 import android.os.storage.StorageManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
@@ -3219,7 +3223,10 @@
                     checkTime(startTime, "startProcess: getting gids from package manager");
                     final IPackageManager pm = AppGlobals.getPackageManager();
                     permGids = pm.getPackageGids(app.info.packageName, app.userId);
-                    mountExternal = pm.getMountExternalMode(uid);
+                    MountServiceInternal mountServiceInternal = LocalServices.getService(
+                            MountServiceInternal.class);
+                    mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
+                            app.info.packageName);
                 } catch (RemoteException e) {
                     throw e.rethrowAsRuntimeException();
                 }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8c3a950..470bbb0e 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2669,8 +2669,13 @@
             if (!r.finishing) {
                 if (!mService.isSleeping()) {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
-                    requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                            "stop-no-history", false);
+                    if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
+                            "stop-no-history", false)) {
+                        // Activity was finished, no need to continue trying to schedule stop.
+                        adjustFocusedActivityLocked(r, "stopActivityFinished");
+                        r.resumeKeyDispatchingLocked();
+                        return;
+                    }
                 } else {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "Not finishing noHistory " + r
                             + " on stop because we're just sleeping");
@@ -2963,6 +2968,7 @@
         r.state = ActivityState.FINISHING;
 
         if (mode == FINISH_IMMEDIATELY
+                || (mode == FINISH_AFTER_PAUSE && prevState == ActivityState.PAUSED)
                 || prevState == ActivityState.STOPPED
                 || prevState == ActivityState.INITIALIZING) {
             // If this activity is already stopped, we can just finish
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f618c3e..f8f00ef 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
 import static android.content.Intent.ACTION_PACKAGE_ADDED;
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.ACTION_USER_ADDED;
@@ -1651,11 +1652,16 @@
     @Override
     public NetworkPolicy[] getNetworkPolicies(String callingPackage) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
+        try {
+            mContext.enforceCallingPermission(READ_PRIVILEGED_PHONE_STATE, TAG);
+            // SKIP checking run-time OP_READ_PHONE_STATE since using PRIVILEGED
+        } catch (SecurityException e) {
+            mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
 
-        if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
-                callingPackage) != AppOpsManager.MODE_ALLOWED) {
-            return new NetworkPolicy[0];
+            if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                return new NetworkPolicy[0];
+            }
         }
 
         synchronized (mRulesLock) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b23b856..7a6895f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1837,7 +1837,7 @@
 
     void dumpImpl(PrintWriter pw, DumpFilter filter) {
         pw.print("Current Notification Manager state");
-        if (filter != null) {
+        if (filter.filtered) {
             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
         }
         pw.println(':');
@@ -1865,7 +1865,7 @@
                     for (int i=0; i<N; i++) {
                         final NotificationRecord nr = mNotificationList.get(i);
                         if (filter != null && !filter.matches(nr.sbn)) continue;
-                        nr.dump(pw, "    ", getContext());
+                        nr.dump(pw, "    ", getContext(), filter.redact);
                     }
                     pw.println("  ");
                 }
@@ -1948,7 +1948,7 @@
                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
                 if (mNotificationsByKey.get(r.getKey()) != r) {
                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
-                    r.dump(pw, "      ", getContext());
+                    r.dump(pw, "      ", getContext(), filter.redact);
                 }
             }
 
@@ -3499,46 +3499,59 @@
     }
 
     public static final class DumpFilter {
+        public boolean filtered = false;
         public String pkgFilter;
         public boolean zen;
         public long since;
         public boolean stats;
-        private boolean all;
+        public boolean redact = true;
 
         public static DumpFilter parseFromArguments(String[] args) {
-            if (args != null && args.length == 2 && "p".equals(args[0])
-                    && args[1] != null && !args[1].trim().isEmpty()) {
-                final DumpFilter filter = new DumpFilter();
-                filter.pkgFilter = args[1].trim().toLowerCase();
-                return filter;
+            final DumpFilter filter = new DumpFilter();
+            for (int ai = 0; ai < args.length; ai++) {
+                final String a = args[ai];
+                if ("--noredact".equals(a) || "--reveal".equals(a)) {
+                    filter.redact = false;
+                } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
+                    if (ai < args.length-1) {
+                        ai++;
+                        filter.pkgFilter = args[ai].trim().toLowerCase();
+                        if (filter.pkgFilter.isEmpty()) {
+                            filter.pkgFilter = null;
+                        } else {
+                            filter.filtered = true;
+                        }
+                    }
+                } else if ("--zen".equals(a) || "zen".equals(a)) {
+                    filter.filtered = true;
+                    filter.zen = true;
+                } else if ("--stats".equals(a)) {
+                    filter.stats = true;
+                    if (ai < args.length-1) {
+                        ai++;
+                        filter.since = Long.valueOf(args[ai]);
+                    } else {
+                        filter.since = 0;
+                    }
+                }
             }
-            if (args != null && args.length == 1 && "zen".equals(args[0])) {
-                final DumpFilter filter = new DumpFilter();
-                filter.zen = true;
-                filter.all = true;
-                return filter;
-            }
-            if (args != null && args.length >= 1 && "--stats".equals(args[0])) {
-                final DumpFilter filter = new DumpFilter();
-                filter.stats = true;
-                filter.since = args.length == 2 ? Long.valueOf(args[1]) : 0;
-                filter.all = true;
-                return filter;
-            }
-            return null;
+            return filter;
         }
 
         public boolean matches(StatusBarNotification sbn) {
-            return all ? true : sbn != null
+            if (!filtered) return true;
+            return zen ? true : sbn != null
                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
         }
 
         public boolean matches(ComponentName component) {
-            return all ? true : component != null && matches(component.getPackageName());
+            if (!filtered) return true;
+            return zen ? true : component != null && matches(component.getPackageName());
         }
 
         public boolean matches(String pkg) {
-            return all ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
+            if (!filtered) return true;
+            return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index b7aea9d..f37702c 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -114,7 +114,7 @@
     /** @deprecated Use {@link #getUser()} instead. */
     public int getUserId() { return sbn.getUserId(); }
 
-    void dump(PrintWriter pw, String prefix, Context baseContext) {
+    void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
         final Notification notification = sbn.getNotification();
         final Icon icon = notification.getSmallIcon();
         String iconStr = String.valueOf(icon);
@@ -164,7 +164,7 @@
                     pw.println("null");
                 } else {
                     pw.print(val.getClass().getSimpleName());
-                    if (val instanceof CharSequence || val instanceof String) {
+                    if (redact && (val instanceof CharSequence || val instanceof String)) {
                         // redact contents from bugreports
                     } else if (val instanceof Bitmap) {
                         pw.print(String.format(" (%dx%d)",
@@ -172,7 +172,14 @@
                                 ((Bitmap) val).getHeight()));
                     } else if (val.getClass().isArray()) {
                         final int N = Array.getLength(val);
-                        pw.println(" (" + N + ")");
+                        pw.print(" (" + N + ")");
+                        if (!redact) {
+                            for (int j=0; j<N; j++) {
+                                pw.println();
+                                pw.print(String.format("%s      [%d] %s",
+                                        prefix, j, String.valueOf(Array.get(val, j))));
+                            }
+                        }
                     } else {
                         pw.print(" (" + String.valueOf(val) + ")");
                     }
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 7a74729..e3c6037 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -29,6 +29,7 @@
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Debug;
 import android.os.UserHandle;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
@@ -174,7 +175,7 @@
 
         synchronized (mService.mPackages) {
             for (PackageParser.Package pkg : mService.mPackages.values()) {
-                if (!isSysComponentOrPersistentPrivApp(pkg)
+                if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
                         || !doesPackageSupportRuntimePermissions(pkg)) {
                     continue;
                 }
@@ -344,7 +345,6 @@
             Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
             PackageParser.Package cbrPackage =
                     getDefaultSystemHandlerActivityPackageLPr(cbrIntent, userId);
-
             if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
                 grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, false, userId);
             }
@@ -625,8 +625,9 @@
 
     private PackageParser.Package getDefaultSystemHandlerActivityPackageLPr(
             Intent intent, int userId) {
-        List<ResolveInfo> handlers = mService.queryIntentActivities(intent,
-                intent.resolveType(mService.mContext.getContentResolver()), 0, userId);
+        List<ResolveInfo> handlers = mService.mActivities.queryIntent(intent,
+                intent.resolveType(mService.mContext.getContentResolver()),
+                PackageManager.GET_DISABLED_COMPONENTS, userId);
         final int handlerCount = handlers.size();
         for (int i = 0; i < handlerCount; i++) {
             ResolveInfo handler = handlers.get(i);
@@ -650,8 +651,9 @@
         for (String syncAdapterPackageName : syncAdapterPackageNames) {
             homeIntent.setPackage(syncAdapterPackageName);
 
-            List<ResolveInfo> homeActivities = mService.queryIntentActivities(homeIntent,
-                    homeIntent.resolveType(mService.mContext.getContentResolver()), 0, userId);
+            List<ResolveInfo> homeActivities = mService.mActivities.queryIntent(homeIntent,
+                    homeIntent.resolveType(mService.mContext.getContentResolver()),
+                    PackageManager.GET_DISABLED_COMPONENTS, userId);
             if (!homeActivities.isEmpty()) {
                 continue;
             }
@@ -681,7 +683,7 @@
     private PackageParser.Package getSystemPackageLPr(String packageName) {
         PackageParser.Package pkg = getPackageLPr(packageName);
         if (pkg != null && pkg.isSystemApp()) {
-            return !isSysComponentOrPersistentPrivApp(pkg) ? pkg : null;
+            return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null;
         }
         return null;
     }
@@ -730,11 +732,16 @@
         }
     }
 
-    private static boolean isSysComponentOrPersistentPrivApp(PackageParser.Package pkg) {
-        return UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID
-                || ((pkg.applicationInfo.privateFlags
-                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0
-                && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0);
+    private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) {
+        if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
+            return true;
+        }
+        if ((pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0
+                || (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+            return false;
+        }
+        return PackageManagerService.compareSignatures(mService.mPlatformPackage.mSignatures,
+                pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
     }
 
     private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 13aca79..ef9bc8b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -62,6 +62,7 @@
 import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
 import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Process.PACKAGE_INFO_GID;
@@ -143,10 +144,10 @@
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
+import android.os.Debug;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Debug;
 import android.os.Environment;
 import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
@@ -166,6 +167,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
@@ -284,7 +286,7 @@
     static final boolean DEBUG_PREFERRED = false;
     static final boolean DEBUG_UPGRADE = false;
     static final boolean DEBUG_DOMAIN_VERIFICATION = false;
-    private static final boolean DEBUG_BACKUP = true;
+    private static final boolean DEBUG_BACKUP = false;
     private static final boolean DEBUG_INSTALL = false;
     private static final boolean DEBUG_REMOVE = false;
     private static final boolean DEBUG_BROADCASTS = false;
@@ -2727,23 +2729,6 @@
         return null;
     }
 
-    @Override
-    public int getMountExternalMode(int uid) {
-        if (Process.isIsolated(uid)) {
-            return Zygote.MOUNT_EXTERNAL_NONE;
-        } else {
-            if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
-                return Zygote.MOUNT_EXTERNAL_DEFAULT;
-            } else if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
-                return Zygote.MOUNT_EXTERNAL_WRITE;
-            } else if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
-                return Zygote.MOUNT_EXTERNAL_READ;
-            } else {
-                return Zygote.MOUNT_EXTERNAL_DEFAULT;
-            }
-        }
-    }
-
     static PermissionInfo generatePermissionInfo(
             BasePermission bp, int flags) {
         if (bp.perm != null) {
@@ -3466,8 +3451,9 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 if (sUserManager.isInitialized(userId)) {
-                    final StorageManager storage = mContext.getSystemService(StorageManager.class);
-                    storage.remountUid(uid);
+                    MountServiceInternal mountServiceInternal = LocalServices.getService(
+                            MountServiceInternal.class);
+                    mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -4531,7 +4517,7 @@
                     } else if (result.size() <= 1) {
                         return result;
                     }
-                    result = filterCandidatesWithDomainPreferredActivitiesLPr(flags, result,
+                    result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,
                             xpDomainInfo, userId);
                     Collections.sort(result, mResolvePrioritySorter);
                 }
@@ -4581,7 +4567,8 @@
             if (ps == null) {
                 continue;
             }
-            int status = getDomainVerificationStatusLPr(ps, parentUserId);
+            long verificationState = getDomainVerificationStatusLPr(ps, parentUserId);
+            int status = (int)(verificationState >> 32);
             if (result == null) {
                 result = new CrossProfileDomainInfo();
                 result.resolveInfo =
@@ -4648,9 +4635,11 @@
         return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS);
     }
 
-    private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(
-            int flags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
+    private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
+            int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
             int userId) {
+        final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
+
         if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
             Slog.v(TAG, "Filtering results with preferred activities. Candidates count: " +
                     candidates.size());
@@ -4678,11 +4667,17 @@
                         continue;
                     }
                     // Try to get the status from User settings first
-                    int status = getDomainVerificationStatusLPr(ps, userId);
+                    long packedStatus = getDomainVerificationStatusLPr(ps, userId);
+                    int status = (int)(packedStatus >> 32);
+                    int linkGeneration = (int)(packedStatus & 0xFFFFFFFF);
                     if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
-                            Slog.i(TAG, "  + always: " + info.activityInfo.packageName);
+                            Slog.i(TAG, "  + always: " + info.activityInfo.packageName
+                                    + " : linkgen=" + linkGeneration);
                         }
+                        // Use link-enabled generation as preferredOrder, i.e.
+                        // prefer newly-enabled over earlier-enabled.
+                        info.preferredOrder = linkGeneration;
                         alwaysList.add(info);
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
@@ -4698,7 +4693,7 @@
                     }
                 }
             }
-            // First try to add the "always" resolution for the current user if there is any
+            // First try to add the "always" resolution(s) for the current user, if any
             if (alwaysList.size() > 0) {
                 result.addAll(alwaysList);
             // if there is an "always" for the parent user, add it.
@@ -4716,26 +4711,41 @@
                     result.add(xpDomainInfo.resolveInfo);
                 }
                 // Also add Browsers (all of them or only the default one)
-                if ((flags & MATCH_ALL) != 0) {
+                if ((matchFlags & MATCH_ALL) != 0) {
                     result.addAll(matchAllList);
                 } else {
-                    // Try to add the Default Browser if we can
+                    // Browser/generic handling case.  If there's a default browser, go straight
+                    // to that (but only if there is no other higher-priority match).
                     final String defaultBrowserPackageName = getDefaultBrowserPackageName(
                             UserHandle.myUserId());
-                    if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
-                        boolean defaultBrowserFound = false;
-                        final int browserCount = matchAllList.size();
-                        for (int n=0; n<browserCount; n++) {
-                            ResolveInfo browser = matchAllList.get(n);
-                            if (browser.activityInfo.packageName.equals(defaultBrowserPackageName)) {
-                                result.add(browser);
-                                defaultBrowserFound = true;
-                                break;
+                    int maxMatchPrio = 0;
+                    ResolveInfo defaultBrowserMatch = null;
+                    final int numCandidates = matchAllList.size();
+                    for (int n = 0; n < numCandidates; n++) {
+                        ResolveInfo info = matchAllList.get(n);
+                        // track the highest overall match priority...
+                        if (info.priority > maxMatchPrio) {
+                            maxMatchPrio = info.priority;
+                        }
+                        // ...and the highest-priority default browser match
+                        if (info.activityInfo.packageName.equals(defaultBrowserPackageName)) {
+                            if (defaultBrowserMatch == null
+                                    || (defaultBrowserMatch.priority < info.priority)) {
+                                if (debug) {
+                                    Slog.v(TAG, "Considering default browser match " + info);
+                                }
+                                defaultBrowserMatch = info;
                             }
                         }
-                        if (!defaultBrowserFound) {
-                            result.addAll(matchAllList);
+                    }
+                    if (defaultBrowserMatch != null
+                            && defaultBrowserMatch.priority >= maxMatchPrio
+                            && !TextUtils.isEmpty(defaultBrowserPackageName))
+                    {
+                        if (debug) {
+                            Slog.v(TAG, "Default browser match " + defaultBrowserMatch);
                         }
+                        result.add(defaultBrowserMatch);
                     } else {
                         result.addAll(matchAllList);
                     }
@@ -4759,15 +4769,19 @@
         return result;
     }
 
-    private int getDomainVerificationStatusLPr(PackageSetting ps, int userId) {
-        int status = ps.getDomainVerificationStatusForUser(userId);
+    // Returns a packed value as a long:
+    //
+    // high 'int'-sized word: link status: undefined/ask/never/always.
+    // low 'int'-sized word: relative priority among 'always' results.
+    private long getDomainVerificationStatusLPr(PackageSetting ps, int userId) {
+        long result = ps.getDomainVerificationStatusForUser(userId);
         // if none available, get the master status
-        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+        if (result >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
             if (ps.getIntentFilterVerificationInfo() != null) {
-                status = ps.getIntentFilterVerificationInfo().getStatus();
+                result = ((long)ps.getIntentFilterVerificationInfo().getStatus()) << 32;
             }
         }
-        return status;
+        return result;
     }
 
     private ResolveInfo querySkipCurrentProfileIntents(
@@ -12963,7 +12977,7 @@
                         false, //hidden
                         null, null, null,
                         false, // blockUninstall
-                        INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+                        INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
                 if (!isSystemApp(ps)) {
                     if (ps.isAnyInstalled(sUserManager.getUserIds())) {
                         // Other user still have this package installed, so all
@@ -14439,6 +14453,33 @@
 
         mInstallerService.systemReady();
         mPackageDexOptimizer.systemReady();
+
+        MountServiceInternal mountServiceInternal = LocalServices.getService(
+                MountServiceInternal.class);
+        mountServiceInternal.addExternalStoragePolicy(
+                new MountServiceInternal.ExternalStorageMountPolicy() {
+            @Override
+            public int getMountMode(int uid, String packageName) {
+                if (Process.isIsolated(uid)) {
+                    return Zygote.MOUNT_EXTERNAL_NONE;
+                }
+                if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
+                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
+                }
+                if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
+                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
+                }
+                if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
+                    return Zygote.MOUNT_EXTERNAL_READ;
+                }
+                return Zygote.MOUNT_EXTERNAL_WRITE;
+            }
+
+            @Override
+            public boolean hasExternalStorage(int uid, String packageName) {
+                return true;
+            }
+        });
     }
 
     @Override
@@ -14886,8 +14927,8 @@
                             pw.println();
                             count = 0;
                             for (PackageSetting ps : allPackageSettings) {
-                                final int status = ps.getDomainVerificationStatusForUser(userId);
-                                if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+                                final long status = ps.getDomainVerificationStatusForUser(userId);
+                                if (status >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
                                     continue;
                                 }
                                 pw.println(prefix + "Package: " + ps.name);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 6f46f69..4faf75a 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -341,7 +341,8 @@
     void setUserState(int userId, int enabled, boolean installed, boolean stopped,
             boolean notLaunched, boolean hidden,
             String lastDisableAppCaller, ArraySet<String> enabledComponents,
-            ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState) {
+            ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
+            int linkGeneration) {
         PackageUserState state = modifyUserState(userId);
         state.enabled = enabled;
         state.installed = installed;
@@ -353,6 +354,7 @@
         state.disabledComponents = disabledComponents;
         state.blockUninstall = blockUninstall;
         state.domainVerificationStatus = domainVerifState;
+        state.appLinkGeneration = linkGeneration;
     }
 
     ArraySet<String> getEnabledComponents(int userId) {
@@ -449,12 +451,23 @@
         verificationInfo = info;
     }
 
-    int getDomainVerificationStatusForUser(int userId) {
-        return readUserState(userId).domainVerificationStatus;
+    // Returns a packed value as a long:
+    //
+    // high 'int'-sized word: link status: undefined/ask/never/always.
+    // low 'int'-sized word: relative priority among 'always' results.
+    long getDomainVerificationStatusForUser(int userId) {
+        PackageUserState state = readUserState(userId);
+        long result = (long) state.appLinkGeneration;
+        result |= ((long) state.domainVerificationStatus) << 32;
+        return result;
     }
 
-    void setDomainVerificationStatusForUser(int status, int userId) {
-        modifyUserState(userId).domainVerificationStatus = status;
+    void setDomainVerificationStatusForUser(final int status, int generation, int userId) {
+        PackageUserState state = modifyUserState(userId);
+        state.domainVerificationStatus = status;
+        if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
+            state.appLinkGeneration = generation;
+        }
     }
 
     void clearDomainVerificationStatusForUser(int userId) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bdcd714..312b7b3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -87,6 +87,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.Xml;
 
 import java.io.BufferedOutputStream;
@@ -196,6 +197,7 @@
     private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
     private static final String ATTR_PACKAGE_NAME= "packageName";
     private static final String ATTR_FINGERPRINT = "fingerprint";
+    private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
 
     private final Object mLock;
 
@@ -294,6 +296,9 @@
     // For every user, it is used to find the package name of the default Browser App.
     final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>();
 
+    // App-link priority tracking, per-user
+    final SparseIntArray mNextAppLinkGeneration = new SparseIntArray();
+
     final StringBuilder mReadMessages = new StringBuilder();
 
     /**
@@ -624,7 +629,7 @@
                                     false, // hidden
                                     null, null, null,
                                     false, // blockUninstall
-                                    INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+                                    INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
                             writePackageRestrictionsLPr(user.id);
                         }
                     }
@@ -1051,7 +1056,7 @@
             }
             return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
         }
-        int status = ps.getDomainVerificationStatusForUser(userId);
+        int status = (int)(ps.getDomainVerificationStatusForUser(userId) >> 32);
         if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
             if (ps.getIntentFilterVerificationInfo() != null) {
                 status = ps.getIntentFilterVerificationInfo().getStatus();
@@ -1060,7 +1065,7 @@
         return status;
     }
 
-    boolean updateIntentFilterVerificationStatusLPw(String packageName, int status, int userId) {
+    boolean updateIntentFilterVerificationStatusLPw(String packageName, final int status, int userId) {
         // Update the status for the current package
         PackageSetting current = mPackages.get(packageName);
         if (current == null) {
@@ -1070,7 +1075,15 @@
             return false;
         }
 
-        current.setDomainVerificationStatusForUser(status, userId);
+        final int alwaysGeneration;
+        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
+            alwaysGeneration = mNextAppLinkGeneration.get(userId) + 1;
+            mNextAppLinkGeneration.put(userId, alwaysGeneration);
+        } else {
+            alwaysGeneration = 0;
+        }
+
+        current.setDomainVerificationStatusForUser(status, alwaysGeneration, userId);
         return true;
     }
 
@@ -1382,7 +1395,7 @@
                                 false,  // hidden
                                 null, null, null,
                                 false, // blockUninstall
-                                INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+                                INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
                     }
                     return;
                 }
@@ -1404,6 +1417,8 @@
                 return;
             }
 
+            int maxAppLinkGeneration = 0;
+
             int outerDepth = parser.getDepth();
             PackageSetting ps = null;
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1457,6 +1472,12 @@
                             PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED :
                             Integer.parseInt(verifStateStr);
 
+                    final String linkGenStr = parser.getAttributeValue(null, ATTR_APP_LINK_GENERATION);
+                    final int linkGeneration = linkGenStr == null ? 0 : Integer.parseInt(linkGenStr);
+                    if (linkGeneration > maxAppLinkGeneration) {
+                        maxAppLinkGeneration = linkGeneration;
+                    }
+
                     ArraySet<String> enabledComponents = null;
                     ArraySet<String> disabledComponents = null;
 
@@ -1478,7 +1499,7 @@
 
                     ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden,
                             enabledCaller, enabledComponents, disabledComponents, blockUninstall,
-                            verifState);
+                            verifState, linkGeneration);
                 } else if (tagName.equals("preferred-activities")) {
                     readPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -1496,6 +1517,8 @@
 
             str.close();
 
+            mNextAppLinkGeneration.put(userId, maxAppLinkGeneration + 1);
+
         } catch (XmlPullParserException e) {
             mReadMessages.append("Error reading: " + e.toString());
             PackageManagerService.reportSettingsProblem(Log.ERROR,
@@ -1749,6 +1772,10 @@
                         serializer.attribute(null, ATTR_DOMAIN_VERIFICATON_STATE,
                                 Integer.toString(ustate.domainVerificationStatus));
                     }
+                    if (ustate.appLinkGeneration != 0) {
+                        serializer.attribute(null, ATTR_APP_LINK_GENERATION,
+                                Integer.toString(ustate.appLinkGeneration));
+                    }
                     if (ustate.enabledComponents != null
                             && ustate.enabledComponents.size() > 0) {
                         serializer.startTag(null, TAG_ENABLED_COMPONENTS);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 87efb8d..9e41f70 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -44,6 +44,9 @@
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiPlaybackClient;
+import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -356,6 +359,7 @@
     boolean mSystemReady;
     boolean mSystemBooted;
     boolean mHdmiPlugged;
+    HdmiControl mHdmiControl;
     IUiModeManager mUiModeManager;
     int mUiMode;
     int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -1212,6 +1216,9 @@
     }
 
     private void handleShortPressOnHome() {
+        // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
+        getHdmiControl().turnOnTv();
+
         // If there's a dream running then use home to escape the dream
         // but don't actually go home.
         if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
@@ -1223,6 +1230,46 @@
         launchHomeFromHotKey();
     }
 
+    /**
+     * Creates an accessor to HDMI control service that performs the operation of
+     * turning on TV (optional) and switching input to us. If HDMI control service
+     * is not available or we're not a HDMI playback device, the operation is no-op.
+     */
+    private HdmiControl getHdmiControl() {
+        if (null == mHdmiControl) {
+            HdmiControlManager manager = (HdmiControlManager) mContext.getSystemService(
+                        Context.HDMI_CONTROL_SERVICE);
+            HdmiPlaybackClient client = null;
+            if (manager != null) {
+                client = manager.getPlaybackClient();
+            }
+            mHdmiControl = new HdmiControl(client);
+        }
+        return mHdmiControl;
+    }
+
+    private static class HdmiControl {
+        private final HdmiPlaybackClient mClient;
+
+        private HdmiControl(HdmiPlaybackClient client) {
+            mClient = client;
+        }
+
+        public void turnOnTv() {
+            if (mClient == null) {
+                return;
+            }
+            mClient.oneTouchPlay(new OneTouchPlayCallback() {
+                @Override
+                public void onComplete(int result) {
+                    if (result != HdmiControlManager.RESULT_SUCCESS) {
+                        Log.w(TAG, "One touch play failed: " + result);
+                    }
+                }
+            });
+        }
+    }
+
     private void handleLongPressOnHome(int deviceId) {
         if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
             mHomeConsumed = true;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 89e9d2e..0bb04f8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4230,7 +4230,7 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
         } catch (SecurityException e) {
-            Log.w(TAG, "Permission error calling ITelephony#canChangeDtmfToneLength", e);
+            Log.e(TAG, "Permission error calling ITelephony#canChangeDtmfToneLength", e);
         }
         return false;
     }
@@ -4248,6 +4248,8 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
+        } catch (SecurityException e) {
+            Log.e(TAG, "Permission error calling ITelephony#isWorldPhone", e);
         }
         return false;
     }
@@ -4265,6 +4267,8 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isTtyModeSupported", e);
+        } catch (SecurityException e) {
+            Log.e(TAG, "Permission error calling ITelephony#isTtyModeSupported", e);
         }
         return false;
     }
@@ -4283,6 +4287,8 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isHearingAidCompatibilitySupported", e);
+        } catch (SecurityException e) {
+            Log.e(TAG, "Permission error calling ITelephony#isHearingAidCompatibilitySupported", e);
         }
         return false;
     }