Merge "SensorManager API changes." into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index b07907b..dba086c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5382,7 +5382,6 @@
     method public android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
     method public void enableSystemApp(android.content.ComponentName, java.lang.String);
     method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
-    method public void setTrustAgentFeaturesEnabled(android.content.ComponentName, android.content.ComponentName, java.util.List<java.lang.String>);
     method public java.lang.String[] getAccountTypesWithManagementDisabled();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
@@ -5454,6 +5453,7 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
+    method public void setTrustAgentFeaturesEnabled(android.content.ComponentName, android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
@@ -12669,7 +12669,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PHYSICAL_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PIXEL_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_SENSITIVITY_RANGE;
-    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_TIMESTAMP_CALIBRATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_TIMESTAMP_SOURCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_WHITE_LEVEL;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_MAX_ANALOG_SENSITIVITY;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_ORIENTATION;
@@ -12863,8 +12863,8 @@
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG = 1; // 0x1
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB = 4; // 0x4
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB = 0; // 0x0
-    field public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED = 1; // 0x1
-    field public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED = 0; // 0x0
+    field public static final int SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME = 1; // 0x1
+    field public static final int SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN = 0; // 0x0
     field public static final int SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER = 10; // 0xa
     field public static final int SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14; // 0xe
     field public static final int SENSOR_REFERENCE_ILLUMINANT1_D50 = 23; // 0x17
@@ -12992,7 +12992,7 @@
 
   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
     method public T get(android.hardware.camera2.CaptureResult.Key<T>);
-    method public int getFrameNumber();
+    method public long getFrameNumber();
     method public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
     field public static final android.hardware.camera2.CaptureResult.Key BLACK_LEVEL_LOCK;
@@ -13038,7 +13038,6 @@
     field public static final android.hardware.camera2.CaptureResult.Key LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key LENS_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key NOISE_REDUCTION_MODE;
-    field public static final android.hardware.camera2.CaptureResult.Key REQUEST_FRAME_COUNT;
     field public static final android.hardware.camera2.CaptureResult.Key REQUEST_PIPELINE_DEPTH;
     field public static final android.hardware.camera2.CaptureResult.Key SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_EXPOSURE_TIME;
@@ -13175,7 +13174,6 @@
     method public boolean isOutputSupportedFor(int);
     method public static boolean isOutputSupportedFor(java.lang.Class<T>);
     method public boolean isOutputSupportedFor(android.view.Surface);
-    field public static final long NO_MIN_FRAME_DURATION = 0L; // 0x0L
   }
 
   public final class TonemapCurve {
@@ -28559,9 +28557,11 @@
   }
 
   public final class CallCameraCapabilities implements android.os.Parcelable {
-    ctor public CallCameraCapabilities(boolean, float);
+    ctor public CallCameraCapabilities(boolean, float, int, int);
     method public int describeContents();
+    method public int getHeight();
     method public float getMaxZoom();
+    method public int getWidth();
     method public boolean isZoomSupported();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -28692,15 +28692,15 @@
 
   public abstract class ConnectionService extends android.app.Service {
     ctor public ConnectionService();
-    method public final android.telecomm.RemoteConnection createRemoteIncomingConnection(android.telecomm.ConnectionRequest);
-    method public final android.telecomm.RemoteConnection createRemoteOutgoingConnection(android.telecomm.ConnectionRequest);
+    method public final android.telecomm.RemoteConnection createRemoteIncomingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
+    method public final android.telecomm.RemoteConnection createRemoteOutgoingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     method public final java.util.Collection<android.telecomm.Connection> getAllConnections();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnectionAdded(android.telecomm.Connection);
     method public void onConnectionRemoved(android.telecomm.Connection);
     method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
-    method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.ConnectionRequest);
-    method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.ConnectionRequest);
+    method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
+    method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecomm.ConnectionService";
   }
 
