Merge "Apply splash screen and transfer starting window to all activities"
diff --git a/api/current.txt b/api/current.txt
index 86fd650..2b34f4f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38348,6 +38348,11 @@
     field public static final java.lang.String VALUE = "value";
   }
 
+  public static final class Settings.Panel {
+    field public static final java.lang.String ACTION_INTERNET_CONNECTIVITY = "android.settings.panel.action.INTERNET_CONNECTIVITY";
+    field public static final java.lang.String ACTION_VOLUME = "android.settings.panel.action.VOLUME";
+  }
+
   public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
     ctor public Settings.Secure();
     method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index fb9d951..4278003 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2534,7 +2534,37 @@
   }
 
   public class UsbManager {
+    method public java.util.List<android.hardware.usb.UsbPort> getPorts();
     method public void grantPermission(android.hardware.usb.UsbDevice, java.lang.String);
+    field public static final java.lang.String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
+  }
+
+  public final class UsbPort {
+    method public android.hardware.usb.UsbPortStatus getStatus();
+    method public void setRoles(int, int);
+  }
+
+  public final class UsbPortStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCurrentDataRole();
+    method public int getCurrentMode();
+    method public int getCurrentPowerRole();
+    method public int getSupportedRoleCombinations();
+    method public boolean isConnected();
+    method public boolean isRoleCombinationSupported(int, int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbPortStatus> CREATOR;
+    field public static final int DATA_ROLE_DEVICE = 2; // 0x2
+    field public static final int DATA_ROLE_HOST = 1; // 0x1
+    field public static final int DATA_ROLE_NONE = 0; // 0x0
+    field public static final int MODE_AUDIO_ACCESSORY = 4; // 0x4
+    field public static final int MODE_DEBUG_ACCESSORY = 8; // 0x8
+    field public static final int MODE_DFP = 2; // 0x2
+    field public static final int MODE_NONE = 0; // 0x0
+    field public static final int MODE_UFP = 1; // 0x1
+    field public static final int POWER_ROLE_NONE = 0; // 0x0
+    field public static final int POWER_ROLE_SINK = 2; // 0x2
+    field public static final int POWER_ROLE_SOURCE = 1; // 0x1
   }
 
 }
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index f4e776c..edc3f94 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -20,7 +20,7 @@
 import android.content.ComponentName;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbPort;
+import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbPortStatus;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -112,7 +112,7 @@
     ParcelFileDescriptor getControlFd(long function);
 
     /* Gets the list of USB ports. */
-    UsbPort[] getPorts();
+    List<ParcelableUsbPort> getPorts();
 
     /* Gets the status of the specified USB port. */
     UsbPortStatus getPortStatus(in String portId);
diff --git a/core/java/android/hardware/usb/UsbPort.aidl b/core/java/android/hardware/usb/ParcelableUsbPort.aidl
similarity index 87%
rename from core/java/android/hardware/usb/UsbPort.aidl
rename to core/java/android/hardware/usb/ParcelableUsbPort.aidl
index b7a7920..4431551 100644
--- a/core/java/android/hardware/usb/UsbPort.aidl
+++ b/core/java/android/hardware/usb/ParcelableUsbPort.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, The Android Open Source Project
+ * Copyright (C) 2018, 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.
@@ -16,4 +16,4 @@
 
 package android.hardware.usb;
 
-parcelable UsbPort;
+parcelable ParcelableUsbPort;
diff --git a/core/java/android/hardware/usb/ParcelableUsbPort.java b/core/java/android/hardware/usb/ParcelableUsbPort.java
new file mode 100644
index 0000000..7f7ba96
--- /dev/null
+++ b/core/java/android/hardware/usb/ParcelableUsbPort.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.usb;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.Immutable;
+
+/**
+ * A parcelable wrapper to send UsbPorts over binders.
+ *
+ * @hide
+ */
+@Immutable
+public final class ParcelableUsbPort implements Parcelable {
+    private final @NonNull String mId;
+    private final int mSupportedModes;
+
+    private ParcelableUsbPort(@NonNull String id, int supportedModes) {
+        mId = id;
+        mSupportedModes = supportedModes;
+    }
+
+    /**
+     * Create the parcelable version of a {@link UsbPort}.
+     *
+     * @param port The port to create a parcealable version of
+     *
+     * @return The parcelable version of the port
+     */
+    public static @NonNull ParcelableUsbPort of(@NonNull UsbPort port) {
+        return new ParcelableUsbPort(port.getId(), port.getSupportedModes());
+    }
+
+    /**
+     * Create a {@link UsbPort} from this object.
+     *
+     * @param usbManager A link to the usbManager in the current context
+     *
+     * @return The UsbPort for this object
+     */
+    public @NonNull UsbPort getUsbPort(@NonNull UsbManager usbManager) {
+        return new UsbPort(usbManager, mId, mSupportedModes);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+        dest.writeInt(mSupportedModes);
+    }
+
+    public static final Creator<ParcelableUsbPort> CREATOR =
+            new Creator<ParcelableUsbPort>() {
+                @Override
+                public ParcelableUsbPort createFromParcel(Parcel in) {
+                    String id = in.readString();
+                    int supportedModes = in.readInt();
+                    return new ParcelableUsbPort(id, supportedModes);
+                }
+
+                @Override
+                public ParcelableUsbPort[] newArray(int size) {
+                    return new ParcelableUsbPort[size];
+                }
+            };
+}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 4111941..6014478 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -18,6 +18,7 @@
 package android.hardware.usb;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
@@ -39,9 +40,10 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
-
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
 
@@ -97,15 +99,11 @@
      * Broadcast Action: A broadcast for USB port changes.
      *
      * This intent is sent when a USB port is added, removed, or changes state.