@@ -28818,7 +28818,7 @@
   }
 
   public class PhoneAccount implements android.os.Parcelable {
-    ctor public PhoneAccount(android.telecomm.PhoneAccountHandle, android.net.Uri, java.lang.String, int, int, java.lang.CharSequence, java.lang.CharSequence, boolean);
+    ctor public PhoneAccount(android.telecomm.PhoneAccountHandle, android.net.Uri, java.lang.String, int, int, java.lang.CharSequence, java.lang.CharSequence);
     method public int describeContents();
     method public android.telecomm.PhoneAccountHandle getAccountHandle();
     method public int getCapabilities();
@@ -28828,10 +28828,10 @@
     method public java.lang.CharSequence getLabel();
     method public java.lang.CharSequence getShortDescription();
     method public java.lang.String getSubscriptionNumber();
-    method public boolean isVideoCallingSupported();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final int CAPABILITY_SIM_CALL_MANAGER = 1; // 0x1
+    field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+    field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index de5b9c4..3a764fa 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5081,7 +5081,12 @@
     }
 
     public static ActivityThread systemMain() {
-        HardwareRenderer.disable(true);
+        // The system process on low-memory devices do not get to use hardware
+        // accelerated drawing, since this can add too much overhead to the
+        // process.
+        if (!ActivityManager.isHighEndGfx()) {
+            HardwareRenderer.disable(true);
+        }
         ActivityThread thread = new ActivityThread();
         thread.attach(true);
         return thread;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0e6f86e..9310bf8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -361,6 +361,40 @@
             = "android.app.action.ADD_DEVICE_ADMIN";
 
     /**
+     * @hide
+     * Activity action: ask the user to add a new device administrator as the profile owner
+     * for this user. Only system privileged apps that have MANAGE_USERS and MANAGE_DEVICE_ADMINS
+     * permission can call this API.
+     *
+     * <p>The ComponentName of the profile owner admin is pass in {@link #EXTRA_DEVICE_ADMIN} extra
+     * field. This will invoke a UI to bring the user through adding the profile owner admin
+     * to remotely control restrictions on the user.
+     *
+     * <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
+     * result of whether or not the user approved the action. If approved, the result will
+     * be {@link Activity#RESULT_OK} and the component will be set as an active admin as well
+     * as a profile owner.
+     *
+     * <p>You can optionally include the {@link #EXTRA_ADD_EXPLANATION}
+     * field to provide the user with additional explanation (in addition
+     * to your component's description) about what is being added.
+     *
+     * <p>If there is already a profile owner active or the caller doesn't have the required
+     * permissions, the operation will return a failure result.
+     */
+    @SystemApi
+    public static final String ACTION_SET_PROFILE_OWNER
+            = "android.app.action.SET_PROFILE_OWNER";
+
+    /**
+     * @hide
+     * Name of the profile owner admin that controls the user.
+     */
+    @SystemApi
+    public static final String EXTRA_PROFILE_OWNER_NAME
+            = "android.app.extra.PROFILE_OWNER_NAME";
+
+    /**
      * Activity action: send when any policy admin changes a policy.
      * This is generally used to find out when a new policy is in effect.
      *
@@ -397,6 +431,7 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SET_NEW_PASSWORD
             = "android.app.action.SET_NEW_PASSWORD";
+
     /**
      * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from a
      * managed profile to its parent.
@@ -2018,7 +2053,6 @@
         return false;
     }
 
-
     /**
      * Used to determine if a particular package has been registered as a Device Owner app.
      * A device owner app is a special device admin that cannot be deactivated by the user, once
@@ -2096,6 +2130,7 @@
 
     /**
      * @hide
+     * @deprecated Use #ACTION_SET_PROFILE_OWNER
      * Sets the given component as an active admin and registers the package as the profile
      * owner for this user. The package must already be installed and there shouldn't be
      * an existing profile owner registered for this user. Also, this method must be called
@@ -2116,7 +2151,7 @@
             try {
                 final int myUserId = UserHandle.myUserId();
                 mService.setActiveAdmin(admin, false, myUserId);
-                return mService.setProfileOwner(admin.getPackageName(), ownerName, myUserId);
+                return mService.setProfileOwner(admin, ownerName, myUserId);
             } catch (RemoteException re) {
                 Log.w(TAG, "Failed to set profile owner " + re);
                 throw new IllegalArgumentException("Couldn't set profile owner.", re);
@@ -2127,6 +2162,42 @@
 
     /**
      * @hide
+     * Clears the active profile owner and removes all user restrictions. The caller must
+     * be from the same package as the active profile owner for this user, otherwise a
+     * SecurityException will be thrown.
+     *
+     * @param admin The component to remove as the profile owner.
+     * @return
+     */
+    @SystemApi
+    public void clearProfileOwner(ComponentName admin) {
+        if (mService != null) {
+            try {
+                mService.clearProfileOwner(admin);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to clear profile owner " + admin + re);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Checks if the user was already setup.
+     */
+    public boolean hasUserSetupCompleted() {
+        if (mService != null) {
+            try {
+                return mService.hasUserSetupCompleted();
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to check if user setup has completed");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @deprecated Use setProfileOwner(ComponentName ...)
+     * @hide
      * Sets the given package as the profile owner of the given user profile. The package must
      * already be installed and there shouldn't be an existing profile owner registered for this
      * user. Also, this method must be called before the user has been used for the first time.
@@ -2139,9 +2210,35 @@
      */
     public boolean setProfileOwner(String packageName, String ownerName, int userHandle)
             throws IllegalArgumentException {
+        if (packageName == null) {
+            throw new NullPointerException("packageName cannot be null");
+        }
+        return setProfileOwner(new ComponentName(packageName, ""), ownerName, userHandle);
+    }
+
+    /**
+     * @hide
+     * Sets the given component as the profile owner of the given user profile. The package must
+     * already be installed and there shouldn't be an existing profile owner registered for this
+     * user. Only the system can call this API if the user has already completed setup.
+     * @param admin the component name to be registered as profile owner.
+     * @param ownerName the human readable name of the organisation associated with this DPM.
+     * @param userHandle the userId to set the profile owner for.
+     * @return whether the component was successfully registered as the profile owner.
+     * @throws IllegalArgumentException if admin is null, the package isn't installed, or
+     *         the user has already been set up.
+     */
+    public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle)
+            throws IllegalArgumentException {
+        if (admin == null) {
+            throw new NullPointerException("admin cannot be null");
+        }
         if (mService != null) {
             try {
-                return mService.setProfileOwner(packageName, ownerName, userHandle);
+                if (ownerName == null) {
+                    ownerName = "";
+                }
+                return mService.setProfileOwner(admin, ownerName, userHandle);
             } catch (RemoteException re) {
                 Log.w(TAG, "Failed to set profile owner", re);
                 throw new IllegalArgumentException("Couldn't set profile owner.", re);
@@ -2200,7 +2297,7 @@
         if (mService != null) {
             try {
                 String profileOwnerPackage = mService.getProfileOwner(
-                        Process.myUserHandle().getIdentifier());
+                        Process.myUserHandle().getIdentifier()).getPackageName();
                 return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
             } catch (RemoteException re) {
                 Log.w(TAG, "Failed to check profile owner");
@@ -2215,7 +2312,7 @@
      * owner has been set for that user.
      * @throws IllegalArgumentException if the userId is invalid.
      */
-    public String getProfileOwner() throws IllegalArgumentException {
+    public ComponentName getProfileOwner() throws IllegalArgumentException {
         if (mService != null) {
             try {
                 return mService.getProfileOwner(Process.myUserHandle().getIdentifier());
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a6544e6..6ce737a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -113,11 +113,13 @@
     String getDeviceOwnerName();
     void clearDeviceOwner(String packageName);
 
-    boolean setProfileOwner(String packageName, String ownerName, int userHandle);
-    String getProfileOwner(int userHandle);
+    boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
+    ComponentName getProfileOwner(int userHandle);
     String getProfileOwnerName(int userHandle);
     void setProfileEnabled(in ComponentName who);
     void setProfileName(in ComponentName who, String profileName);
+    void clearProfileOwner(in ComponentName who);
+    boolean hasUserSetupCompleted();
 
     boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
     void uninstallCaCert(in ComponentName admin, in String alias);
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 2ce18b0..30aaf2e 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -110,21 +110,27 @@
         dest.writeInt(mServiceDataUuid == null ? 0 : 1);
         if (mServiceDataUuid != null) {
             dest.writeParcelable(mServiceDataUuid, flags);
-            dest.writeInt(mServiceData == null ? 0 : mServiceData.length);
+            dest.writeInt(mServiceData == null ? 0 : 1);
             if (mServiceData != null) {
+                dest.writeInt(mServiceData.length);
                 dest.writeByteArray(mServiceData);
-                dest.writeInt(mServiceDataMask == null ? 0 : mServiceDataMask.length);
+
+                dest.writeInt(mServiceDataMask == null ? 0 : 1);
                 if (mServiceDataMask != null) {
+                    dest.writeInt(mServiceDataMask.length);
                     dest.writeByteArray(mServiceDataMask);
                 }
             }
         }
         dest.writeInt(mManufacturerId);
-        dest.writeInt(mManufacturerData == null ? 0 : mManufacturerData.length);
+        dest.writeInt(mManufacturerData == null ? 0 : 1);
         if (mManufacturerData != null) {
+            dest.writeInt(mManufacturerData.length);
             dest.writeByteArray(mManufacturerData);
-            dest.writeInt(mManufacturerDataMask == null ? 0 : mManufacturerDataMask.length);
+
+            dest.writeInt(mManufacturerDataMask == null ? 0 : 1);
             if (mManufacturerDataMask != null) {
+                dest.writeInt(mManufacturerDataMask.length);
                 dest.writeByteArray(mManufacturerDataMask);
             }
         }
@@ -164,29 +170,31 @@
                     if (in.readInt() == 1) {
                         ParcelUuid servcieDataUuid =
                                 in.readParcelable(ParcelUuid.class.getClassLoader());
-                        int serviceDataLength = in.readInt();
-                        if (serviceDataLength > 0) {
+                        if (in.readInt() == 1) {
+                            int serviceDataLength = in.readInt();
                             byte[] serviceData = new byte[serviceDataLength];
                             in.readByteArray(serviceData);
-                            builder.setServiceData(servcieDataUuid, serviceData);
-                            int serviceDataMaskLength = in.readInt();
-                            if (serviceDataMaskLength > 0) {
+                            if (in.readInt() == 0) {
+                                builder.setServiceData(servcieDataUuid, serviceData);
+                            } else {
+                                int serviceDataMaskLength = in.readInt();
                                 byte[] serviceDataMask = new byte[serviceDataMaskLength];
                                 in.readByteArray(serviceDataMask);
                                 builder.setServiceData(
-                                        servcieDataUuid, serviceData, serviceDataMask);
+                                            servcieDataUuid, serviceData, serviceDataMask);
                             }
                         }
                     }
 
                     int manufacturerId = in.readInt();
-                    int manufacturerDataLength = in.readInt();
-                    if (manufacturerDataLength > 0) {
+                    if (in.readInt() == 1) {
+                        int manufacturerDataLength = in.readInt();
                         byte[] manufacturerData = new byte[manufacturerDataLength];
                         in.readByteArray(manufacturerData);
-                        builder.setManufacturerData(manufacturerId, manufacturerData);
-                        int manufacturerDataMaskLength = in.readInt();
-                        if (manufacturerDataMaskLength > 0) {
+                        if (in.readInt() == 0) {
+                            builder.setManufacturerData(manufacturerId, manufacturerData);
+                        } else {
+                            int manufacturerDataMaskLength = in.readInt();
                             byte[] manufacturerDataMask = new byte[manufacturerDataMaskLength];
                             in.readByteArray(manufacturerDataMask);
                             builder.setManufacturerData(manufacturerId, manufacturerData,
@@ -349,12 +357,17 @@
 
     // Check whether the data pattern matches the parsed data.
     private boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) {
-        if (dataMask == null) {
-            return Arrays.equals(data, parsedData);
-        }
-        if (parsedData == null) {
+        if (parsedData == null || parsedData.length < data.length) {
             return false;
         }
+        if (dataMask == null) {
+            for (int i = 0; i < data.length; ++i) {
+                if (parsedData[i] != data[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
         for (int i = 0; i < data.length; ++i) {
             if ((dataMask[i] & parsedData[i]) != (dataMask[i] & data[i])) {
                 return false;
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 2d50b5a..c95a5bf 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -190,7 +190,7 @@
                 return info;
             }
         } catch (RemoteException re) {
-            return null;
+            throw new RuntimeException("Failed to call LauncherAppsService");
         }
         return null;
     }
@@ -259,7 +259,7 @@
         try {
             return mService.isPackageEnabled(packageName, user);
         } catch (RemoteException re) {
-            return false;
+            throw new RuntimeException("Failed to call LauncherAppsService");
         }
     }
 
@@ -275,7 +275,7 @@
         try {
             return mService.isActivityEnabled(component, user);
         } catch (RemoteException re) {
-            return false;
+            throw new RuntimeException("Failed to call LauncherAppsService");
         }
     }
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 6cb6a24..4e7f9dd 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1551,17 +1551,17 @@
             new Key<Integer>("android.sensor.info.whiteLevel", int.class);
 
     /**
-     * <p>The sensor timestamp calibration quality.</p>
-     * <p>The sensor timestamp calibration quality determines the reliability of
-     * {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} provided by the camera device.</p>
-     *
-     * @see CaptureResult#SENSOR_TIMESTAMP
-     * @see #SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED
-     * @see #SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED
+     * <p>The time base source for sensor capture start timestamps.</p>
+     * <p>The timestamps provided for captures are always in nanoseconds and monotonic, but
+     * may not based on a time source that can be compared to other system time sources.</p>
+     * <p>This characteristic defines the source for the timestamps, and therefore whether they
+     * can be compared against other system time sources/timestamps.</p>
+     * @see #SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN
+     * @see #SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME
      */
     @PublicKey
-    public static final Key<Integer> SENSOR_INFO_TIMESTAMP_CALIBRATION =
-            new Key<Integer>("android.sensor.info.timestampCalibration", int.class);
+    public static final Key<Integer> SENSOR_INFO_TIMESTAMP_SOURCE =
+            new Key<Integer>("android.sensor.info.timestampSource", int.class);
 
     /**
      * <p>The standard reference illuminant used as the scene light source when
@@ -1934,7 +1934,7 @@
      * android.sync.frameNumber to a non-negative value).</p>
      * <p>This defines the maximum distance (in number of metadata results),
      * between android.sync.frameNumber and the equivalent
-     * android.request.frameCount.</p>
+     * frame number for that result.</p>
      * <p>In other words this acts as an upper boundary for how many frames
      * must occur before the camera device knows for a fact that the new
      * submitted camera settings have been applied in outgoing frames.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ebbfc63..fbca395 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -494,7 +494,7 @@
     public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB = 4;
 
     //
-    // Enumeration values for CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+    // Enumeration values for CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
     //
 
     /**
@@ -506,9 +506,9 @@
      * and the result metadata generated by a single capture are identical.</p>
      *
      * @see CaptureResult#SENSOR_TIMESTAMP
-     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
      */
-    public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED = 0;
+    public static final int SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN = 0;
 
     /**
      * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in the same timebase as
@@ -516,9 +516,9 @@
      * and they can be compared to other timestamps using that base.</p>
      *
      * @see CaptureResult#SENSOR_TIMESTAMP
-     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
      */
-    public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED = 1;
+    public static final int SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME = 1;
 
     //
     // Enumeration values for CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
@@ -664,7 +664,7 @@
     /**
      * <p>Every frame has the requests immediately applied.</p>
      * <p>Furthermore for all results,
-     * <code>android.sync.frameNumber == android.request.frameCount</code></p>
+     * <code>android.sync.frameNumber == CaptureResult#getFrameNumber()</code></p>
      * <p>Changing controls over multiple requests one after another will
      * produce results that have those controls applied atomically
      * each frame.</p>
@@ -679,6 +679,7 @@
      * <p>By submitting a series of identical requests, the camera device
      * will eventually have the camera settings applied, but it is
      * unknown when that exact point will be.</p>
+     * <p>All LEGACY capability devices will have this as their maxLatency.</p>
      * @see CameraCharacteristics#SYNC_MAX_LATENCY
      */
     public static final int SYNC_MAX_LATENCY_UNKNOWN = -1;
@@ -1207,8 +1208,7 @@
      * image while recording video) use case.</p>
      * <p>The camera device should take the highest-quality image
      * possible (given the other settings) without disrupting the
-     * frame rate of video recording.<br />
-     * </p>
+     * frame rate of video recording.  </p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 20a04f0..63dff55 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.impl.PublicKey;
 import android.hardware.camera2.impl.SyntheticKey;
 import android.hardware.camera2.utils.TypeReference;
@@ -142,12 +143,16 @@
     private final CameraMetadataNative mResults;
     private final CaptureRequest mRequest;
     private final int mSequenceId;
+    private final long mFrameNumber;
 
     /**
      * Takes ownership of the passed-in properties object
+     *
+     * <p>For internal use only</p>
      * @hide
      */
-    public CaptureResult(CameraMetadataNative results, CaptureRequest parent, int sequenceId) {
+    public CaptureResult(CameraMetadataNative results, CaptureRequest parent,
+            CaptureResultExtras extras) {
         if (results == null) {
             throw new IllegalArgumentException("results was null");
         }
@@ -156,12 +161,17 @@
             throw new IllegalArgumentException("parent was null");
         }
 
+        if (extras == null) {
+            throw new IllegalArgumentException("extras was null");
+        }
+
         mResults = CameraMetadataNative.move(results);
         if (mResults.isEmpty()) {
             throw new AssertionError("Results must not be empty");
         }
         mRequest = parent;
-        mSequenceId = sequenceId;
+        mSequenceId = extras.getRequestId();
+        mFrameNumber = extras.getFrameNumber();
     }
 
     /**
@@ -190,6 +200,7 @@
 
         mRequest = null;
         mSequenceId = sequenceId;
+        mFrameNumber = -1;
     }
 
     /**
@@ -288,11 +299,10 @@
      * for every new result or failure; and the scope is the lifetime of the
      * {@link CameraDevice}.</p>
      *
-     * @return int frame number
+     * @return The frame number
      */
-    public int getFrameNumber() {
-        // TODO: @hide REQUEST_FRAME_COUNT
-        return get(REQUEST_FRAME_COUNT);
+    public long getFrameNumber() {
+        return mFrameNumber;
     }
 
     /**
@@ -2026,8 +2036,10 @@
      * increases with every new result (that is, each new result has a unique
      * frameCount value).</p>
      * <p>Reset on release()</p>
+     * @deprecated
+     * @hide
      */
-    @PublicKey
+    @Deprecated
     public static final Key<Integer> REQUEST_FRAME_COUNT =
             new Key<Integer>("android.request.frameCount", int.class);
 
@@ -2209,18 +2221,18 @@
      * <p>The timestamps are also included in all image
      * buffers produced for the same capture, and will be identical
      * on all the outputs.</p>
-     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION android.sensor.info.timestampCalibration} <code>==</code> UNCALIBRATED,
+     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE android.sensor.info.timestampSource} <code>==</code> UNKNOWN,
      * the timestamps measure time since an unspecified starting point,
      * and are monotonically increasing. They can be compared with the
      * timestamps for other captures from the same camera device, but are
      * not guaranteed to be comparable to any other time source.</p>
-     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION android.sensor.info.timestampCalibration} <code>==</code> CALIBRATED,
+     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE android.sensor.info.timestampSource} <code>==</code> REALTIME,
      * the timestamps measure time in the same timebase as
      * android.os.SystemClock#elapsedRealtimeNanos(), and they can be
      * compared to other timestamps from other subsystems that are using
      * that base.</p>
      *
-     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
      */
     @PublicKey
     public static final Key<Long> SENSOR_TIMESTAMP =
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index 226f09d..ec4bc7d 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 
 import java.util.Collections;
 import java.util.List;
@@ -51,8 +52,9 @@
      * Takes ownership of the passed-in properties object
      * @hide
      */
-    public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent, int sequenceId) {
-        super(results, parent, sequenceId);
+    public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent,
+            CaptureResultExtras extras) {
+        super(results, parent, extras);
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index ed4e457..18b1202 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -313,6 +313,7 @@
         return mCameraId;
     }
 
+    @Override
     public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
         // Treat a null input the same an empty list
         if (outputs == null) {
@@ -448,6 +449,7 @@
         }
     }
 
+    @Override
     public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
             throws CameraAccessException {
         if (DEBUG) {
@@ -458,6 +460,7 @@
         return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
     }
 
+    @Override
     public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
         if (requests == null || requests.isEmpty()) {
@@ -610,6 +613,7 @@
         }
     }
 
+    @Override
     public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
             Handler handler) throws CameraAccessException {
         List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
@@ -617,6 +621,7 @@
         return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
     }
 
+    @Override
     public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
         if (requests == null || requests.isEmpty()) {
@@ -625,6 +630,7 @@
         return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
     }
 
+    @Override
     public void stopRepeating() throws CameraAccessException {
 
         synchronized(mInterfaceLock) {
@@ -675,6 +681,7 @@
         }
     }
 
+    @Override
     public void flush() throws CameraAccessException {
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
@@ -1031,8 +1038,10 @@
                 CaptureResultExtras resultExtras) throws RemoteException {
 
             int requestId = resultExtras.getRequestId();
+            long frameNumber = resultExtras.getFrameNumber();
+
             if (DEBUG) {
-                Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
+                Log.v(TAG, "Received result frame " + frameNumber + " for id "
                         + requestId);
             }
 
@@ -1051,7 +1060,7 @@
 
                 // Update tracker (increment counter) when it's not a partial result.
                 if (!isPartialResult) {
-                    mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(),
+                    mFrameNumberTracker.updateTracker(frameNumber,
                             /*error*/false);
                 }
 
@@ -1060,7 +1069,7 @@
                     if (DEBUG) {
                         Log.d(TAG,
                                 "holder is null, early return at frame "
-                                        + resultExtras.getFrameNumber());
+                                        + frameNumber);
                     }
                     return;
                 }
@@ -1069,7 +1078,7 @@
                     if (DEBUG) {
                         Log.d(TAG,
                                 "camera is closed, early return at frame "
-                                        + resultExtras.getFrameNumber());
+                                        + frameNumber);
                     }
                     return;
                 }
@@ -1082,7 +1091,7 @@
                 // Either send a partial result or the final capture completed result
                 if (isPartialResult) {
                     final CaptureResult resultAsCapture =
-                            new CaptureResult(result, request, requestId);
+                            new CaptureResult(result, request, resultExtras);
 
                     // Partial result
                     resultDispatch = new Runnable() {
@@ -1098,7 +1107,7 @@
                     };
                 } else {
                     final TotalCaptureResult resultAsCapture =
-                            new TotalCaptureResult(result, request, requestId);
+                            new TotalCaptureResult(result, request, resultExtras);
 
                     // Final capture result
                     resultDispatch = new Runnable() {
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
index ab31d8c..af58a8a 100644
--- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java
+++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
@@ -15,11 +15,12 @@
  */
 package android.hardware.camera2.legacy;
 
-import android.hardware.camera2.impl.CameraMetadataNative;
 import android.util.Log;
+import android.util.MutableLong;
 import android.util.Pair;
 
 import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
@@ -77,7 +78,7 @@
                 if (needsPreview && isPreviewCompleted()) {
                     CaptureCollector.this.onPreviewCompleted();
                 }
-                CaptureCollector.this.onRequestCompleted(mRequest, mLegacy, mTimestamp);
+                CaptureCollector.this.onRequestCompleted(this);
             }
         }
 
@@ -176,13 +177,13 @@
     private final ArrayDeque<CaptureHolder> mJpegProduceQueue;
     private final ArrayDeque<CaptureHolder> mPreviewCaptureQueue;
     private final ArrayDeque<CaptureHolder> mPreviewProduceQueue;
+    private final ArrayList<CaptureHolder> mCompletedRequests = new ArrayList<>();
 
     private final ReentrantLock mLock = new ReentrantLock();
     private final Condition mIsEmpty;
     private final Condition mPreviewsEmpty;
     private final Condition mNotFull;
     private final CameraDeviceState mDeviceState;
-    private final LegacyResultMapper mMapper = new LegacyResultMapper();
     private int mInFlight = 0;
     private int mInFlightPreviews = 0;
     private final int mMaxInFlight;
@@ -320,6 +321,54 @@
     }
 
     /**
+     * Wait for the specified request to be completed (all buffers available).
+     *
+     * <p>May not wait for the same request more than once, since a successful wait
+     * will erase the history of that request.</p>
+     *
+     * @param holder the {@link RequestHolder} for this request.
+     * @param timeout a timeout to use for this call.
+     * @param unit the units to use for the timeout.
+     * @param timestamp the timestamp of the request will be written out to here, in ns
+     *
+     * @return {@code false} if this method timed out.
+     *
+     * @throws InterruptedException if this thread is interrupted.
+     */
+    public boolean waitForRequestCompleted(RequestHolder holder, long timeout, TimeUnit unit,
+            MutableLong timestamp)
+            throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.mLock;
+        lock.lock();
+        try {
+            while (!removeRequestIfCompleted(holder, /*out*/timestamp)) {
+                if (nanos <= 0) {
+                    return false;
+                }
+                nanos = mNotFull.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    private boolean removeRequestIfCompleted(RequestHolder holder, MutableLong timestamp) {
+        int i = 0;
+        for (CaptureHolder h : mCompletedRequests) {
+            if (h.mRequest.equals(holder)) {
+                timestamp.value = h.mTimestamp;
+                mCompletedRequests.remove(i);
+                return true;
+            }
+            i++;
+        }
+
+        return false;
+    }
+
+    /**
      * Called to alert the {@link CaptureCollector} that the jpeg capture has begun.
      *
      * @param timestamp the time of the jpeg capture.
@@ -431,8 +480,9 @@
         }
     }
 
-    private void onRequestCompleted(RequestHolder request, LegacyRequest legacyHolder,
-                                    long timestamp) {
+    private void onRequestCompleted(CaptureHolder capture) {
+        RequestHolder request = capture.mRequest;
+
         mInFlight--;
         if (DEBUG) {
             Log.d(TAG, "Completed request " + request.getRequestId() +
@@ -442,12 +492,12 @@
             throw new IllegalStateException(
                     "More captures completed than requests queued.");
         }
+
+        mCompletedRequests.add(capture);
+
         mNotFull.signalAll();
         if (mInFlight == 0) {
             mIsEmpty.signalAll();
         }
-        CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
-                legacyHolder, timestamp);
-        mDeviceState.setCaptureResult(request, result);
     }
 }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
new file mode 100644
index 0000000..e576b43
--- /dev/null
+++ b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.legacy;
+
+import android.hardware.Camera;
+import android.hardware.Camera.Parameters;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.utils.ParamsUtils;
+import android.util.Log;
+
+import java.util.Objects;
+
+import static android.hardware.camera2.CaptureRequest.*;
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Map capture request data into legacy focus state transitions.
+ *
+ * <p>This object will asynchronously process auto-focus changes, so no interaction
+ * with it is necessary beyond reading the current state and updating with the latest trigger.</p>
+ */
+@SuppressWarnings("deprecation")
+public class LegacyFocusStateMapper {
+    private static String TAG = "LegacyFocusStateMapper";
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+    private final Camera mCamera;
+
+    private int mAfStatePrevious = CONTROL_AF_STATE_INACTIVE;
+    private String mAfModePrevious = null;
+
+    /** Guard mAfRun and mAfState */
+    private final Object mLock = new Object();
+    /** Guard access with mLock */
+    private int mAfRun = 0;
+    /** Guard access with mLock */
+    private int mAfState = CONTROL_AF_STATE_INACTIVE;
+
+    /**
+     * Instantiate a new focus state mapper.
+     *
+     * @param camera a non-{@code null} camera1 device
+     *
+     * @throws NullPointerException if any of the args were {@code null}
+     */
+    public LegacyFocusStateMapper(Camera camera) {
+        mCamera = checkNotNull(camera, "camera must not be null");
+    }
+
+    /**
+     * Process the AF triggers from the request as a camera1 autofocus routine.
+     *
+     * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped}
+     * with the request.</p>
+     *
+     * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers}
+     * will have the latest AF state as reflected by the camera1 callbacks.</p>
+     *
+     * <p>None of the arguments will be mutated.</p>
+     *
+     * @param captureRequest a non-{@code null} request
+     * @param parameters a non-{@code null} parameters corresponding to this request (read-only)
+     */
+    public void processRequestTriggers(CaptureRequest captureRequest,
+            Camera.Parameters parameters) {
+        checkNotNull(captureRequest, "captureRequest must not be null");
+
+        /*
+         * control.afTrigger
+         */
+        int afTrigger = ParamsUtils.getOrDefault(captureRequest, CONTROL_AF_TRIGGER,
+                CONTROL_AF_TRIGGER_IDLE);
+
+        final String afMode = parameters.getFocusMode();
+
+        if (!Objects.equals(mAfModePrevious, afMode)) {
+            if (VERBOSE) {
+                Log.v(TAG, "processRequestTriggers - AF mode switched from " + mAfModePrevious +
+                        " to " + afMode);
+            }
+
+            // Switching modes always goes back to INACTIVE; ignore callbacks from previous modes
+
+            synchronized (mLock) {
+                ++mAfRun;
+                mAfState = CONTROL_AF_STATE_INACTIVE;
+            }
+            mCamera.cancelAutoFocus();
+        }
+
+        mAfModePrevious = afMode;
+
+        // Passive AF Scanning
+        {
+            final int currentAfRun;
+
+            synchronized (mLock) {
+                currentAfRun = mAfRun;
+            }
+
+            mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
+                @Override
+                public void onAutoFocusMoving(boolean start, Camera camera) {
+                    synchronized (mLock) {
+                        int latestAfRun = mAfRun;
+
+                        if (VERBOSE) {
+                            Log.v(TAG, "onAutoFocusMoving - start " + start + " latest AF run " +
+                                    latestAfRun + ", last AF run " + currentAfRun);
+                        }
+
+                        if (currentAfRun != latestAfRun) {
+                            Log.d(TAG,
+                                    "onAutoFocusMoving - ignoring move callbacks from old af run"
+                                            + currentAfRun);
+                            return;
+                        }
+
+                        int newAfState = start ?
+                                CONTROL_AF_STATE_PASSIVE_SCAN :
+                                CONTROL_AF_STATE_PASSIVE_FOCUSED;
+                        // We never send CONTROL_AF_STATE_PASSIVE_UNFOCUSED
+
+                        switch (afMode) {
+                            case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+                            case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+                                break;
+                            // This callback should never be sent in any other AF mode
+                            default:
+                                Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
+                                        + afMode);
+
+                        }
+
+                        mAfState = newAfState;
+                    }
+                }
+            });
+        }
+
+        // AF Locking
+        switch (afTrigger) {
+            case CONTROL_AF_TRIGGER_START:
+
+                int afStateAfterStart;
+                switch (afMode) {
+                    case Parameters.FOCUS_MODE_AUTO:
+                    case Parameters.FOCUS_MODE_MACRO:
+                        afStateAfterStart = CONTROL_AF_STATE_ACTIVE_SCAN;
+                        break;
+                    case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+                    case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+                        afStateAfterStart = CONTROL_AF_STATE_PASSIVE_SCAN;
+                    default:
+                        // EDOF, INFINITY
+                        afStateAfterStart = CONTROL_AF_STATE_INACTIVE;
+                }
+
+                final int currentAfRun;
+                synchronized (mLock) {
+                    currentAfRun = ++mAfRun;
+                    mAfState = afStateAfterStart;
+                }
+
+                if (VERBOSE) {
+                    Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_START, " +
+                            "new AF run is " + currentAfRun);
+                }
+
+                mCamera.autoFocus(new Camera.AutoFocusCallback() {
+                    @Override
+                    public void onAutoFocus(boolean success, Camera camera) {
+                        synchronized (mLock) {
+                            int latestAfRun = mAfRun;
+
+                            if (VERBOSE) {
+                                Log.v(TAG, "onAutoFocus - success " + success + " latest AF run " +
+                                        latestAfRun + ", last AF run " + currentAfRun);
+                            }
+
+                            // Ignore old auto-focus results, since another trigger was requested
+                            if (latestAfRun != currentAfRun) {
+                                Log.d(TAG, String.format("onAutoFocus - ignoring AF callback " +
+                                        "(old run %d, new run %d)", currentAfRun, latestAfRun));
+
+                                return;
+                            }
+
+                            int newAfState = success ?
+                                    CONTROL_AF_STATE_FOCUSED_LOCKED :
+                                    CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
+
+                            switch (afMode) {
+                                case Parameters.FOCUS_MODE_AUTO:
+                                case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+                                case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+                                case Parameters.FOCUS_MODE_MACRO:
+                                    break;
+                                // This callback should never be sent in any other AF mode
+                                default:
+                                    Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
+                                            + afMode);
+
+                            }
+
+                            mAfState = newAfState;
+                        }
+                    }
+                });
+
+                break;
+            case CONTROL_AF_TRIGGER_CANCEL:
+                synchronized (mLock) {
+                    int updatedAfRun;
+
+                    synchronized (mLock) {
+                        updatedAfRun = ++mAfRun;
+                        mAfState = CONTROL_AF_STATE_INACTIVE;
+                    }
+
+                    mCamera.cancelAutoFocus();
+
+                    if (VERBOSE) {
+                        Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_CANCEL, " +
+                                "new AF run is " + updatedAfRun);
+                    }
+                }
+
+                break;
+            case CONTROL_AF_TRIGGER_IDLE:
+                // No action necessary. The callbacks will handle transitions.
+                break;
+            default:
+                Log.w(TAG, "mapTriggers - ignoring unknown control.afTrigger = " + afTrigger);
+        }
+    }
+
+    /**
+     * Update the {@code result} camera metadata map with the new value for the
+     * {@code control.afState}.
+     *
+     * <p>AF callbacks are processed in the background, and each call to {@link #mapResultTriggers}
+     * will have the latest AF state as reflected by the camera1 callbacks.</p>
+     *
+     * @param result a non-{@code null} result
+     */
+    public void mapResultTriggers(CameraMetadataNative result) {
+        checkNotNull(result, "result must not be null");
+
+        int newAfState;
+        synchronized (mLock) {
+            newAfState = mAfState;
+        }
+
+        if (VERBOSE && newAfState != mAfStatePrevious) {
+            Log.v(TAG, String.format("mapResultTriggers - afState changed from %s to %s",
+                    afStateToString(mAfStatePrevious), afStateToString(newAfState)));
+        }
+
+        result.set(CaptureResult.CONTROL_AF_STATE, newAfState);
+
+        mAfStatePrevious = newAfState;
+    }
+
+    private static String afStateToString(int afState) {
+        switch (afState) {
+            case CONTROL_AF_STATE_ACTIVE_SCAN:
+                return "ACTIVE_SCAN";
+            case CONTROL_AF_STATE_FOCUSED_LOCKED:
+                return "FOCUSED_LOCKED";
+            case CONTROL_AF_STATE_INACTIVE:
+                return "INACTIVE";
+            case CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
+                return "NOT_FOCUSED_LOCKED";
+            case CONTROL_AF_STATE_PASSIVE_FOCUSED:
+                return "PASSIVE_FOCUSED";
+            case CONTROL_AF_STATE_PASSIVE_SCAN:
+                return "PASSIVE_SCAN";
+            case CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
+                return "PASSIVE_UNFOCUSED";
+            default :
+                return "UNKNOWN(" + afState + ")";
+        }
+    }
+}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 157c159..633bada 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -48,6 +48,7 @@
  * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the
  * camera characteristics.
  */
+@SuppressWarnings("deprecation")
 public class LegacyMetadataMapper {
     private static final String TAG = "LegacyMetadataMapper";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -87,8 +88,8 @@
      */
     static final boolean LIE_ABOUT_AE_STATE = false;
     static final boolean LIE_ABOUT_AE_MAX_REGIONS = false;
-    static final boolean LIE_ABOUT_AF = true;
-    static final boolean LIE_ABOUT_AF_MAX_REGIONS = true;
+    static final boolean LIE_ABOUT_AF = false;
+    static final boolean LIE_ABOUT_AF_MAX_REGIONS = false;
     static final boolean LIE_ABOUT_AWB_STATE = false;
     static final boolean LIE_ABOUT_AWB = true;
 
@@ -162,6 +163,10 @@
          */
         mapControlAe(m, p);
         /*
+         * control.af*
+         */
+        mapControlAf(m, p);
+        /*
          * control.awb*
          */
         mapControlAwb(m, p);
@@ -379,6 +384,54 @@
         }
     }
 
+
+    @SuppressWarnings({"unchecked"})
+    private static void mapControlAf(CameraMetadataNative m, Camera.Parameters p) {
+        /*
+         * control.afAvailableModes
+         */
+        {
+            List<String> focusModes = p.getSupportedFocusModes();
+
+            String[] focusModeStrings = new String[] {
+                    Camera.Parameters.FOCUS_MODE_AUTO,
+                    Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
+                    Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
+                    Camera.Parameters.FOCUS_MODE_EDOF,
+                    Camera.Parameters.FOCUS_MODE_INFINITY,
+                    Camera.Parameters.FOCUS_MODE_MACRO,
+                    Camera.Parameters.FOCUS_MODE_FIXED,
+            };
+
+            int[] focusModeInts = new int[] {
+                    CONTROL_AF_MODE_AUTO,
+                    CONTROL_AF_MODE_CONTINUOUS_PICTURE,
+                    CONTROL_AF_MODE_CONTINUOUS_VIDEO,
+                    CONTROL_AF_MODE_EDOF,
+                    CONTROL_AF_MODE_OFF,
+                    CONTROL_AF_MODE_MACRO,
+                    CONTROL_AF_MODE_OFF
+            };
+
+            List<Integer> afAvail = ArrayUtils.convertStringListToIntList(
+                    focusModes, focusModeStrings, focusModeInts);
+
+            // No AF modes supported? That's unpossible!
+            if (afAvail == null || afAvail.size() == 0) {
+                Log.w(TAG, "No AF modes supported (HAL bug); defaulting to AF_MODE_OFF only");
+                afAvail = new ArrayList<Integer>(/*capacity*/1);
+                afAvail.add(CONTROL_AF_MODE_OFF);
+            }
+
+            m.set(CONTROL_AF_AVAILABLE_MODES, ArrayUtils.toIntArray(afAvail));
+
+            if (VERBOSE) {
+                Log.v(TAG, "mapControlAf - control.afAvailableModes set to " +
+                        ListUtils.listToString(afAvail));
+            }
+        }
+    }
+
     private static void mapControlAwb(CameraMetadataNative m, Camera.Parameters p) {
         if (!LIE_ABOUT_AWB) {
             throw new AssertionError("Not implemented yet");
@@ -548,7 +601,6 @@
                     CaptureResult.JPEG_QUALITY                                     ,
                     CaptureResult.JPEG_THUMBNAIL_QUALITY                           ,
                     CaptureResult.LENS_FOCAL_LENGTH                                ,
-                    CaptureResult.REQUEST_FRAME_COUNT                              ,
                     CaptureResult.REQUEST_PIPELINE_DEPTH                           ,
                     CaptureResult.SCALER_CROP_REGION                               ,
                     CaptureResult.SENSOR_TIMESTAMP                                 ,
@@ -794,4 +846,55 @@
 
         return tags;
     }
+
+    /**
+     * Convert the requested AF mode into its equivalent supported parameter.
+     *
+     * @param mode {@code CONTROL_AF_MODE}
+     * @param supportedFocusModes list of camera1's supported focus modes
+     * @return the stringified af mode, or {@code null} if its not supported
+     */
+    static String convertAfModeToLegacy(int mode, List<String> supportedFocusModes) {
+        if (supportedFocusModes == null || supportedFocusModes.isEmpty()) {
+            Log.w(TAG, "No focus modes supported; API1 bug");
+            return null;
+        }
+
+        String param = null;
+        switch (mode) {
+            case CONTROL_AF_MODE_AUTO:
+                param = Parameters.FOCUS_MODE_AUTO;
+                break;
+            case CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+                param = Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
+                break;
+            case CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+                param = Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
+                break;
+            case CONTROL_AF_MODE_EDOF:
+                param = Parameters.FOCUS_MODE_EDOF;
+                break;
+            case CONTROL_AF_MODE_MACRO:
+                param = Parameters.FOCUS_MODE_MACRO;
+                break;
+            case CONTROL_AF_MODE_OFF:
+                if (supportedFocusModes.contains(Parameters.FOCUS_MODE_FIXED)) {
+                    param = Parameters.FOCUS_MODE_FIXED;
+                } else {
+                    param = Parameters.FOCUS_MODE_INFINITY;
+                }
+        }
+
+        if (!supportedFocusModes.contains(param)) {
+            // Weed out bad user input by setting to the first arbitrary focus mode
+            String defaultMode = supportedFocusModes.get(0);
+            Log.w(TAG,
+                    String.format(
+                            "convertAfModeToLegacy - ignoring unsupported mode %d, " +
+                            "defaulting to %s", mode, defaultMode));
+            param = defaultMode;
+        }
+
+        return param;
+    }
 }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index 4a9afa6..fbfc39f 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -23,6 +23,7 @@
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.utils.ListUtils;
+import android.hardware.camera2.utils.ParamsUtils;
 import android.util.Log;
 import android.util.Range;
 import android.util.Size;
@@ -38,6 +39,7 @@
 /**
  * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.
  */
+@SuppressWarnings("deprecation")
 public class LegacyRequestMapper {
     private static final String TAG = "LegacyRequestMapper";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -158,7 +160,7 @@
         {
             Range<Integer> compensationRange =
                     characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
-            int compensation = getOrDefault(request,
+            int compensation = ParamsUtils.getOrDefault(request,
                     CONTROL_AE_EXPOSURE_COMPENSATION,
                     /*defaultValue*/0);
 
@@ -192,6 +194,23 @@
         // control.aeMode, flash.mode
         mapAeAndFlashMode(request, /*out*/params);
 
+        // control.afMode
+        {
+            int afMode = ParamsUtils.getOrDefault(request, CONTROL_AF_MODE,
+                    /*defaultValue*/CONTROL_AF_MODE_OFF);
+            String focusMode = LegacyMetadataMapper.convertAfModeToLegacy(afMode,
+                    params.getSupportedFocusModes());
+
+            if (focusMode != null) {
+                params.setFocusMode(focusMode);
+            }
+
+            if (VERBOSE) {
+                Log.v(TAG, "convertRequestToMetadata - control.afMode "
+                        + afMode + " mapped to " + focusMode);
+            }
+        }
+
         // control.awbLock
         {
             Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false,
@@ -204,6 +223,21 @@
 
          // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
         }
+
+        // lens.focusDistance
+        {
+            boolean infinityFocusSupported =
+                    ListUtils.listContains(params.getSupportedFocusModes(),
+                            Parameters.FOCUS_MODE_INFINITY);
+            Float focusDistance = getIfSupported(request, LENS_FOCUS_DISTANCE,
+                    /*defaultValue*/0f, infinityFocusSupported, /*allowedValue*/0f);
+
+            if (focusDistance == null || focusDistance != 0f) {
+                Log.w(TAG,
+                        "convertRequestToMetadata - Ignoring android.lens.focusDistance "
+                                + infinityFocusSupported + ", only 0.0f is supported");
+            }
+        }
     }
 
     private static List<Camera.Area> convertMeteringRegionsToLegacy(
@@ -253,8 +287,8 @@
     }
 
     private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) {
-        int flashMode = getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
-        int aeMode = getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
+        int flashMode = ParamsUtils.getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
+        int aeMode = ParamsUtils.getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
 
         List<String> supportedFlashModes = p.getSupportedFlashModes();
 
@@ -355,20 +389,6 @@
         return legacyFps;
     }
 
-    /** Return the value set by the key, or the {@code defaultValue} if no value was set. */
-    private static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) {
-        checkNotNull(r, "r must not be null");
-        checkNotNull(key, "key must not be null");
-        checkNotNull(defaultValue, "defaultValue must not be null");
-
-        T value = r.get(key);
-        if (value == null) {
-            return defaultValue;
-        } else {
-            return value;
-        }
-    }
-
     /**
      * Return {@code null} if the value is not supported, otherwise return the retrieved key's
      * value from the request (or the default value if it wasn't set).
@@ -382,7 +402,7 @@
     private static <T> T getIfSupported(
             CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported,
             T allowedValue) {
-        T val = getOrDefault(r, key, defaultValue);
+        T val = ParamsUtils.getOrDefault(r, key, defaultValue);
 
         if (!isSupported) {
             if (!Objects.equals(val, allowedValue)) {
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index 88f95e1..07852b9 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -34,11 +34,13 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.android.internal.util.Preconditions.*;
 import static android.hardware.camera2.CaptureResult.*;
 
 /**
  * Provide legacy-specific implementations of camera2 CaptureResult for legacy devices.
  */
+@SuppressWarnings("deprecation")
 public class LegacyResultMapper {
     private static final String TAG = "LegacyResultMapper";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -60,17 +62,43 @@
      */
     public CameraMetadataNative cachedConvertResultMetadata(
             LegacyRequest legacyRequest, long timestamp) {
-        if (mCachedRequest != null && legacyRequest.parameters.same(mCachedRequest.parameters)) {
-            CameraMetadataNative newResult = new CameraMetadataNative(mCachedResult);
+        CameraMetadataNative result;
+        boolean cached;
 
-            // sensor.timestamp
-            newResult.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
-            return newResult;
+        /*
+         * Attempt to look up the result from the cache if the parameters haven't changed
+         */
+        if (mCachedRequest != null && legacyRequest.parameters.same(mCachedRequest.parameters)) {
+            result = new CameraMetadataNative(mCachedResult);
+            cached = true;
+        } else {
+            result = convertResultMetadata(legacyRequest, timestamp);
+            cached = false;
+
+            // Always cache a *copy* of the metadata result,
+            // since api2's client side takes ownership of it after it receives a result
+            mCachedRequest = legacyRequest;
+            mCachedResult = new CameraMetadataNative(result);
         }
 
-        mCachedRequest = legacyRequest;
-        mCachedResult = convertResultMetadata(mCachedRequest, timestamp);
-        return mCachedResult;
+        /*
+         * Unconditionally set fields that change in every single frame
+         */
+        {
+            // sensor.timestamp
+            result.set(SENSOR_TIMESTAMP, timestamp);
+        }
+
+        if (VERBOSE) {
+            Log.v(TAG, "cachedConvertResultMetadata - cached? " + cached +
+                    " timestamp = " + timestamp);
+
+            Log.v(TAG, "----- beginning of result dump ------");
+            result.dumpToLog();
+            Log.v(TAG, "----- end of result dump ------");
+        }
+
+        return result;
     }
 
     /**
@@ -81,7 +109,7 @@
      *
      * @return a {@link CameraMetadataNative} object containing result metadata.
      */
-    public static CameraMetadataNative convertResultMetadata(LegacyRequest legacyRequest,
+    private static CameraMetadataNative convertResultMetadata(LegacyRequest legacyRequest,
                                                       long timestamp) {
         CameraCharacteristics characteristics = legacyRequest.characteristics;
         CaptureRequest request = legacyRequest.captureRequest;
@@ -98,17 +126,15 @@
         /*
          * control
          */
-        // control.afState
-        if (LegacyMetadataMapper.LIE_ABOUT_AF) {
-            // TODO: Implement autofocus state machine
-            result.set(CaptureResult.CONTROL_AF_MODE, request.get(CaptureRequest.CONTROL_AF_MODE));
-        }
 
         /*
          * control.ae*
          */
         mapAe(result, characteristics, request, activeArraySize, zoomData, /*out*/params);
 
+        // control.afMode
+        result.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(params.getFocusMode()));
+
         // control.awbLock
         result.set(CaptureResult.CONTROL_AWB_LOCK, params.getAutoWhiteBalanceLock());
 
@@ -137,10 +163,24 @@
         /*
          * lens
          */
+        // lens.focusDistance
+        {
+            if (Parameters.FOCUS_MODE_INFINITY.equals(params.getFocusMode())) {
+                result.set(CaptureResult.LENS_FOCUS_DISTANCE, 0.0f);
+            }
+        }
+
         // lens.focalLength
         result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength());
 
         /*
+         * request
+         */
+        // request.pipelineDepth
+        result.set(REQUEST_PIPELINE_DEPTH,
+                characteristics.get(CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH));
+
+        /*
          * scaler
          */
         mapScaler(result, zoomData, /*out*/params);
@@ -148,8 +188,6 @@
         /*
          * sensor
          */
-        // sensor.timestamp
-        result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
 
         // TODO: Remaining result metadata tags conversions.
         return result;
@@ -301,6 +339,33 @@
         m.set(CONTROL_AE_MODE, aeMode);
     }
 
+    private static int convertLegacyAfMode(String mode) {
+        if (mode == null) {
+            Log.w(TAG, "convertLegacyAfMode - no AF mode, default to OFF");
+            return CONTROL_AF_MODE_OFF;
+        }
+
+        switch (mode) {
+            case Parameters.FOCUS_MODE_AUTO:
+                return CONTROL_AF_MODE_AUTO;
+            case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+                return CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+            case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+                return CONTROL_AF_MODE_CONTINUOUS_VIDEO;
+            case Parameters.FOCUS_MODE_EDOF:
+                return CONTROL_AF_MODE_EDOF;
+            case Parameters.FOCUS_MODE_MACRO:
+                return CONTROL_AF_MODE_MACRO;
+            case Parameters.FOCUS_MODE_FIXED:
+                return CONTROL_AF_MODE_OFF;
+            case Parameters.FOCUS_MODE_INFINITY:
+                return CONTROL_AF_MODE_OFF;
+            default:
+                Log.w(TAG, "convertLegacyAfMode - unknown mode " + mode + " , ignoring");
+                return CONTROL_AF_MODE_OFF;
+        }
+    }
+
     /** Map results for scaler.* */
     private static void mapScaler(CameraMetadataNative m,
             ZoomData zoomData,
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 066b416..c556c32 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -28,6 +28,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.util.Log;
+import android.util.MutableLong;
 import android.util.Pair;
 import android.util.Size;
 import android.view.Surface;
@@ -65,6 +66,7 @@
 
     private final CameraDeviceState mDeviceState;
     private final CaptureCollector mCaptureCollector;
+    private final LegacyFocusStateMapper mFocusStateMapper;
 
     private static final int MSG_CONFIGURE_OUTPUTS = 1;
     private static final int MSG_SUBMIT_CAPTURE_REQUEST = 2;
@@ -74,6 +76,7 @@
 
     private static final int PREVIEW_FRAME_TIMEOUT = 300; // ms
     private static final int JPEG_FRAME_TIMEOUT = 3000; // ms (same as CTS for API2)
+    private static final int REQUEST_COMPLETE_TIMEOUT = 3000; // ms (same as JPEG timeout)
 
     private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
     private boolean mPreviewRunning = false;
@@ -510,7 +513,7 @@
 
     private final Handler.Callback mRequestHandlerCb = new Handler.Callback() {
         private boolean mCleanup = false;
-        private LegacyResultMapper mMapper = new LegacyResultMapper();
+        private final LegacyResultMapper mMapper = new LegacyResultMapper();
 
         @Override
         public boolean handleMessage(Message msg) {
@@ -586,6 +589,8 @@
                         CaptureRequest request = holder.getRequest();
 
                         boolean paramsChanged = false;
+
+                        // Lazily process the rest of the request
                         if (mLastRequest == null || mLastRequest.captureRequest != request) {
 
                             // The intermediate buffer is sometimes null, but we always need
@@ -608,6 +613,10 @@
                             }
                         }
 
+                        // Unconditionally process AF triggers, since they're non-idempotent
+                        // - must be done after setting the most-up-to-date AF mode
+                        mFocusStateMapper.processRequestTriggers(request, mParams);
+
                         try {
                             boolean success = mCaptureCollector.queueRequest(holder,
                                     mLastRequest, JPEG_FRAME_TIMEOUT, TimeUnit.MILLISECONDS);
@@ -649,6 +658,27 @@
                             // Update parameters to the latest that we think the camera is using
                             mLastRequest.setParameters(mParams);
                         }
+
+                        MutableLong timestampMutable = new MutableLong(/*value*/0L);
+                        try {
+                            boolean success = mCaptureCollector.waitForRequestCompleted(holder,
+                                    REQUEST_COMPLETE_TIMEOUT, TimeUnit.MILLISECONDS,
+                                    /*out*/timestampMutable);
+
+                            if (!success) {
+                                Log.e(TAG, "Timed out while waiting for request to complete.");
+                            }
+                        } catch (InterruptedException e) {
+                         // TODO: report error to CameraDevice
+                            Log.e(TAG, "Interrupted during request completition.", e);
+                        }
+
+                        CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
+                                mLastRequest, timestampMutable.value);
+                        // Update AF state
+                        mFocusStateMapper.mapResultTriggers(result);
+
+                        mDeviceState.setCaptureResult(holder, result);
                     }
                     if (DEBUG) {
                         long totalTime = SystemClock.elapsedRealtimeNanos() - startTime;
@@ -700,6 +730,7 @@
         String name = String.format("RequestThread-%d", cameraId);
         TAG = name;
         mDeviceState = checkNotNull(deviceState, "deviceState must not be null");
+        mFocusStateMapper = new LegacyFocusStateMapper(mCamera);
         mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState);
         mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb);
     }
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index c31f59e..1efabb1 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -67,11 +67,6 @@
     private static final String TAG = "StreamConfigurationMap";
 
     /**
-     * Indicates that a minimum frame duration is not available for a particular configuration.
-     */
-    public static final long NO_MIN_FRAME_DURATION = 0;
-
-    /**
      * Create a new {@link StreamConfigurationMap}.
      *
      * <p>The array parameters ownership is passed to this object after creation; do not
@@ -536,7 +531,7 @@
      *
      * <p>For devices that do not support manual sensor control
      * ({@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR}),
-     * this function may return {@link #NO_MIN_FRAME_DURATION}.</p>
+     * this function may return 0.</p>
      *
      * <!--
      * TODO: uncomment after adding input stream support
@@ -547,7 +542,7 @@
      * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
      * @param size an output-compatible size
      * @return a minimum frame duration {@code >} 0 in nanoseconds, or
-     *          {@link #NO_MIN_FRAME_DURATION} if the minimum frame duration is not available.
+     *          0 if the minimum frame duration is not available.
      *
      * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
      * @throws NullPointerException if {@code size} was {@code null}
@@ -586,7 +581,7 @@
      *
      * <p>For devices that do not support manual sensor control
      * ({@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR}),
-     * this function may return {@link #NO_MIN_FRAME_DURATION}.</p>
+     * this function may return 0.</p>
      *
      * <!--
      * TODO: uncomment after adding input stream support
@@ -599,7 +594,7 @@
      *          non-empty array returned by {@link #getOutputSizes(Class)}
      * @param size an output-compatible size
      * @return a minimum frame duration {@code >} 0 in nanoseconds, or
-     *          {@link #NO_MIN_FRAME_DURATION} if the minimum frame duration is not available.
+     *          0 if the minimum frame duration is not available.
      *
      * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
      * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
@@ -1065,8 +1060,8 @@
                 return configurationDuration.getDuration();
             }
         }
-
-        return getDurationDefault(duration);
+        // Default duration is '0' (unsupported/no extra stall)
+        return 0;
     }
 
     /**
@@ -1086,17 +1081,6 @@
         }
     }
 
-    private long getDurationDefault(int duration) {
-        switch (duration) {
-            case DURATION_MIN_FRAME:
-                return NO_MIN_FRAME_DURATION;
-            case DURATION_STALL:
-                return 0L; // OK. A lack of a stall duration implies a 0 stall duration
-            default:
-                throw new IllegalArgumentException("duration was invalid");
-        }
-    }
-
     /** Count the number of publicly-visible output formats */
     private int getPublicFormatCount(boolean output) {
         HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
diff --git a/core/java/android/hardware/camera2/utils/ArrayUtils.java b/core/java/android/hardware/camera2/utils/ArrayUtils.java
index c5a56cd..24c85d0 100644
--- a/core/java/android/hardware/camera2/utils/ArrayUtils.java
+++ b/core/java/android/hardware/camera2/utils/ArrayUtils.java
@@ -67,6 +67,36 @@
             return null;
         }
 
+        List<Integer> convertedList = convertStringListToIntList(list, convertFrom, convertTo);
+
+        int[] returnArray = new int[convertedList.size()];
+        for (int i = 0; i < returnArray.length; ++i) {
+            returnArray[i] = convertedList.get(i);
+        }
+
+        return returnArray;
+    }
+
+    /**
+     * Create an {@code List<Integer>} from the {@code List<>} by using {@code convertFrom} and
+     * {@code convertTo} as a one-to-one map (via the index).
+     *
+     * <p>Strings not appearing in {@code convertFrom} are ignored (with a logged warning);
+     * strings appearing in {@code convertFrom} but not {@code convertTo} are silently
+     * dropped.</p>
+     *
+     * @param list Source list of strings
+     * @param convertFrom Conversion list of strings
+     * @param convertTo Conversion list of ints
+     * @return A list of ints where the values correspond to the ones in {@code convertTo}
+     *         or {@code null} if {@code list} was {@code null}
+     */
+    public static List<Integer> convertStringListToIntList(
+            List<String> list, String[] convertFrom, int[] convertTo) {
+        if (list == null) {
+            return null;
+        }
+
         List<Integer> convertedList = new ArrayList<>(list.size());
 
         for (String str : list) {
@@ -84,12 +114,33 @@
             }
         }
 
-        int[] returnArray = new int[convertedList.size()];
-        for (int i = 0; i < returnArray.length; ++i) {
-            returnArray[i] = convertedList.get(i);
+        return convertedList;
+    }
+
+    /**
+     * Convert the list of integers in {@code list} to an {@code int} array.
+     *
+     * <p>Every element in {@code list} must be non-{@code null}.</p>
+     *
+     * @param list a list of non-{@code null} integers
+     *
+     * @return a new int array containing all the elements from {@code list}
+     *
+     * @throws NullPointerException if any of the elements in {@code list} were {@code null}
+     */
+    public static int[] toIntArray(List<Integer> list) {
+        if (list == null) {
+            return null;
         }
 
-        return returnArray;
+        int[] arr = new int[list.size()];
+        int i = 0;
+        for (int elem : list) {
+            arr[i] = elem;
+            i++;
+        }
+
+        return arr;
     }
 
     private ArrayUtils() {
diff --git a/core/java/android/hardware/camera2/utils/ParamsUtils.java b/core/java/android/hardware/camera2/utils/ParamsUtils.java
index 232a4f6..976fa2e 100644
--- a/core/java/android/hardware/camera2/utils/ParamsUtils.java
+++ b/core/java/android/hardware/camera2/utils/ParamsUtils.java
@@ -19,6 +19,7 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.hardware.camera2.CaptureRequest;
 import android.util.Rational;
 import android.util.Size;
 
@@ -175,6 +176,24 @@
         destination.top = source.top;
     }
 
+    /**
+     * Return the value set by the key, or the {@code defaultValue} if no value was set.
+     *
+     * @throws NullPointerException if any of the args were {@code null}
+     */
+    public static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) {
+        checkNotNull(r, "r must not be null");
+        checkNotNull(key, "key must not be null");
+        checkNotNull(defaultValue, "defaultValue must not be null");
+
+        T value = r.get(key);
+        if (value == null) {
+            return defaultValue;
+        } else {
+            return value;
+        }
+    }
+
     private ParamsUtils() {
         throw new AssertionError();
     }
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
index d663714..27829a7 100644
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
@@ -24,6 +24,8 @@
  * A class to encapsulate device information for HDMI-CEC. This container
  * include basic information such as logical address, physical address and
  * device type, and additional information like vendor id and osd name.
+ * Also used to keep the information of non-CEC devices for which only
+ * port ID, physical address are meaningful.
  *
  * @hide
  */
@@ -71,6 +73,7 @@
     private final int mDeviceType;
     private final int mVendorId;
     private final String mDisplayName;
+    private final boolean mIsCecDevice;
 
     /**
      * A helper class to deserialize {@link HdmiCecDeviceInfo} for a parcel.
@@ -96,7 +99,7 @@
             };
 
     /**
-     * Constructor.
+     * Constructor. Used to initialize the instance for CEC device.
      *
      * @param logicalAddress logical address of HDMI-CEC device
      * @param physicalAddress physical address of HDMI-CEC device
@@ -114,6 +117,24 @@
         mDeviceType = deviceType;
         mDisplayName = displayName;
         mVendorId = vendorId;
+        mIsCecDevice = true;
+    }
+
+    /**
+     * Constructor. Used to initialize the instance for non-CEC device.
+     *
+     * @param physicalAddress physical address of HDMI device
+     * @param portId HDMI port ID (1 for HDMI1)
+     * @hide
+     */
+    public HdmiCecDeviceInfo(int physicalAddress, int portId) {
+        mLogicalAddress = -1;
+        mPhysicalAddress = physicalAddress;
+        mPortId = portId;
+        mDeviceType = DEVICE_RESERVED;
+        mDisplayName = null;
+        mVendorId = 0;
+        mIsCecDevice = false;
     }
 
     /**
@@ -155,6 +176,14 @@
     }
 
     /**
+     * Return {@code true} if the device represents an HDMI-CEC device. {@code false}
+     * if the device is either MHL or non-CEC device.
+     */
+    public boolean isCecDevice() {
+        return mIsCecDevice;
+    }
+
+    /**
      * Return display (OSD) name of the device.
      */
     public String getDisplayName() {
@@ -199,12 +228,19 @@
     @Override
     public String toString() {
         StringBuffer s = new StringBuffer();
-        s.append("logical_address: ").append(mLogicalAddress).append(", ");
-        s.append("physical_address: ").append(mPhysicalAddress).append(", ");
-        s.append("port_id: ").append(mPortId).append(", ");
-        s.append("device_type: ").append(mDeviceType).append(", ");
-        s.append("vendor_id: ").append(mVendorId).append(", ");
-        s.append("display_name: ").append(mDisplayName);
+        if (isCecDevice()) {
+            s.append("CEC: ");
+            s.append("logical_address: ").append(mLogicalAddress).append(", ");
+            s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+            s.append("port_id: ").append(mPortId).append(", ");
+            s.append("device_type: ").append(mDeviceType).append(", ");
+            s.append("vendor_id: ").append(mVendorId).append(", ");
+            s.append("display_name: ").append(mDisplayName);
+        } else {
+            s.append("Non-CEC: ");
+            s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+            s.append("port_id: ").append(mPortId).append(", ");
+        }
         return s.toString();
     }
 
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 626bd2a..43869264 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -48,6 +48,12 @@
     boolean setActiveScorer(in String packageName);
 
     /**
+     * Disable the current active scorer and clear existing scores.
+     * @throws SecurityException if the caller is not the current scorer or the system.
+     */
+    void disableScoring();
+
+    /**
      * Register a network subsystem for scoring.
      *
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index b497c6e..9215853 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -205,6 +205,20 @@
     }
 
     /**
+     * Turn off network scoring.
+     *
+     * <p>May only be called by the current scorer app, or the system.
+     *
+     * @throws SecurityException if the caller is neither the active scorer nor the system.
+     */
+    public void disableScoring() throws SecurityException {
+        try {
+            mService.disableScoring();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Request scoring for networks.
      *
      * <p>Note that this is just a helper method to assemble the broadcast, and will run in the
@@ -222,6 +236,7 @@
         }
         Intent intent = new Intent(ACTION_SCORE_NETWORKS);
         intent.setPackage(activeScorer);
+        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         intent.putExtra(EXTRA_NETWORKS_TO_SCORE, networks);
         mContext.sendBroadcast(intent);
         return true;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a506c42..9935317 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -615,6 +615,12 @@
         if (guest != null) {
             Settings.Secure.putStringForUser(context.getContentResolver(),
                     Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+            try {
+                mService.setUserRestrictions(
+                        mService.getDefaultGuestRestrictions(), guest.id);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Could not update guest restrictions");
+            }
         }
         return guest;
     }
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 74bc186..c39ec97 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -19,7 +19,9 @@
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
 import android.content.ComponentCallbacks2;
+import android.content.Context;
 import android.content.res.Configuration;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -204,6 +206,14 @@
         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
         if (parentWindow != null) {
             parentWindow.adjustLayoutParamsForSubWindow(wparams);
+        } else {
+            // If there's no parent and we're running on L or above (or in the
+            // system context), assume we want hardware acceleration.
+            final Context context = view.getContext();
+            if (context != null
+                    && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) {
+                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+            }
         }
 
         ViewRootImpl root;
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
index 81f4baf..35da4bc 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
@@ -96,38 +96,56 @@
     @SmallTest
     public void testsetServiceDataFilter() {
         byte[] setServiceData = new byte[] {
-                0x0b, 0x11, 0x50, 0x64 };
+                0x50, 0x64 };
         ParcelUuid serviceDataUuid = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
         ScanFilter filter = mFilterBuilder.setServiceData(serviceDataUuid, setServiceData).build();
         assertTrue("service data filter fails", filter.matches(mScanResult));
 
-        byte[] nonMatchData = new byte[] {
-                0x0b, 0x01, 0x50, 0x64 };
-        filter = mFilterBuilder.setServiceData(serviceDataUuid, nonMatchData).build();
-        assertFalse("service data filter fails", filter.matches(mScanResult));
+        byte[] emptyData = new byte[0];
+        filter = mFilterBuilder.setServiceData(serviceDataUuid, emptyData).build();
+        assertTrue("service data filter fails", filter.matches(mScanResult));
 
+        byte[] prefixData = new byte[] {
+                0x50 };
+        filter = mFilterBuilder.setServiceData(serviceDataUuid, prefixData).build();
+        assertTrue("service data filter fails", filter.matches(mScanResult));
+
+        byte[] nonMatchData = new byte[] {
+                0x51, 0x64 };
         byte[] mask = new byte[] {
-                (byte) 0xFF, (byte) 0x00, (byte) 0xFF, (byte) 0xFF };
+                (byte) 0x00, (byte) 0xFF };
         filter = mFilterBuilder.setServiceData(serviceDataUuid, nonMatchData, mask).build();
         assertTrue("partial service data filter fails", filter.matches(mScanResult));
+
+        filter = mFilterBuilder.setServiceData(serviceDataUuid, nonMatchData).build();
+        assertFalse("service data filter fails", filter.matches(mScanResult));
     }
 
     @SmallTest
     public void testManufacturerSpecificData() {
         byte[] setManufacturerData = new byte[] {
-                (byte) 0xE0, 0x00, 0x02, 0x15 };
-        int manufacturerId = 224;
+                0x02, 0x15 };
+        int manufacturerId = 0xE0;
         ScanFilter filter =
                 mFilterBuilder.setManufacturerData(manufacturerId, setManufacturerData).build();
-        assertTrue("setManufacturerData filter fails", filter.matches(mScanResult));
+        assertTrue("manufacturer data filter fails", filter.matches(mScanResult));
 
+        byte[] emptyData = new byte[0];
+        filter = mFilterBuilder.setManufacturerData(manufacturerId, emptyData).build();
+        assertTrue("manufacturer data filter fails", filter.matches(mScanResult));
+
+        byte[] prefixData = new byte[] {
+                0x02 };
+        filter = mFilterBuilder.setManufacturerData(manufacturerId, prefixData).build();
+        assertTrue("manufacturer data filter fails", filter.matches(mScanResult));
+
+        // Test data mask
         byte[] nonMatchData = new byte[] {
-                (byte) 0xF0, 0x00, 0x02, 0x15 };
+                0x02, 0x14 };
         filter = mFilterBuilder.setManufacturerData(manufacturerId, nonMatchData).build();
-        assertFalse("setManufacturerData filter fails", filter.matches(mScanResult));
-
+        assertFalse("manufacturer data filter fails", filter.matches(mScanResult));
         byte[] mask = new byte[] {
-                (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+                (byte) 0xFF, (byte) 0x00
         };
         filter = mFilterBuilder.setManufacturerData(manufacturerId, nonMatchData, mask).build();
         assertTrue("partial setManufacturerData filter fails", filter.matches(mScanResult));
@@ -153,27 +171,33 @@
                 ParcelUuid.fromString("FFFFFFF0-FFFF-FFFF-FFFF-FFFFFFFFFFFF")).build();
         testReadWriteParcelForFilter(filter);
 
-        byte[] setServiceData = new byte[] {
-                0x0b, 0x11, 0x50, 0x64 };
+        byte[] serviceData = new byte[] {
+                0x50, 0x64 };
 
         ParcelUuid serviceDataUuid = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
-        filter = mFilterBuilder.setServiceData(serviceDataUuid, setServiceData).build();
+        filter = mFilterBuilder.setServiceData(serviceDataUuid, serviceData).build();
+        testReadWriteParcelForFilter(filter);
+
+        filter = mFilterBuilder.setServiceData(serviceDataUuid, new byte[0]).build();
         testReadWriteParcelForFilter(filter);
 
         byte[] serviceDataMask = new byte[] {
-                (byte) 0xFF, (byte) 0x00, (byte) 0xFF, (byte) 0xFF };
-        filter = mFilterBuilder.setServiceData(serviceDataUuid, setServiceData, serviceDataMask)
+                (byte) 0xFF, (byte) 0xFF };
+        filter = mFilterBuilder.setServiceData(serviceDataUuid, serviceData, serviceDataMask)
                 .build();
         testReadWriteParcelForFilter(filter);
 
         byte[] manufacturerData = new byte[] {
-                (byte) 0xE0, 0x00, 0x02, 0x15 };
-        int manufacturerId = 224;
+                0x02, 0x15 };
+        int manufacturerId = 0xE0;
         filter = mFilterBuilder.setManufacturerData(manufacturerId, manufacturerData).build();
         testReadWriteParcelForFilter(filter);
 
+        filter = mFilterBuilder.setServiceData(serviceDataUuid, new byte[0]).build();
+        testReadWriteParcelForFilter(filter);
+
         byte[] manufacturerDataMask = new byte[] {
-                (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+                (byte) 0xFF, (byte) 0xFF
         };
         filter = mFilterBuilder.setManufacturerData(manufacturerId, manufacturerData,
                 manufacturerDataMask).build();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 2962460..2fa0c93 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2161,7 +2161,7 @@
      * @param fd the FileDescriptor for the file you want to play
      * @param offset the offset into the file where the data to be played starts, in bytes
      * @param length the length in bytes of the data to be played
-     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
+     * @param mime The mime type of the file. Must be one of the mime types listed above.
      * @throws IllegalArgumentException if the mimeType is not supported.
      * @throws IllegalStateException if called in an invalid state.
      */
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 3861cc1..915e2f9 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -11,7 +11,7 @@
 
         <activity
             android:name=".DocumentsActivity"
-            android:theme="@style/Theme"
+            android:theme="@style/DocumentsTheme"
             android:icon="@drawable/ic_doc_text">
             <intent-filter>
                 <action android:name="android.intent.action.OPEN_DOCUMENT" />
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow_am.9.png
deleted file mode 100644
index 904d525..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
index e462727..bf0ac6c 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
index 8ac89b6..d4de3bd3 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png
index 3cbff21..1e3a623 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png
index 7c8b540..7d320fc 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
index 8644171..250208d 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
index 0a3a9a6..1bbdb21 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
index d37d9bf..124486d 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact.png
new file mode 100644
index 0000000..f1af4bd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event.png
new file mode 100644
index 0000000..9639efc
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png
index 0f5159b..c744499 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
index b3e7192..206d95f 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic.png
new file mode 100644
index 0000000..484288a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png
index 10c0b99..d2e5e6a 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png
index c857519..a1badcf 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
index b168481..1e9ad7b 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png
index 4af36b7..fa425d3 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
index 9167c7d..5274bb3 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet.png
new file mode 100644
index 0000000..82ffc32
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text.png
new file mode 100644
index 0000000..a741027
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png
index ff8d3aa..f2cad34 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png
index d422eb7..75c1f0d 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png
index 3860241..9d5b864 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_glyph.png
deleted file mode 100644
index 251ecfb..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_glyph.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png
deleted file mode 100644
index 0d75172..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_am.9.png
deleted file mode 100644
index 4a710ce..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_tablet_am.9.png
deleted file mode 100644
index a1bbc8b..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_shadow_tablet_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png
deleted file mode 100644
index 403eddb..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
index e9cfdb1..59bf931 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
index ab4d176..503b982 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
index 4eeafad..ceeb8c6 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
index 3563e97..0864867 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
index 2d61dc7..b66e252 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb_dark.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb_dark.png
new file mode 100644
index 0000000..92fa552
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb_light.png
similarity index 87%
rename from packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png
rename to packages/DocumentsUI/res/drawable-hdpi/ic_root_usb_light.png
index 665ee0b..bf6e373 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_root_usb_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
index 6be1f5b..61bb371 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow_am.9.png
deleted file mode 100644
index 068619b..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
index 0d3d5d7..d4f5814 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
index f9597f0..37379f8 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png
index deba408..994d04f 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png
index 88f0127..00526e5 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
index b1323da..ca1e4ed 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
index ff99fd7..8ba2307 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
index 4af71f3..c0b9bce 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact.png
new file mode 100644
index 0000000..da4d0ce
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event.png
new file mode 100644
index 0000000..ada1bfa
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png
index 3adff71..822815d 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
index 0a4a841..97fe282 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic.png
new file mode 100644
index 0000000..2a02045
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png
index f061b0c..58542b9 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png
index fa3d2ea..dc94502 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
index b558d08..90d624d 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png
index efc0b13..3b72269 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
index 655d866..72751e2 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet.png
new file mode 100644
index 0000000..75de220
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text.png
new file mode 100644
index 0000000..dc4c7ac
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png
index 1b6f00f..64f34c3 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png
index 24dad11..955755e 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png
index 7f26252..b56b2e9 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_glyph.png
deleted file mode 100644
index ae0da34..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_glyph.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png
deleted file mode 100644
index 0d75172..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_am.9.png
deleted file mode 100644
index 9343a39..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_tablet_am.9.png
deleted file mode 100644
index fabb56e..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_shadow_tablet_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png
deleted file mode 100644
index 9a9cf5e..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
index 5534c74e..9453739 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
index 86b9256..fa934b3 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
index dc9bbc9..415134a 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
index 86e1cf9..15fa247 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
index ed0ee5d..470dbf3 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb_dark.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb_dark.png
new file mode 100644
index 0000000..b11b60c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb_light.png
similarity index 78%
rename from packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png
rename to packages/DocumentsUI/res/drawable-mdpi/ic_root_usb_light.png
index a4f474b..5594a20 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_root_usb_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
index c8c9f1a..43df5af 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow_am.9.png
deleted file mode 100644
index e38a868..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
index 8952222..b7aafac 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
index bc833b4..01e761c 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png
index c782d0f..5fb0de6 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png
index fbc1e24..3600694 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
index de17d0b..0a9e49c 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
index d396745..b99e8cf 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
index 1627d8e..cf113e2 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact.png
new file mode 100644
index 0000000..5c5d658
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event.png
new file mode 100644
index 0000000..15f864f
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png
index 884dd58..f6b4862 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
index 9f70fb8..2419ef8 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic.png
new file mode 100644
index 0000000..abcf342
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png
index 49e4d0a..da85005 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png
index 09609e3..e3ed4ee 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
index cdb8471..7f713dc 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png
index f319929..c69cd9a 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
index ee8f63c..c09c36d 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet.png
new file mode 100644
index 0000000..f91abe85
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text.png
new file mode 100644
index 0000000..81d3267
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png
index aaa951b..0d16830 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png
index 1342087..b808ee1 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png
index 8c883ad..a05532e 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_glyph.png
deleted file mode 100644
index 7402c6d..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_glyph.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png
deleted file mode 100644
index 0d75172..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_am.9.png
deleted file mode 100644
index 027c64a..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_tablet_am.9.png
deleted file mode 100644
index 2c39a67..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_shadow_tablet_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png
deleted file mode 100644
index 205c34b..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
index a1c9789..890fda9 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
index bbdee7e..d2717ab 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
index 8ccca63..d87a0b1 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
index 28b7d5c..902f6ab 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
index 1121c43..d4b0341 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb_dark.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb_dark.png
new file mode 100644
index 0000000..15014a5
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb_light.png
similarity index 86%
rename from packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png
rename to packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb_light.png
index 6ccfb76..f16b81f 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_usb_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
index 94a757a..ef81618 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow_am.9.png
deleted file mode 100644
index 0b332e4..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
index e7151cf..5487507 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
index 5c10593..36ce5d4 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png
index e96ed99..0e911f5 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png
index cac2aaf..e96cec7 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
index 1ee0875..0bd6576 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
index 8d3dabf..27f551b 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
index c3e21ae..22ddd69 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact.png
new file mode 100644
index 0000000..0decac87
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event.png
new file mode 100644
index 0000000..0d2a932
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png
index 1a373f3..bbd6617 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
index b4308b4..817032b 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic.png
new file mode 100644
index 0000000..ebb9cc2
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png
index 63e4255..6754891 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png
index 6237ded..d802d7f 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
index 2c0a81e..3a7bb41 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png
index 2fba5ed..2bbf482 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
index 3e391ce..7da0b8b 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet.png
new file mode 100644
index 0000000..b1f2097
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text.png
new file mode 100644
index 0000000..210060e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png
index 48b4a72..2914c85 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_dark_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png
index 15d6c50..ab104b7 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_light_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png
index 9ccf41e..6b58983 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_glyph.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_glyph.png
deleted file mode 100644
index 4160699..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_glyph.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png
deleted file mode 100644
index 32b5f98..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_am.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_am.9.png
deleted file mode 100644
index 1a59e1a8..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_tablet_am.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_tablet_am.9.png
deleted file mode 100644
index 3c95790..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_shadow_tablet_am.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png
deleted file mode 100644
index f47d50a..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
index 10cdd51..6215385 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_grid_folder.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
index 4013b7c..c336147 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_new_folder_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
index 0fef9d0..414e199 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_rename_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
index 89bf79f..473e2da 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_sortby_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
index 7acc684e..9c3cc28 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_menu_undo_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png
deleted file mode 100644
index c31b4dc..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb_dark.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb_dark.png
new file mode 100644
index 0000000..657a116
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb_dark.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb_light.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb_light.png
new file mode 100644
index 0000000..75fb374
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_usb_light.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
index d852b8ec..755a79c 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_dir_shadow.xml b/packages/DocumentsUI/res/drawable/ic_dir_shadow.xml
deleted file mode 100644
index 1153e69..0000000
--- a/packages/DocumentsUI/res/drawable/ic_dir_shadow.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013, 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.
- */
--->
-
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_dir_shadow_am"
-        android:autoMirrored="true">
-</nine-patch>
diff --git a/packages/DocumentsUI/res/drawable/ic_drawer_shadow.xml b/packages/DocumentsUI/res/drawable/ic_drawer_shadow.xml
deleted file mode 100644
index 8d457be..0000000
--- a/packages/DocumentsUI/res/drawable/ic_drawer_shadow.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013, 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.
- */
--->
-
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_drawer_shadow_am"
-        android:autoMirrored="true">
-</nine-patch>
diff --git a/packages/DocumentsUI/res/drawable/ic_drawer_shadow_tablet.xml b/packages/DocumentsUI/res/drawable/ic_drawer_shadow_tablet.xml
deleted file mode 100644
index 382ebff..0000000
--- a/packages/DocumentsUI/res/drawable/ic_drawer_shadow_tablet.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013, 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.
- */
--->
-
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_drawer_shadow_tablet_am"
-        android:autoMirrored="true">
-</nine-patch>
diff --git a/packages/DocumentsUI/res/drawable/item_activated.xml b/packages/DocumentsUI/res/drawable/item_activated.xml
index 6ffefdb..1b3f44a 100644
--- a/packages/DocumentsUI/res/drawable/item_activated.xml
+++ b/packages/DocumentsUI/res/drawable/item_activated.xml
@@ -15,7 +15,11 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:state_activated="true" android:drawable="@color/accent_item_activated" />
-    <item android:state_focused="false" android:state_activated="true" android:drawable="@color/accent_item_activated" />
+    <item android:state_focused="true" android:state_activated="true">
+        <color android:color="?android:attr/colorAccent" />
+    </item>
+    <item android:state_focused="false" android:state_activated="true">
+        <color android:color="?android:attr/colorAccent" />
+    </item>
     <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/packages/DocumentsUI/res/drawable/item_root.xml b/packages/DocumentsUI/res/drawable/item_activated_overlay.xml
similarity index 73%
rename from packages/DocumentsUI/res/drawable/item_root.xml
rename to packages/DocumentsUI/res/drawable/item_activated_overlay.xml
index 60d4ab0..83e4d7e 100644
--- a/packages/DocumentsUI/res/drawable/item_root.xml
+++ b/packages/DocumentsUI/res/drawable/item_activated_overlay.xml
@@ -15,8 +15,11 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@color/item_root_pressed" />
-    <item android:state_activated="true" android:drawable="@color/item_root_focused" />
-    <item android:state_focused="true" android:drawable="@color/item_root_focused" />
+    <item android:state_focused="true" android:state_activated="true">
+        <color android:color="@color/accent_color_overlay" />
+    </item>
+    <item android:state_focused="false" android:state_activated="true">
+        <color android:color="@color/accent_color_overlay" />
+    </item>
     <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
index 5f1e432..95af7e9 100644
--- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -17,7 +17,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:foreground="@drawable/item_activated">
+    android:background="@drawable/item_activated">
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
index 9286277..c33932d 100644
--- a/packages/DocumentsUI/res/layout-sw720dp/activity.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
@@ -17,44 +17,59 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="horizontal"
-    android:baselineAligned="false">
+    android:orientation="vertical">
 
-    <FrameLayout
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:id="@+id/dialog_roots">
+    <Toolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="?android:attr/actionBarSize"
+        android:background="?android:attr/colorPrimary"
+        android:elevation="8dp"
+        android:theme="?android:attr/actionBarTheme">
+
+        <Spinner
+            android:id="@+id/stack"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="4dp"
+            android:overlapAnchor="true" />
+
+    </Toolbar>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="horizontal"
+        android:baselineAligned="false">
 
         <FrameLayout
             android:id="@+id/container_roots"
-            android:layout_width="250dp"
+            android:layout_width="256dp"
             android:layout_height="match_parent" />
 
-        <ImageView
-            android:layout_width="wrap_content"
+        <LinearLayout
+            android:layout_width="0dp"
             android:layout_height="match_parent"
-            android:layout_gravity="end"
-            android:scaleType="fitXY"
-            android:src="@drawable/ic_drawer_shadow_tablet" />
+            android:layout_weight="1"
+            android:orientation="vertical"
+            android:elevation="8dp"
+            android:background="@*android:color/material_grey_50">
 
-    </FrameLayout>
+            <com.android.documentsui.DirectoryContainerView
+                android:id="@+id/container_directory"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
 
-    <LinearLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:orientation="vertical">
+            <FrameLayout
+                android:id="@+id/container_save"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:background="@*android:color/material_grey_50"
+                android:elevation="8dp" />
 
-        <com.android.documentsui.DirectoryContainerView
-            android:id="@+id/container_directory"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
-
-        <FrameLayout
-            android:id="@+id/container_save"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+        </LinearLayout>
 
     </LinearLayout>
 
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/activity.xml
index 2ef7e9c..d580821 100644
--- a/packages/DocumentsUI/res/layout/activity.xml
+++ b/packages/DocumentsUI/res/layout/activity.xml
@@ -24,6 +24,23 @@
         android:layout_height="match_parent"
         android:orientation="vertical">
 
+        <Toolbar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?android:attr/actionBarSize"
+            android:background="?android:attr/colorPrimary"
+            android:elevation="8dp"
+            android:theme="?android:attr/actionBarTheme">
+
+            <Spinner
+                android:id="@+id/stack"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="4dp"
+                android:overlapAnchor="true" />
+
+        </Toolbar>
+
         <com.android.documentsui.DirectoryContainerView
             android:id="@+id/container_directory"
             android:layout_width="match_parent"
@@ -33,15 +50,35 @@
         <FrameLayout
             android:id="@+id/container_save"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            android:background="@*android:color/material_grey_50"
+            android:elevation="8dp" />
 
     </LinearLayout>
 
-    <FrameLayout
-        android:id="@+id/container_roots"
-        android:layout_width="250dp"
+    <LinearLayout
+        android:id="@+id/drawer_roots"
+        android:layout_width="256dp"
         android:layout_height="match_parent"
         android:layout_gravity="start"
-        android:background="#fff" />
+        android:orientation="vertical"
+        android:elevation="16dp"
+        android:background="@*android:color/white">
+
+        <Toolbar
+            android:id="@+id/roots_toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?android:attr/actionBarSize"
+            android:background="?android:attr/colorPrimary"
+            android:elevation="8dp"
+            android:theme="?android:attr/actionBarTheme" />
+
+        <FrameLayout
+            android:id="@+id/container_roots"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+    </LinearLayout>
 
 </android.support.v4.widget.DrawerLayout>
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 09b50c0..ffbd3f0 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -17,7 +17,7 @@
 <com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/ic_dir_shadow">
+    android:background="@*android:color/material_grey_50">
 
     <TextView
         android:id="@android:id/empty"
diff --git a/packages/DocumentsUI/res/layout/fragment_pick.xml b/packages/DocumentsUI/res/layout/fragment_pick.xml
index 4a2fd03..5735871 100644
--- a/packages/DocumentsUI/res/layout/fragment_pick.xml
+++ b/packages/DocumentsUI/res/layout/fragment_pick.xml
@@ -17,32 +17,16 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="vertical">
+    android:orientation="horizontal"
+    android:baselineAligned="false"
+    android:gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall">
 
-    <!-- Le sigh, this really should be an asset -->
-    <View
+    <Button
+        android:id="@android:id/button1"
         android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="#ccc" />
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:baselineAligned="false"
-        android:gravity="center_vertical"
-        android:background="#ddd"
-        android:minHeight="?android:attr/listPreferredItemHeightSmall">
-
-        <Button
-            android:id="@android:id/button1"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="?android:attr/selectableItemBackground"
-            android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textAllCaps="false"
-            android:padding="8dp" />
-
-    </LinearLayout>
+        android:layout_height="match_parent"
+        android:textAllCaps="false"
+        style="?android:attr/buttonBarPositiveButtonStyle" />
 
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/fragment_roots.xml b/packages/DocumentsUI/res/layout/fragment_roots.xml
index c3a3da0..2d624d8 100644
--- a/packages/DocumentsUI/res/layout/fragment_roots.xml
+++ b/packages/DocumentsUI/res/layout/fragment_roots.xml
@@ -18,4 +18,5 @@
     android:id="@android:id/list"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:divider="@drawable/ic_drawer_hairline_divider" />
+    android:paddingTop="8dp"
+    android:divider="@null" />
diff --git a/packages/DocumentsUI/res/layout/fragment_save.xml b/packages/DocumentsUI/res/layout/fragment_save.xml
index d601194..7aac620 100644
--- a/packages/DocumentsUI/res/layout/fragment_save.xml
+++ b/packages/DocumentsUI/res/layout/fragment_save.xml
@@ -17,66 +17,55 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="vertical">
+    android:paddingStart="@dimen/list_item_padding"
+    android:orientation="horizontal"
+    android:baselineAligned="false"
+    android:gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall">
 
-    <!-- Le sigh, this really should be an asset -->
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="#ccc" />
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:baselineAligned="false"
-        android:gravity="center_vertical"
-        android:background="#ddd"
-        android:minHeight="?android:attr/listPreferredItemHeightSmall">
+    <FrameLayout
+        android:layout_width="@dimen/icon_size"
+        android:layout_height="@dimen/icon_size"
+        android:layout_marginEnd="16dp">
 
         <ImageView
             android:id="@android:id/icon"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
+            android:layout_width="@dimen/root_icon_size"
+            android:layout_height="match_parent"
             android:scaleType="centerInside"
             android:contentDescription="@null" />
 
-        <EditText
-            android:id="@android:id/title"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:singleLine="true"
-            android:selectAllOnFocus="true" />
+    </FrameLayout>
 
-        <FrameLayout
+    <EditText
+        android:id="@android:id/title"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:singleLine="true"
+        android:selectAllOnFocus="true" />
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent">
+
+        <Button
+            android:id="@android:id/button1"
             android:layout_width="wrap_content"
-            android:layout_height="match_parent">
+            android:layout_height="match_parent"
+            android:text="@string/menu_save"
+            style="?android:attr/buttonBarPositiveButtonStyle" />
 
-            <Button
-                android:id="@android:id/button1"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:background="?android:attr/selectableItemBackground"
-                android:text="@string/menu_save"
-                android:textAllCaps="true"
-                android:textAppearance="?android:attr/textAppearanceSmall"
-                android:padding="8dp" />
+        <ProgressBar
+            android:id="@android:id/progress"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:visibility="gone"
+            android:indeterminate="true"
+            android:padding="8dp"
+            style="?android:attr/progressBarStyle" />
 
-            <ProgressBar
-                android:id="@android:id/progress"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:visibility="gone"
-                android:indeterminate="true"
-                android:padding="8dp"
-                style="?android:attr/progressBarStyle" />
-
-        </FrameLayout>
-
-    </LinearLayout>
+    </FrameLayout>
 
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 0fc606d..bdb3184 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -19,7 +19,7 @@
     android:layout_height="@dimen/grid_item_height"
     android:orientation="vertical"
     android:background="@color/grid_item_background"
-    android:foreground="@drawable/item_activated">
+    android:foreground="@drawable/item_activated_overlay">
 
     <ImageView
         android:id="@+id/icon_thumb"
@@ -46,8 +46,8 @@
             android:layout_height="wrap_content"
             android:background="@drawable/grid_protect_background"
             android:orientation="vertical"
-            android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+            android:paddingStart="16dp"
+            android:paddingEnd="12dp"
             android:paddingTop="8dp"
             android:paddingBottom="8dp">
 
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 50ed2d6..c5f1842 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -17,7 +17,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:foreground="@drawable/item_activated">
+    android:background="@drawable/item_activated">
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index f17c261..266b9b0 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -17,25 +17,33 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:minHeight="48dp"
+    android:paddingStart="@dimen/list_item_padding"
+    android:paddingEnd="@dimen/list_item_padding"
     android:gravity="center_vertical"
     android:orientation="horizontal"
     android:baselineAligned="false"
-    android:background="@drawable/item_root">
+    android:background="@drawable/item_activated">
 
-    <ImageView
-        android:id="@android:id/icon"
+    <FrameLayout
         android:layout_width="@dimen/icon_size"
         android:layout_height="@dimen/icon_size"
-        android:layout_marginEnd="8dp"
-        android:scaleType="centerInside"
-        android:contentDescription="@null" />
+        android:layout_marginEnd="16dp">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/root_icon_size"
+            android:layout_height="match_parent"
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
+
+    </FrameLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
         android:orientation="vertical">
 
         <TextView
@@ -45,7 +53,8 @@
             android:singleLine="true"
             android:ellipsize="end"
             android:textAlignment="viewStart"
-            style="@style/TextAppearance.Medium" />
+            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textColor="?android:attr/textColorPrimary" />
 
         <TextView
             android:id="@android:id/summary"
@@ -54,7 +63,8 @@
             android:singleLine="true"
             android:ellipsize="end"
             android:textAlignment="viewStart"
-            style="@style/TextAppearance.Small" />
+            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textColor="?android:attr/textColorSecondary" />
 
     </LinearLayout>
 
diff --git a/packages/DocumentsUI/res/layout/item_root_spacer.xml b/packages/DocumentsUI/res/layout/item_root_spacer.xml
index 7d96ac8..b3beced 100644
--- a/packages/DocumentsUI/res/layout/item_root_spacer.xml
+++ b/packages/DocumentsUI/res/layout/item_root_spacer.xml
@@ -14,7 +14,15 @@
      limitations under the License.
 -->
 
-<View xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/ic_drawer_tall_divider" />
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/listDivider" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_title.xml b/packages/DocumentsUI/res/layout/item_subdir.xml
similarity index 87%
rename from packages/DocumentsUI/res/layout/item_title.xml
rename to packages/DocumentsUI/res/layout/item_subdir.xml
index 6e96fb5..b2a739a 100644
--- a/packages/DocumentsUI/res/layout/item_title.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir.xml
@@ -28,6 +28,7 @@
         android:id="@+id/subdir"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:paddingEnd="8dp"
         android:scaleType="centerInside"
         android:visibility="gone"
         android:src="@drawable/ic_subdirectory_arrow"
@@ -35,11 +36,13 @@
 
     <TextView
         android:id="@android:id/title"
-        android:layout_width="match_parent"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
+        android:layout_weight="1"
         android:singleLine="true"
         android:ellipsize="middle"
         android:textAlignment="viewStart"
-        style="@style/TextAppearance.Medium" />
+        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+        android:textColor="?android:attr/textColorPrimary" />
 
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_title.xml b/packages/DocumentsUI/res/layout/item_subdir_title.xml
similarity index 63%
copy from packages/DocumentsUI/res/layout/item_title.xml
copy to packages/DocumentsUI/res/layout/item_subdir_title.xml
index 6e96fb5..4c839d0 100644
--- a/packages/DocumentsUI/res/layout/item_title.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir_title.xml
@@ -15,31 +15,19 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:gravity="center_vertical"
+    android:paddingEnd="8dp"
     android:orientation="horizontal"
     android:baselineAligned="false">
 
-    <ImageView
-        android:id="@+id/subdir"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:scaleType="centerInside"
-        android:visibility="gone"
-        android:src="@drawable/ic_subdirectory_arrow"
-        android:contentDescription="@null" />
-
     <TextView
         android:id="@android:id/title"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:singleLine="true"
         android:ellipsize="middle"
         android:textAlignment="viewStart"
-        style="@style/TextAppearance.Medium" />
+        android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
 
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
index 75afe01..068c806 100644
--- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -21,7 +21,7 @@
     <item type="dimen" name="dialog_height">90%</item>
 
     <dimen name="grid_padding_horiz">24dp</dimen>
-    <dimen name="grid_padding_vert">8dp</dimen>
+    <dimen name="grid_padding_vert">16dp</dimen>
 
     <dimen name="grid_item_padding">8dp</dimen>
 
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
deleted file mode 100644
index 8d31444..0000000
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <style name="Theme" parent="@android:style/Theme.DeviceDefault.Light">
-        <item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
-        <item name="android:windowBackground">@*android:drawable/dialog_full_holo_light</item>
-        <item name="android:colorBackgroundCacheHint">@null</item>
-        <item name="android:windowIsTranslucent">true</item>
-        <item name="android:windowAnimationStyle">@*android:style/Animation.DeviceDefault.Dialog</item>
-    </style>
-</resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index e3d7f2d..08159c4 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -15,12 +15,10 @@
 -->
 
 <resources>
-    <color name="chip">#ddd</color>
-    <color name="item_root_pressed">#33cccccc</color>
-    <color name="item_root_focused">#66cccccc</color>
 
-    <color name="grid_item_background">#ffe1e1e0</color>
+    <!-- Half-alpha of material_teal_500 -->
+    <color name="accent_color_overlay">#8800bcd4</color>
 
-    <color name="accent_item_activated">#88009587</color>
+    <color name="grid_item_background">@*android:color/material_grey_300</color>
 
 </resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index 83a0bf4..d4d7ede 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -37,4 +37,6 @@
     <bool name="show_as_dialog">false</bool>
     <bool name="always_show_summary">false</bool>
 
+    <dimen name="dir_elevation">8dp</dimen>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index a416eb4..4bd6991 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -15,6 +15,29 @@
 -->
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="DocumentsTheme" parent="@android:style/Theme.DeviceDefault.Light.DialogWhenLarge">
+        <item name="android:actionBarWidgetTheme">@null</item>
+        <item name="android:actionBarTheme">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
+        <item name="android:actionBarPopupTheme">@*android:style/ThemeOverlay.Material.Light</item>
+
+        <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_900</item>
+        <item name="android:colorPrimary">@*android:color/material_blue_grey_800</item>
+        <item name="android:colorAccent">@*android:color/material_teal_500</item>
+
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowNoTitle">true</item>
+
+        <item name="*android:windowFixedWidthMajor">@null</item>
+        <item name="*android:windowFixedWidthMinor">@null</item>
+        <item name="*android:windowMinWidthMajor">@null</item>
+        <item name="*android:windowMinWidthMinor">@null</item>
+        <item name="*android:windowFixedHeightMajor">80%</item>
+        <item name="*android:windowFixedHeightMinor">90%</item>
+
+        <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+    </style>
+
     <style name="TextAppearance" />
 
     <style name="TextAppearance.Medium">
@@ -27,14 +50,4 @@
         <item name="android:textColor">?android:attr/textColorTertiary</item>
     </style>
 
-    <!-- Normally just a redirection, but this is used to make ourselves a
-         dialog on large tablets -->
-    <style name="Theme" parent="@android:style/Theme.DeviceDefault.Light">
-        <item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
-    </style>
-    
-    <style name="DarkerOverflow" parent="@android:style/Widget.DeviceDefault.Light.ActionButton.Overflow">
-        <item name="android:src">@drawable/ic_menu_overflow</item>
-    </style>
-
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
index 00b3c87..71ea8a9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
@@ -36,14 +36,6 @@
     }
 
     @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        setClipChildren(false);