-     * <ul>
-     * <li> {@link #EXTRA_PORT} containing the {@link android.hardware.usb.UsbPort}
-     * for the port.
-     * <li> {@link #EXTRA_PORT_STATUS} containing the {@link android.hardware.usb.UsbPortStatus}
-     * for the port, or null if the port has been removed
-     * </ul>
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
     public static final String ACTION_USB_PORT_CHANGED =
             "android.hardware.usb.action.USB_PORT_CHANGED";
 
@@ -796,34 +794,44 @@
      * device class (which supports all types of ports despite its name).
      * </p>
      *
-     * @return The list of USB ports, or null if none.
+     * @return The list of USB ports
      *
      * @hide
      */
-    @UnsupportedAppUsage
-    public UsbPort[] getPorts() {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    public @NonNull List<UsbPort> getPorts() {
         if (mService == null) {
-            return null;
+            return Collections.emptyList();
         }
+
+        List<ParcelableUsbPort> parcelablePorts;
         try {
-            return mService.getPorts();
+            parcelablePorts = mService.getPorts();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+
+        if (parcelablePorts == null) {
+            return Collections.emptyList();
+        } else {
+            int numPorts = parcelablePorts.size();
+
+            ArrayList<UsbPort> ports = new ArrayList<>(numPorts);
+            for (int i = 0; i < numPorts; i++) {
+                ports.add(parcelablePorts.get(i).getUsbPort(this));
+            }
+
+            return ports;
+        }
     }
 
     /**
-     * Gets the status of the specified USB port.
-     *
-     * @param port The port to query.
-     * @return The status of the specified USB port, or null if unknown.
+     * Should only be called by {@link UsbPort#getStatus}.
      *
      * @hide
      */
-    @UnsupportedAppUsage
-    public UsbPortStatus getPortStatus(UsbPort port) {
-        Preconditions.checkNotNull(port, "port must not be null");
-
+    UsbPortStatus getPortStatus(UsbPort port) {
         try {
             return mService.getPortStatus(port.getId());
         } catch (RemoteException e) {
@@ -832,29 +840,11 @@
     }
 
     /**
-     * Sets the desired role combination of the port.
-     * <p>
-     * The supported role combinations depend on what is connected to the port and may be
-     * determined by consulting
-     * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
-     * </p><p>
-     * Note: This function is asynchronous and may fail silently without applying
-     * the requested changes.  If this function does cause a status change to occur then
-     * a {@link #ACTION_USB_PORT_CHANGED} broadcast will be sent.
-     * </p>
-     *
-     * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE}
-     * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
-     * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST}
-     * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+     * Should only be called by {@link UsbPort#setRoles}.
      *
      * @hide
      */
-    @UnsupportedAppUsage
-    public void setPortRoles(UsbPort port, int powerRole, int dataRole) {
-        Preconditions.checkNotNull(port, "port must not be null");
-        UsbPort.checkRoles(powerRole, dataRole);
-
+    void setPortRoles(UsbPort port, int powerRole, int dataRole) {
         Log.d(TAG, "setPortRoles Package:" + mContext.getPackageName());
         try {
             mService.setPortRoles(port.getId(), powerRole, dataRole);
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index afdb202..37154e4 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -16,104 +16,53 @@
 
 package android.hardware.usb;
 
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY;
+import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY;
+import static android.hardware.usb.UsbPortStatus.MODE_DFP;
+import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
+import static android.hardware.usb.UsbPortStatus.MODE_NONE;
+import static android.hardware.usb.UsbPortStatus.MODE_UFP;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.hardware.usb.V1_0.Constants;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 import com.android.internal.util.Preconditions;
 
 /**
  * Represents a physical USB port and describes its characteristics.
- * <p>
- * This object is immutable.
- * </p>
  *
  * @hide
  */
-public final class UsbPort implements Parcelable {
+@SystemApi
+public final class UsbPort {
     private final String mId;
     private final int mSupportedModes;
-
-    public static final int MODE_NONE = Constants.PortMode.NONE;
-    /**
-     * Mode bit: This USB port can act as a downstream facing port (host).
-     * <p>
-     * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST}
-     * combination of roles (and possibly others as well).
-     * </p>
-     */
-    public static final int MODE_DFP = Constants.PortMode.DFP;
-
-    /**
-     * Mode bit: This USB port can act as an upstream facing port (device).
-     * <p>
-     * Implies that the port supports the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE}
-     * combination of roles (and possibly others as well).
-     * </p>
-     */
-    public static final int MODE_UFP = Constants.PortMode.UFP;
-
-    /**
-     * Mode bit: This USB port can act either as an downstream facing port (host) or as
-     * an upstream facing port (device).
-     * <p>
-     * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST}
-     * combination of roles and the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE}
-     * combination of roles (and possibly others as well).
-     * </p>
-     */
-    public static final int MODE_DUAL = Constants.PortMode.DRP;
-
-    /**
-     * Mode bit: This USB port can support USB Type-C Audio accessory.
-     */
-    public static final int MODE_AUDIO_ACCESSORY =
-            android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY;
-
-    /**
-     * Mode bit: This USB port can support USB Type-C debug accessory.
-     */
-    public static final int MODE_DEBUG_ACCESSORY =
-            android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
-
-    /**
-     * Power role: This USB port does not have a power role.
-     */
-    public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE;
-
-    /**
-     * Power role: This USB port can act as a source (provide power).
-     */
-    public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE;
-
-    /**
-     * Power role: This USB port can act as a sink (receive power).
-     */
-    public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
-
-    /**
-     * Power role: This USB port does not have a data role.
-     */
-    public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE;
-
-    /**
-     * Data role: This USB port can act as a host (access data services).
-     */
-    public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST;
-
-    /**
-     * Data role: This USB port can act as a device (offer data services).
-     */
-    public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
+    private final UsbManager mUsbManager;
 
     private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
+
     /**
      * Points to the first power role in the IUsb HAL.
      */
     private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
 
     /** @hide */
-    public UsbPort(String id, int supportedModes) {
+    public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes) {
+        Preconditions.checkNotNull(id);
+        Preconditions.checkFlagsArgument(supportedModes,
+                MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY);
+
+        mUsbManager = usbManager;
         mId = id;
         mSupportedModes = supportedModes;
     }
@@ -122,6 +71,8 @@
      * Gets the unique id of the port.
      *
      * @return The unique id of the port; not intended for display.
+     *
+     * @hide
      */
     public String getId() {
         return mId;
@@ -133,23 +84,62 @@
      * The actual mode of the port may vary depending on what is plugged into it.
      * </p>
      *
-     * @return The supported modes: one of {@link #MODE_DFP}, {@link #MODE_UFP}, or
-     * {@link #MODE_DUAL}.
+     * @return The supported modes: one of {@link UsbPortStatus#MODE_DFP},
+     * {@link UsbPortStatus#MODE_UFP}, or {@link UsbPortStatus#MODE_DUAL}.
+     *
+     * @hide
      */
     public int getSupportedModes() {
         return mSupportedModes;
     }
 
     /**
+     * Gets the status of this USB port.
+     *
+     * @return The status of the this port, or {@code null} if port is unknown.
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    public @Nullable UsbPortStatus getStatus() {
+        return mUsbManager.getPortStatus(this);
+    }
+
+    /**
+     * Sets the desired role combination of the port.
+     * <p>
+     * The supported role combinations depend on what is connected to the port and may be
+     * determined by consulting
+     * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
+     * </p><p>
+     * Note: This function is asynchronous and may fail silently without applying
+     * the requested changes.  If this function does cause a status change to occur then
+     * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent.
+     * </p>
+     *
+     * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} or
+     *                  {@link UsbPortStatus#POWER_ROLE_SINK}, or
+     *                  {@link UsbPortStatus#POWER_ROLE_NONE} if no power role.
+     * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} or
+     *                 {@link UsbPortStatus#DATA_ROLE_DEVICE}, or
+     *                 {@link UsbPortStatus#DATA_ROLE_NONE} if no data role.
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    public void setRoles(@UsbPortStatus.UsbPowerRole int powerRole,
+            @UsbPortStatus.UsbDataRole int dataRole) {
+        UsbPort.checkRoles(powerRole, dataRole);
+
+        mUsbManager.setPortRoles(this, powerRole, dataRole);
+    }
+
+    /**
      * Combines one power and one data role together into a unique value with
      * exactly one bit set.  This can be used to efficiently determine whether
      * a combination of roles is supported by testing whether that bit is present
      * in a bit-field.
      *
-     * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE}
-     *                  or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
-     * @param dataRole  The desired data role: {@link UsbPort#DATA_ROLE_HOST}
-     *                  or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+     * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE}
+     *                  or {@link UsbPortStatus#POWER_ROLE_SINK}, or 0 if no power role.
+     * @param dataRole  The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST}
+     *                  or {@link UsbPortStatus#DATA_ROLE_DEVICE}, or 0 if no data role.
      * @hide
      */
     public static int combineRolesAsBit(int powerRole, int dataRole) {
@@ -276,30 +266,4 @@
     public String toString() {
         return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) + "}";
     }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mId);
-        dest.writeInt(mSupportedModes);
-    }
-
-    public static final Parcelable.Creator<UsbPort> CREATOR =
-            new Parcelable.Creator<UsbPort>() {
-                @Override
-                public UsbPort createFromParcel(Parcel in) {
-                    String id = in.readString();
-                    int supportedModes = in.readInt();
-                    return new UsbPort(id, supportedModes);
-                }
-
-                @Override
-                public UsbPort[] newArray(int size) {
-                    return new UsbPort[size];
-                }
-            };
 }
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index 2cd8209..d30201a 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -16,27 +16,134 @@
 
 package android.hardware.usb;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.hardware.usb.V1_0.Constants;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.Immutable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Describes the status of a USB port.
- * <p>
- * This object is immutable.
- * </p>
  *
  * @hide
  */
+@Immutable
+@SystemApi
 public final class UsbPortStatus implements Parcelable {
     private final int mCurrentMode;
-    private final int mCurrentPowerRole;
-    private final int mCurrentDataRole;
+    private final @UsbPowerRole int mCurrentPowerRole;
+    private final @UsbDataRole int mCurrentDataRole;
     private final int mSupportedRoleCombinations;
 
+    /**
+     * Power role: This USB port does not have a power role.
+     */
+    public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE;
+
+    /**
+     * Power role: This USB port can act as a source (provide power).
+     */
+    public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE;
+
+    /**
+     * Power role: This USB port can act as a sink (receive power).
+     */
+    public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
+
+    @IntDef(prefix = { "POWER_ROLE_" }, value = {
+            POWER_ROLE_NONE,
+            POWER_ROLE_SOURCE,
+            POWER_ROLE_SINK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UsbPowerRole{}
+
+    /**
+     * Power role: This USB port does not have a data role.
+     */
+    public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE;
+
+    /**
+     * Data role: This USB port can act as a host (access data services).
+     */
+    public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST;
+
+    /**
+     * Data role: This USB port can act as a device (offer data services).
+     */
+    public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
+
+    @IntDef(prefix = { "DATA_ROLE_" }, value = {
+            DATA_ROLE_NONE,
+            DATA_ROLE_HOST,
+            DATA_ROLE_DEVICE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UsbDataRole{}
+
+    /**
+     * There is currently nothing connected to this USB port.
+     */
+    public static final int MODE_NONE = Constants.PortMode.NONE;
+
+    /**
+     * This USB port can act as a downstream facing port (host).
+     *
+     * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and
+     * {@link #DATA_ROLE_HOST} combination of roles (and possibly others as well).
+     */
+    public static final int MODE_DFP = Constants.PortMode.DFP;
+
+    /**
+     * This USB port can act as an upstream facing port (device).
+     *
+     * <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and
+     * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well).
+     */
+    public static final int MODE_UFP = Constants.PortMode.UFP;
+
+    /**
+     * This USB port can act either as an downstream facing port (host) or as
+     * an upstream facing port (device).
+     *
+     * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and
+     * {@link #DATA_ROLE_HOST} combination of roles and the {@link #POWER_ROLE_SINK} and
+     * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well).
+     *
+     * @hide
+     */
+    public static final int MODE_DUAL = Constants.PortMode.DRP;
+
+    /**
+     * This USB port can support USB Type-C Audio accessory.
+     */
+    public static final int MODE_AUDIO_ACCESSORY =
+            android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY;
+
+    /**
+     * This USB port can support USB Type-C debug accessory.
+     */
+    public static final int MODE_DEBUG_ACCESSORY =
+            android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
+
+    @IntDef(prefix = { "MODE_" }, flag = true, value = {
+            MODE_NONE,
+            MODE_DFP,
+            MODE_UFP,
+            MODE_AUDIO_ACCESSORY,
+            MODE_DEBUG_ACCESSORY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UsbPortMode{}
+
     /** @hide */
-    public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
-            int supportedRoleCombinations) {
+    public UsbPortStatus(int currentMode, @UsbPowerRole int currentPowerRole,
+            @UsbDataRole int currentDataRole, int supportedRoleCombinations) {
         mCurrentMode = currentMode;
         mCurrentPowerRole = currentPowerRole;
         mCurrentDataRole = currentDataRole;
@@ -46,9 +153,8 @@
     /**
      * Returns true if there is anything connected to the port.
      *
-     * @return True if there is anything connected to the port.
+     * @return {@code true} iff there is anything connected to the port.
      */
-    @UnsupportedAppUsage
     public boolean isConnected() {
         return mCurrentMode != 0;
     }
@@ -56,33 +162,31 @@
     /**
      * Gets the current mode of the port.
      *
-     * @return The current mode: {@link UsbPort#MODE_DFP}, {@link UsbPort#MODE_UFP},
-     * or 0 if nothing is connected.
+     * @return The current mode: {@link #MODE_DFP}, {@link #MODE_UFP},
+     * {@link #MODE_AUDIO_ACCESSORY}, {@link #MODE_DEBUG_ACCESSORY}, or {@link {@link #MODE_NONE} if
+     * nothing is connected.
      */
-    @UnsupportedAppUsage
-    public int getCurrentMode() {
+    public @UsbPortMode int getCurrentMode() {
         return mCurrentMode;
     }
 
     /**
      * Gets the current power role of the port.
      *
-     * @return The current power role: {@link UsbPort#POWER_ROLE_SOURCE},
-     * {@link UsbPort#POWER_ROLE_SINK}, or 0 if nothing is connected.
+     * @return The current power role: {@link #POWER_ROLE_SOURCE}, {@link #POWER_ROLE_SINK}, or
+     * {@link #POWER_ROLE_NONE} if nothing is connected.
      */
-    @UnsupportedAppUsage
-    public int getCurrentPowerRole() {
+    public @UsbPowerRole int getCurrentPowerRole() {
         return mCurrentPowerRole;
     }
 
     /**
      * Gets the current data role of the port.
      *
-     * @return The current data role: {@link UsbPort#DATA_ROLE_HOST},
-     * {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if nothing is connected.
+     * @return The current data role: {@link #DATA_ROLE_HOST}, {@link #DATA_ROLE_DEVICE}, or
+     * {@link #DATA_ROLE_NONE} if nothing is connected.
      */
-    @UnsupportedAppUsage
-    public int getCurrentDataRole() {
+    public @UsbDataRole int getCurrentDataRole() {
         return mCurrentDataRole;
     }
 
@@ -90,19 +194,20 @@
      * Returns true if the specified power and data role combination is supported
      * given what is currently connected to the port.
      *
-     * @param powerRole The power role to check: {@link UsbPort#POWER_ROLE_SOURCE}
-     * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
-     * @param dataRole The data role to check: either {@link UsbPort#DATA_ROLE_HOST}
-     * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
+     * @param powerRole The power role to check: {@link #POWER_ROLE_SOURCE}  or
+     *                  {@link #POWER_ROLE_SINK}, or {@link #POWER_ROLE_NONE} if no power role.
+     * @param dataRole  The data role to check: either {@link #DATA_ROLE_HOST} or
+     *                  {@link #DATA_ROLE_DEVICE}, or {@link #DATA_ROLE_NONE} if no data role.
      */
-    @UnsupportedAppUsage
-    public boolean isRoleCombinationSupported(int powerRole, int dataRole) {
+    public boolean isRoleCombinationSupported(@UsbPowerRole int powerRole,
+            @UsbDataRole int dataRole) {
         return (mSupportedRoleCombinations &
                 UsbPort.combineRolesAsBit(powerRole, dataRole)) != 0;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Get the supported role combinations.
+     */
     public int getSupportedRoleCombinations() {
         return mSupportedRoleCombinations;
     }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 299db73..40f1946 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14260,6 +14260,44 @@
         }
     }
 
+    /**
+     * <p>
+     *     A Settings panel is floating UI that contains a fixed subset of settings to address a
+     *     particular user problem. For example, the
+     *     {@link #ACTION_INTERNET_CONNECTIVITY Internet Panel} surfaces settings related to
+     *     connecting to the internet.
+     * <p>
+     *     Settings panels appear above the calling app to address the problem without
+     *     the user needing to open Settings and thus leave their current screen.
+     */
+    public static final class Panel {
+        private Panel() {
+        }
+
+        /**
+         * Activity Action: Show a settings dialog containing settings to enable internet
+         * connection.
+         * <p>
+         * Input: Nothing.
+         * <p>
+         * Output: Nothing.
+         */
+        @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+        public static final String ACTION_INTERNET_CONNECTIVITY =
+                "android.settings.panel.action.INTERNET_CONNECTIVITY";
+
+        /**
+         * Activity Action: Show a settings dialog containing all volume streams.
+         * <p>
+         * Input: Nothing.
+         * <p>
+         * Output: Nothing.
+         */
+        @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+        public static final String ACTION_VOLUME =
+                "android.settings.panel.action.VOLUME";
+    }
+
     private static final String[] PM_WRITE_SETTINGS = {
         android.Manifest.permission.WRITE_SETTINGS
     };
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index cac2265..240c2e7 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -16,12 +16,12 @@
 
 package com.android.internal.usb;
 
-import static android.hardware.usb.UsbPort.MODE_AUDIO_ACCESSORY;
-import static android.hardware.usb.UsbPort.MODE_DEBUG_ACCESSORY;
-import static android.hardware.usb.UsbPort.MODE_DFP;
-import static android.hardware.usb.UsbPort.MODE_DUAL;
-import static android.hardware.usb.UsbPort.MODE_NONE;
-import static android.hardware.usb.UsbPort.MODE_UFP;
+import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY;
+import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY;
+import static android.hardware.usb.UsbPortStatus.MODE_DFP;
+import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
+import static android.hardware.usb.UsbPortStatus.MODE_NONE;
+import static android.hardware.usb.UsbPortStatus.MODE_UFP;
 
 import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull;
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3f1f9cd..7688c8d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2615,6 +2615,11 @@
     <!-- Package name for default network scorer app; overridden by product overlays. -->
     <string name="config_defaultNetworkScorerPackageName"></string>
 
+    <!-- Feature flag to enable memory efficient task snapshots that are used in recents optimized
+         for low memory devices and replace the app transition starting window with the splash
+         screen. -->
+    <bool name="config_lowRamTaskSnapshotsAndRecents">false</bool>
+
     <!-- Determines whether recent tasks are provided to the user. Default device has recents
          property. If this is false, then the following recents config flags are ignored. -->
     <bool name="config_hasRecents">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ed9f3b1..c3d5f63 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -329,6 +329,7 @@
   <java-symbol type="bool" name="config_enableMultiUserUI"/>
   <java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
   <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
+  <java-symbol type="bool" name="config_lowRamTaskSnapshotsAndRecents" />
   <java-symbol type="bool" name="config_hasRecents" />
   <java-symbol type="string" name="config_recentsComponentName" />
   <java-symbol type="integer" name="config_minNumVisibleRecentTasks_lowRam" />
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 293fa9a..9b6ad38 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -69,6 +69,7 @@
         ],
     },
     resource_dirs: [
+        "res-keyguard",
         "res",
     ],
 
diff --git a/packages/CarSystemUI/res-keyguard/drawable/ic_backspace.xml b/packages/CarSystemUI/res-keyguard/drawable/ic_backspace.xml
new file mode 100644
index 0000000..f3a2f0f
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/drawable/ic_backspace.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License")
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="36dp"
+        android:height="36dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12L19,15.59L17.59,17L14,13.41L10.41,17L9,15.59zM21,6H8l-4.5,6L8,18h13V6M21,4c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H8c-0.63,0 -1.22,-0.3 -1.6,-0.8L1,12l5.4,-7.2C6.78,4.3 7.37,4 8,4H21L21,4z"/>
+</vector>
diff --git a/packages/CarSystemUI/res-keyguard/drawable/ic_done.xml b/packages/CarSystemUI/res-keyguard/drawable/ic_done.xml
new file mode 100644
index 0000000..ef0aac2
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/drawable/ic_done.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License")
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="36dp"
+        android:height="36dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M9,16.2l-3.5,-3.5a0.984,0.984 0,0 0,-1.4 0,0.984 0.984,0 0,0 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7a0.984,0.984 0,0 0,0 -1.4,0.984 0.984,0 0,0 -1.4,0L9,16.2z"/>
+</vector>
diff --git a/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml b/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml
new file mode 100644
index 0000000..b428931
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/car_button_radius"/>
+            <solid android:color="#131315"/>
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/car_button_radius"/>
+            <solid android:color="@color/button_background"/>
+        </shape>
+    </item>
+</selector>
diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
new file mode 100644
index 0000000..b115a1f
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, 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.
+*/
+-->
+
+<!-- Car customizations
+     - Added title "Enter your Pattern" at the top
+     - Hid the emergency call at the bottom
+-->
+
+<com.android.keyguard.KeyguardPatternView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_pattern_view"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingHorizontal="@dimen/car_margin">
+
+    <FrameLayout
+        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_weight="1">
+
+        <com.android.internal.widget.LockPatternView
+            android:id="@+id/lockPatternView"
+            android:layout_width="@dimen/keyguard_pattern_dimension"
+            android:layout_height="@dimen/keyguard_pattern_dimension"
+            android:layout_gravity="center"/>
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:gravity="center_vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/car_padding_2"
+            android:gravity="center"
+            android:textColor="@android:color/white"
+            android:textSize="@dimen/car_body1_size"
+            android:text="@string/keyguard_enter_your_pattern" />
+
+        <include layout="@layout/keyguard_message_area" />
+
+        <Button
+            android:id="@+id/cancel_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            style="@style/KeyguardButton"
+            android:text="@string/cancel"/>
+
+        <include layout="@layout/keyguard_eca"
+            android:id="@+id/keyguard_selector_fade_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_gravity="bottom|center_horizontal"
+            android:gravity="center_horizontal"
+            android:visibility="gone" />
+    </LinearLayout>
+
+</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
new file mode 100644
index 0000000..ed88c62
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, 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.
+-->
+
+<!-- Car customizations
+     - Added title "Enter your PIN" under the entry field
+     - Put backspace and enter buttons in row 4
+     - PIN pad is on start side while entry field and title are on the end side
+     -  Hid the emergency call at the bottom
+-->
+
+<com.android.keyguard.KeyguardPINView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_pin_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:paddingHorizontal="@dimen/car_margin">
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_height="match_parent">
+
+        <GridLayout
+            android:id="@+id/container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:columnCount="3">
+
+            <include layout="@layout/num_pad_keys"/>
+        </GridLayout>
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <com.android.keyguard.PasswordTextView
+            android:id="@+id/pinEntry"
+            android:layout_width="@dimen/keyguard_security_width"
+            android:layout_height="@dimen/pin_entry_height"
+            android:gravity="center"
+            app:scaledTextSize="@integer/password_text_view_scale"
+            android:contentDescription="@string/keyguard_accessibility_pin_area" />
+
+        <View
+            android:id="@+id/divider"
+            android:layout_width="@dimen/keyguard_security_width"
+            android:layout_height="@dimen/divider_height"
+            android:background="@android:color/white" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/car_padding_2"
+            android:gravity="center"
+            android:textColor="@android:color/white"
+            android:textSize="@dimen/car_body1_size"
+            android:text="@string/keyguard_enter_your_pin" />
+
+        <include layout="@layout/keyguard_message_area" />
+
+        <Button
+            android:id="@+id/cancel_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            style="@style/KeyguardButton"
+            android:text="@string/cancel"/>
+    </LinearLayout>
+
+    <!-- KeyguardPinView references these resources ids in code so removing them will cause the
+         keyguard to crash. Instead put them down here where they are out of the way and set their
+         visibility to gone. -->
+    <com.android.keyguard.AlphaOptimizedRelativeLayout
+        android:id="@+id/row0"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row1"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row2"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row3"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row4"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+
+    <include layout="@layout/keyguard_eca"
+         android:id="@+id/keyguard_selector_fade_container"
+         android:layout_width="0dp"
+         android:layout_height="0dp"
+         android:visibility="gone" />
+</com.android.keyguard.KeyguardPINView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml
new file mode 100644
index 0000000..062f7bd
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2018 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
+  -->
+
+<!-- Car customizations
+     Car has solid black background instead of a transparent one
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/black"
+    android:fitsSystemWindows="true">
+
+    <include
+        style="@style/BouncerSecurityContainer"
+        layout="@layout/keyguard_host_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</FrameLayout>
+
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml
new file mode 100644
index 0000000..c230414
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, 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.
+*/
+-->
+
+<com.android.keyguard.KeyguardMessageArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    style="@style/Keyguard.TextView"
+    android:id="@+id/keyguard_message_area"
+    android:singleLine="true"
+    android:ellipsize="marquee"
+    android:focusable="true"
+    android:layout_marginBottom="@dimen/car_padding_4"
+    android:textSize="@dimen/car_body2_size" />
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_num_pad_key.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
new file mode 100644
index 0000000..c7eda38
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2018 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
+  -->
+
+<!-- Car customizations
+     The mnemonics is not shown for car but KeyguardPinView references the resource id in code.
+     Removing it will cause the keyguard to crash. Hide them instead
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <TextView
+        android:id="@+id/digit_text"
+        style="@style/Widget.TextView.NumPadKey"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+    <!-- The mnemonics is not shown for car but KeyguardPinView references the resource id in code.
+         Removing it will cause the keyguard to crash. Hide them instead -->
+    <TextView
+        android:id="@+id/klondike_text"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone"
+        />
+</merge>
+
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml
new file mode 100644
index 0000000..e701fdb
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, 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.
+*/
+-->
+
+<!-- Car customizations
+     - Added title "Enter your Password" below the password field
+     - Hid the emergency call at the bottom
+-->
+
+<com.android.keyguard.KeyguardPasswordView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_password_view"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
+    android:gravity="center">
+
+    <include layout="@layout/keyguard_message_area" />
+
+    <!-- Password entry field -->
+    <LinearLayout
+         android:layout_height="wrap_content"
+         android:layout_width="wrap_content"
+         android:layout_gravity="center_horizontal"
+         android:orientation="vertical"
+         android:theme="?attr/passwordStyle">
+
+        <EditText
+            android:id="@+id/passwordEntry"
+            android:layout_width="@dimen/password_field_width"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:singleLine="true"
+            android:textStyle="normal"
+            android:inputType="textPassword"
+            android:textSize="@dimen/car_body1_size"
+            android:textColor="?attr/wallpaperTextColor"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:imeOptions="flagForceAscii|actionDone"
+            android:maxLength="@integer/password_text_view_scale"
+         />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/car_padding_2"
+            android:gravity="center"
+            android:textColor="@android:color/white"
+            android:textSize="@dimen/car_body1_size"
+            android:text="@string/keyguard_enter_your_password" />
+
+        <Button
+            android:id="@+id/cancel_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            style="@style/KeyguardButton"
+            android:text="@string/cancel"/>
+
+        <ImageView android:id="@+id/switch_ime_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="12dp"
+            android:src="@drawable/ic_lockscreen_ime"
+            android:contentDescription="@string/accessibility_ime_switch_button"
+            android:clickable="true"
+            android:padding="8dp"
+            android:tint="@color/background_protected"
+            android:layout_gravity="end|center_vertical"
+            android:background="?android:attr/selectableItemBackground"
+            android:visibility="gone"
+        />
+    </LinearLayout>
+
+    <include layout="@layout/keyguard_eca"
+        android:id="@+id/keyguard_selector_fade_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="12dp"
+        android:orientation="vertical"
+        android:layout_gravity="bottom|center_horizontal"
+        android:gravity="center_horizontal"
+        android:visibility="gone"
+    />
+
+</com.android.keyguard.KeyguardPasswordView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml
new file mode 100644
index 0000000..00333a8
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, 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.
+*/
+-->
+
+<!-- Car customizations
+     - Added title "Enter your Pattern" at the top
+     - Hid the emergency call at the bottom
+-->
+
+<com.android.keyguard.KeyguardPatternView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_pattern_view"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    android:gravity="center_horizontal">
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/container"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:orientation="vertical"
+            android:layout_gravity="center">
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/car_padding_2"
+                android:gravity="center"
+                android:textColor="@android:color/white"
+                android:textSize="@dimen/car_body1_size"
+                android:text="@string/keyguard_enter_your_pattern" />
+
+            <include layout="@layout/keyguard_message_area" />
+
+            <com.android.internal.widget.LockPatternView
+                android:id="@+id/lockPatternView"
+                android:layout_width="@dimen/keyguard_pattern_dimension"
+                android:layout_height="@dimen/keyguard_pattern_dimension"
+                android:layout_marginVertical="@dimen/pin_pattern_pad_margin_vertical"
+                android:layout_gravity="center_horizontal"
+                android:gravity="center" />
+
+            <Button
+                android:id="@+id/cancel_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                style="@style/KeyguardButton"
+                android:text="@string/cancel"/>
+
+          <include layout="@layout/keyguard_eca"
+              android:id="@+id/keyguard_selector_fade_container"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical"
+              android:layout_gravity="bottom|center_horizontal"
+              android:gravity="center_horizontal"
+              android:visibility="gone" />
+        </LinearLayout>
+    </FrameLayout>
+
+</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml
new file mode 100644
index 0000000..1662251
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, 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.
+-->
+
+<!-- Car customizations
+     - Added title "Enter your PIN" under the entry field
+     - Put backspace and enter buttons in row 4
+     - Hid the emergency call at the bottom
+-->
+
+<com.android.keyguard.KeyguardPINView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/keyguard_pin_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginLeft="@dimen/num_pad_margin_left"
+        android:layout_marginRight="@dimen/num_pad_margin_right"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical">
+
+            <com.android.keyguard.PasswordTextView
+                android:id="@+id/pinEntry"
+                android:layout_width="@dimen/keyguard_security_width"
+                android:layout_height="@dimen/pin_entry_height"
+                android:gravity="center"
+                app:scaledTextSize="@integer/password_text_view_scale"
+                android:contentDescription="@string/keyguard_accessibility_pin_area" />
+
+            <View
+                android:id="@+id/divider"
+                android:layout_width="@dimen/keyguard_security_width"
+                android:layout_height="@dimen/divider_height"
+                android:background="@android:color/white" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/car_padding_2"
+                android:gravity="center"
+                android:textColor="@android:color/white"
+                android:textSize="@dimen/car_body1_size"
+                android:text="@string/keyguard_enter_your_pin" />
+
+            <include layout="@layout/keyguard_message_area" />
+
+        </LinearLayout>
+
+        <GridLayout
+            android:id="@+id/container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginVertical="@dimen/pin_pattern_pad_margin_vertical"
+            android:columnCount="3">
+
+            <include layout="@layout/num_pad_keys"/>
+        </GridLayout>
+
+        <Button
+            android:id="@+id/cancel_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            style="@style/KeyguardButton"
+            android:text="@string/cancel"/>
+
+    </LinearLayout>
+
+    <!-- KeyguardPinView references these resources ids in code so removing them will cause the
+         keyguard to crash. Instead put them down here where they are out of the way and set their
+         visibility to gone. -->
+    <com.android.keyguard.AlphaOptimizedRelativeLayout
+        android:id="@+id/row0"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row1"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row2"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row3"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+    <LinearLayout
+        android:id="@+id/row4"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+
+    <include
+        layout="@layout/keyguard_eca"
+        android:id="@+id/keyguard_selector_fade_container"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone" />
+</com.android.keyguard.KeyguardPINView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/num_pad_keys.xml b/packages/CarSystemUI/res-keyguard/layout/num_pad_keys.xml
new file mode 100644
index 0000000..8306cb4
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/layout/num_pad_keys.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2018 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
+  -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:app="http://schemas.android.com/apk/res-auto">
+    <!-- Row 1 -->
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key1"
+        style="@style/NumPadKeyButton"
+        app:digit="1" />
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key2"
+        style="@style/NumPadKeyButton.MiddleColumn"
+        app:digit="2" />
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key3"
+        style="@style/NumPadKeyButton"
+        app:digit="3" />
+
+    <!-- Row 2 -->
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key4"
+        style="@style/NumPadKeyButton"
+        app:digit="4" />
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key5"
+        style="@style/NumPadKeyButton.MiddleColumn"
+        app:digit="5" />
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key6"
+        style="@style/NumPadKeyButton"
+        app:digit="6" />
+
+    <!-- Row 3 -->
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key7"
+        style="@style/NumPadKeyButton"
+        app:digit="7" />
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key8"
+        style="@style/NumPadKeyButton.MiddleColumn"
+        app:digit="8" />
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key9"
+        style="@style/NumPadKeyButton"
+        app:digit="9" />
+
+    <!-- Row 4 -->
+    <ImageButton
+        android:id="@+id/delete_button"
+        style="@style/NumPadKeyButton.LastRow"
+        android:gravity="center_vertical"
+        android:src="@drawable/ic_backspace"
+        android:clickable="true"
+        android:tint="@android:color/white"
+        android:background="@drawable/ripple_drawable"
+        android:contentDescription="@string/keyboardview_keycode_delete" />
+    <com.android.keyguard.NumPadKey
+        android:id="@+id/key0"
+        style="@style/NumPadKeyButton.LastRow.MiddleColumn"
+        app:digit="0" />
+    <ImageButton
+        android:id="@+id/key_enter"
+        style="@style/NumPadKeyButton.LastRow"
+        android:src="@drawable/ic_done"
+        android:tint="@android:color/white"
+        android:background="@drawable/ripple_drawable"
+        android:contentDescription="@string/keyboardview_keycode_enter" />
+</merge>
+
diff --git a/packages/CarSystemUI/res-keyguard/values-h1000dp/dimens.xml b/packages/CarSystemUI/res-keyguard/values-h1000dp/dimens.xml
new file mode 100644
index 0000000..d055efa
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/values-h1000dp/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, 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>
+    <dimen name="pin_pattern_pad_margin_vertical">178dp</dimen>
+</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values-land/dimens.xml b/packages/CarSystemUI/res-keyguard/values-land/dimens.xml
new file mode 100644
index 0000000..805a134
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/values-land/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, 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>
+    <dimen name="num_pad_key_margin_horizontal">@dimen/car_padding_5</dimen>
+    <dimen name="num_pad_key_margin_bottom">@dimen/car_padding_4</dimen>
+</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values/colors.xml b/packages/CarSystemUI/res-keyguard/values/colors.xml
new file mode 100644
index 0000000..e6edbea3
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/values/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018, 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>
+    <color name="button_background">@color/car_dark_blue_grey_600</color>
+    <color name="button_text">@color/car_action1_light</color>
+</resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res-keyguard/values/dimens.xml b/packages/CarSystemUI/res-keyguard/values/dimens.xml
new file mode 100644
index 0000000..9424dc3
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/values/dimens.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2017, 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>
+    <dimen name="num_pad_margin_left">112dp</dimen>
+    <dimen name="num_pad_margin_right">144dp</dimen>
+    <dimen name="num_pad_key_width">80dp</dimen>
+    <dimen name="num_pad_key_height">80dp</dimen>
+    <dimen name="num_pad_key_margin_horizontal">@dimen/car_padding_6</dimen>
+    <dimen name="num_pad_key_margin_bottom">@dimen/car_padding_5</dimen>
+    <dimen name="pin_entry_height">@dimen/num_pad_key_height</dimen>
+    <dimen name="divider_height">1dp</dimen>
+    <dimen name="key_enter_margin_top">128dp</dimen>
+    <dimen name="keyguard_pattern_dimension">400dp</dimen>
+    <dimen name="password_field_width">350dp</dimen>
+    <dimen name="pin_pattern_pad_margin_vertical">0dp</dimen>
+</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values/integers.xml b/packages/CarSystemUI/res-keyguard/values/integers.xml
new file mode 100644
index 0000000..bad1346
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/values/integers.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2017, 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>
+    <integer name="password_text_view_scale">40</integer>
+    <integer name="password_max_length">500</integer>
+</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values/styles.xml b/packages/CarSystemUI/res-keyguard/values/styles.xml
new file mode 100644
index 0000000..b39e6e6
--- /dev/null
+++ b/packages/CarSystemUI/res-keyguard/values/styles.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2017, 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">
+
+    <!-- The style for the volume icons in the volume dialog. This style makes the icon scale to
+         fit its container since auto wants the icon to be larger. The padding is added to make it
+         so the icon does not press along the edges of the dialog. -->
+    <style name="NumPadKeyButton">
+        <item name="android:layout_width">@dimen/num_pad_key_width</item>
+        <item name="android:layout_height">@dimen/num_pad_key_height</item>
+        <item name="android:layout_marginBottom">@dimen/num_pad_key_margin_bottom</item>
+        <item name="textView">@id/pinEntry</item>
+    </style>
+
+    <style name="NumPadKeyButton.MiddleColumn">
+        <item name="android:layout_marginStart">@dimen/num_pad_key_margin_horizontal</item>
+        <item name="android:layout_marginEnd">@dimen/num_pad_key_margin_horizontal</item>
+    </style>
+
+    <style name="NumPadKeyButton.LastRow">
+        <item name="android:layout_marginBottom">0dp</item>
+    </style>
+
+    <style name="NumPadKeyButton.LastRow.MiddleColumn">
+        <item name="android:layout_marginStart">@dimen/num_pad_key_margin_horizontal</item>
+        <item name="android:layout_marginEnd">@dimen/num_pad_key_margin_horizontal</item>
+    </style>
+
+    <style name="KeyguardButton" parent="Widget.Car.Button">
+        <item name="android:background">@drawable/keyguard_button_background</item>
+        <item name="android:textColor">@color/button_text</item>
+        <item name="android:textAllCaps">false</item>
+    </style>
+
+    <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.TextView">
+        <!-- Only replaces the text size. -->
+        <item name="android:textSize">@dimen/car_body1_size</item>
+    </style>
+</resources>
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d114397..3bfd363 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -25,6 +25,7 @@
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
 import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
@@ -15711,7 +15712,7 @@
     }
 
     private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
-            boolean doingAll, long now) {
+            boolean doingAll, long now, boolean cycleReEval) {
         if (mAdjSeq == app.adjSeq) {
             if (app.adjSeq == app.completedAdjSeq) {
                 // This adjustment has already been computed successfully.
@@ -15777,20 +15778,21 @@
                 app.systemNoUi = false;
             }
             if (!app.systemNoUi) {
-              if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
-                  // screen on, promote UI
-                  app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
-                  app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
-              } else {
-                  // screen off, restrict UI scheduling
-                  app.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
-                  app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
-              }
+                if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
+                    // screen on, promote UI
+                    app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
+                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
+                } else {
+                    // screen off, restrict UI scheduling
+                    app.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
+                }
             }
+            app.setCurRawProcState(app.getCurProcState());
             app.curAdj = app.maxAdj;
             app.completedAdjSeq = app.adjSeq;
             // if curAdj is less than prevAppAdj, then this process was promoted
-            return app.curAdj < prevAppAdj;
+            return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
         }
 
         app.systemNoUi = false;
@@ -16032,8 +16034,13 @@
         // By default, we use the computed adjustment.  It may be changed if
         // there are applications dependent on our services or providers, but
         // this gives us a baseline and makes sure we don't get into an
-        // infinite recursion.
-        app.setCurRawAdj(adj);
+        // infinite recursion. If we're re-evaluating due to cycles, use the previously computed
+        // values.
+        app.setCurRawAdj(!cycleReEval ? adj : Math.min(adj, app.getCurRawAdj()));
+        app.setCurRawProcState(!cycleReEval
+                ? procState
+                : Math.min(procState, app.getCurRawProcState()));
+
         app.hasStartedServices = false;
         app.adjSeq = mAdjSeq;
 
@@ -16135,21 +16142,15 @@
                     boolean trackedProcState = false;
                     if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
                         ProcessRecord client = cr.binding.client;
-                        computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
-                        if (client.containsCycle) {
-                            // We've detected a cycle. We should retry computeOomAdjLocked later in
-                            // case a later-checked connection from a client  would raise its
-                            // priority legitimately.
-                            app.containsCycle = true;
-                            // If the client has not been completely evaluated, skip using its
-                            // priority. Else use the conservative value for now and look for a
-                            // better state in the next iteration.
-                            if (client.completedAdjSeq < mAdjSeq) {
-                                continue;
-                            }
+                        computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
+
+                        if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
+                            continue;
                         }
+
                         int clientAdj = client.getCurRawAdj();
-                        int clientProcState = client.getCurProcState();
+                        int clientProcState = client.getCurRawProcState();
+
                         if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                             // If the other app is cached for any reason, for purposes here
                             // we are going to consider it empty.  The specific cached state
@@ -16234,6 +16235,7 @@
                                 }
                                 if (adj >  newAdj) {
                                     adj = newAdj;
+                                    app.setCurRawAdj(adj);
                                     adjType = "service";
                                 }
                             }
@@ -16305,6 +16307,7 @@
                         }
                         if (procState > clientProcState) {
                             procState = clientProcState;
+                            app.setCurRawProcState(procState);
                             if (adjType == null) {
                                 adjType = "service";
                             }
@@ -16336,6 +16339,7 @@
                         if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
                                 && a.isActivityVisible()) {
                             adj = ProcessList.FOREGROUND_APP_ADJ;
+                            app.setCurRawAdj(adj);
                             if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                                 if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
                                     schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND;
@@ -16377,21 +16381,15 @@
                     // Being our own client is not interesting.
                     continue;
                 }
-                computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
-                if (client.containsCycle) {
-                    // We've detected a cycle. We should retry computeOomAdjLocked later in
-                    // case a later-checked connection from a client  would raise its
-                    // priority legitimately.
-                    app.containsCycle = true;
-                    // If the client has not been completely evaluated, skip using its
-                    // priority. Else use the conservative value for now and look for a
-                    // better state in the next iteration.
-                    if (client.completedAdjSeq < mAdjSeq) {
-                        continue;
-                    }
+                computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
+
+                if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
+                    continue;
                 }
+
                 int clientAdj = client.getCurRawAdj();
-                int clientProcState = client.getCurProcState();
+                int clientProcState = client.getCurRawProcState();
+
                 if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                     // If the other app is cached for any reason, for purposes here
                     // we are going to consider it empty.
@@ -16405,6 +16403,7 @@
                     } else {
                         adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
                                 ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
+                        app.setCurRawAdj(adj);
                         adjType = "provider";
                     }
                     app.cached &= client.cached;
@@ -16440,6 +16439,7 @@
                 conn.trackProcState(clientProcState, mAdjSeq, now);
                 if (procState > clientProcState) {
                     procState = clientProcState;
+                    app.setCurRawProcState(procState);
                 }
                 if (client.getCurrentSchedulingGroup() > schedGroup) {
                     schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -16465,6 +16465,7 @@
             if (cpr.hasExternalProcessHandles()) {
                 if (adj > ProcessList.FOREGROUND_APP_ADJ) {
                     adj = ProcessList.FOREGROUND_APP_ADJ;
+                    app.setCurRawAdj(adj);
                     schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                     app.cached = false;
                     app.adjType = "ext-provider";
@@ -16476,6 +16477,7 @@
                 }
                 if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
                     procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                    app.setCurRawProcState(procState);
                     if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                         reportOomAdjMessageLocked(TAG_OOM_ADJ,
                                 "Raise procstate to external provider: " + app);
@@ -16620,6 +16622,7 @@
         app.curAdj = app.modifyRawOomAdj(adj);
         app.setCurrentSchedulingGroup(schedGroup);
         app.setCurProcState(procState);
+        app.setCurRawProcState(procState);
         app.setHasForegroundActivities(foregroundActivities);
         app.completedAdjSeq = mAdjSeq;
 
@@ -16627,6 +16630,44 @@
         return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
     }
 
+    /**
+     * Checks if for the given app and client, there's a cycle that should skip over the client
+     * for now or use partial values to evaluate the effect of the client binding.
+     * @param app
+     * @param client
+     * @param procState procstate evaluated so far for this app
+     * @param adj oom_adj evaluated so far for this app
+     * @param cycleReEval whether we're currently re-evaluating due to a cycle, and not the first
+     *                    evaluation.
+     * @return whether to skip using the client connection at this time
+     */
+    private boolean shouldSkipDueToCycle(ProcessRecord app, ProcessRecord client,
+            int procState, int adj, boolean cycleReEval) {
+        if (client.containsCycle) {
+            // We've detected a cycle. We should retry computeOomAdjLocked later in
+            // case a later-checked connection from a client  would raise its
+            // priority legitimately.
+            app.containsCycle = true;
+            // If the client has not been completely evaluated, check if it's worth
+            // using the partial values.
+            if (client.completedAdjSeq < mAdjSeq) {
+                if (cycleReEval) {
+                    // If the partial values are no better, skip until the next
+                    // attempt
+                    if (client.getCurRawProcState() >= procState
+                            && client.getCurRawAdj() >= adj) {
+                        return true;
+                    }
+                    // Else use the client's partial procstate and adj to adjust the
+                    // effect of the binding
+                } else {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private static final class RecordPssRunnable implements Runnable {
         private final ActivityManagerService mService;
         private final ProcessRecord mProc;
@@ -17493,7 +17534,7 @@
             return false;
         }
 
-        computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
+        computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false);
 
         return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
     }
@@ -17868,12 +17909,14 @@
         for (int i=N-1; i>=0; i--) {
             ProcessRecord app = mProcessList.mLruProcesses.get(i);
             app.containsCycle = false;
+            app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
+            app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
         }
         for (int i=N-1; i>=0; i--) {
             ProcessRecord app = mProcessList.mLruProcesses.get(i);
             if (!app.killedByAm && app.thread != null) {
                 app.procStateChanged = false;
-                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
+                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now, false);
 
                 // if any app encountered a cycle, we need to perform an additional loop later
                 retryCycles |= app.containsCycle;
@@ -17976,8 +18019,8 @@
             for (int i=0; i<N; i++) {
                 ProcessRecord app = mProcessList.mLruProcesses.get(i);
                 if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
-
-                    if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now)) {
+                    if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now,
+                            true)) {
                         retryCycles = true;
                     }
                 }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c4b7150..c15b7c7 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -153,6 +153,7 @@
     int trimMemoryLevel;        // Last selected memory trimming level
     private int mCurProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
     private int mRepProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
+    private int mCurRawProcState = PROCESS_STATE_NONEXISTENT; // Temp state during computation
     int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker
     int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for
     int pssStatType;            // The type of stat collection that we are currently requesting
@@ -902,6 +903,7 @@
         if (mRepProcState > newState) {
             mRepProcState = newState;
             setCurProcState(newState);
+            setCurRawProcState(newState);
             for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
                 StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
                         uid, processName, pkgList.keyAt(ipkg),
@@ -984,6 +986,14 @@
         return mCurProcState;
     }
 
+    void setCurRawProcState(int curRawProcState) {
+        mCurRawProcState = curRawProcState;
+    }
+
+    int getCurRawProcState() {
+        return mCurRawProcState;
+    }
+
     void setReportedProcState(int repProcState) {
         mRepProcState = repProcState;
         for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 60cb08f..294b750 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -16,6 +16,12 @@
 
 package com.android.server.usb;
 
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
 import static com.android.internal.usb.DumpUtils.writeAccessory;
 import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull;
 
@@ -36,6 +42,7 @@
 import android.content.res.Resources;
 import android.debug.AdbManagerInternal;
 import android.debug.IAdbTransport;
+import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
@@ -294,9 +301,10 @@
         BroadcastReceiver portReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
+                ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
                 UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS);
-                mHandler.updateHostState(port, status);
+                mHandler.updateHostState(
+                        port.getUsbPort(context.getSystemService(UsbManager.class)), status);
             }
         };
 
@@ -821,23 +829,20 @@
                     boolean prevHostConnected = mHostConnected;
                     UsbPort port = (UsbPort) args.arg1;
                     UsbPortStatus status = (UsbPortStatus) args.arg2;
-                    mHostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
-                    mSourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE;
-                    mSinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK;
-                    mAudioAccessoryConnected =
-                            (status.getCurrentMode() == UsbPort.MODE_AUDIO_ACCESSORY);
-                    mAudioAccessorySupported = port.isModeSupported(UsbPort.MODE_AUDIO_ACCESSORY);
+                    mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST;
+                    mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE;
+                    mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK;
+                    mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY);
+                    mAudioAccessorySupported = port.isModeSupported(MODE_AUDIO_ACCESSORY);
                     // Ideally we want to see if PR_SWAP and DR_SWAP is supported.
                     // But, this should be suffice, since, all four combinations are only supported
                     // when PR_SWAP and DR_SWAP are supported.
                     mSupportsAllCombinations = status.isRoleCombinationSupported(
-                            UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST)
-                            && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK,
-                            UsbPort.DATA_ROLE_HOST)
-                            && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE,
-                            UsbPort.DATA_ROLE_DEVICE)
-                            && status.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK,
-                            UsbPort.DATA_ROLE_HOST);
+                            POWER_ROLE_SOURCE, DATA_ROLE_HOST)
+                            && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST)
+                            && status.isRoleCombinationSupported(POWER_ROLE_SOURCE,
+                            DATA_ROLE_DEVICE)
+                            && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST);
 
                     args.recycle();
                     updateUsbNotification(false);
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 96618f5..6f210e3 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -16,12 +16,22 @@
 
 package com.android.server.usb;
 
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.MODE_DFP;
+import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
+import static android.hardware.usb.UsbPortStatus.MODE_UFP;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
 import static com.android.internal.usb.DumpUtils.writePort;
 import static com.android.internal.usb.DumpUtils.writePortStatus;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbManager;
 import android.hardware.usb.UsbPort;
 import android.hardware.usb.UsbPortStatus;
@@ -78,13 +88,13 @@
 
     // All non-trivial role combinations.
     private static final int COMBO_SOURCE_HOST =
-            UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
-    private static final int COMBO_SOURCE_DEVICE =
-            UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE);
+            UsbPort.combineRolesAsBit(POWER_ROLE_SOURCE, DATA_ROLE_HOST);
+    private static final int COMBO_SOURCE_DEVICE = UsbPort.combineRolesAsBit(
+            POWER_ROLE_SOURCE, DATA_ROLE_DEVICE);
     private static final int COMBO_SINK_HOST =
-            UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST);
-    private static final int COMBO_SINK_DEVICE =
-            UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+            UsbPort.combineRolesAsBit(POWER_ROLE_SINK, DATA_ROLE_HOST);
+    private static final int COMBO_SINK_DEVICE = UsbPort.combineRolesAsBit(
+            POWER_ROLE_SINK, DATA_ROLE_DEVICE);
 
     // The system context.
     private final Context mContext;
@@ -217,12 +227,12 @@
             final int newMode;
             if ((!canChangePowerRole && currentPowerRole != newPowerRole)
                     || (!canChangeDataRole && currentDataRole != newDataRole)) {
-                if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SOURCE
-                        && newDataRole == UsbPort.DATA_ROLE_HOST) {
-                    newMode = UsbPort.MODE_DFP;
-                } else if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SINK
-                        && newDataRole == UsbPort.DATA_ROLE_DEVICE) {
-                    newMode = UsbPort.MODE_UFP;
+                if (canChangeMode && newPowerRole == POWER_ROLE_SOURCE
+                        && newDataRole == DATA_ROLE_HOST) {
+                    newMode = MODE_DFP;
+                } else if (canChangeMode && newPowerRole == POWER_ROLE_SINK
+                        && newDataRole == DATA_ROLE_DEVICE) {
+                    newMode = MODE_UFP;
                 } else {
                     logAndPrint(Log.ERROR, pw, "Found mismatch in supported USB role combinations "
                             + "while attempting to change role: " + portInfo
@@ -607,7 +617,7 @@
             IndentingPrintWriter pw) {
         // Only allow mode switch capability for dual role ports.
         // Validate that the current mode matches the supported modes we expect.
-        if ((supportedModes & UsbPort.MODE_DUAL) != UsbPort.MODE_DUAL) {
+        if ((supportedModes & MODE_DUAL) != MODE_DUAL) {
             canChangeMode = false;
             if (currentMode != 0 && currentMode != supportedModes) {
                 logAndPrint(Log.WARN, pw, "Ignoring inconsistent current mode from USB "
@@ -633,16 +643,16 @@
                 // Can only change power role.
                 // Assume data role must remain at its current value.
                 supportedRoleCombinations |= UsbPort.combineRolesAsBit(
-                        UsbPort.POWER_ROLE_SOURCE, currentDataRole);
+                        POWER_ROLE_SOURCE, currentDataRole);
                 supportedRoleCombinations |= UsbPort.combineRolesAsBit(
-                        UsbPort.POWER_ROLE_SINK, currentDataRole);
+                        POWER_ROLE_SINK, currentDataRole);
             } else if (canChangeDataRole) {
                 // Can only change data role.
                 // Assume power role must remain at its current value.
                 supportedRoleCombinations |= UsbPort.combineRolesAsBit(
-                        currentPowerRole, UsbPort.DATA_ROLE_HOST);
+                        currentPowerRole, DATA_ROLE_HOST);
                 supportedRoleCombinations |= UsbPort.combineRolesAsBit(
-                        currentPowerRole, UsbPort.DATA_ROLE_DEVICE);
+                        currentPowerRole, DATA_ROLE_DEVICE);
             } else if (canChangeMode) {
                 // Can only change the mode.
                 // Assume both standard UFP and DFP configurations will become available
@@ -654,7 +664,8 @@
         // Update the port data structures.
         PortInfo portInfo = mPorts.get(portId);
         if (portInfo == null) {
-            portInfo = new PortInfo(portId, supportedModes);
+            portInfo = new PortInfo(mContext.getSystemService(UsbManager.class), portId,
+                    supportedModes);
             portInfo.setStatus(currentMode, canChangeMode,
                     currentPowerRole, canChangePowerRole,
                     currentDataRole, canChangeDataRole,
@@ -701,12 +712,13 @@
         intent.addFlags(
                 Intent.FLAG_RECEIVER_FOREGROUND |
                         Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-        intent.putExtra(UsbManager.EXTRA_PORT, portInfo.mUsbPort);
+        intent.putExtra(UsbManager.EXTRA_PORT, ParcelableUsbPort.of(portInfo.mUsbPort));
         intent.putExtra(UsbManager.EXTRA_PORT_STATUS, portInfo.mUsbPortStatus);
 
         // Guard against possible reentrance by posting the broadcast from the handler
         // instead of from within the critical section.
-        mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL));
+        mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                Manifest.permission.MANAGE_USB));
 
         // Log to statsd
         if (!mConnected.containsKey(portInfo.mUsbPort.getId())
@@ -772,8 +784,8 @@
         // 0 when port is connected. Else reports the last connected duration
         public long mLastConnectDurationMillis;
 
-        public PortInfo(String portId, int supportedModes) {
-            mUsbPort = new UsbPort(portId, supportedModes);
+        PortInfo(@NonNull UsbManager usbManager, @NonNull String portId, int supportedModes) {
+            mUsbPort = new UsbPort(usbManager, portId, supportedModes);
         }
 
         public boolean setStatus(int currentMode, boolean canChangeMode,
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index f9abedf..9115477 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -16,6 +16,14 @@
 
 package com.android.server.usb;
 
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.MODE_DFP;
+import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
+import static android.hardware.usb.UsbPortStatus.MODE_UFP;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.PendingIntent;
@@ -27,6 +35,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.hardware.usb.IUsbManager;
+import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
@@ -52,7 +61,9 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 
 /**
  * UsbService manages all USB related state, including both host and device support.
@@ -489,12 +500,25 @@
     }
 
     @Override
-    public UsbPort[] getPorts() {
+    public List<ParcelableUsbPort> getPorts() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
 
         final long ident = Binder.clearCallingIdentity();
         try {
-            return mPortManager != null ? mPortManager.getPorts() : null;
+            if (mPortManager == null) {
+                return null;
+            } else {
+                final UsbPort[] ports = mPortManager.getPorts();
+
+                final int numPorts = ports.length;
+                ArrayList<ParcelableUsbPort> parcelablePorts = new ArrayList<>();
+                for (int i = 0; i < numPorts; i++) {
+                    parcelablePorts.add(ParcelableUsbPort.of(ports[i]));
+                }
+
+                return parcelablePorts;
+            }
+
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -588,10 +612,10 @@
                 final int powerRole;
                 switch (args[2]) {
                     case "source":
-                        powerRole = UsbPort.POWER_ROLE_SOURCE;
+                        powerRole = POWER_ROLE_SOURCE;
                         break;
                     case "sink":
-                        powerRole = UsbPort.POWER_ROLE_SINK;
+                        powerRole = POWER_ROLE_SINK;
                         break;
                     case "no-power":
                         powerRole = 0;
@@ -603,10 +627,10 @@
                 final int dataRole;
                 switch (args[3]) {
                     case "host":
-                        dataRole = UsbPort.DATA_ROLE_HOST;
+                        dataRole = DATA_ROLE_HOST;
                         break;
                     case "device":
-                        dataRole = UsbPort.DATA_ROLE_DEVICE;
+                        dataRole = DATA_ROLE_DEVICE;
                         break;
                     case "no-data":
                         dataRole = 0;
@@ -631,13 +655,13 @@
                 final int supportedModes;
                 switch (args[2]) {
                     case "ufp":
-                        supportedModes = UsbPort.MODE_UFP;
+                        supportedModes = MODE_UFP;
                         break;
                     case "dfp":
-                        supportedModes = UsbPort.MODE_DFP;
+                        supportedModes = MODE_DFP;
                         break;
                     case "dual":
-                        supportedModes = UsbPort.MODE_DUAL;
+                        supportedModes = MODE_DUAL;
                         break;
                     case "none":
                         supportedModes = 0;
@@ -658,10 +682,10 @@
                 final boolean canChangeMode = args[2].endsWith("?");
                 switch (canChangeMode ? removeLastChar(args[2]) : args[2]) {
                     case "ufp":
-                        mode = UsbPort.MODE_UFP;
+                        mode = MODE_UFP;
                         break;
                     case "dfp":
-                        mode = UsbPort.MODE_DFP;
+                        mode = MODE_DFP;
                         break;
                     default:
                         pw.println("Invalid mode: " + args[2]);
@@ -671,10 +695,10 @@
                 final boolean canChangePowerRole = args[3].endsWith("?");
                 switch (canChangePowerRole ? removeLastChar(args[3]) : args[3]) {
                     case "source":
-                        powerRole = UsbPort.POWER_ROLE_SOURCE;
+                        powerRole = POWER_ROLE_SOURCE;
                         break;
                     case "sink":
-                        powerRole = UsbPort.POWER_ROLE_SINK;
+                        powerRole = POWER_ROLE_SINK;
                         break;
                     default:
                         pw.println("Invalid power role: " + args[3]);
@@ -684,10 +708,10 @@
                 final boolean canChangeDataRole = args[4].endsWith("?");
                 switch (canChangeDataRole ? removeLastChar(args[4]) : args[4]) {
                     case "host":
-                        dataRole = UsbPort.DATA_ROLE_HOST;
+                        dataRole = DATA_ROLE_HOST;
                         break;
                     case "device":
-                        dataRole = UsbPort.DATA_ROLE_DEVICE;
+                        dataRole = DATA_ROLE_DEVICE;
                         break;
                     default:
                         pw.println("Invalid data role: " + args[4]);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 04c28e5..c8a899b 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -169,6 +170,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown.
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 04b6a6c..8e1877d 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -197,6 +198,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown.
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 8b1c1b9..f77c468 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
 
@@ -116,6 +117,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 3416ffe..31f9e6d 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -173,6 +174,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c7df36b..29d32e9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4908,7 +4908,7 @@
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
     public void requestCellInfoUpdate(
-            @NonNull Executor executor, @NonNull CellInfoCallback callback) {
+            @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony == null) return;