-        setClipToOutline(false);
-        setClipToPadding(false);
-    }
-
-    @Override
     protected void dispatchDraw(Canvas canvas) {
         final ArrayList<View> disappearing = mDisappearingChildren;
         if (mDisappearingFirst && disappearing != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index e013cc3..001cac46 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -853,7 +853,11 @@
                 // We've already had to enumerate roots before any results can
                 // be shown, so this will never block.
                 final RootInfo root = roots.getRootBlocking(docAuthority, docRootId);
-                iconDrawable = root.loadIcon(context);
+                if (state.derivedMode == MODE_GRID) {
+                    iconDrawable = root.loadLightIcon(context);
+                } else {
+                    iconDrawable = root.loadIcon(context);
+                }
 
                 if (summary != null) {
                     final boolean alwaysShowSummary = getResources()
@@ -880,7 +884,7 @@
                 if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
                         && showThumbnail) {
                     iconDrawable = context.getResources().getDrawable(
-                            R.drawable.ic_root_folder_dark);
+                            R.drawable.ic_root_folder_light);
                 }
 
                 if (summary != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
index c163c46..4f52a03d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -37,19 +37,6 @@
     }
 
     @Override
-    public void setBackground(Drawable background) {
-        final Rect rect = new Rect();
-        background.getPadding(rect);
-
-        final boolean insetLeft = getResources().getBoolean(R.bool.list_divider_inset_left);
-        if (insetLeft) {
-            super.setBackground(new InsetDrawable(background, -rect.left, 0, -rect.right, 0));
-        } else {
-            super.setBackground(new InsetDrawable(background, -rect.right, 0, -rect.left, 0));
-        }
-    }
-
-    @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
         mWidth = w;
@@ -63,5 +50,11 @@
     public void setPosition(float position) {
         mPosition = position;
         setX((mWidth > 0) ? (mPosition * mWidth) : 0);
+
+        if (mPosition != 0) {
+            setTranslationZ(getResources().getDimensionPixelSize(R.dimen.dir_elevation));
+        } else {
+            setTranslationZ(0);
+        }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index d0b6a1d..a2e8432 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -28,8 +28,6 @@
 import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
 import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
 
-import android.app.ActionBar;
-import android.app.ActionBar.OnNavigationListener;
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -39,14 +37,12 @@
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Point;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -55,7 +51,6 @@
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
 import android.support.v4.app.ActionBarDrawerToggle;
-import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v4.widget.DrawerLayout.DrawerListener;
 import android.util.Log;
@@ -64,17 +59,19 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MenuItem.OnActionExpandListener;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
 import android.widget.SearchView;
 import android.widget.SearchView.OnQueryTextListener;
+import android.widget.Spinner;
 import android.widget.TextView;
 import android.widget.Toast;
+import android.widget.Toolbar;
 
 import com.android.documentsui.RecentsProvider.RecentColumns;
 import com.android.documentsui.RecentsProvider.ResumeColumns;
@@ -105,9 +102,14 @@
 
     private SearchView mSearchView;
 
+    private Toolbar mToolbar;
+    private Spinner mToolbarStack;
+
+    private Toolbar mRootsToolbar;
+
     private DrawerLayout mDrawerLayout;
     private ActionBarDrawerToggle mDrawerToggle;
-    private View mRootsContainer;
+    private View mRootsDrawer;
 
     private DirectoryContainerView mDirectoryContainer;
 
@@ -115,6 +117,8 @@
     private boolean mIgnoreNextClose;
     private boolean mIgnoreNextCollapse;
 
+    private boolean mSearchExpanded;
+
     private RootsCache mRoots;
     private State mState;
 
@@ -127,59 +131,31 @@
         setResult(Activity.RESULT_CANCELED);
         setContentView(R.layout.activity);
 
+        final Context context = this;
         final Resources res = getResources();
         mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
 
         if (mShowAsDialog) {
-            // backgroundDimAmount from theme isn't applied; do it manually
+            // Strongly define our horizontal dimension; we leave vertical as
+            // WRAP_CONTENT so that system resizes us when IME is showing.
             final WindowManager.LayoutParams a = getWindow().getAttributes();
-            a.dimAmount = 0.6f;
-            getWindow().setAttributes(a);
 
-            getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
-            getWindow().setFlags(~0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-
-            // Inset ourselves to look like a dialog
             final Point size = new Point();
             getWindowManager().getDefaultDisplay().getSize(size);
+            a.width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
 
-            final int width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
-            final int height = (int) res.getFraction(R.dimen.dialog_height, size.y, size.y);
-            final int insetX = (size.x - width) / 2;
-            final int insetY = (size.y - height) / 2;
-
-            final Drawable before = getWindow().getDecorView().getBackground();
-            final Drawable after = new InsetDrawable(before, insetX, insetY, insetX, insetY);
-            getWindow().getDecorView().setBackground(after);
-
-            // Dismiss when touch down in the dimmed inset area
-            getWindow().getDecorView().setOnTouchListener(new OnTouchListener() {
-                @Override
-                public boolean onTouch(View v, MotionEvent event) {
-                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                        final float x = event.getX();
-                        final float y = event.getY();
-                        if (x < insetX || x > v.getWidth() - insetX || y < insetY
-                                || y > v.getHeight() - insetY) {
-                            finish();
-                            return true;
-                        }
-                    }
-                    return false;
-                }
-            });
+            getWindow().setAttributes(a);
 
         } else {
             // Non-dialog means we have a drawer
             mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
 
             mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
-                    R.drawable.ic_drawer_glyph, R.string.drawer_open, R.string.drawer_close);
+                    R.drawable.ic_hamburger, R.string.drawer_open, R.string.drawer_close);
 
             mDrawerLayout.setDrawerListener(mDrawerListener);
-            mDrawerLayout.setDrawerShadow(R.drawable.ic_drawer_shadow, GravityCompat.START);
 
-            mRootsContainer = findViewById(R.id.container_roots);
+            mRootsDrawer = findViewById(R.id.drawer_roots);
         }
 
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
@@ -190,10 +166,25 @@
             buildDefaultState();
         }
 
+        mToolbar = (Toolbar) findViewById(R.id.toolbar);
+        mToolbar.setTitleTextAppearance(context,
+                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+
+        mToolbarStack = (Spinner) findViewById(R.id.stack);
+        mToolbarStack.setOnItemSelectedListener(mStackListener);
+
+        mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
+        if (mRootsToolbar != null) {
+            mRootsToolbar.setTitleTextAppearance(context,
+                    android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+        }
+
+        setActionBar(mToolbar);
+
         // Hide roots when we're managing a specific root
         if (mState.action == ACTION_MANAGE) {
             if (mShowAsDialog) {
-                findViewById(R.id.dialog_roots).setVisibility(View.GONE);
+                findViewById(R.id.container_roots).setVisibility(View.GONE);
             } else {
                 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
             }
@@ -382,15 +373,11 @@
         @Override
         public void onDrawerOpened(View drawerView) {
             mDrawerToggle.onDrawerOpened(drawerView);
-            updateActionBar();
-            invalidateOptionsMenu();
         }
 
         @Override
         public void onDrawerClosed(View drawerView) {
             mDrawerToggle.onDrawerClosed(drawerView);
-            updateActionBar();
-            invalidateOptionsMenu();
         }
 
         @Override
@@ -410,9 +397,9 @@
     public void setRootsDrawerOpen(boolean open) {
         if (!mShowAsDialog) {
             if (open) {
-                mDrawerLayout.openDrawer(mRootsContainer);
+                mDrawerLayout.openDrawer(mRootsDrawer);
             } else {
-                mDrawerLayout.closeDrawer(mRootsContainer);
+                mDrawerLayout.closeDrawer(mRootsDrawer);
             }
         }
     }
@@ -421,44 +408,51 @@
         if (mShowAsDialog) {
             return false;
         } else {
-            return mDrawerLayout.isDrawerOpen(mRootsContainer);
+            return mDrawerLayout.isDrawerOpen(mRootsDrawer);
         }
     }
 
     public void updateActionBar() {
-        final ActionBar actionBar = getActionBar();
-
-        actionBar.setDisplayShowHomeEnabled(true);
-
-        final boolean showIndicator = !mShowAsDialog && (mState.action != ACTION_MANAGE);
-        actionBar.setDisplayHomeAsUpEnabled(showIndicator);
-        if (mDrawerToggle != null) {
-            mDrawerToggle.setDrawerIndicatorEnabled(showIndicator);
-        }
-
-        if (isRootsDrawerOpen()) {
-            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
-            actionBar.setIcon(new ColorDrawable());
-
+        if (mRootsToolbar != null) {
             if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT
                     || mState.action == ACTION_OPEN_TREE) {
-                actionBar.setTitle(R.string.title_open);
+                mRootsToolbar.setTitle(R.string.title_open);
             } else if (mState.action == ACTION_CREATE) {
-                actionBar.setTitle(R.string.title_save);
+                mRootsToolbar.setTitle(R.string.title_save);
             }
-        } else {
-            final RootInfo root = getCurrentRoot();
-            actionBar.setIcon(root != null ? root.loadIcon(this) : null);
+        }
 
+        final RootInfo root = getCurrentRoot();
+        final boolean showRootIcon = mShowAsDialog || (mState.action == ACTION_MANAGE);
+        if (showRootIcon) {
+            mToolbar.setNavigationIcon(root != null ? root.loadLightIcon(this) : null);
+            mToolbar.setNavigationOnClickListener(null);
+        } else {
+            mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
+            mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    setRootsDrawerOpen(true);
+                }
+            });
+        }
+
+        if (mSearchExpanded) {
+            mToolbar.setTitle(null);
+            mToolbarStack.setVisibility(View.GONE);
+            mToolbarStack.setAdapter(null);
+        } else {
             if (mState.stack.size() <= 1) {
-                actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
-                actionBar.setTitle(root.title);
+                mToolbar.setTitle(root.title);
+                mToolbarStack.setVisibility(View.GONE);
+                mToolbarStack.setAdapter(null);
             } else {
+                mToolbar.setTitle(null);
+                mToolbarStack.setVisibility(View.VISIBLE);
+                mToolbarStack.setAdapter(mStackAdapter);
+
                 mIgnoreNextNavigation = true;
-                actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
-                actionBar.setTitle(null);
-                actionBar.setListNavigationCallbacks(mStackAdapter, mStackListener);
-                actionBar.setSelectedNavigationItem(mStackAdapter.getCount() - 1);
+                mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
             }
         }
     }
@@ -480,6 +474,7 @@
         mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
             @Override
             public boolean onQueryTextSubmit(String query) {
+                mSearchExpanded = true;
                 mState.currentSearch = query;
                 mSearchView.clearFocus();
                 onCurrentDirectoryChanged(ANIM_NONE);
@@ -495,11 +490,14 @@
         searchMenu.setOnActionExpandListener(new OnActionExpandListener() {
             @Override
             public boolean onMenuItemActionExpand(MenuItem item) {
+                mSearchExpanded = true;
+                updateActionBar();
                 return true;
             }
 
             @Override
             public boolean onMenuItemActionCollapse(MenuItem item) {
+                mSearchExpanded = false;
                 if (mIgnoreNextCollapse) {
                     mIgnoreNextCollapse = false;
                     return true;
@@ -514,6 +512,7 @@
         mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
             @Override
             public boolean onClose() {
+                mSearchExpanded = false;
                 if (mIgnoreNextClose) {
                     mIgnoreNextClose = false;
                     return false;
@@ -545,18 +544,6 @@
         final MenuItem list = menu.findItem(R.id.menu_list);
         final MenuItem settings = menu.findItem(R.id.menu_settings);
 
-        // Open drawer means we hide most actions
-        if (isRootsDrawerOpen()) {
-            createDir.setVisible(false);
-            search.setVisible(false);
-            sort.setVisible(false);
-            grid.setVisible(false);
-            list.setVisible(false);
-            mIgnoreNextCollapse = true;
-            search.collapseActionView();
-            return true;
-        }
-
         sort.setVisible(cwd != null);
         grid.setVisible(mState.derivedMode != MODE_GRID);
         list.setVisible(mState.derivedMode != MODE_LIST);
@@ -730,7 +717,7 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.item_title, parent, false);
+                        .inflate(R.layout.item_subdir_title, parent, false);
             }
 
             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
@@ -743,8 +730,6 @@
                 title.setText(doc.displayName);
             }
 
-            // No padding when shown in actionbar
-            convertView.setPadding(0, 0, 0, 0);
             return convertView;
         }
 
@@ -752,7 +737,7 @@
         public View getDropDownView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.item_title, parent, false);
+                        .inflate(R.layout.item_subdir, parent, false);
             }
 
             final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
@@ -772,20 +757,24 @@
         }
     };
 
-    private OnNavigationListener mStackListener = new OnNavigationListener() {
+    private OnItemSelectedListener mStackListener = new OnItemSelectedListener() {
         @Override
-        public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
             if (mIgnoreNextNavigation) {
                 mIgnoreNextNavigation = false;
-                return false;
+                return;
             }
 
-            while (mState.stack.size() > itemPosition + 1) {
+            while (mState.stack.size() > position + 1) {
                 mState.stackTouched = true;
                 mState.stack.pop();
             }
             onCurrentDirectoryChanged(ANIM_UP);
-            return true;
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+            // Ignored
         }
     };
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index d06e858..1235c9b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -104,6 +104,7 @@
         mRecentsRoot.authority = null;
         mRecentsRoot.rootId = null;
         mRecentsRoot.icon = R.drawable.ic_root_recent_dark;
+        mRecentsRoot.lightIcon = R.drawable.ic_root_recent_light;
         mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE
                 | Root.FLAG_SUPPORTS_IS_CHILD;
         mRecentsRoot.title = mContext.getString(R.string.root_recent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index efa7785..79cbf26 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -48,6 +48,7 @@
     public String rootId;
     public int flags;
     public int icon;
+    public int lightIcon;
     public String title;
     public String summary;
     public String documentId;
@@ -58,6 +59,7 @@
     public String derivedPackageName;
     public String[] derivedMimeTypes;
     public int derivedIcon;
+    public int derivedLightIcon;
 
     public RootInfo() {
         reset();
@@ -69,6 +71,7 @@
         rootId = null;
         flags = 0;
         icon = 0;
+        lightIcon = 0;
         title = null;
         summary = null;
         documentId = null;
@@ -78,6 +81,7 @@
         derivedPackageName = null;
         derivedMimeTypes = null;
         derivedIcon = 0;
+        derivedLightIcon = 0;
     }
 
     @Override
@@ -160,14 +164,19 @@
         // TODO: remove these special case icons
         if (isExternalStorage()) {
             derivedIcon = R.drawable.ic_root_sdcard_dark;
+            derivedLightIcon = R.drawable.ic_root_sdcard_light;
         } else if (isDownloads()) {
             derivedIcon = R.drawable.ic_root_download_dark;
+            derivedLightIcon = R.drawable.ic_root_download_light;
         } else if (isImages()) {
             derivedIcon = R.drawable.ic_doc_image_dark;
+            derivedLightIcon = R.drawable.ic_doc_image_light;
         } else if (isVideos()) {
             derivedIcon = R.drawable.ic_doc_video_dark;
+            derivedLightIcon = R.drawable.ic_doc_video_light;
         } else if (isAudio()) {
             derivedIcon = R.drawable.ic_doc_audio_dark;
+            derivedLightIcon = R.drawable.ic_doc_audio_light;
         }
     }
 
@@ -211,6 +220,16 @@
         }
     }
 
+    public Drawable loadLightIcon(Context context) {
+        if (derivedLightIcon != 0) {
+            return context.getResources().getDrawable(derivedLightIcon);
+        } else if (lightIcon != 0) {
+            return IconUtils.loadPackageIcon(context, authority, lightIcon);
+        } else {
+            return loadIcon(context);
+        }
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o instanceof RootInfo) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b80a33b..1932843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -937,12 +937,16 @@
     }
     private void updateNotificationTranslucency() {
         float alpha = (getNotificationsTopY() + mNotificationStackScroller.getItemHeight())
-                / (mQsMinExpansionHeight + mNotificationStackScroller.getItemHeight() / 2);
+                / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
+                        + mNotificationStackScroller.getCollapseSecondCardPadding());
         alpha = Math.max(0, Math.min(alpha, 1));
         alpha = (float) Math.pow(alpha, 0.75);
-
-        // TODO: Draw a rect with DST_OUT over the notifications to achieve the same effect -
-        // this would be much more efficient.
+        if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) {
+            mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null);
+        } else if (alpha == 1f
+                && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
+            mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
+        }
         mNotificationStackScroller.setAlpha(alpha);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 9b819f2b..e0167e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -470,6 +470,10 @@
         return mBottomStackPeekSize;
     }
 
+    public int getCollapseSecondCardPadding() {
+        return mCollapseSecondCardPadding;
+    }
+
     public void setLongPressListener(SwipeHelper.LongPressListener listener) {
         mSwipeHelper.setLongPressListener(listener);
         mLongPressListener = listener;
@@ -1955,8 +1959,10 @@
     }
 
     public void setScrimAlpha(float progress) {
-        mAmbientState.setScrimAmount(progress);
-        requestChildrenUpdate();
+        if (progress != mAmbientState.getScrimAmount()) {
+            mAmbientState.setScrimAmount(progress);
+            requestChildrenUpdate();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
new file mode 100644
index 0000000..616b670
--- /dev/null
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import com.android.internal.telephony.IMms;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+/**
+ * This class is a proxy for MmsService APIs. We need this because MmsService runs
+ * in phone process and may crash anytime. This manages a connection to the actual
+ * MmsService and bridges the public SMS/MMS APIs with MmsService implementation.
+ */
+public class MmsServiceBroker extends SystemService {
+    private static final String TAG = "MmsServiceBroker";
+
+    private static final ComponentName MMS_SERVICE_COMPONENT =
+            new ComponentName("com.android.mms.service", "com.android.mms.service.MmsService");
+
+    private static final int MSG_TRY_CONNECTING = 1;
+
+    private Context mContext;
+    // The actual MMS service instance to invoke
+    private volatile IMms mService;
+    private boolean mIsConnecting;
+
+    // Cached system service instances
+    private volatile AppOpsManager mAppOpsManager = null;
+    private volatile PackageManager mPackageManager = null;
+    private volatile TelephonyManager mTelephonyManager = null;
+
+    private final Handler mConnectionHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_TRY_CONNECTING:
+                    tryConnecting();
+                    break;
+                default:
+                    Slog.e(TAG, "Unknown message");
+            }
+        }
+    };
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Slog.i(TAG, "MmsService connected");
+            synchronized (MmsServiceBroker.this) {
+                mService = IMms.Stub.asInterface(service);
+                mIsConnecting = false;
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Slog.i(TAG, "MmsService unexpectedly disconnected");
+            synchronized (MmsServiceBroker.this) {
+                mService = null;
+                mIsConnecting = false;
+            }
+        }
+    };
+
+    public MmsServiceBroker(Context context) {
+        super(context);
+        mContext = context;
+        mService = null;
+        mIsConnecting = false;
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService("imms", new BinderService());
+    }
+
+    public void systemRunning() {
+        tryConnecting();
+    }
+
+    private void tryConnecting() {
+        Slog.i(TAG, "Connecting to MmsService");
+        synchronized (this) {
+            if (mIsConnecting) {
+                Slog.d(TAG, "Already connecting");
+                return;
+            }
+            final Intent intent = new Intent();
+            intent.setComponent(MMS_SERVICE_COMPONENT);
+            try {
+                if (mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+                    mIsConnecting = true;
+                } else {
+                    Slog.e(TAG, "Failed to connect to MmsService");
+                }
+            } catch (SecurityException e) {
+                Slog.e(TAG, "Forbidden to connect to MmsService", e);
+            }
+        }
+    }
+
+    private void ensureService() {
+        if (mService == null) {
+            // Service instance lost, kicking off the connection again
+            mConnectionHandler.sendMessage(mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
+            throw new RuntimeException("MMS service is not connected");
+        }
+    }
+
+    /**
+     * Making sure when we obtain the mService instance it is always valid.
+     * Throws {@link RuntimeException} when it is empty.
+     */
+    private IMms getServiceGuarded() {
+        ensureService();
+        return mService;
+    }
+
+    private AppOpsManager getAppOpsManager() {
+        if (mAppOpsManager == null) {
+            mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        }
+        return mAppOpsManager;
+    }
+
+    private PackageManager getPackageManager() {
+        if (mPackageManager == null) {
+            mPackageManager = mContext.getPackageManager();
+        }
+        return mPackageManager;
+    }
+
+    private TelephonyManager getTelephonyManager() {
+        if (mTelephonyManager == null) {
+            mTelephonyManager = (TelephonyManager) mContext.getSystemService(
+                    Context.TELEPHONY_SERVICE);
+        }
+        return mTelephonyManager;
+    }
+
+    /*
+     * Throws a security exception unless the caller has carrier privilege.
+     */
+    private void enforceCarrierPrivilege() {
+        String[] packages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
+        for (String pkg : packages) {
+            if (getTelephonyManager().checkCarrierPrivilegesForPackage(pkg) ==
+                    TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                return;
+            }
+        }
+        throw new SecurityException("No carrier privilege");
+    }
+
+    // Service API calls implementation, proxied to the real MmsService in "com.android.mms.service"
+    private final class BinderService extends IMms.Stub {
+        @Override
+        public void sendMessage(long subId, String callingPkg, byte[] pdu, String locationUrl,
+                PendingIntent sentIntent) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
+            getServiceGuarded().sendMessage(subId, callingPkg, pdu, locationUrl, sentIntent);
+        }
+
+        @Override
+        public void downloadMessage(long subId, String callingPkg, String locationUrl,
+                PendingIntent downloadedIntent) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
+                    "Download MMS message");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_RECEIVE_MMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
+            getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, downloadedIntent);
+        }
+
+        @Override
+        public void updateMmsSendStatus(int messageRef, boolean success) throws RemoteException {
+            enforceCarrierPrivilege();
+            getServiceGuarded().updateMmsSendStatus(messageRef, success);
+        }
+
+        @Override
+        public void updateMmsDownloadStatus(int messageRef, byte[] pdu) throws RemoteException {
+            enforceCarrierPrivilege();
+            getServiceGuarded().updateMmsDownloadStatus(messageRef, pdu);
+        }
+
+        @Override
+        public boolean getCarrierConfigBoolean(String name, boolean defaultValue)
+                throws RemoteException {
+            return getServiceGuarded().getCarrierConfigBoolean(name, defaultValue);
+        }
+
+        @Override
+        public int getCarrierConfigInt(String name, int defaultValue) throws RemoteException {
+            return getServiceGuarded().getCarrierConfigInt(name, defaultValue);
+        }
+
+        @Override
+        public String getCarrierConfigString(String name, String defaultValue)
+                throws RemoteException {
+            return getServiceGuarded().getCarrierConfigString(name, defaultValue);
+        }
+
+        @Override
+        public void setCarrierConfigBoolean(String callingPkg, String name, boolean value)
+                throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Set MMS config");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
+            getServiceGuarded().setCarrierConfigBoolean(callingPkg, name, value);
+        }
+
+        @Override
+        public void setCarrierConfigInt(String callingPkg, String name, int value)
+                throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Set MMS config");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
+            getServiceGuarded().setCarrierConfigInt(callingPkg, name, value);
+        }
+
+        @Override
+        public void setCarrierConfigString(String callingPkg, String name, String value)
+                throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Set MMS config");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
+            getServiceGuarded().setCarrierConfigString(callingPkg, name, value);
+        }
+
+        @Override
+        public Uri importTextMessage(String callingPkg, String address, int type, String text,
+                long timestampMillis, boolean seen, boolean read) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import SMS message");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return null;
+            }
+            return getServiceGuarded().importTextMessage(
+                    callingPkg, address, type, text, timestampMillis, seen, read);
+        }
+
+        @Override
+        public Uri importMultimediaMessage(String callingPkg, byte[] pdu, String messageId,
+                long timestampSecs, boolean seen, boolean read) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import MMS message");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return null;
+            }
+            return getServiceGuarded().importMultimediaMessage(
+                    callingPkg, pdu, messageId, timestampSecs, seen, read);
+        }
+
+        @Override
+        public boolean deleteStoredMessage(String callingPkg, Uri messageUri)
+                throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
+                    "Delete SMS/MMS message");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return false;
+            }
+            return getServiceGuarded().deleteStoredMessage(callingPkg, messageUri);
+        }
+
+        @Override
+        public boolean deleteStoredConversation(String callingPkg, long conversationId)
+                throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Delete conversation");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return false;
+            }
+            return getServiceGuarded().deleteStoredConversation(callingPkg, conversationId);
+        }
+
+        @Override
+        public boolean updateStoredMessageStatus(String callingPkg, Uri messageUri,
+                ContentValues statusValues) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
+                    "Update SMS/MMS message");
+            return getServiceGuarded()
+                    .updateStoredMessageStatus(callingPkg, messageUri, statusValues);
+        }
+
+        @Override
+        public Uri addTextMessageDraft(String callingPkg, String address, String text)
+                throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add SMS draft");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return null;
+            }
+            return getServiceGuarded().addTextMessageDraft(callingPkg, address, text);
+        }
+
+        @Override
+        public Uri addMultimediaMessageDraft(String callingPkg, byte[] pdu) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add MMS draft");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return null;
+            }
+            return getServiceGuarded().addMultimediaMessageDraft(callingPkg, pdu);
+        }
+
+        @Override
+        public void sendStoredMessage(long subId, String callingPkg, Uri messageUri,
+                PendingIntent sentIntent) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.SEND_SMS,
+                    "Send stored MMS message");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
+            getServiceGuarded().sendStoredMessage(subId, callingPkg, messageUri, sentIntent);
+        }
+
+        @Override
+        public void setAutoPersisting(String callingPkg, boolean enabled) throws RemoteException {
+            mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Set auto persist");
+            if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
+                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                return;
+            }
+            getServiceGuarded().setAutoPersisting(callingPkg, enabled);
+        }
+
+        @Override
+        public boolean getAutoPersisting() throws RemoteException {
+            return getServiceGuarded().getAutoPersisting();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 538501b..3e2f260 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -27,6 +27,7 @@
 import android.net.NetworkScorerAppManager;
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.net.ScoredNetwork;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.Log;
@@ -131,17 +132,44 @@
     @Override
     public boolean setActiveScorer(String packageName) {
         mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
-        // Preemptively clear scores even though the set operation could fail. We do this for safety
-        // as scores should never be compared across apps; in practice, Settings should only be
-        // allowing valid apps to be set as scorers, so failure here should be rare.
-        clearInternal();
-        boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
-        if (result) {
-            Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
-            intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
-            mContext.sendBroadcast(intent);
+        return setScorerInternal(packageName);
+    }
+
+    @Override
+    public void disableScoring() {
+        // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETOWRKS) should
+        // be allowed to disable scoring.
+        if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
+                mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) ==
+                        PackageManager.PERMISSION_GRANTED) {
+            // The return value is discarded here because at this point, the call should always
+            // succeed. The only reason for failure is if the new package is not a valid scorer, but
+            // we're disabling scoring altogether here.
+            setScorerInternal(null /* packageName */);
+        } else {
+            throw new SecurityException(
+                    "Caller is neither the active scorer nor the scorer manager.");
         }
-        return result;
+    }
+
+    /** Set the active scorer. Callers are responsible for checking permissions as appropriate. */
+    private boolean setScorerInternal(String packageName) {
+        long token = Binder.clearCallingIdentity();
+        try {
+            // Preemptively clear scores even though the set operation could fail. We do this for
+            // safety as scores should never be compared across apps; in practice, Settings should
+            // only be allowing valid apps to be set as scorers, so failure here should be rare.
+            clearInternal();
+            boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
+            if (result) {
+                Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
+                intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
+                mContext.sendBroadcast(intent);
+            }
+            return result;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     /** Clear scores. Callers are responsible for checking permissions as appropriate. */
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d7b2a98..cfdf7cf 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3698,7 +3698,7 @@
                 // specified, then replace it with the existing recent task.
                 task = tr;
             }
-            mTaskPersister.notify(tr, false);
+            notifyTaskPersisterLocked(tr, false);
         }
         if (N >= MAX_RECENT_TASKS) {
             final TaskRecord tr = mRecentTasks.remove(N - 1);
@@ -7646,7 +7646,7 @@
             tr.removeTaskActivitiesLocked();
             cleanUpRemovedTaskLocked(tr, flags);
             if (tr.isPersistable) {
-                notifyTaskPersisterLocked(tr, true);
+                notifyTaskPersisterLocked(null, true);
             }
             return true;
         }
@@ -9089,7 +9089,11 @@
     }
 
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
-        mTaskPersister.notify(task, flush);
+        if (task != null && task.stack != null && task.stack.isHomeStack()) {
+            // Never persist the home stack.
+            return;
+        }
+        mTaskPersister.wakeup(task, flush);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 38eef208..0180db3 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -39,15 +39,17 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
-import java.util.LinkedList;
 
 public class TaskPersister {
     static final String TAG = "TaskPersister";
     static final boolean DEBUG = false;
 
-    /** When in slow mode don't write tasks out faster than this */
-    private static final long INTER_TASK_DELAY_MS = 10000;
-    private static final long DEBUG_INTER_TASK_DELAY_MS = 5000;
+    /** When not flushing don't write out files faster than this */
+    private static final long INTER_WRITE_DELAY_MS = 500;
+
+    /** When not flushing delay this long before writing the first file out. This gives the next
+     * task being launched a chance to load its resources without this occupying IO bandwidth. */
+    private static final long PRE_TASK_DELAY_MS = 3000;
 
     private static final String RECENTS_FILENAME = "_task";
     private static final String TASKS_DIRNAME = "recent_tasks";
@@ -63,10 +65,34 @@
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
 
-    private boolean mRecentsChanged = false;
+    /** Value determines write delay mode as follows:
+     *    < 0 We are Flushing. No delays between writes until the image queue is drained and all
+     * tasks needing persisting are written to disk. There is no delay between writes.
+     *    == 0 We are Idle. Next writes will be delayed by #PRE_TASK_DELAY_MS.
+     *    > 0 We are Actively writing. Next write will be at this time. Subsequent writes will be
+     * delayed by #INTER_WRITE_DELAY_MS. */
+    private long mNextWriteTime = 0;
 
     private final LazyTaskWriterThread mLazyTaskWriterThread;
 
+    private static class WriteQueueItem {}
+    private static class TaskWriteQueueItem extends WriteQueueItem {
+        final TaskRecord mTask;
+        TaskWriteQueueItem(TaskRecord task) {
+            mTask = task;
+        }
+    }
+    private static class ImageWriteQueueItem extends WriteQueueItem {
+        final String mFilename;
+        Bitmap mImage;
+        ImageWriteQueueItem(String filename, Bitmap image) {
+            mFilename = filename;
+            mImage = image;
+        }
+    }
+
+    ArrayList<WriteQueueItem> mWriteQueue = new ArrayList<WriteQueueItem>();
+
     TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor) {
         sTasksDir = new File(systemDir, TASKS_DIRNAME);
         if (!sTasksDir.exists()) {
@@ -94,19 +120,77 @@
         mLazyTaskWriterThread.start();
     }
 
-    public void notify(TaskRecord task, boolean flush) {
-        if (DEBUG) Slog.d(TAG, "notify: task=" + task + " flush=" + flush +
-                " Callers=" + Debug.getCallers(4));
-        if (task != null) {
-            task.needsPersisting = true;
-        }
+    void wakeup(TaskRecord task, boolean flush) {
         synchronized (this) {
-            mLazyTaskWriterThread.mSlow = !flush;
-            mRecentsChanged = true;
+            if (task != null) {
+                int queueNdx;
+                for (queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
+                    final WriteQueueItem item = mWriteQueue.get(queueNdx);
+                    if (item instanceof TaskWriteQueueItem &&
+                            ((TaskWriteQueueItem) item).mTask == task) {
+                        break;
+                    }
+                }
+                if (queueNdx < 0) {
+                    mWriteQueue.add(new TaskWriteQueueItem(task));
+                }
+            } else {
+                // Dummy.
+                mWriteQueue.add(new WriteQueueItem());
+            }
+            if (flush) {
+                mNextWriteTime = -1;
+            } else if (mNextWriteTime == 0) {
+                mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
+            }
+            if (DEBUG) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush + " mNextWriteTime="
+                    + mNextWriteTime + " Callers=" + Debug.getCallers(4));
             notifyAll();
         }
     }
 
+    void saveImage(Bitmap image, String filename) {
+        synchronized (this) {
+            int queueNdx;
+            for (queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
+                final WriteQueueItem item = mWriteQueue.get(queueNdx);
+                if (item instanceof ImageWriteQueueItem) {
+                    ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
+                    if (imageWriteQueueItem.mFilename.equals(filename)) {
+                        // replace the Bitmap with the new one.
+                        imageWriteQueueItem.mImage = image;
+                        break;
+                    }
+                }
+            }
+            if (queueNdx < 0) {
+                mWriteQueue.add(new ImageWriteQueueItem(filename, image));
+            }
+            if (mNextWriteTime == 0) {
+                mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
+            }
+            if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
+                    SystemClock.uptimeMillis() + " mNextWriteTime=" +
+                    mNextWriteTime + " Callers=" + Debug.getCallers(4));
+            notifyAll();
+        }
+    }
+
+    Bitmap getThumbnail(String filename) {
+        synchronized (this) {
+            for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
+                final WriteQueueItem item = mWriteQueue.get(queueNdx);
+                if (item instanceof ImageWriteQueueItem) {
+                    ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
+                    if (imageWriteQueueItem.mFilename.equals(filename)) {
+                        return imageWriteQueueItem.mImage;
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
     private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException {
         if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
         final XmlSerializer xmlSerializer = new FastXmlSerializer();
@@ -129,10 +213,6 @@
         return stringWriter;
     }
 
-    void saveImage(Bitmap image, String filename) {
-        mLazyTaskWriterThread.saveImage(image, filename);
-    }
-
     private String fileToString(File file) {
         final String newline = System.lineSeparator();
         try {
@@ -197,7 +277,7 @@
                                     task);
                             if (task != null) {
                                 task.isPersistable = true;
-                                task.needsPersisting = true;
+                                mWriteQueue.add(new TaskWriteQueueItem(task));
                                 tasks.add(task);
                                 final int taskId = task.taskId;
                                 recoveredTaskIds.add(taskId);
@@ -262,6 +342,8 @@
     }
 
     private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
+        if (DEBUG) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds=" + persistentTaskIds +
+                " files=" + files);
         for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
             File file = files[fileNdx];
             String filename = file.getName();
@@ -270,6 +352,7 @@
                 final int taskId;
                 try {
                     taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
+                    if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId);
                 } catch (Exception e) {
                     Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName());
                     file.delete();
@@ -295,63 +378,89 @@
     }
 
     private class LazyTaskWriterThread extends Thread {
-        boolean mSlow = true;
-        LinkedList<BitmapQueueEntry> mSaveImagesQueue = new LinkedList<BitmapQueueEntry>();
 
         LazyTaskWriterThread(String name) {
             super(name);
         }
 
-        class BitmapQueueEntry {
-            final Bitmap mImage;
-            final String mFilename;
-            BitmapQueueEntry(Bitmap image, String filename) {
-                mImage = image;
-                mFilename = filename;
-            }
-        }
-
-        void saveImage(Bitmap image, String filename) {
-            synchronized (mSaveImagesQueue) {
-                mSaveImagesQueue.add(new BitmapQueueEntry(image, filename));
-            }
-            TaskPersister.this.notify(null, false);
-        }
-
         @Override
         public void run() {
             ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>();
             while (true) {
-                // If mSlow, then delay between each call to saveToXml().
+                // We can't lock mService while holding TaskPersister.this, but we don't want to
+                // call removeObsoleteFiles every time through the loop, only the last time before
+                // going to sleep. The risk is that we call removeObsoleteFiles() successively.
+                final boolean probablyDone;
                 synchronized (TaskPersister.this) {
+                    probablyDone = mWriteQueue.isEmpty();
+                }
+                if (probablyDone) {
+                    if (DEBUG) Slog.d(TAG, "Looking for obsolete files.");
+                    persistentTaskIds.clear();
+                    synchronized (mService) {
+                        final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
+                        if (DEBUG) Slog.d(TAG, "mRecents=" + tasks);
+                        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                            final TaskRecord task = tasks.get(taskNdx);
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
+                                    task.isPersistable);
+                            if (task.isPersistable && !task.stack.isHomeStack()) {
+                                if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
+                                persistentTaskIds.add(task.taskId);
+                            } else {
+                                if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task);
+                            }
+                        }
+                    }
+                    removeObsoleteFiles(persistentTaskIds);
+                }
+
+                // If mNextWriteTime, then don't delay between each call to saveToXml().
+                final WriteQueueItem item;
+                synchronized (TaskPersister.this) {
+                    if (mNextWriteTime >= 0) {
+                        // The next write we don't have to wait so long.
+                        mNextWriteTime = SystemClock.uptimeMillis() + INTER_WRITE_DELAY_MS;
+                        if (DEBUG) Slog.d(TAG, "Next write time may be in " +
+                                INTER_WRITE_DELAY_MS + " msec. (" + mNextWriteTime + ")");
+                    }
+
+                    while (mWriteQueue.isEmpty()) {
+                        mNextWriteTime = 0; // idle.
+                        try {
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting indefinitely.");
+                            TaskPersister.this.wait();
+                        } catch (InterruptedException e) {
+                        }
+                        // Invariant: mNextWriteTime is either -1 or PRE_WRITE_DELAY_MS from now.
+                    }
+                    item = mWriteQueue.remove(0);
+
                     long now = SystemClock.uptimeMillis();
-                    final long releaseTime =
-                            now + (DEBUG ? DEBUG_INTER_TASK_DELAY_MS: INTER_TASK_DELAY_MS);
-                    while (mSlow && now < releaseTime) {
+                    if (DEBUG) Slog.d(TAG, "LazyTaskWriter: now=" + now + " mNextWriteTime=" +
+                            mNextWriteTime);
+                    while (now < mNextWriteTime) {
                         try {
                             if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting " +
-                                    (releaseTime - now));
-                            TaskPersister.this.wait(releaseTime - now);
+                                    (mNextWriteTime - now));
+                            TaskPersister.this.wait(mNextWriteTime - now);
                         } catch (InterruptedException e) {
                         }
                         now = SystemClock.uptimeMillis();
                     }
+
+                    // Got something to do.
                 }
 
-                // Write out one bitmap that needs saving each time through.
-                BitmapQueueEntry entry;
-                synchronized (mSaveImagesQueue) {
-                    entry = mSaveImagesQueue.poll();
-                    // Are there any more after this one?
-                    mRecentsChanged |= !mSaveImagesQueue.isEmpty();
-                }
-                if (entry != null) {
-                    final String filename = entry.mFilename;
-                    if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename);
+                if (item instanceof ImageWriteQueueItem) {
+                    ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
+                    final String filename = imageWriteQueueItem.mFilename;
+                    final Bitmap bitmap = imageWriteQueueItem.mImage;
+                    if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filename);
                     FileOutputStream imageFile = null;
                     try {
                         imageFile = new FileOutputStream(new File(sImagesDir, filename));
-                        entry.mImage.compress(Bitmap.CompressFormat.PNG, 100, imageFile);
+                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, imageFile);
                     } catch (Exception e) {
                         Slog.e(TAG, "saveImage: unable to save " + filename, e);
                     } finally {
@@ -362,79 +471,42 @@
                             }
                         }
                     }
-                }
-
-                StringWriter stringWriter = null;
-                TaskRecord task = null;
-                synchronized(mService) {
-                    final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
-                    persistentTaskIds.clear();
-                    if (DEBUG) Slog.d(TAG, "mRecents=" + tasks);
-                    for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                        task = tasks.get(taskNdx);
-                        if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
-                                task.isPersistable + " needsPersisting=" + task.needsPersisting);
-                        if (task.isPersistable && !task.stack.isHomeStack()) {
-                            if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
-                            persistentTaskIds.add(task.taskId);
-
-                            if (task.needsPersisting) {
-                                try {
-                                    if (DEBUG) Slog.d(TAG, "Saving task=" + task);
-                                    stringWriter = saveToXml(task);
-                                    break;
-                                } catch (IOException e) {
-                                } catch (XmlPullParserException e) {
-                                } finally {
-                                    task.needsPersisting = false;
-                                }
-                            }
-                        } else {
-                            if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task);
-                        }
-                    }
-                }
-
-                if (stringWriter != null) {
-                    // Write out xml file while not holding mService lock.
-                    FileOutputStream file = null;
-                    AtomicFile atomicFile = null;
-                    try {
-                        atomicFile = new AtomicFile(new File(sTasksDir,
-                                String.valueOf(task.taskId) + RECENTS_FILENAME + TASK_EXTENSION));
-                        file = atomicFile.startWrite();
-                        file.write(stringWriter.toString().getBytes());
-                        file.write('\n');
-                        atomicFile.finishWrite(file);
-                    } catch (IOException e) {
-                        if (file != null) {
-                            atomicFile.failWrite(file);
-                        }
-                        Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " + e);
-                    }
-                } else {
-                    // Made it through the entire list and didn't find anything new that needed
-                    // persisting.
-                    if (!DEBUG) {
-                        if (DEBUG) Slog.d(TAG, "Calling removeObsoleteFiles persistentTaskIds=" +
-                                persistentTaskIds);
-                        removeObsoleteFiles(persistentTaskIds);
-                    }
-
-                    // Wait here for someone to call setRecentsChanged().
-                    synchronized (TaskPersister.this) {
-                        while (!mRecentsChanged) {
-                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: Waiting.");
+                } else if (item instanceof TaskWriteQueueItem) {
+                    // Write out one task.
+                    StringWriter stringWriter = null;
+                    TaskRecord task = ((TaskWriteQueueItem) item).mTask;
+                    if (DEBUG) Slog.d(TAG, "Writing task=" + task);
+                    synchronized (mService) {
+                        if (mService.mRecentTasks.contains(task)) {
+                            // Still there.
                             try {
-                                TaskPersister.this.wait();
-                            } catch (InterruptedException e) {
+                                if (DEBUG) Slog.d(TAG, "Saving task=" + task);
+                                stringWriter = saveToXml(task);
+                            } catch (IOException e) {
+                            } catch (XmlPullParserException e) {
                             }
                         }
-                        mRecentsChanged = false;
-                        if (DEBUG) Slog.d(TAG, "LazyTaskWriter: Awake");
+                        if (stringWriter != null) {
+                            // Write out xml file while not holding mService lock.
+                            FileOutputStream file = null;
+                            AtomicFile atomicFile = null;
+                            try {
+                                atomicFile = new AtomicFile(new File(sTasksDir, String.valueOf(
+                                        task.taskId) + RECENTS_FILENAME + TASK_EXTENSION));
+                                file = atomicFile.startWrite();
+                                file.write(stringWriter.toString().getBytes());
+                                file.write('\n');
+                                atomicFile.finishWrite(file);
+                            } catch (IOException e) {
+                                if (file != null) {
+                                    atomicFile.failWrite(file);
+                                }
+                                Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " +
+                                        e);
+                            }
+                        }
                     }
                 }
-                // Some recents file needs to be written.
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index d6f922f..4a84941 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -122,9 +122,6 @@
      * (positive) or back (negative). Absolute value indicates time. */
     long mLastTimeMoved = System.currentTimeMillis();
 
-    /** True if persistable, has changed, and has not yet been persisted */
-    boolean needsPersisting = false;
-
     /** Indication of what to run next when task exits. Use ActivityRecord types.
      * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
      * task stack. */
@@ -362,6 +359,9 @@
     void getLastThumbnail(TaskThumbnail thumbs) {
         thumbs.mainThumbnail = mLastThumbnail;
         thumbs.thumbnailFileDescriptor = null;
+        if (mLastThumbnail == null) {
+            thumbs.mainThumbnail = mService.mTaskPersister.getThumbnail(mFilename);
+        }
         if (mLastThumbnailFile.exists()) {
             try {
                 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 40eb3e44..c16be50 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -20,13 +20,13 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.SystemProperties;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -53,6 +53,9 @@
         int logicalAddress;
         int physicalAddress;
 
+        public ActiveSource() {
+            invalidate();
+        }
         public ActiveSource(int logical, int physical) {
             logicalAddress = logical;
             physicalAddress = physical;
@@ -63,6 +66,10 @@
         public boolean isValid() {
             return HdmiUtils.isValidAddress(logicalAddress);
         }
+        public void invalidate() {
+            logicalAddress = Constants.ADDR_INVALID;
+            physicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
+        }
         public boolean equals(int logical, int physical) {
             return logicalAddress == logical && physicalAddress == physical;
         }
@@ -82,8 +89,7 @@
     }
     // Logical address of the active source.
     @GuardedBy("mLock")
-    protected final ActiveSource mActiveSource =
-            new ActiveSource(-1, Constants.INVALID_PHYSICAL_ADDRESS);
+    protected final ActiveSource mActiveSource = new ActiveSource();
 
     // Active routing path. Physical address of the active source but not all the time, such as
     // when the new active source does not claim itself to be one. Note that we don't keep
@@ -505,9 +511,12 @@
     @ServiceThreadOnly
     <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
         assertRunOnServiceThread();
-        ArrayList<T> actions = new ArrayList<>();
+        List<T> actions = Collections.<T>emptyList();
         for (FeatureAction action : mActions) {
             if (action.getClass().equals(clazz)) {
+                if (actions.isEmpty()) {
+                    actions = new ArrayList<T>();
+                }
                 actions.add((T) action);
             }
         }
@@ -552,7 +561,10 @@
 
     protected void checkIfPendingActionsCleared() {
         if (mActions.isEmpty() && mPendingActionClearedCallback != null) {
-            mPendingActionClearedCallback.onCleared(this);
+            PendingActionClearedCallback callback = mPendingActionClearedCallback;
+            // To prevent from calling the callback again during handling the callback itself.
+            mPendingActionClearedCallback = null;
+            callback.onCleared(this);
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index f93d20f..9038fbc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -234,10 +234,10 @@
     void updateActiveInput(int path, boolean notifyInputChange) {
         assertRunOnServiceThread();
         // Seq #15
-        int portId = mService.pathToPortId(path);
-        if (portId == getActivePortId()) {
+        if (path == getActivePath()) {
             return;
         }
+        int portId = mService.pathToPortId(path);
         setActivePath(path);
         setPrevPortId(portId);
         // TODO: Handle PAP/PIP case.
@@ -265,7 +265,7 @@
             invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
             return;
         }
-        setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+        mActiveSource.invalidate();
         if (!mService.isControlEnabled()) {
             setActivePortId(portId);
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
@@ -480,9 +480,9 @@
         byte[] params = message.getParams();
         int currentPath = HdmiUtils.twoBytesToInt(params);
         if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) {
-            int newPath = HdmiUtils.twoBytesToInt(params, 2);
-            setActivePath(newPath);
+            mActiveSource.invalidate();
             removeAction(RoutingControlAction.class);
+            int newPath = HdmiUtils.twoBytesToInt(params, 2);
             addAndStartAction(new RoutingControlAction(this, newPath, true, null));
         }
         return true;
@@ -1249,18 +1249,6 @@
         }
     }
 
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleStandby(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        // Seq #12
-        // Tv accepts directly addressed <Standby> only.
-        if (message.getDestination() == mAddress) {
-            super.handleStandby(message);
-        }
-        return false;
-    }
-
     boolean isProhibitMode() {
         return mService.isProhibitMode();
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 2272283..390d121 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -200,10 +200,10 @@
     private List<HdmiPortInfo> mPortInfo;
 
     // Map from path(physical address) to port ID.
-    private SparseIntArray mPortIdMap = new SparseIntArray();
+    private final SparseIntArray mPortIdMap = new SparseIntArray();
 
     // Map from port ID to HdmiPortInfo.
-    private SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>();
+    private final SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>();
 
     private HdmiCecMessageValidator mMessageValidator;
 
@@ -1414,8 +1414,8 @@
                 Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType);
                 devices.remove(device);
                 if (devices.isEmpty()) {
-                    clearLocalDevices();
                     onStandbyCompleted();
+                    clearLocalDevices();
                 }
             }
         });
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 65e617b..077d16f 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -20,6 +20,7 @@
 import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
 
 import android.content.Context;
+import android.content.Intent;
 import android.hardware.hdmi.HdmiCecDeviceInfo;
 import android.hardware.hdmi.HdmiHotplugEvent;
 import android.hardware.hdmi.IHdmiControlService;
@@ -34,6 +35,7 @@
 import android.media.tv.ITvInputHardware;
 import android.media.tv.ITvInputHardwareCallback;
 import android.media.tv.TvInputHardwareInfo;
+import android.media.tv.TvContract;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvStreamConfig;
 import android.os.Handler;
@@ -759,8 +761,21 @@
     private final class HdmiInputChangeListener extends IHdmiInputChangeListener.Stub {
         @Override
         public void onChanged(HdmiCecDeviceInfo device) throws RemoteException {
-            // TODO: Build a channel Uri for the TvInputInfo associated with the logical device
-            //       and send an intent to TV app
+            String inputId;
+            synchronized (mLock) {
+                if (device.isCecDevice()) {
+                    inputId = mHdmiCecInputIdMap.get(device.getLogicalAddress());
+                } else {
+                    inputId = findInputIdForHdmiPortLocked(device.getPortId());
+                }
+            }
+            if (inputId != null) {
+                Intent intent = new Intent(Intent.ACTION_VIEW);
+                intent.setData(TvContract.buildChannelUriForPassthroughTvInput(inputId));
+                mContext.startActivity(intent);
+            } else {
+                Slog.w(TAG, "onChanged: InputId cannot be found for :" + device);
+            }
         }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index f1284d80..4b60c9f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -17,6 +17,7 @@
 package com.android.server.devicepolicy;
 
 import android.app.AppGlobals;
+import android.content.ComponentName;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -53,6 +54,7 @@
     private static final String TAG_PROFILE_OWNER = "profile-owner";
     private static final String ATTR_NAME = "name";
     private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_COMPONENT_NAME = "component";
     private static final String ATTR_USERID = "userId";
 
     private AtomicFile fileForWriting;
@@ -100,6 +102,7 @@
     }
 
     /**
+     * @deprecated Use a component name instead of package name
      * Creates an instance of the device owner object with the profile owner set.
      */
     static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
@@ -108,6 +111,15 @@
         return owner;
     }
 
+    /**
+     * Creates an instance of the device owner object with the profile owner set.
+     */
+    static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
+        DeviceOwner owner = new DeviceOwner();
+        owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
+        return owner;
+    }
+
     String getDeviceOwnerPackageName() {
         return mDeviceOwner != null ? mDeviceOwner.packageName : null;
     }
@@ -124,19 +136,36 @@
         mDeviceOwner = null;
     }
 
+    /**
+     * @deprecated
+     */
     void setProfileOwner(String packageName, String ownerName, int userId) {
         mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName));
     }
 
+    void setProfileOwner(ComponentName admin, String ownerName, int userId) {
+        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
+    }
+
     void removeProfileOwner(int userId) {
         mProfileOwners.remove(userId);
     }
 
+    /**
+     * @deprecated Use getProfileOwnerComponent
+     * @param userId
+     * @return
+     */
     String getProfileOwnerPackageName(int userId) {
         OwnerInfo profileOwner = mProfileOwners.get(userId);
         return profileOwner != null ? profileOwner.packageName : null;
     }
 
+    ComponentName getProfileOwnerComponent(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.admin : null;
+    }
+
     String getProfileOwnerName(int userId) {
         OwnerInfo profileOwner = mProfileOwners.get(userId);
         return profileOwner != null ? profileOwner.name : null;
@@ -191,15 +220,23 @@
 
                 String tag = parser.getName();
                 if (tag.equals(TAG_DEVICE_OWNER)) {
-                    mDeviceOwner = new OwnerInfo(
-                            parser.getAttributeValue(null, ATTR_NAME),
-                            parser.getAttributeValue(null, ATTR_PACKAGE));
+                    String name = parser.getAttributeValue(null, ATTR_NAME);
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    mDeviceOwner = new OwnerInfo(name, packageName);
                 } else if (tag.equals(TAG_PROFILE_OWNER)) {
                     String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                    String profileOwnerComponentStr =
+                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
                     int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
-                    mProfileOwners.put(userId,
-                            new OwnerInfo(profileOwnerName, profileOwnerPackageName));
+                    OwnerInfo profileOwnerInfo;
+                    if (profileOwnerComponentStr != null) {
+                        profileOwnerInfo = new OwnerInfo(profileOwnerName,
+                                ComponentName.unflattenFromString(profileOwnerComponentStr));
+                    } else {
+                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
+                    }
+                    mProfileOwners.put(userId, profileOwnerInfo);
                 } else {
                     throw new XmlPullParserException(
                             "Unexpected tag in device owner file: " + tag);
@@ -230,9 +267,6 @@
             if (mDeviceOwner != null) {
                 out.startTag(null, TAG_DEVICE_OWNER);
                 out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
-                if (mDeviceOwner.packageName != null) {
-                    out.attribute(null, ATTR_NAME, mDeviceOwner.packageName);
-                }
                 out.endTag(null, TAG_DEVICE_OWNER);
             }
 
@@ -240,9 +274,13 @@
             if (mProfileOwners.size() > 0) {
                 for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
                     out.startTag(null, TAG_PROFILE_OWNER);
-                    out.attribute(null, ATTR_PACKAGE, owner.getValue().packageName);
-                    out.attribute(null, ATTR_NAME, owner.getValue().name);
+                    OwnerInfo ownerInfo = owner.getValue();
+                    out.attribute(null, ATTR_PACKAGE, ownerInfo.packageName);
+                    out.attribute(null, ATTR_NAME, ownerInfo.name);
                     out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
+                    if (ownerInfo.admin != null) {
+                        out.attribute(null, ATTR_COMPONENT_NAME, ownerInfo.admin.flattenToString());
+                    }
                     out.endTag(null, TAG_PROFILE_OWNER);
                 }
             }
@@ -282,10 +320,18 @@
     static class OwnerInfo {
         public String name;
         public String packageName;
+        public ComponentName admin;
 
         public OwnerInfo(String name, String packageName) {
             this.name = name;
             this.packageName = packageName;
+            this.admin = new ComponentName(packageName, "");
+        }
+
+        public OwnerInfo(String name, ComponentName admin) {
+            this.name = name;
+            this.admin = admin;
+            this.packageName = admin.getPackageName();
         }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f49451e..15bea5a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -905,7 +905,8 @@
         for (ActiveAdmin admin : candidates) {
             boolean ownsDevice = isDeviceOwner(admin.info.getPackageName());
             boolean ownsProfile = (getProfileOwner(userHandle) != null
-                    && getProfileOwner(userHandle).equals(admin.info.getPackageName()));
+                    && getProfileOwner(userHandle).getPackageName()
+                        .equals(admin.info.getPackageName()));
 
             if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
                 if (ownsDevice) {
@@ -3310,7 +3311,7 @@
     }
 
     @Override
-    public boolean setProfileOwner(String packageName, String ownerName, int userHandle) {
+    public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
         if (!mHasFeature) {
             return false;
         }
@@ -3322,26 +3323,28 @@
                     "Attempted to set profile owner for invalid userId: " + userHandle);
         }
 
-        if (packageName == null
-                || !DeviceOwner.isInstalledForUser(packageName, userHandle)) {
-            throw new IllegalArgumentException("Package name " + packageName
+        if (who == null
+                || !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) {
+            throw new IllegalArgumentException("Component " + who
                     + " not installed for userId:" + userHandle);
         }
         synchronized (this) {
-            if (isUserSetupComplete(userHandle)) {
+            // Only SYSTEM_UID can override the userSetupComplete
+            if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
+                    && isUserSetupComplete(userHandle)) {
                 throw new IllegalStateException(
                         "Trying to set profile owner but user is already set-up.");
             }
 
             if (mDeviceOwner == null) {
                 // Device owner state does not exist, create it.
-                mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
+                mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName,
                         userHandle);
                 mDeviceOwner.writeOwnerFile();
                 return true;
             } else {
                 // Device owner already exists, update it.
-                mDeviceOwner.setProfileOwner(packageName, ownerName, userHandle);
+                mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
                 mDeviceOwner.writeOwnerFile();
                 return true;
             }
@@ -3349,6 +3352,38 @@
     }
 
     @Override
+    public void clearProfileOwner(ComponentName who) {
+        if (!mHasFeature) {
+            return;
+        }
+        UserHandle callingUser = Binder.getCallingUserHandle();
+        // Check if this is the profile owner who is calling
+        getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                mUserManager.setUserRestrictions(new Bundle(), callingUser);
+                if (mDeviceOwner != null) {
+                    mDeviceOwner.removeProfileOwner(callingUser.getIdentifier());
+                    mDeviceOwner.writeOwnerFile();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
+    public boolean hasUserSetupCompleted() {
+        if (!mHasFeature) {
+            return true;
+        }
+        DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+        // If policy is null, return true, else check if the setup has completed.
+        return policy == null || policy.mUserSetupComplete;
+    }
+
+    @Override
     public void setProfileEnabled(ComponentName who) {
         if (!mHasFeature) {
             return;
@@ -3397,14 +3432,14 @@
     }
 
     @Override
-    public String getProfileOwner(int userHandle) {
+    public ComponentName getProfileOwner(int userHandle) {
         if (!mHasFeature) {
             return null;
         }
 
         synchronized (this) {
             if (mDeviceOwner != null) {
-                return mDeviceOwner.getProfileOwnerPackageName(userHandle);
+                return mDeviceOwner.getProfileOwnerComponent(userHandle);
             }
         }
         return null;
@@ -3413,8 +3448,9 @@
     // Returns the active profile owner for this user or null if the current user has no
     // profile owner.
     private ActiveAdmin getProfileOwnerAdmin(int userHandle) {
-        String profileOwnerPackage = getProfileOwner(userHandle);
-        if (profileOwnerPackage == null) {
+        ComponentName profileOwner =
+                mDeviceOwner != null ? mDeviceOwner.getProfileOwnerComponent(userHandle) : null;
+        if (profileOwner == null) {
             return null;
         }
 
@@ -3422,7 +3458,7 @@
         final int n = policy.mAdminList.size();
         for (int i = 0; i < n; i++) {
             ActiveAdmin admin = policy.mAdminList.get(i);
-            if (profileOwnerPackage.equals(admin.info.getPackageName())) {
+            if (profileOwner.equals(admin.info)) {
                 return admin;
             }
         }
@@ -3800,7 +3836,7 @@
             }
 
             setActiveAdmin(profileOwnerComponent, true, user.getIdentifier(), adminExtras);
-            setProfileOwner(profileOwnerPkg, ownerName, user.getIdentifier());
+            setProfileOwner(profileOwnerComponent, ownerName, user.getIdentifier());
             return user;
         } finally {
             restoreCallingIdentity(id);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 70266ee..d955354 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -406,6 +406,7 @@
         TelephonyRegistry telephonyRegistry = null;
         ConsumerIrService consumerIr = null;
         AudioService audioService = null;
+        MmsServiceBroker mmsService = null;
 
         boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
         boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
@@ -976,6 +977,9 @@
             VMRuntime.getRuntime().startJitCompilation();
         }
 
+        // MMS service broker
+        mmsService = mSystemServiceManager.startService(MmsServiceBroker.class);
+
         // It is now time to start up the app processes...
 
         try {
@@ -1057,6 +1061,7 @@
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
         final AudioService audioServiceF = audioService;
+        final MmsServiceBroker mmsServiceF = mmsService;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -1187,6 +1192,11 @@
                     reportWtf("Notifying MediaRouterService running", e);
                 }
 
+                try {
+                    if (mmsServiceF != null) mmsServiceF.systemRunning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying MmsService running", e);
+                }
                 mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE);
             }
         });
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 94f227c..c0e536a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -96,13 +96,6 @@
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            try {
-                if (mService != null) {
-                    mService.shutdown();
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException in shutdown", e);
-            }
             mService = null;
         }
     };
@@ -307,6 +300,14 @@
     }
 
     void shutdownLocked() {
+        try {
+            if (mService != null) {
+                mService.shutdown();
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in shutdown", e);
+        }
+
         if (mBound) {
             mContext.unbindService(mConnection);
             mBound = false;
diff --git a/telecomm/java/android/telecomm/CallCameraCapabilities.java b/telecomm/java/android/telecomm/CallCameraCapabilities.java
index 87a411a..74904e3 100644
--- a/telecomm/java/android/telecomm/CallCameraCapabilities.java
+++ b/telecomm/java/android/telecomm/CallCameraCapabilities.java
@@ -36,14 +36,28 @@
     private final float mMaxZoom;
 
     /**
+     * The width of the camera video in pixels.
+     */
+    private final int mWidth;
+
+    /**
+     * The height of the camera video in pixels.
+     */
+    private final int mHeight;
+
+    /**
      * Create a call camera capabilities instance.
      *
      * @param zoomSupported True when camera supports zoom.
      * @param maxZoom Maximum zoom supported by camera.
+     * @param width The width of the camera video (in pixels).
+     * @param height The height of the camera video (in pixels).
      */
-    public CallCameraCapabilities(boolean zoomSupported, float maxZoom) {
+    public CallCameraCapabilities(boolean zoomSupported, float maxZoom, int width, int height) {
         mZoomSupported = zoomSupported;
         mMaxZoom = maxZoom;
+        mWidth = width;
+        mHeight = height;
     }
 
     /**
@@ -61,8 +75,10 @@
                 public CallCameraCapabilities createFromParcel(Parcel source) {
                     boolean supportsZoom = source.readByte() != 0;
                     float maxZoom = source.readFloat();
+                    int width = source.readInt();
+                    int height = source.readInt();
 
-                    return new CallCameraCapabilities(supportsZoom, maxZoom);
+                    return new CallCameraCapabilities(supportsZoom, maxZoom, width, height);
                 }
 
                 @Override
@@ -94,7 +110,8 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeByte((byte) (isZoomSupported() ? 1 : 0));
         dest.writeFloat(getMaxZoom());
-
+        dest.writeInt(getWidth());
+        dest.writeInt(getHeight());
     }
 
     /**
@@ -110,4 +127,18 @@
     public float getMaxZoom() {
         return mMaxZoom;
     }
+
+    /**
+     * The width of the camera video in pixels.
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * The height of the camera video in pixels.
+     */
+    public int getHeight() {
+        return mHeight;
+    }
 }
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index fb719a3..1484021 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -121,9 +121,15 @@
         }
 
         @Override
-        public void createConnection(ConnectionRequest request, boolean isIncoming) {
-            mHandler.obtainMessage(
-                    MSG_CREATE_CONNECTION, isIncoming ? 1 : 0, 0, request).sendToTarget();
+        public void createConnection(
+                PhoneAccountHandle connectionManagerPhoneAccount,
+                ConnectionRequest request,
+                boolean isIncoming) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = connectionManagerPhoneAccount;
+            args.arg2 = request;
+            args.argi1 = isIncoming ? 1 : 0;
+            mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
         }
 
         @Override
@@ -217,9 +223,19 @@
                     mAdapter.addAdapter((IConnectionServiceAdapter) msg.obj);
                     onAdapterAttached();
                     break;
-                case MSG_CREATE_CONNECTION:
-                    createConnection((ConnectionRequest) msg.obj, msg.arg1 == 1);
+                case MSG_CREATE_CONNECTION: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        PhoneAccountHandle connectionManagerPhoneAccount =
+                                (PhoneAccountHandle) args.arg1;
+                        ConnectionRequest request = (ConnectionRequest) args.arg2;
+                        boolean isIncoming = args.argi1 == 1;
+                        createConnection(connectionManagerPhoneAccount, request, isIncoming);
+                    } finally {
+                        args.recycle();
+                    }
                     break;
+                }
                 case MSG_ABORT:
                     abort((String) msg.obj);
                     break;
@@ -428,14 +444,17 @@
      * incoming call. In either case, telecomm will cycle through a set of services and call
      * createConnection util a connection service cancels the process or completes it successfully.
      */
-    private void createConnection(final ConnectionRequest request, boolean isIncoming) {
+    private void createConnection(
+            final PhoneAccountHandle callManagerAccount,
+            final ConnectionRequest request,
+            boolean isIncoming) {
         Log.d(this, "call %s", request);
 
         final Connection createdConnection;
         if (isIncoming) {
-            createdConnection = onCreateIncomingConnection(request);
+            createdConnection = onCreateIncomingConnection(callManagerAccount, request);
         } else {
-            createdConnection = onCreateOutgoingConnection(request);
+            createdConnection = onCreateOutgoingConnection(callManagerAccount, request);
         }
 
         if (createdConnection != null) {
@@ -641,40 +660,94 @@
         });
     }
 
-    public final RemoteConnection createRemoteIncomingConnection(ConnectionRequest request) {
-        return mRemoteConnectionManager.createRemoteConnection(request, true);
-    }
-
-    public final RemoteConnection createRemoteOutgoingConnection(ConnectionRequest request) {
-        return mRemoteConnectionManager.createRemoteConnection(request, false);
+    /**
+     * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
+     * incoming request. This is used to attach to existing incoming calls.
+     *
+     * @param connectionManagerPhoneAccount See description at
+     *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+     * @param request Details about the incoming call.
+     * @return The {@code Connection} object to satisfy this call, or {@code null} to
+     *         not handle the call.
+     */
+    public final RemoteConnection createRemoteIncomingConnection(
+            PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        return mRemoteConnectionManager.createRemoteConnection(
+                connectionManagerPhoneAccount, request, true);
     }
 
     /**
-     * Returns all connections currently associated with this connection service.
+     * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
+     * outgoing request. This is used to initiate new outgoing calls.
+     *
+     * @param connectionManagerPhoneAccount See description at
+     *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+     * @param request Details about the incoming call.
+     * @return The {@code Connection} object to satisfy this call, or {@code null} to
+     *         not handle the call.
+     */
+    public final RemoteConnection createRemoteOutgoingConnection(
+            PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        return mRemoteConnectionManager.createRemoteConnection(
+                connectionManagerPhoneAccount, request, false);
+    }
+
+    /**
+     * Returns all the active {@code Connection}s for which this {@code ConnectionService}
+     * has taken responsibility.
+     *
+     * @return A collection of {@code Connection}s created by this {@code ConnectionService}.
      */
     public final Collection<Connection> getAllConnections() {
         return mConnectionById.values();
     }
 
     /**
-     * Create a Connection given an incoming request. This is used to attach to existing incoming
-     * calls.
-     * @param request Details about the incoming call.
+     * Create a {@code Connection} given an incoming request. This is used to attach to existing
+     * incoming calls.
      *
-     * @return The {@link Connection} object to satisfy this call, or {@code null} to not handle
-     * the call.
+     * @param connectionManagerPhoneAccount See description at
+     *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+     * @param request Details about the incoming call.
+     * @return The {@code Connection} object to satisfy this call, or {@code null} to
+     *         not handle the call.
      */
-    public Connection onCreateIncomingConnection(ConnectionRequest request) { return null; }
+    public Connection onCreateIncomingConnection(
+            PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        return null;
+    }
 
     /**
-     * Create a Connection given an outgoing request. This is used to initiate new outgoing calls.
-     *  @param request Details about the outgoing call.
+     * Create a {@code Connection} given an outgoing request. This is used to initiate new
+     * outgoing calls.
      *
-     * @return The {@link Connection} object to satisfy this request,
-     * or null to not handle the call.
-     *
+     * @param connectionManagerPhoneAccount The connection manager account to use for managing
+     *         this call.
+     *         <p>
+     *         If this parameter is not {@code null}, it means that this {@code ConnectionService}
+     *         has registered one or more {@code PhoneAccount}s having
+     *         {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain
+     *         one of these {@code PhoneAccount}s, while the {@code request} will contain another
+     *         (usually but not always distinct) {@code PhoneAccount} to be used for actually
+     *         making the connection.
+     *         <p>
+     *         If this parameter is {@code null}, it means that this {@code ConnectionService} is
+     *         being asked to make a direct connection. The
+     *         {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be
+     *         a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
+     *         making the connection.
+     * @param request Details about the outgoing call.
+     * @return The {@code Connection} object to satisfy this call, or the result of an invocation
+     *         of {@link Connection#getFailedConnection(int, String)} to not handle the call.
      */
-    public Connection onCreateOutgoingConnection(ConnectionRequest request) { return null; }
+    public Connection onCreateOutgoingConnection(
+            PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        return null;
+    }
 
     /**
      * Returns a new or existing conference connection when the the user elects to convert the
diff --git a/telecomm/java/android/telecomm/PhoneAccount.java b/telecomm/java/android/telecomm/PhoneAccount.java
index 1f9071e..0fea7ba 100644
--- a/telecomm/java/android/telecomm/PhoneAccount.java
+++ b/telecomm/java/android/telecomm/PhoneAccount.java
@@ -32,24 +32,24 @@
 public class PhoneAccount implements Parcelable {
 
     /**
-     * Flag indicating that this {@code PhoneAccount} can act as a call manager for
-     * traditional SIM-based telephony calls. The {@link ConnectionService} associated with this
-     * phone-account will be allowed to manage SIM-based phone calls including using its own
-     * proprietary phone-call implementation (like VoIP calling) to make calls instead of the
-     * telephony stack.
+     * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
+     * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
+     * will be allowed to manage phone calls including using its own proprietary phone-call
+     * implementation (like VoIP calling) to make calls instead of the telephony stack.
+     * <p>
      * When a user opts to place a call using the SIM-based telephony stack, the connection-service
      * associated with this phone-account will be attempted first if the user has explicitly
-     * selected it to be used as the default call-manager.
+     * selected it to be used as the default connection manager.
      * <p>
      * See {@link #getCapabilities}
      */
-    public static final int CAPABILITY_SIM_CALL_MANAGER = 0x1;
+    public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
 
     /**
      * Flag indicating that this {@code PhoneAccount} can make phone calls in place of
      * traditional SIM-based telephony calls. This account will be treated as a distinct method
      * for placing calls alongside the traditional SIM-based telephony stack. This flag is
-     * distinct from {@link #CAPABILITY_SIM_CALL_MANAGER} in that it is not allowed to manage
+     * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage
      * calls from or use the built-in telephony stack to place its calls.
      * <p>
      * See {@link #getCapabilities}
@@ -66,6 +66,11 @@
      */
     public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
 
+    /**
+     * Flag indicating that this {@code PhoneAccount} is capable of video calling.
+     */
+    public static final int CAPABILITY_VIDEO_CALLING = 0x8;
+
     private final PhoneAccountHandle mAccountHandle;
     private final Uri mHandle;
     private final String mSubscriptionNumber;
@@ -73,7 +78,6 @@
     private final int mIconResId;
     private final CharSequence mLabel;
     private final CharSequence mShortDescription;
-    private boolean mVideoCallingSupported;
 
     public PhoneAccount(
             PhoneAccountHandle account,
@@ -82,8 +86,7 @@
             int capabilities,
             int iconResId,
             CharSequence label,
-            CharSequence shortDescription,
-            boolean supportsVideoCalling) {
+            CharSequence shortDescription) {
         mAccountHandle = account;
         mHandle = handle;
         mSubscriptionNumber = subscriptionNumber;
@@ -91,7 +94,6 @@
         mIconResId = iconResId;
         mLabel = label;
         mShortDescription = shortDescription;
-        mVideoCallingSupported = supportsVideoCalling;
     }
 
     /**
@@ -189,15 +191,6 @@
         }
     }
 
-    /**
-     * Determines whether this {@code PhoneAccount} supports video calling.
-     *
-     * @return {@code true} if this {@code PhoneAccount} supports video calling.
-     */
-    public boolean isVideoCallingSupported() {
-        return mVideoCallingSupported;
-    }
-
     //
     // Parcelable implementation
     //
@@ -216,7 +209,6 @@
         out.writeInt(mIconResId);
         out.writeCharSequence(mLabel);
         out.writeCharSequence(mShortDescription);
-        out.writeInt(mVideoCallingSupported ? 1 : 0);
     }
 
     public static final Creator<PhoneAccount> CREATOR
@@ -240,6 +232,5 @@
         mIconResId = in.readInt();
         mLabel = in.readCharSequence();
         mShortDescription = in.readCharSequence();
-        mVideoCallingSupported = in.readInt() == 1;
     }
 }
diff --git a/telecomm/java/android/telecomm/RemoteConnectionManager.java b/telecomm/java/android/telecomm/RemoteConnectionManager.java
index 3ca68a2..ce8bfbd 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionManager.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionManager.java
@@ -50,6 +50,7 @@
     }
 
     public RemoteConnection createRemoteConnection(
+            PhoneAccountHandle connectionManagerPhoneAccount,
             ConnectionRequest request,
             boolean isIncoming) {
         PhoneAccountHandle accountHandle = request.getAccountHandle();
@@ -65,7 +66,8 @@
 
         RemoteConnectionService remoteService = mRemoteConnectionServices.get(componentName);
         if (remoteService != null) {
-            return remoteService.createRemoteConnection(request, isIncoming);
+            return remoteService.createRemoteConnection(
+                    connectionManagerPhoneAccount, request, isIncoming);
         }
         return null;
     }
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index e6f47d2a..501e843 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -32,8 +32,6 @@
 import com.android.internal.telecomm.IVideoCallProvider;
 import com.android.internal.telecomm.RemoteServiceCallback;
 
-import java.util.LinkedList;
-import java.util.List;
 import java.util.UUID;
 
 /**
@@ -421,7 +419,10 @@
         release();
     }
 
-    final RemoteConnection createRemoteConnection(ConnectionRequest request, boolean isIncoming) {
+    final RemoteConnection createRemoteConnection(
+            PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request,
+            boolean isIncoming) {
         if (mConnectionId == null) {
             String id = UUID.randomUUID().toString();
             ConnectionRequest newRequest = new ConnectionRequest(
@@ -433,7 +434,10 @@
                     request.getVideoState());
             mConnection = new RemoteConnection(mConnectionService, request, isIncoming);
             try {
-                mConnectionService.createConnection(newRequest, isIncoming);
+                mConnectionService.createConnection(
+                        connectionManagerPhoneAccount,
+                        newRequest,
+                        isIncoming);
                 mConnectionId = id;
             } catch (RemoteException e) {
                 mConnection = RemoteConnection.failure(DisconnectCause.ERROR_UNSPECIFIED,
diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
index 05375c9..4b05fb9 100644
--- a/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import android.telecomm.CallAudioState;
 import android.telecomm.ConnectionRequest;
+import android.telecomm.PhoneAccountHandle;
 
 import com.android.internal.telecomm.IConnectionServiceAdapter;
 
@@ -32,7 +33,10 @@
 oneway interface IConnectionService {
     void addConnectionServiceAdapter(in IConnectionServiceAdapter adapter);
 
-    void createConnection(in ConnectionRequest request, boolean isIncoming);
+    void createConnection(
+            in PhoneAccountHandle connectionManagerPhoneAccount,
+            in ConnectionRequest request,
+            boolean isIncoming);
 
     void abort(String callId);