Merge "Build android.test.* with java_sdk_library"
diff --git a/Android.bp b/Android.bp
index 87f50af..7658fb2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1480,7 +1480,7 @@
     installable: false,
     metalava_enabled: true,
     metalava_annotations_enabled: true,
-    metalava_previous_api: ":public-api-for-metalava-annotations",
+    metalava_previous_api: ":last-released-public-api",
     metalava_merge_annotations_dirs: [
         "metalava-manual",
         "ojluni-annotated-stubs",
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 528c4df..0e0a8c7 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -177,7 +177,7 @@
 Landroid/app/INotificationManager;->cancelAllNotifications(Ljava/lang/String;I)V
 Landroid/app/INotificationManager;->cancelNotificationWithTag(Ljava/lang/String;Ljava/lang/String;II)V
 Landroid/app/INotificationManager;->cancelToast(Ljava/lang/String;Landroid/app/ITransientNotification;)V
-Landroid/app/INotificationManager;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;I)V
+Landroid/app/INotificationManager;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;II)V
 Landroid/app/INotificationManager;->getActiveNotifications(Ljava/lang/String;)[Landroid/service/notification/StatusBarNotification;
 Landroid/app/INotificationManager;->getHistoricalNotifications(Ljava/lang/String;I)[Landroid/service/notification/StatusBarNotification;
 Landroid/app/INotificationManager;->getZenMode()I
@@ -1986,11 +1986,6 @@
 Landroid/R$styleable;->Window_windowBackground:I
 Landroid/R$styleable;->Window_windowFrame:I
 Landroid/security/Credentials;->convertToPem([Ljava/security/cert/Certificate;)[B
-Landroid/security/Credentials;->getInstance()Landroid/security/Credentials;
-Landroid/security/Credentials;->install(Landroid/content/Context;Ljava/lang/String;[B)V
-Landroid/security/Credentials;->install(Landroid/content/Context;Ljava/security/KeyPair;)V
-Landroid/security/Credentials;->unlock(Landroid/content/Context;)V
-Landroid/security/GateKeeper;->getSecureUserId()J
 Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
 Landroid/security/IKeyChainService;->requestPrivateKey(Ljava/lang/String;)Ljava/lang/String;
 Landroid/security/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeystoreService;
@@ -2009,36 +2004,6 @@
 Landroid/security/IKeystoreService;->sign(Ljava/lang/String;[B)[B
 Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I
 Landroid/security/IKeystoreService;->verify(Ljava/lang/String;[B[B)I
-Landroid/security/keymaster/ExportResult;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/security/keymaster/KeyCharacteristics;-><init>()V
-Landroid/security/keymaster/KeyCharacteristics;->readFromParcel(Landroid/os/Parcel;)V
-Landroid/security/keymaster/KeymasterArguments;-><init>()V
-Landroid/security/keymaster/KeymasterArguments;->addEnum(II)V
-Landroid/security/keymaster/KeymasterArguments;->addUnsignedInt(IJ)V
-Landroid/security/keymaster/KeymasterArguments;->addUnsignedLong(ILjava/math/BigInteger;)V
-Landroid/security/keymaster/KeymasterArguments;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/security/keymaster/KeymasterArguments;->readFromParcel(Landroid/os/Parcel;)V
-Landroid/security/keymaster/KeymasterBlob;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/security/keymaster/OperationResult;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/security/KeyStore$State;->LOCKED:Landroid/security/KeyStore$State;
-Landroid/security/KeyStore$State;->UNLOCKED:Landroid/security/KeyStore$State;
-Landroid/security/keystore/AndroidKeyStoreProvider;->getKeyStoreOperationHandle(Ljava/lang/Object;)J
-Landroid/security/keystore/KeyGenParameterSpec;->getUid()I
-Landroid/security/keystore/KeyGenParameterSpec;->isUniqueIdIncluded()Z
-Landroid/security/KeyStore;->delete(Ljava/lang/String;)Z
-Landroid/security/KeyStore;->get(Ljava/lang/String;)[B
-Landroid/security/KeyStore;->getApplicationContext()Landroid/content/Context;
-Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
-Landroid/security/KeyStore;->getKeyStoreException(I)Landroid/security/KeyStoreException;
-Landroid/security/KeyStore;->isEmpty()Z
-Landroid/security/KeyStore;->NO_ERROR:I
-Landroid/security/KeyStore;->reset()Z
-Landroid/security/KeyStore;->state()Landroid/security/KeyStore$State;
-Landroid/security/KeyStore;->state(I)Landroid/security/KeyStore$State;
-Landroid/security/KeyStore;->unlock(Ljava/lang/String;)Z
-Landroid/security/KeystoreArguments;-><init>([[B)V
-Landroid/security/KeystoreArguments;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
 Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
 Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
 Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
diff --git a/config/hiddenapi-p-light-greylist.txt b/config/hiddenapi-p-light-greylist.txt
index e360879..e26a4c7 100644
--- a/config/hiddenapi-p-light-greylist.txt
+++ b/config/hiddenapi-p-light-greylist.txt
@@ -534,7 +534,7 @@
 Landroid/app/INotificationManager;->cancelAllNotifications(Ljava/lang/String;I)V
 Landroid/app/INotificationManager;->cancelNotificationWithTag(Ljava/lang/String;Ljava/lang/String;II)V
 Landroid/app/INotificationManager;->cancelToast(Ljava/lang/String;Landroid/app/ITransientNotification;)V
-Landroid/app/INotificationManager;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;I)V
+Landroid/app/INotificationManager;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;II)V
 Landroid/app/IProcessObserver$Stub;-><init>()V
 Landroid/app/ISearchManager$Stub$Proxy;->getGlobalSearchActivity()Landroid/content/ComponentName;
 Landroid/app/ISearchManager$Stub$Proxy;->getWebSearchActivity()Landroid/content/ComponentName;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index cd12710..3171e3e 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -43,7 +43,7 @@
     void cancelAllNotifications(String pkg, int userId);
 
     void clearData(String pkg, int uid, boolean fromApp);
-    void enqueueToast(String pkg, ITransientNotification callback, int duration);
+    void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId);
     void cancelToast(String pkg, ITransientNotification callback);
     void finishToken(String pkg, ITransientNotification callback);
 
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1275a85..caa99d5 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -819,11 +819,11 @@
      * camera in the list of supported camera devices.</p>
      * <p>This capability requires the camera device to support the following:</p>
      * <ul>
-     * <li>This camera device must list the following static metadata entries in {@link android.hardware.camera2.CameraCharacteristics }:<ul>
-     * <li>android.logicalMultiCamera.physicalIds</li>
-     * <li>{@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType}</li>
-     * </ul>
-     * </li>
+     * <li>The IDs of underlying physical cameras are returned via
+     *   {@link android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds }.</li>
+     * <li>This camera device must list static metadata
+     *   {@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType} in
+     *   {@link android.hardware.camera2.CameraCharacteristics }.</li>
      * <li>The underlying physical cameras' static metadata must list the following entries,
      *   so that the application can correlate pixels from the physical streams:<ul>
      * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d09c416..7980af1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7247,6 +7247,14 @@
         private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Whether the device should pulse on reach gesture.
+         * @hide
+         */
+        public static final String DOZE_REACH_GESTURE = "doze_reach_gesture";
+
+        private static final Validator DOZE_REACH_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * The current night mode that has been selected by the user.  Owned
          * and controlled by UiModeManagerService.  Constants are as per
          * UiModeManager.
@@ -8148,6 +8156,7 @@
             DOZE_ALWAYS_ON,
             DOZE_PICK_UP_GESTURE,
             DOZE_DOUBLE_TAP_GESTURE,
+            DOZE_REACH_GESTURE,
             NFC_PAYMENT_DEFAULT_COMPONENT,
             AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
             FACE_UNLOCK_KEYGUARD_ENABLED,
@@ -8291,6 +8300,7 @@
             VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR);
             VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR);
+            VALIDATORS.put(DOZE_REACH_GESTURE, DOZE_REACH_GESTURE_VALIDATOR);
             VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
             VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
                     AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
diff --git a/core/java/android/security/KeystoreArguments.java b/core/java/android/security/KeystoreArguments.java
index 16054e5..7d85ca7 100644
--- a/core/java/android/security/KeystoreArguments.java
+++ b/core/java/android/security/KeystoreArguments.java
@@ -16,6 +16,7 @@
 
 package android.security;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -27,6 +28,7 @@
 public class KeystoreArguments implements Parcelable {
     public byte[][] args;
 
+    @UnsupportedAppUsage
     public static final Parcelable.Creator<KeystoreArguments> CREATOR = new
             Parcelable.Creator<KeystoreArguments>() {
                 public KeystoreArguments createFromParcel(Parcel in) {
@@ -41,6 +43,7 @@
         args = null;
     }
 
+    @UnsupportedAppUsage
     public KeystoreArguments(byte[][] args) {
         this.args = args;
     }
diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java
index 2b3ccbc..c104671 100644
--- a/core/java/android/security/keymaster/ExportResult.java
+++ b/core/java/android/security/keymaster/ExportResult.java
@@ -16,6 +16,7 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -27,6 +28,7 @@
     public final int resultCode;
     public final byte[] exportData;
 
+    @UnsupportedAppUsage
     public static final Parcelable.Creator<ExportResult> CREATOR = new
             Parcelable.Creator<ExportResult>() {
                 public ExportResult createFromParcel(Parcel in) {
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
index 89300d1..555863e 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.java
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -16,6 +16,7 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -44,6 +45,7 @@
                 }
             };
 
+    @UnsupportedAppUsage
     public KeyCharacteristics() {}
 
     protected KeyCharacteristics(Parcel in) {
@@ -61,6 +63,7 @@
         hwEnforced.writeToParcel(out, flags);
     }
 
+    @UnsupportedAppUsage
     public void readFromParcel(Parcel in) {
         swEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
         hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index e862252..5aa0f91 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -16,6 +16,7 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -40,6 +41,7 @@
 
     private List<KeymasterArgument> mArguments;
 
+    @UnsupportedAppUsage
     public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
             Parcelable.Creator<KeymasterArguments>() {
                 @Override
@@ -53,6 +55,7 @@
                 }
             };
 
+    @UnsupportedAppUsage
     public KeymasterArguments() {
         mArguments = new ArrayList<KeymasterArgument>();
     }
@@ -66,6 +69,7 @@
      *
      * @throws IllegalArgumentException if {@code tag} is not an enum tag.
      */
+    @UnsupportedAppUsage
     public void addEnum(int tag, int value) {
         int tagType = KeymasterDefs.getTagType(tag);
         if ((tagType != KeymasterDefs.KM_ENUM) && (tagType != KeymasterDefs.KM_ENUM_REP)) {
@@ -137,6 +141,7 @@
      * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag or if
      *         {@code value} is outside of the permitted range [0; 2^32).
      */
+    @UnsupportedAppUsage
     public void addUnsignedInt(int tag, long value) {
         int tagType = KeymasterDefs.getTagType(tag);
         if ((tagType != KeymasterDefs.KM_UINT) && (tagType != KeymasterDefs.KM_UINT_REP)) {
@@ -173,6 +178,7 @@
      * @throws IllegalArgumentException if {@code tag} is not an unsigned 64-bit long tag or if
      *         {@code value} is outside of the permitted range [0; 2^64).
      */
+    @UnsupportedAppUsage
     public void addUnsignedLong(int tag, BigInteger value) {
         int tagType = KeymasterDefs.getTagType(tag);
         if ((tagType != KeymasterDefs.KM_ULONG) && (tagType != KeymasterDefs.KM_ULONG_REP)) {
@@ -358,6 +364,7 @@
         out.writeTypedList(mArguments);
     }
 
+    @UnsupportedAppUsage
     public void readFromParcel(Parcel in) {
         in.readTypedList(mArguments, KeymasterArgument.CREATOR);
     }
diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java
index cd36870..0659a22 100644
--- a/core/java/android/security/keymaster/KeymasterBlob.java
+++ b/core/java/android/security/keymaster/KeymasterBlob.java
@@ -16,6 +16,7 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,6 +29,7 @@
     public KeymasterBlob(byte[] blob) {
         this.blob = blob;
     }
+    @UnsupportedAppUsage
     public static final Parcelable.Creator<KeymasterBlob> CREATOR = new
             Parcelable.Creator<KeymasterBlob>() {
                 public KeymasterBlob createFromParcel(Parcel in) {
diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java
index 4c962ec..2943211 100644
--- a/core/java/android/security/keymaster/OperationResult.java
+++ b/core/java/android/security/keymaster/OperationResult.java
@@ -16,6 +16,7 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,6 +34,7 @@
     public final byte[] output;
     public final KeymasterArguments outParams;
 
+    @UnsupportedAppUsage
     public static final Parcelable.Creator<OperationResult> CREATOR = new
             Parcelable.Creator<OperationResult>() {
                 @Override
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index 2a30f11..d8936d9 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -21,6 +21,7 @@
 import java.security.cert.X509Certificate;
 import java.util.List;
 
+import android.annotation.UnsupportedAppUsage;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLSession;
@@ -121,6 +122,7 @@
      * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not
      * modify without modifying those callers.
      */
+    @UnsupportedAppUsage
     public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType,
             String hostname) throws CertificateException {
         if (hostname == null && mConfig.hasPerDomainConfigs()) {
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index bbdf15c..d1de498 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1247,7 +1247,10 @@
         private int[] mRules = new int[VERB_COUNT];
         private int[] mInitialRules = new int[VERB_COUNT];
 
-        private int mLeft, mTop, mRight, mBottom;
+        private int mLeft;
+        private int mTop;
+        private int mRight;
+        private int mBottom;
 
         /**
          * Whether this view had any relative rules modified following the most
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5cadbe4..3941d6a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -421,7 +421,9 @@
     private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
     private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
 
-    private float mShadowRadius, mShadowDx, mShadowDy;
+    private float mShadowRadius;
+    private float mShadowDx;
+    private float mShadowDy;
     private int mShadowColor;
 
     private boolean mPreDrawRegistered;
@@ -717,8 +719,10 @@
     private Scroller mScroller;
     private TextPaint mTempTextPaint;
 
-    private BoringLayout.Metrics mBoring, mHintBoring;
-    private BoringLayout mSavedLayout, mSavedHintLayout;
+    private BoringLayout.Metrics mBoring;
+    private BoringLayout.Metrics mHintBoring;
+    private BoringLayout mSavedLayout;
+    private BoringLayout mSavedHintLayout;
 
     private TextDirectionHeuristic mTextDir;
 
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index d74a60e..f6071d8 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -133,9 +133,10 @@
         String pkg = mContext.getOpPackageName();
         TN tn = mTN;
         tn.mNextView = mNextView;
+        final int displayId = mContext.getDisplay().getDisplayId();
 
         try {
-            service.enqueueToast(pkg, tn, mDuration);
+            service.enqueueToast(pkg, tn, mDuration, displayId);
         } catch (RemoteException e) {
             // Empty
         }
@@ -354,7 +355,8 @@
         final Handler mHandler;
 
         int mGravity;
-        int mX, mY;
+        int mX;
+        int mY;
         float mHorizontalMargin;
         float mVerticalMargin;
 
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index c21159e..8728367 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -66,6 +66,15 @@
         return !TextUtils.isEmpty(doubleTapSensorType());
     }
 
+    public boolean reachGestureEnabled(int user) {
+        return boolSettingDefaultOn(Settings.Secure.DOZE_REACH_GESTURE, user)
+                && reachGestureAvailable();
+    }
+
+    public boolean reachGestureAvailable() {
+        return !TextUtils.isEmpty(reachSensorType());
+    }
+
     public String doubleTapSensorType() {
         return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
     }
@@ -74,6 +83,10 @@
         return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
     }
 
+    public String reachSensorType() {
+        return mContext.getResources().getString(R.string.config_dozeReachSensorType);
+    }
+
     public boolean pulseOnLongPressEnabled(int user) {
         return pulseOnLongPressAvailable() && boolSettingDefaultOff(
                 Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user);
diff --git a/core/res/res/values-mcc214-mnc01/config.xml b/core/res/res/values-mcc214-mnc01/config.xml
index 24150a7..41e24d7 100644
--- a/core/res/res/values-mcc214-mnc01/config.xml
+++ b/core/res/res/values-mcc214-mnc01/config.xml
@@ -40,4 +40,7 @@
       <item>INTERNET,airtelnet.es,,,vodafone,vodafone,,,,,214,01,1,DUN</item>
     </string-array>
 
+    <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+    <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc222-mnc10/config.xml b/core/res/res/values-mcc222-mnc10/config.xml
index c819de2..0085a1b 100644
--- a/core/res/res/values-mcc222-mnc10/config.xml
+++ b/core/res/res/values-mcc222-mnc10/config.xml
@@ -28,4 +28,8 @@
     <string-array translatable="false" name="config_tether_apndata">
       <item>Tethering Internet,web.omnitel.it,,,,,,,,,222,10,,DUN</item>
     </string-array>
+
+    <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+    <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc234-mnc15/config.xml b/core/res/res/values-mcc234-mnc15/config.xml
new file mode 100644
index 0000000..84e779d
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc15/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+    <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc234-mnc91/config.xml b/core/res/res/values-mcc234-mnc91/config.xml
new file mode 100644
index 0000000..84e779d
--- /dev/null
+++ b/core/res/res/values-mcc234-mnc91/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+    <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc262-mnc02/config.xml b/core/res/res/values-mcc262-mnc02/config.xml
new file mode 100644
index 0000000..84e779d
--- /dev/null
+++ b/core/res/res/values-mcc262-mnc02/config.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+    <bool name="config_safe_media_disable_on_volume_up">false</bool>
+
+</resources>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 688040b..351f8ea 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -19,12 +19,12 @@
 <resources>
     <!-- The primary text color if the text is on top of a dark background.
     This is also affects colorized notifications with dark backgrounds. -->
-    <color name="notification_primary_text_color_dark">#dadada</color>
+    <color name="notification_primary_text_color_dark">#ddffffff</color>
 
     <!-- The secondary text color if the text is on top of a dark background. -->
-    <color name="notification_secondary_text_color_dark">#dadada</color>
+    <color name="notification_secondary_text_color_dark">#ddffffff</color>
 
-    <color name="notification_default_color_dark">#dadada</color>
+    <color name="notification_default_color_dark">#ddffffff</color>
 
     <!-- The background color of a notification card. -->
     <color name="notification_material_background_color">@*android:color/material_grey_900</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c8343e2..b15c9c5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2105,6 +2105,9 @@
     <!-- Type of the long press sensor. Empty if long press is not supported. -->
     <string name="config_dozeLongPressSensorType" translatable="false"></string>
 
+    <!-- Type of the reach sensor. Empty if reach is not supported. -->
+    <string name="config_dozeReachSensorType" translatable="false"></string>
+
     <!-- Control whether the always on display mode is available. This should only be enabled on
          devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND
          states. -->
@@ -2356,6 +2359,9 @@
     <!-- Whether safe headphone volume is enabled or not (country specific). -->
     <bool name="config_safe_media_volume_enabled">true</bool>
 
+    <!-- Whether safe headphone volume warning dialog is disabled on Vol+ (operator specific). -->
+    <bool name="config_safe_media_disable_on_volume_up">true</bool>
+
     <!-- Set to true if the wifi display supports compositing content stored
          in gralloc protected buffers.  For this to be true, there must exist
          a protected hardware path for surface flinger to composite and send
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5e1109e..2271baa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -309,6 +309,7 @@
   <java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" />
   <java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
   <java-symbol type="bool" name="config_safe_media_volume_enabled" />
+  <java-symbol type="bool" name="config_safe_media_disable_on_volume_up" />
   <java-symbol type="bool" name="config_camera_sound_forced" />
   <java-symbol type="bool" name="config_dontPreferApn" />
   <java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
@@ -3261,6 +3262,7 @@
   <java-symbol type="array" name="config_hideWhenDisabled_packageNames" />
 
   <java-symbol type="string" name="config_dozeLongPressSensorType" />
+  <java-symbol type="string" name="config_dozeReachSensorType" />
 
   <java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />
   <java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f6587d3..616a8d6 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -126,6 +126,7 @@
     <privapp-permissions package="com.android.omadm.service">
         <permission name="android.permission.CHANGE_CONFIGURATION"/>
         <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.WRITE_APN_SETTINGS"/>
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 57db20b..7216a22 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -16,6 +16,7 @@
 
 package android.security;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -172,6 +173,7 @@
 
     private static Credentials singleton;
 
+    @UnsupportedAppUsage
     public static Credentials getInstance() {
         if (singleton == null) {
             singleton = new Credentials();
@@ -179,6 +181,7 @@
         return singleton;
     }
 
+    @UnsupportedAppUsage
     public void unlock(Context context) {
         try {
             Intent intent = new Intent(UNLOCK_ACTION);
@@ -197,6 +200,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public void install(Context context, KeyPair pair) {
         try {
             Intent intent = KeyChain.createInstallIntent();
@@ -208,6 +212,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public void install(Context context, String type, byte[] value) {
         try {
             Intent intent = KeyChain.createInstallIntent();
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index 03df5de..a50ff79 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -16,6 +16,7 @@
 
 package android.security;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -42,6 +43,7 @@
         return service;
     }
 
+    @UnsupportedAppUsage
     public static long getSecureUserId() throws IllegalStateException {
         try {
             return getService().getSecureUserId(UserHandle.myUserId());
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 4f4ca3f..0a4ac8c 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,6 +16,7 @@
 
 package android.security;
 
+import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -57,6 +58,7 @@
     private static final String TAG = "KeyStore";
 
     // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
+    @UnsupportedAppUsage
     public static final int NO_ERROR = 1;
     public static final int LOCKED = 2;
     public static final int UNINITIALIZED = 3;
@@ -129,7 +131,9 @@
 
     // States
     public enum State {
+        @UnsupportedAppUsage
         UNLOCKED,
+        @UnsupportedAppUsage
         LOCKED,
         UNINITIALIZED
     };
@@ -146,6 +150,7 @@
         mContext = getApplicationContext();
     }
 
+    @UnsupportedAppUsage
     public static Context getApplicationContext() {
         Application application = ActivityThread.currentApplication();
         if (application == null) {
@@ -155,6 +160,7 @@
         return application;
     }
 
+    @UnsupportedAppUsage
     public static KeyStore getInstance() {
         IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
                 .getService("android.security.keystore"));
@@ -168,6 +174,7 @@
         return mToken;
     }
 
+    @UnsupportedAppUsage
     public State state(int userId) {
         final int ret;
         try {
@@ -185,6 +192,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public State state() {
         return state(UserHandle.myUserId());
     }
@@ -197,6 +205,7 @@
         return get(key, uid, false);
     }
 
+    @UnsupportedAppUsage
     public byte[] get(String key) {
         return get(key, UID_SELF);
     }
@@ -247,6 +256,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public boolean delete(String key) {
         return delete(key, UID_SELF);
     }
@@ -283,6 +293,7 @@
         return list(prefix, UID_SELF);
     }
 
+    @UnsupportedAppUsage
     public boolean reset() {
         try {
             return mBinder.reset() == NO_ERROR;
@@ -333,6 +344,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public boolean unlock(String password) {
         return unlock(UserHandle.getUserId(Process.myUid()), password);
     }
@@ -349,6 +361,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public boolean isEmpty() {
         return isEmpty(UserHandle.myUserId());
     }
@@ -818,6 +831,7 @@
      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
      * code.
      */
+    @UnsupportedAppUsage
     public static KeyStoreException getKeyStoreException(int errorCode) {
         if (errorCode > 0) {
             // KeyStore layer error
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index c048e82..c7c9ee4 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -17,6 +17,7 @@
 package android.security.keystore;
 
 import android.annotation.NonNull;
+import android.annotation.UnsupportedAppUsage;
 import android.security.KeyStore;
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
@@ -156,6 +157,7 @@
      *         by AndroidKeyStore provider.
      * @throws IllegalStateException if the provided primitive is not initialized.
      */
+    @UnsupportedAppUsage
     public static long getKeyStoreOperationHandle(Object cryptoPrimitive) {
         if (cryptoPrimitive == null) {
             throw new NullPointerException();
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 89d370f..c4df274 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.security.GateKeeper;
@@ -371,6 +372,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     public int getUid() {
         return mUid;
     }
@@ -645,6 +647,7 @@
      *
      * Returns {@code true} if the attestation certificate will contain a unique ID field.
      */
+    @UnsupportedAppUsage
     public boolean isUniqueIdIncluded() {
         return mUniqueIdIncluded;
     }
diff --git a/media/java/android/media/EncoderCapabilities.java b/media/java/android/media/EncoderCapabilities.java
index 332e360..59c9b82 100644
--- a/media/java/android/media/EncoderCapabilities.java
+++ b/media/java/android/media/EncoderCapabilities.java
@@ -42,11 +42,15 @@
      */
     static public class VideoEncoderCap {
         // These are not modifiable externally, thus are public accessible
-        public final int mCodec;                                 // @see android.media.MediaRecorder.VideoEncoder
-        public final int mMinBitRate, mMaxBitRate;               // min and max bit rate (bps)
-        public final int mMinFrameRate, mMaxFrameRate;           // min and max frame rate (fps)
-        public final int mMinFrameWidth, mMaxFrameWidth;         // min and max frame width (pixel)
-        public final int mMinFrameHeight, mMaxFrameHeight;       // minn and max frame height (pixel)
+        public final int mCodec;                // @see android.media.MediaRecorder.VideoEncoder
+        public final int mMinBitRate;           // min bit rate (bps)
+        public final int mMaxBitRate;           // max bit rate (bps)
+        public final int mMinFrameRate;         // min frame rate (fps)
+        public final int mMaxFrameRate;         // max frame rate (fps)
+        public final int mMinFrameWidth;        // min frame width (pixel)
+        public final int mMaxFrameWidth;        // max frame width (pixel)
+        public final int mMinFrameHeight;       // min frame height (pixel)
+        public final int mMaxFrameHeight;       // max frame height (pixel)
 
         // Private constructor called by JNI
         private VideoEncoderCap(int codec,
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
new file mode 100644
index 0000000..36ef04a
--- /dev/null
+++ b/packages/CarSystemUI/Android.bp
@@ -0,0 +1,76 @@
+//
+// 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.
+//
+android_app {
+    name: "CarSystemUI",
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+
+    static_libs: [
+        "SystemUI-core",
+        "SystemUIPluginLib",
+        "SystemUISharedLib",
+        "SettingsLib",
+        "androidx.car_car",
+        "androidx.legacy_legacy-support-v4",
+        "androidx.recyclerview_recyclerview",
+        "androidx.preference_preference",
+        "androidx.appcompat_appcompat",
+        "androidx.mediarouter_mediarouter",
+        "androidx.palette_palette",
+        "androidx.legacy_legacy-preference-v14",
+        "androidx.leanback_leanback",
+        "androidx.slice_slice-core",
+        "androidx.slice_slice-view",
+        "androidx.slice_slice-builders",
+        "androidx.arch.core_core-runtime",
+        "androidx.lifecycle_lifecycle-extensions",
+        "SystemUI-tags",
+        "SystemUI-proto",
+    ],
+
+    libs: [
+        "telephony-common",
+        "android.car",
+    ],
+
+    manifest: "AndroidManifest.xml",
+
+    owner: "google",
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        proguard_flags_files: [
+            "proguard.flags",
+        ],
+    },
+    resource_dirs: [
+        "res",
+    ],
+
+
+    dxflags: ["--multi-dex"],
+
+    aaptflags: [
+        "--extra-packages",
+        "com.android.keyguard",
+    ],
+
+}
diff --git a/packages/CarSystemUI/Android.mk b/packages/CarSystemUI/Android.mk
deleted file mode 100644
index 0d40b7f..0000000
--- a/packages/CarSystemUI/Android.mk
+++ /dev/null
@@ -1,86 +0,0 @@
-# LOCAL_PATH is not the current directory of this file.
-# If you need the local path, use CAR_SYSUI_PATH.
-# This tweak ensures that the resource overlay that is device-specific still works
-# which requires that LOCAL_PATH match the original path (which must be frameworks/base/packages/SystemUI).
-#
-# For clarity, we also define SYSTEM_UI_AOSP_PATH to frameworks/base/packages/SystemUI and refer to that
-SYSTEM_UI_AOSP_PATH := frameworks/base/packages/SystemUI
-SYSTEM_UI_CAR_PATH := frameworks/base/packages/CarSystemUI
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := optional
-
-# The same as SYSTEM_UI_AOSP_PATH but based on the value of LOCAL_PATH which is
-# frameworks/base/packages/CarSystemUI.
-RELATIVE_SYSTEM_UI_AOSP_PATH := ../../../../$(SYSTEM_UI_AOSP_PATH)
-
-
-LOCAL_SRC_FILES :=  \
-    $(call all-java-files-under, src) \
-    $(call all-Iaidl-files-under, src) \
-    $(call all-java-files-under, $(RELATIVE_SYSTEM_UI_AOSP_PATH)/src) \
-    $(call all-Iaidl-files-under, $(RELATIVE_SYSTEM_UI_AOSP_PATH)/src)
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    SystemUIPluginLib \
-    SystemUISharedLib \
-    androidx.car_car \
-    androidx.legacy_legacy-support-v4 \
-    androidx.recyclerview_recyclerview \
-    androidx.preference_preference \
-    androidx.appcompat_appcompat \
-    androidx.mediarouter_mediarouter \
-    androidx.palette_palette \
-    androidx.legacy_legacy-preference-v14 \
-    androidx.leanback_leanback \
-    androidx.slice_slice-core \
-    androidx.slice_slice-view \
-    androidx.slice_slice-builders \
-    androidx.arch.core_core-runtime \
-    androidx.lifecycle_lifecycle-extensions \
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    SystemUI-tags \
-    SystemUI-proto
-
-LOCAL_JAVA_LIBRARIES := telephony-common \
-    android.car
-
-LOCAL_FULL_LIBS_MANIFEST_FILES := $(SYSTEM_UI_AOSP_PATH)/AndroidManifest.xml
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-
-LOCAL_MODULE_OWNER := google
-LOCAL_PACKAGE_NAME := CarSystemUI
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAG_FILES := $(RELATIVE_SYSTEM_UI_AOSP_PATH)/proguard.flags \
-    proguard.flags
-
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/res \
-    $(SYSTEM_UI_AOSP_PATH)/res-keyguard \
-    $(SYSTEM_UI_AOSP_PATH)/res
-
-ifneq ($(INCREMENTAL_BUILDS),)
-    LOCAL_PROGUARD_ENABLED := disabled
-    LOCAL_JACK_ENABLED := incremental
-endif
-
-LOCAL_DX_FLAGS := --multi-dex
-LOCAL_JACK_FLAGS := --multi-dex native
-
-include frameworks/base/packages/SettingsLib/common.mk
-
-LOCAL_OVERRIDES_PACKAGES := SystemUI
-
-LOCAL_AAPT_FLAGS := --extra-packages com.android.keyguard
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(SYSTEM_UI_CAR_PATH))
diff --git a/packages/CarSystemUI/proguard.flags b/packages/CarSystemUI/proguard.flags
index ceb037c..a81c7e0 100644
--- a/packages/CarSystemUI/proguard.flags
+++ b/packages/CarSystemUI/proguard.flags
@@ -1 +1,3 @@
 -keep class com.android.systemui.CarSystemUIFactory
+
+-include ../SystemUI/proguard.flags
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
new file mode 100644
index 0000000..4791517
--- /dev/null
+++ b/packages/SettingsLib/Android.bp
@@ -0,0 +1,25 @@
+android_library {
+
+    name: "SettingsLib",
+
+    libs: [
+        "androidx.annotation_annotation",
+        "androidx.legacy_legacy-support-v4",
+        "androidx.recyclerview_recyclerview",
+        "androidx.preference_preference",
+        "androidx.appcompat_appcompat",
+        "androidx.lifecycle_lifecycle-runtime",
+    ],
+
+    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
+    // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common
+
+    resource_dirs: ["res"],
+
+    srcs: ["src/**/*.java"],
+
+    min_sdk_version: "21",
+
+}
+
+// For the test package.
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
deleted file mode 100644
index 96012c1..0000000
--- a/packages/SettingsLib/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_AAPT2_ONLY := true
-
-LOCAL_MODULE := SettingsLib
-
-LOCAL_JAVA_LIBRARIES := \
-    androidx.annotation_annotation
-
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    androidx.legacy_legacy-support-v4 \
-    androidx.recyclerview_recyclerview \
-    androidx.preference_preference \
-    androidx.appcompat_appcompat \
-    androidx.lifecycle_lifecycle-runtime
-
-LOCAL_SHARED_JAVA_LIBRARIES := \
-    androidx.lifecycle_lifecycle-common
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_JAR_EXCLUDE_FILES := none
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MIN_SDK_VERSION := 21
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# For the test package.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 2af406d..b523ae2 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -449,7 +449,6 @@
     <string name="alarm_template_far" msgid="3779172822607461675">"<xliff:g id="WHEN">%1$s</xliff:g> વાગ્યે"</string>
     <string name="zen_mode_duration_settings_title" msgid="229547412251222757">"અવધિ"</string>
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"દર વખતે પૂછો"</string>
-    <!-- no translation found for zen_mode_forever (2704305038191592967) -->
-    <skip />
+    <string name="zen_mode_forever" msgid="2704305038191592967">"તમે બંધ ન કરો ત્યાં સુધી"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"હમણાં જ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index ff1f4f3..63c88cd 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -449,7 +449,6 @@
     <string name="alarm_template_far" msgid="3779172822607461675">"<xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ"</string>
     <string name="zen_mode_duration_settings_title" msgid="229547412251222757">"ਮਿਆਦ"</string>
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string>
-    <!-- no translation found for zen_mode_forever (2704305038191592967) -->
-    <skip />
+    <string name="zen_mode_forever" msgid="2704305038191592967">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ਹੁਣੇ ਹੀ"</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 1ce4484..a710410 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -42,7 +42,6 @@
     private BluetoothA2dp mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
 
     static final ParcelUuid[] SINK_UUIDS = {
@@ -71,7 +70,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "A2dpProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(A2dpProfile.this, BluetoothProfile.STATE_CONNECTED);
                 device.refresh();
@@ -94,14 +93,12 @@
         return BluetoothProfile.A2DP;
     }
 
-    A2dpProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    A2dpProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
         mContext = context;
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new A2dpServiceListener(),
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new A2dpServiceListener(),
                 BluetoothProfile.A2DP);
     }
 
@@ -123,20 +120,6 @@
 
     public boolean connect(BluetoothDevice device) {
         if (mService == null) return false;
-        int max_connected_devices = mLocalAdapter.getMaxConnectedAudioDevices();
-        if (max_connected_devices == 1) {
-            // Original behavior: disconnect currently connected device
-            List<BluetoothDevice> sinks = getConnectedDevices();
-            if (sinks != null) {
-                for (BluetoothDevice sink : sinks) {
-                    if (sink.equals(device)) {
-                        Log.w(TAG, "Connecting to device " + device + " : disconnect skipped");
-                        continue;
-                    }
-                    mService.disconnect(sink);
-                }
-            }
-        }
         return mService.connect(device);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 6a4aa0a..0c4e02b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -38,7 +38,6 @@
     private BluetoothA2dpSink mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
 
     static final ParcelUuid[] SRC_UUIDS = {
@@ -67,7 +66,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "A2dpSinkProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(A2dpSinkProfile.this, BluetoothProfile.STATE_CONNECTED);
                 device.refresh();
@@ -90,13 +89,11 @@
         return BluetoothProfile.A2DP_SINK;
     }
 
-    A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    A2dpSinkProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new A2dpSinkServiceListener(),
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new A2dpSinkServiceListener(),
                 BluetoothProfile.A2DP_SINK);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index a3f3b59..466d02b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -150,7 +150,7 @@
         for (BluetoothDevice device : bondedDevices) {
             CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
             if (cachedDevice == null) {
-                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, device);
+                cachedDevice = mDeviceManager.addDevice(device);
                 dispatchDeviceAdded(cachedDevice);
                 deviceAdded = true;
             }
@@ -282,7 +282,7 @@
             // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
             CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
             if (cachedDevice == null) {
-                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, device);
+                cachedDevice = mDeviceManager.addDevice(device);
                 Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
                         + cachedDevice);
             }
@@ -348,8 +348,7 @@
                 if (cachedDevice == null) {
                     Log.w(TAG, "Got bonding state changed for " + device +
                             ", but we have no record of that device.");
-
-                    cachedDevice = mDeviceManager.addDevice(mLocalAdapter, device);
+                    cachedDevice = mDeviceManager.addDevice(device);
                     dispatchDeviceAdded(cachedDevice);
                 }
             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index b0ff9e3..5ecbe80 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -48,7 +48,7 @@
     private static final String TAG = "CachedBluetoothDevice";
 
     private final Context mContext;
-    private final LocalBluetoothAdapter mLocalAdapter;
+    private final BluetoothAdapter mLocalAdapter;
     private final LocalBluetoothProfileManager mProfileManager;
     private final BluetoothDevice mDevice;
     //TODO: consider remove, BluetoothDevice.getName() is already cached
@@ -143,7 +143,7 @@
             Log.d(TAG, "onProfileStateChanged: profile " + profile +
                     " newProfileState " + newProfileState);
         }
-        if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
+        if (mLocalAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF)
         {
             if (BluetoothUtils.D) {
                 Log.d(TAG, " BT Turninig Off...Profile conn state change ignored...");
@@ -179,11 +179,10 @@
     }
 
     CachedBluetoothDevice(Context context,
-                          LocalBluetoothAdapter adapter,
                           LocalBluetoothProfileManager profileManager,
                           BluetoothDevice device) {
         mContext = context;
-        mLocalAdapter = adapter;
+        mLocalAdapter = BluetoothAdapter.getDefaultAdapter();
         mProfileManager = profileManager;
         mDevice = device;
         mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 475ece8..f8543fc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -107,10 +107,10 @@
      * @param device the address of the new Bluetooth device
      * @return the newly created CachedBluetoothDevice object
      */
-    public CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter, BluetoothDevice device) {
+    public CachedBluetoothDevice addDevice(BluetoothDevice device) {
         LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
-        CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, adapter,
-            profileManager, device);
+        CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, profileManager,
+                device);
         if (profileManager.getHearingAidProfile() != null
             && profileManager.getHearingAidProfile().getHiSyncId(newDevice.getDevice())
                 != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index e284382..99f550b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -41,7 +41,6 @@
     private BluetoothHeadset mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final LocalBluetoothProfileManager mProfileManager;
 
@@ -70,7 +69,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "HeadsetProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(HeadsetProfile.this,
                         BluetoothProfile.STATE_CONNECTED);
@@ -97,13 +96,11 @@
         return BluetoothProfile.HEADSET;
     }
 
-    HeadsetProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    HeadsetProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new HeadsetServiceListener(),
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new HeadsetServiceListener(),
                 BluetoothProfile.HEADSET);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index a0cf105..6eaa620 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -38,7 +38,6 @@
     private BluetoothHearingAid mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
 
     static final String NAME = "HearingAid";
@@ -64,7 +63,7 @@
                     if (V) {
                         Log.d(TAG, "HearingAidProfile found new device: " + nextDevice);
                     }
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(HearingAidProfile.this,
                         BluetoothProfile.STATE_CONNECTED);
@@ -92,15 +91,13 @@
         return BluetoothProfile.HEARING_AID;
     }
 
-    HearingAidProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    HearingAidProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
         mContext = context;
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new HearingAidServiceListener(),
-                BluetoothProfile.HEARING_AID);
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+                new HearingAidServiceListener(), BluetoothProfile.HEARING_AID);
     }
 
     public boolean isConnectable() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index b8c72fb..4b4db75 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -41,7 +41,6 @@
     private BluetoothHeadsetClient mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
 
     static final ParcelUuid[] SRC_UUIDS = {
@@ -71,7 +70,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "HfpClient profile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(
                     HfpClientProfile.this, BluetoothProfile.STATE_CONNECTED);
@@ -97,14 +96,12 @@
         return BluetoothProfile.HEADSET_CLIENT;
     }
 
-    HfpClientProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    HfpClientProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new HfpClientServiceListener(),
-                BluetoothProfile.HEADSET_CLIENT);
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+                new HfpClientServiceListener(), BluetoothProfile.HEADSET_CLIENT);
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index f9da109..8c4bff5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -39,7 +39,6 @@
     private static final int PREFERRED_VALUE = -1;
     private static final boolean DEBUG = true;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final LocalBluetoothProfileManager mProfileManager;
     static final String NAME = "HID DEVICE";
@@ -47,14 +46,12 @@
     private BluetoothHidDevice mService;
     private boolean mIsProfileReady;
 
-    HidDeviceProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    HidDeviceProfile(Context context,CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        adapter.getProfileProxy(context, new HidDeviceServiceListener(),
-                BluetoothProfile.HID_DEVICE);
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+                new HidDeviceServiceListener(), BluetoothProfile.HID_DEVICE);
     }
 
     // These callbacks run on the main thread.
@@ -73,7 +70,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "HidProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 Log.d(TAG, "Connection status changed: " + device);
                 device.onProfileStateChanged(HidDeviceProfile.this,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index c5ba58c..701ef00 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -38,7 +38,6 @@
     private BluetoothHidHost mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final LocalBluetoothProfileManager mProfileManager;
 
@@ -62,7 +61,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "HidProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED);
                 device.refresh();
@@ -85,13 +84,12 @@
         return BluetoothProfile.HID_HOST;
     }
 
-    HidProfile(Context context, LocalBluetoothAdapter adapter,
+    HidProfile(Context context,
         CachedBluetoothDeviceManager deviceManager,
         LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        adapter.getProfileProxy(context, new HidHostServiceListener(),
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new HidHostServiceListener(),
                 BluetoothProfile.HID_HOST);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index 5e7f6d4..8f40ab4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -249,10 +249,6 @@
         return mAdapter.getRemoteDevice(address);
     }
 
-    public int getMaxConnectedAudioDevices() {
-        return mAdapter.getMaxConnectedAudioDevices();
-    }
-
     public List<Integer> getSupportedProfiles() {
         return mAdapter.getSupportedProfiles();
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 3ebbf7e..8bb8210 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothA2dpSink;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHeadsetClient;
@@ -79,7 +80,6 @@
     }
 
     private final Context mContext;
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final BluetoothEventManager mEventManager;
 
@@ -111,14 +111,13 @@
             BluetoothEventManager eventManager) {
         mContext = context;
 
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mEventManager = eventManager;
         mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
         // MAP Client is typically used in the same situations as PBAP Client
         mUseMapClient = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
         // pass this reference to adapter and event manager (circular dependency)
-        mLocalAdapter.setProfileManager(this);
+        adapter.setProfileManager(this);
 
         updateLocalProfiles();
         if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
@@ -128,26 +127,26 @@
      * create profile instance according to bluetooth supported profile list
      */
     void updateLocalProfiles() {
-        List<Integer> supportedList = mLocalAdapter.getSupportedProfiles();
+        List<Integer> supportedList = BluetoothAdapter.getDefaultAdapter().getSupportedProfiles();
         if (CollectionUtils.isEmpty(supportedList)) {
             if(DEBUG) Log.d(TAG, "supportedList is null");
             return;
         }
         if (mA2dpProfile == null && supportedList.contains(BluetoothProfile.A2DP)) {
             if(DEBUG) Log.d(TAG, "Adding local A2DP profile");
-            mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
+            mA2dpProfile = new A2dpProfile(mContext, mDeviceManager, this);
             addProfile(mA2dpProfile, A2dpProfile.NAME,
                     BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
         }
         if (mA2dpSinkProfile == null && supportedList.contains(BluetoothProfile.A2DP_SINK)) {
             if(DEBUG) Log.d(TAG, "Adding local A2DP SINK profile");
-            mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this);
+            mA2dpSinkProfile = new A2dpSinkProfile(mContext, mDeviceManager, this);
             addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME,
                     BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
         }
         if (mHeadsetProfile == null && supportedList.contains(BluetoothProfile.HEADSET)) {
             if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
-            mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter, mDeviceManager, this);
+            mHeadsetProfile = new HeadsetProfile(mContext, mDeviceManager, this);
             addHeadsetProfile(mHeadsetProfile, HeadsetProfile.NAME,
                     BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
                     BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
@@ -155,7 +154,7 @@
         }
         if (mHfpClientProfile == null && supportedList.contains(BluetoothProfile.HEADSET_CLIENT)) {
             if(DEBUG) Log.d(TAG, "Adding local HfpClient profile");
-            mHfpClientProfile = new HfpClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
+            mHfpClientProfile = new HfpClientProfile(mContext, mDeviceManager, this);
             addHeadsetProfile(mHfpClientProfile, HfpClientProfile.NAME,
                     BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED,
                     BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED,
@@ -165,13 +164,13 @@
             if (mMapClientProfile == null && supportedList.contains(BluetoothProfile.MAP_CLIENT)) {
                 if(DEBUG) Log.d(TAG, "Adding local MAP CLIENT profile");
                 mMapClientProfile =
-                        new MapClientProfile(mContext, mLocalAdapter, mDeviceManager,this);
+                        new MapClientProfile(mContext, mDeviceManager,this);
                 addProfile(mMapClientProfile, MapClientProfile.NAME,
                         BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
             }
         } else if (mMapProfile == null && supportedList.contains(BluetoothProfile.MAP)) {
             if(DEBUG) Log.d(TAG, "Adding local MAP profile");
-            mMapProfile = new MapProfile(mContext, mLocalAdapter, mDeviceManager, this);
+            mMapProfile = new MapProfile(mContext, mDeviceManager, this);
             addProfile(mMapProfile, MapProfile.NAME, BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
         }
         if (mOppProfile == null && supportedList.contains(BluetoothProfile.OPP)) {
@@ -182,26 +181,26 @@
         }
         if (mHearingAidProfile == null && supportedList.contains(BluetoothProfile.HEARING_AID)) {
             if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile");
-            mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager,
+            mHearingAidProfile = new HearingAidProfile(mContext, mDeviceManager,
                     this);
             addProfile(mHearingAidProfile, HearingAidProfile.NAME,
                     BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
         }
         if (mHidProfile == null && supportedList.contains(BluetoothProfile.HID_HOST)) {
             if(DEBUG) Log.d(TAG, "Adding local HID_HOST profile");
-            mHidProfile = new HidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+            mHidProfile = new HidProfile(mContext, mDeviceManager, this);
             addProfile(mHidProfile, HidProfile.NAME,
                     BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
         }
         if (mHidDeviceProfile == null && supportedList.contains(BluetoothProfile.HID_DEVICE)) {
             if(DEBUG) Log.d(TAG, "Adding local HID_DEVICE profile");
-            mHidDeviceProfile = new HidDeviceProfile(mContext, mLocalAdapter, mDeviceManager, this);
+            mHidDeviceProfile = new HidDeviceProfile(mContext, mDeviceManager, this);
             addProfile(mHidDeviceProfile, HidDeviceProfile.NAME,
                     BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
         }
         if (mPanProfile == null && supportedList.contains(BluetoothProfile.PAN)) {
             if(DEBUG) Log.d(TAG, "Adding local PAN profile");
-            mPanProfile = new PanProfile(mContext, mLocalAdapter);
+            mPanProfile = new PanProfile(mContext);
             addPanProfile(mPanProfile, PanProfile.NAME,
                     BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
         }
@@ -214,8 +213,7 @@
         if (mUsePbapPce && mPbapClientProfile == null && supportedList.contains(
                 BluetoothProfile.PBAP_CLIENT)) {
             if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile");
-            mPbapClientProfile = new PbapClientProfile(mContext, mLocalAdapter, mDeviceManager,
-                    this);
+            mPbapClientProfile = new PbapClientProfile(mContext, mDeviceManager,this);
             addProfile(mPbapClientProfile, PbapClientProfile.NAME,
                     BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
         }
@@ -271,7 +269,7 @@
             CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
             if (cachedDevice == null) {
                 Log.w(TAG, "StateChangedHandler found new device: " + device);
-                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, device);
+                cachedDevice = mDeviceManager.addDevice(device);
             }
             onReceiveInternal(intent, cachedDevice);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 63af24c..7d334eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -41,7 +41,6 @@
     private BluetoothMapClient mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final LocalBluetoothProfileManager mProfileManager;
 
@@ -71,7 +70,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "MapProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(MapClientProfile.this,
                         BluetoothProfile.STATE_CONNECTED);
@@ -99,14 +98,12 @@
         return BluetoothProfile.MAP_CLIENT;
     }
 
-    MapClientProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    MapClientProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new MapClientServiceListener(),
-                BluetoothProfile.MAP_CLIENT);
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+                new MapClientServiceListener(), BluetoothProfile.MAP_CLIENT);
     }
 
     public boolean isConnectable() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 2c63d50..689669f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -41,7 +41,6 @@
     private BluetoothMap mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final LocalBluetoothProfileManager mProfileManager;
 
@@ -70,7 +69,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "MapProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(MapProfile.this,
                         BluetoothProfile.STATE_CONNECTED);
@@ -98,13 +97,11 @@
         return BluetoothProfile.MAP;
     }
 
-    MapProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    MapProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new MapServiceListener(),
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new MapServiceListener(),
                 BluetoothProfile.MAP);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index e204d03..02afe8d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -38,7 +38,6 @@
 
     private BluetoothPan mService;
     private boolean mIsProfileReady;
-    private final LocalBluetoothAdapter mLocalAdapter;
 
     // Tethering direction for each device
     private final HashMap<BluetoothDevice, Integer> mDeviceRoleMap =
@@ -74,9 +73,8 @@
         return BluetoothProfile.PAN;
     }
 
-    PanProfile(Context context, LocalBluetoothAdapter adapter) {
-        mLocalAdapter = adapter;
-        mLocalAdapter.getProfileProxy(context, new PanServiceListener(),
+    PanProfile(Context context) {
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new PanServiceListener(),
             BluetoothProfile.PAN);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index d34ad30..ad3506f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -39,7 +39,6 @@
     private BluetoothPbapClient mService;
     private boolean mIsProfileReady;
 
-    private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
 
     static final ParcelUuid[] SRC_UUIDS = {
@@ -69,7 +68,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "PbapClientProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(PbapClientProfile.this, BluetoothProfile.STATE_CONNECTED);
                 device.refresh();
@@ -105,14 +104,12 @@
         return BluetoothProfile.PBAP_CLIENT;
     }
 
-    PbapClientProfile(Context context, LocalBluetoothAdapter adapter,
-            CachedBluetoothDeviceManager deviceManager,
+    PbapClientProfile(Context context, CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
-        mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        mLocalAdapter.getProfileProxy(context, new PbapClientServiceListener(),
-                BluetoothProfile.PBAP_CLIENT);
+        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+                new PbapClientServiceListener(), BluetoothProfile.PBAP_CLIENT);
     }
 
     public boolean isConnectable() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index f1d73ed..f0e259e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -69,7 +69,7 @@
                 // we may add a new device here, but generally this should not happen
                 if (device == null) {
                     Log.w(TAG, "SapProfile found new device: " + nextDevice);
-                    device = mDeviceManager.addDevice(mLocalAdapter, nextDevice);
+                    device = mDeviceManager.addDevice(nextDevice);
                 }
                 device.onProfileStateChanged(SapProfile.this,
                         BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index b2ab45c..29831a8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -19,11 +19,11 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothCodecConfig;
 import android.bluetooth.BluetoothCodecStatus;
 import android.bluetooth.BluetoothDevice;
@@ -33,21 +33,23 @@
 
 import com.android.settingslib.R;
 import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
 public class A2dpProfileTest {
 
     @Mock
     Context mContext;
     @Mock
-    LocalBluetoothAdapter mAdapter;
-    @Mock
     CachedBluetoothDeviceManager mDeviceManager;
     @Mock
     LocalBluetoothProfileManager mProfileManager;
@@ -58,20 +60,14 @@
     BluetoothProfile.ServiceListener mServiceListener;
 
     A2dpProfile mProfile;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-
-        // Capture the A2dpServiceListener our A2dpProfile will pass during its constructor, so that
-        // we can call its onServiceConnected method and get it to use our mock BluetoothA2dp
-        // object.
-        doAnswer((invocation) -> {
-            mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
-            return null;
-        }).when(mAdapter).getProfileProxy(any(Context.class), any(), eq(BluetoothProfile.A2DP));
-
-        mProfile = new A2dpProfile(mContext, mAdapter, mDeviceManager, mProfileManager);
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mProfile = new A2dpProfile(mContext, mDeviceManager, mProfileManager);
+        mServiceListener = mShadowBluetoothAdapter.getServiceListener();
         mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp);
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index b33e9c3..2d34f23 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
@@ -59,8 +58,6 @@
     private final BluetoothClass DEVICE_CLASS_2 =
         new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE);
     @Mock
-    private LocalBluetoothAdapter mLocalAdapter;
-    @Mock
     private LocalBluetoothProfileManager mLocalProfileManager;
     @Mock
     private LocalBluetoothManager mLocalBluetoothManager;
@@ -110,18 +107,17 @@
 
         when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager);
-        when(mLocalAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
         when(mHfpProfile.isProfileReady()).thenReturn(true);
         when(mA2dpProfile.isProfileReady()).thenReturn(true);
         when(mPanProfile.isProfileReady()).thenReturn(true);
         when(mHearingAidProfile.isProfileReady()).thenReturn(true);
         mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager);
         mCachedDevice1 = spy(
-            new CachedBluetoothDevice(mContext, mLocalAdapter, mLocalProfileManager, mDevice1));
+            new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1));
         mCachedDevice2 = spy(
-            new CachedBluetoothDevice(mContext, mLocalAdapter, mLocalProfileManager, mDevice2));
+            new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2));
         mCachedDevice3 = spy(
-            new CachedBluetoothDevice(mContext, mLocalAdapter, mLocalProfileManager, mDevice3));
+            new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice3));
     }
 
     /**
@@ -129,11 +125,9 @@
      */
     @Test
     public void testAddDevice_validCachedDevices_devicesAdded() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
 
         Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
@@ -149,8 +143,7 @@
      */
     @Test
     public void testGetName_validCachedDevice_nameFound() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         assertThat(mCachedDeviceManager.getName(mDevice1)).isEqualTo(DEVICE_ALIAS_1);
     }
@@ -160,8 +153,7 @@
      */
     @Test
     public void testOnDeviceNameUpdated_validName_nameUpdated() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         assertThat(cachedDevice1.getName()).isEqualTo(DEVICE_ALIAS_1);
 
@@ -176,11 +168,9 @@
      */
     @Test
     public void testClearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
 
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
@@ -231,11 +221,9 @@
      */
     @Test
     public void testOnHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
 
         // Since both devices do not have hiSyncId, they should be added in mCachedDevices.
@@ -266,11 +254,9 @@
      */
     @Test
     public void testOnHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
         cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
@@ -303,11 +289,9 @@
      */
     @Test
     public void testOnHiSyncIdChanged_differentHiSyncId_populateInSameList() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
 
         // Since both devices do not have hiSyncId, they should be added in mCachedDevices.
@@ -339,8 +323,7 @@
      */
     @Test
     public void testOnProfileConnectionStateChanged_singleDeviceConnected_visible() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
 
@@ -377,11 +360,9 @@
      */
     @Test
     public void testOnProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
         cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
@@ -431,11 +412,9 @@
      */
     @Test
     public void testOnProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
         cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
@@ -486,11 +465,9 @@
      */
     @Test
     public void testOnDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
 
         cachedDevice1.setHiSyncId(HISYNCID1);
@@ -518,14 +495,11 @@
      */
     @Test
     public void testOnDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
-        CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice3);
+        CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
         assertThat(cachedDevice2).isNotNull();
 
         cachedDevice1.setHiSyncId(HISYNCID1);
@@ -570,8 +544,7 @@
         doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
         doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice2);
 
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         // The first hearing aid device should be populated in mCachedDevice and
         // mCachedDevicesMapForHearingAids.
@@ -581,8 +554,7 @@
         assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids.values())
             .contains(cachedDevice1);
 
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
         // The second hearing aid device should be populated in mHearingAidDevicesNotAddedInCache.
         assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(1);
@@ -599,8 +571,7 @@
             .getHearingAidProfile();
         doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
         doAnswer((invocation) -> HISYNCID2).when(mHearingAidProfile).getHiSyncId(mDevice2);
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         // The first hearing aid device should be populated in mCachedDevice and
         // mCachedDevicesMapForHearingAids.
@@ -610,8 +581,7 @@
         assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids.values())
             .contains(cachedDevice1);
 
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-            mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
         // The second hearing aid device should also be populated in mCachedDevice
         // and mCachedDevicesMapForHearingAids as its not a pair of the first one.
@@ -680,8 +650,7 @@
      */
     @Test
     public void testOnBtClassChanged_validBtClass_classChanged() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         assertThat(cachedDevice1.getBtClass()).isEqualTo(DEVICE_CLASS_1);
 
@@ -696,8 +665,7 @@
      */
     @Test
     public void testOnDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
 
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
@@ -712,11 +680,9 @@
      */
     @Test
     public void testOnActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
 
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
@@ -777,11 +743,9 @@
      */
     @Test
     public void testOnActiveDeviceChanged_withA2dpAndHearingAid() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice1);
+        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
-                mDevice2);
+        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         assertThat(cachedDevice2).isNotNull();
 
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index c39fb85..034574f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
 
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
@@ -49,8 +48,6 @@
     private final static String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
     private final static String DEVICE_ALIAS_NEW = "TestAliasNew";
     @Mock
-    private LocalBluetoothAdapter mAdapter;
-    @Mock
     private LocalBluetoothProfileManager mProfileManager;
     @Mock
     private HeadsetProfile mHfpProfile;
@@ -73,13 +70,11 @@
         mContext = RuntimeEnvironment.application;
         mShadowAudioManager = shadowOf(mContext.getSystemService(AudioManager.class));
         when(mDevice.getAddress()).thenReturn(DEVICE_ADDRESS);
-        when(mAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
         when(mHfpProfile.isProfileReady()).thenReturn(true);
         when(mA2dpProfile.isProfileReady()).thenReturn(true);
         when(mPanProfile.isProfileReady()).thenReturn(true);
         when(mHearingAidProfile.isProfileReady()).thenReturn(true);
-        mCachedDevice = spy(
-                new CachedBluetoothDevice(mContext, mAdapter, mProfileManager, mDevice));
+        mCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mDevice));
         doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
     }
 
@@ -477,7 +472,7 @@
         when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS);
         when(mDevice.getName()).thenReturn(DEVICE_NAME);
         CachedBluetoothDevice cachedBluetoothDevice =
-                new CachedBluetoothDevice(mContext, mAdapter, mProfileManager, mDevice);
+                new CachedBluetoothDevice(mContext, mProfileManager, mDevice);
         // Verify alias is returned on getName
         assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ALIAS);
         // Verify device is visible
@@ -487,7 +482,7 @@
     @Test
     public void testDeviceName_testNameNotAvailable() {
         CachedBluetoothDevice cachedBluetoothDevice =
-                new CachedBluetoothDevice(mContext, mAdapter, mProfileManager, mDevice);
+                new CachedBluetoothDevice(mContext, mProfileManager, mDevice);
         // Verify device address is returned on getName
         assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ADDRESS);
         // Verify device is not visible
@@ -504,7 +499,7 @@
         }).when(mDevice).setAlias(anyString());
         when(mDevice.getName()).thenReturn(DEVICE_NAME);
         CachedBluetoothDevice cachedBluetoothDevice =
-                new CachedBluetoothDevice(mContext, mAdapter, mProfileManager, mDevice);
+                new CachedBluetoothDevice(mContext, mProfileManager, mDevice);
         // Verify alias is returned on getName
         assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ALIAS);
         // Verify null name does not get set
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
index bc8be4d..c0a1f0c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
@@ -2,18 +2,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 
 import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -21,13 +20,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
 public class HeadsetProfileTest {
 
     @Mock
-    private LocalBluetoothAdapter mAdapter;
-    @Mock
     private CachedBluetoothDeviceManager mDeviceManager;
     @Mock
     private LocalBluetoothProfileManager mProfileManager;
@@ -39,19 +39,18 @@
     private BluetoothDevice mBluetoothDevice;
     private BluetoothProfile.ServiceListener mServiceListener;
     private HeadsetProfile mProfile;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         Context context = spy(RuntimeEnvironment.application);
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
 
-        doAnswer((invocation) -> {
-            mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
-            return null;
-        }).when(mAdapter).getProfileProxy(any(Context.class), any(), eq(BluetoothProfile.HEADSET));
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
 
-        mProfile = new HeadsetProfile(context, mAdapter, mDeviceManager, mProfileManager);
+        mProfile = new HeadsetProfile(context, mDeviceManager, mProfileManager);
+        mServiceListener = mShadowBluetoothAdapter.getServiceListener();
         mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mService);
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index af66f7a..f223176 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -38,6 +38,7 @@
 import android.os.ParcelUuid;
 
 import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -45,34 +46,38 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
 public class LocalBluetoothProfileManagerTest {
     @Mock
     private CachedBluetoothDeviceManager mDeviceManager;
     @Mock
     private BluetoothEventManager mEventManager;
     @Mock
-    private LocalBluetoothAdapter mAdapter;
-    @Mock
     private BluetoothDevice mDevice;
     @Mock
     private CachedBluetoothDevice mCachedBluetoothDevice;
 
     private Context mContext;
-    private LocalBluetoothProfileManager mProfileManager;
     private Intent mIntent;
+    private LocalBluetoothAdapter mLocalBluetoothAdapter;
+    private LocalBluetoothProfileManager mProfileManager;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
-        mEventManager = spy(new BluetoothEventManager(mAdapter,
-                mDeviceManager, mContext));
-        when(mAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
+        mLocalBluetoothAdapter = LocalBluetoothAdapter.getInstance();
+        mEventManager = spy(new BluetoothEventManager(mLocalBluetoothAdapter, mDeviceManager,
+                mContext));
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
         when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedBluetoothDevice);
     }
 
@@ -81,12 +86,10 @@
      */
     @Test
     public void constructor_initiateHidAndHidDeviceProfile() {
-        when(mAdapter.getSupportedProfiles()).thenReturn(
-                generateList(new int[] {BluetoothProfile.HID_HOST}));
-        when(mAdapter.getSupportedProfiles()).thenReturn(
-                generateList(new int[] {BluetoothProfile.HID_HOST, BluetoothProfile.HID_DEVICE}));
-        mProfileManager =
-                new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager, mEventManager);
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
+                new int[] {BluetoothProfile.HID_HOST, BluetoothProfile.HID_DEVICE}));
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
 
         assertThat(mProfileManager.getHidProfile()).isNotNull();
         assertThat(mProfileManager.getHidDeviceProfile()).isNotNull();
@@ -97,12 +100,12 @@
      */
     @Test
     public void updateLocalProfiles_addA2dpToLocalProfiles() {
-        mProfileManager =
-                new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager, mEventManager);
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         assertThat(mProfileManager.getA2dpProfile()).isNull();
         assertThat(mProfileManager.getHeadsetProfile()).isNull();
 
-        when(mAdapter.getSupportedProfiles()).thenReturn(generateList(
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                 new int[] {BluetoothProfile.A2DP}));
         mProfileManager.updateLocalProfiles();
 
@@ -115,10 +118,10 @@
      */
     @Test
     public void updateProfiles_addHidProfileForRemoteDevice() {
-        when(mAdapter.getSupportedProfiles()).thenReturn(generateList(
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                 new int[] {BluetoothProfile.HID_HOST}));
-        mProfileManager =
-                new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager, mEventManager);
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         ParcelUuid[] uuids = new ParcelUuid[]{BluetoothUuid.Hid};
         ParcelUuid[] localUuids = new ParcelUuid[]{};
         List<LocalBluetoothProfile> profiles = new ArrayList<>();
@@ -138,10 +141,10 @@
      */
     @Test
     public void stateChangedHandler_receiveA2dpConnectionStateChanged_shouldDispatchCallback() {
-        when(mAdapter.getSupportedProfiles()).thenReturn(generateList(
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                 new int[] {BluetoothProfile.A2DP}));
-        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
-                mEventManager);
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
         // LocalBluetoothProfileManager created.
         mEventManager.setReceiverHandler(null);
@@ -162,10 +165,10 @@
      */
     @Test
     public void stateChangedHandler_receiveHeadsetConnectionStateChanged_shouldDispatchCallback() {
-        when(mAdapter.getSupportedProfiles()).thenReturn(generateList(
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                 new int[] {BluetoothProfile.HEADSET}));
-        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
-                mEventManager);
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
         // LocalBluetoothProfileManager created.
         mEventManager.setReceiverHandler(null);
@@ -186,12 +189,10 @@
      */
     @Test
     public void stateChangedHandler_receiveHAPConnectionStateChanged_shouldDispatchCallback() {
-        ArrayList<Integer> supportProfiles = new ArrayList<>();
-        supportProfiles.add(BluetoothProfile.HEARING_AID);
-        when(mAdapter.getSupportedProfiles()).thenReturn(supportProfiles);
-        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.HearingAid});
-        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
-                mEventManager);
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
+                new int[] {BluetoothProfile.HEARING_AID}));
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
         // LocalBluetoothProfileManager created.
         mEventManager.setReceiverHandler(null);
@@ -212,10 +213,10 @@
      */
     @Test
     public void stateChangedHandler_receivePanConnectionStateChanged_shouldNotDispatchCallback() {
-        when(mAdapter.getSupportedProfiles()).thenReturn(
-                generateList(new int[] {BluetoothProfile.PAN}));
-        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
-                mEventManager);
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
+                new int[] {BluetoothProfile.PAN}));
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
         // LocalBluetoothProfileManager created.
         mEventManager.setReceiverHandler(null);
@@ -237,9 +238,9 @@
     @Test
     public void stateChangedHandler_receivePanConnectionStateChangedWithoutProfile_shouldNotRefresh
     () {
-        when(mAdapter.getSupportedProfiles()).thenReturn(null);
-        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
-                mEventManager);
+        mShadowBluetoothAdapter.setSupportedProfiles(null);
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
         // LocalBluetoothProfileManager created.
         mEventManager.setReceiverHandler(null);
@@ -259,10 +260,10 @@
      */
     @Test
     public void stateChangedHandler_receivePanConnectionStateChangedWithProfile_shouldRefresh() {
-        when(mAdapter.getSupportedProfiles()).thenReturn(generateList(
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                 new int[] {BluetoothProfile.PAN}));
-        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
-                mEventManager);
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
+                mDeviceManager, mEventManager);
         // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
         // LocalBluetoothProfileManager created.
         mEventManager.setReceiverHandler(null);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
new file mode 100644
index 0000000..9b8c230
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
@@ -0,0 +1,53 @@
+/*
+ * 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 com.android.settingslib.testutils.shadow;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.List;
+
+@Implements(value = BluetoothAdapter.class, inheritImplementationMethods = true)
+public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBluetoothAdapter {
+
+    private List<Integer> mSupportedProfiles;
+    private BluetoothProfile.ServiceListener mServiceListener;
+
+    @Implementation
+    public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
+            int profile) {
+        mServiceListener = listener;
+        return true;
+    }
+
+    public BluetoothProfile.ServiceListener getServiceListener() {
+        return mServiceListener;
+    }
+
+    @Implementation
+    public List<Integer> getSupportedProfiles() {
+        return mSupportedProfiles;
+    }
+
+    public void setSupportedProfiles(List<Integer> supportedProfiles) {
+        mSupportedProfiles = supportedProfiles;
+    }
+}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
new file mode 100644
index 0000000..c9ba268
--- /dev/null
+++ b/packages/SystemUI/Android.bp
@@ -0,0 +1,101 @@
+//
+// 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.
+//
+
+java_library {
+    name: "SystemUI-proto",
+
+    srcs: ["src/**/*.proto"],
+
+    proto: {
+        type: "nano",
+    },
+}
+
+java_library {
+    name: "SystemUI-tags",
+    srcs: ["src/com/android/systemui/EventLogTags.logtags"],
+}
+
+android_library {
+    name: "SystemUI-core",
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+    resource_dirs: [
+        "res-keyguard",
+        "res",
+    ],
+    static_libs: [
+        "SystemUIPluginLib",
+        "SystemUISharedLib",
+        "SettingsLib",
+        "androidx.car_car",
+        "androidx.legacy_legacy-support-v4",
+        "androidx.recyclerview_recyclerview",
+        "androidx.preference_preference",
+        "androidx.appcompat_appcompat",
+        "androidx.mediarouter_mediarouter",
+        "androidx.palette_palette",
+        "androidx.legacy_legacy-preference-v14",
+        "androidx.leanback_leanback",
+        "androidx.slice_slice-core",
+        "androidx.slice_slice-view",
+        "androidx.slice_slice-builders",
+        "androidx.arch.core_core-runtime",
+        "androidx.lifecycle_lifecycle-extensions",
+        "SystemUI-tags",
+        "SystemUI-proto",
+    ],
+    manifest: "AndroidManifest.xml",
+
+    libs: [
+        "telephony-common",
+        "android.car",
+    ],
+
+    aaptflags: [
+        "--extra-packages",
+        "com.android.keyguard",
+    ],
+}
+
+android_app {
+    name: "SystemUI",
+    static_libs: [
+        "SystemUI-core",
+    ],
+
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+    },
+
+    libs: [
+        "telephony-common",
+        "android.car",
+    ],
+
+    dxflags: ["--multi-dex"],
+    aaptflags: [
+        "--extra-packages",
+        "com.android.keyguard",
+    ],
+
+}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
deleted file mode 100644
index 920e3b6a..0000000
--- a/packages/SystemUI/Android.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := SystemUI-proto
-
-LOCAL_SRC_FILES := $(call all-proto-files-under,src)
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := SystemUI-tags
-
-LOCAL_SRC_FILES := src/com/android/systemui/EventLogTags.logtags
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# ------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := optional
-
-RELATIVE_FINGERPRINT_PATH := ../../core/java/android/hardware/fingerprint
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-Iaidl-files-under, src) \
-    $(call all-Iaidl-files-under, $(RELATIVE_FINGERPRINT_PATH))
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    SystemUIPluginLib \
-    SystemUISharedLib \
-    androidx.car_car \
-    androidx.legacy_legacy-support-v4 \
-    androidx.recyclerview_recyclerview \
-    androidx.preference_preference \
-    androidx.appcompat_appcompat \
-    androidx.mediarouter_mediarouter \
-    androidx.palette_palette \
-    androidx.legacy_legacy-preference-v14 \
-    androidx.leanback_leanback \
-    androidx.slice_slice-core \
-    androidx.slice_slice-view \
-    androidx.slice_slice-builders \
-    androidx.arch.core_core-runtime \
-    androidx.lifecycle_lifecycle-extensions \
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    SystemUI-tags \
-    SystemUI-proto
-
-LOCAL_JAVA_LIBRARIES := telephony-common \
-    android.car
-
-LOCAL_PACKAGE_NAME := SystemUI
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res-keyguard $(LOCAL_PATH)/res
-
-ifneq ($(INCREMENTAL_BUILDS),)
-    LOCAL_PROGUARD_ENABLED := disabled
-    LOCAL_JACK_ENABLED := incremental
-    LOCAL_DX_FLAGS := --multi-dex
-    LOCAL_JACK_FLAGS := --multi-dex native
-endif
-
-include frameworks/base/packages/SettingsLib/common.mk
-
-LOCAL_AAPT_FLAGS := --extra-packages com.android.keyguard
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
new file mode 100644
index 0000000..b38059d
--- /dev/null
+++ b/packages/SystemUI/plugin/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 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.
+
+java_library {
+
+    name: "SystemUIPluginLib",
+
+    srcs: ["src/**/*.java"],
+
+
+}
+
+android_app {
+
+    // Dummy to generate .toc files.
+    name: "PluginDummyLib",
+    platform_apis: true,
+    srcs: ["src/**/*.java"],
+
+    libs: ["SystemUIPluginLib"],
+
+    optimize: {
+        enabled: false,
+    },
+
+}
diff --git a/packages/SystemUI/plugin/Android.mk b/packages/SystemUI/plugin/Android.mk
deleted file mode 100644
index 8634684..0000000
--- a/packages/SystemUI/plugin/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := SystemUIPluginLib
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAR_EXCLUDE_FILES := none
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-
-# Dummy to generate .toc files.
-LOCAL_PACKAGE_NAME := PluginDummyLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := SystemUIPluginLib
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/plugin/ExamplePlugin/Android.bp b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
new file mode 100644
index 0000000..a0eaf14
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
@@ -0,0 +1,14 @@
+android_app {
+
+    name: "ExamplePlugin",
+
+    libs: ["SystemUIPluginLib"],
+
+    certificate: "platform",
+    optimize: {
+        enabled: false,
+    },
+
+    srcs: ["src/**/*.java"],
+
+}
diff --git a/packages/SystemUI/plugin/ExamplePlugin/Android.mk b/packages/SystemUI/plugin/ExamplePlugin/Android.mk
deleted file mode 100644
index 4c82c75..0000000
--- a/packages/SystemUI/plugin/ExamplePlugin/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_PACKAGE_NAME := ExamplePlugin
-
-LOCAL_JAVA_LIBRARIES := SystemUIPluginLib
-
-LOCAL_CERTIFICATE := platform
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 61f7fe8..bf4374a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -43,7 +43,7 @@
     boolean isAvailable();
     void setTileSpec(String tileSpec);
 
-    void clearState();
+    @Deprecated default void clearState() {}
     void refreshState();
 
     void addCallback(Callback callback);
diff --git a/packages/SystemUI/res-keyguard/values/alias.xml b/packages/SystemUI/res-keyguard/values/alias.xml
index f06b450..1c63c79 100644
--- a/packages/SystemUI/res-keyguard/values/alias.xml
+++ b/packages/SystemUI/res-keyguard/values/alias.xml
@@ -25,9 +25,6 @@
     <!-- Alias used to reference framework "OK" string in keyguard.  -->
     <item type="string" name="ok">@*android:string/ok</item>
 
-    <!-- Alias used to reference framework "OK" string in keyguard.  -->
-    <item type="string" name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</item>
-
     <!-- Alias used to reference framework configuration for screen rotation.  -->
     <item type="bool" name="config_enableLockScreenRotation">@*android:bool/config_enableLockScreenRotation</item>
 
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_home.xml b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
index a960af7..da23937 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_home.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
@@ -14,13 +14,13 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval"
-    android:useLevel="false">
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="28dp"
+    android:height="28dp"
+    android:viewportWidth="28"
+    android:viewportHeight="28">
 
-    <solid android:color="?attr/singleToneColor" />
-
-    <size
-        android:height="14dp"
-        android:width="14dp" />
-</shape>
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M 14 7 C 17.8659932488 7 21 10.1340067512 21 14 C 21 17.8659932488 17.8659932488 21 14 21 C 10.1340067512 21 7 17.8659932488 7 14 C 7 10.1340067512 10.1340067512 7 14 7 Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 915fc6e..9a64c60 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1929,23 +1929,17 @@
     <!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
     <string name="accessibility_qs_edit_add_tile_label"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g>. Double tap to add.</string>
 
-    <!-- Accessibility description of a place to drop a tile while editing positions [CHAR LIMIT=NONE] -->
-    <string name="accessibility_qs_edit_position_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>. Double tap to select.</string>
-
     <!-- Accessibility description of option to move QS tile [CHAR LIMIT=NONE] -->
     <string name="accessibility_qs_edit_move_tile">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
 
     <!-- Accessibility description of option to remove QS tile [CHAR LIMIT=NONE] -->
     <string name="accessibility_qs_edit_remove_tile">Remove <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
 
-    <!-- Accessibility action when QS tile is added [CHAR LIMIT=NONE] -->
-    <string name="accessibility_qs_edit_tile_added"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> is added to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
+    <!-- Accessibility action when QS tile is to be added [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_tile_add">Add <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
 
-    <!-- Accessibility action when QS tile is removed [CHAR LIMIT=NONE] -->
-    <string name="accessibility_qs_edit_tile_removed"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> is removed</string>
-
-    <!-- Accessibility action when QS tile is moved [CHAR LIMIT=NONE] -->
-    <string name="accessibility_qs_edit_tile_moved"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> moved to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
+    <!-- Accessibility action when QS tile is to be moved [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_tile_move">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
 
     <!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
new file mode 100644
index 0000000..0fb1200
--- /dev/null
+++ b/packages/SystemUI/shared/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 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.
+
+android_library {
+
+    name: "SystemUISharedLib",
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+
+}
+
+android_app {
+
+    name: "SysUISharedLib",
+    platform_apis: true,
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+
+    static_libs: ["SystemUISharedLib"],
+
+    optimize: {
+        enabled: false,
+    },
+
+}
diff --git a/packages/SystemUI/shared/Android.mk b/packages/SystemUI/shared/Android.mk
deleted file mode 100644
index f20df0c..0000000
--- a/packages/SystemUI/shared/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := SystemUISharedLib
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAR_EXCLUDE_FILES := none
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := SysUISharedLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := SystemUISharedLib
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/SystemUI/shared/tests/Android.mk b/packages/SystemUI/shared/tests/Android.mk
index 4e7cbbf..02774c9 100644
--- a/packages/SystemUI/shared/tests/Android.mk
+++ b/packages/SystemUI/shared/tests/Android.mk
@@ -30,10 +30,10 @@
 LOCAL_COMPATIBILITY_SUITE := device-tests
 
 # Add local path sources as well as shared lib sources
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    $(call all-java-files-under, ../src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+	SystemUISharedLib \
     metrics-helper-lib \
     android-support-test \
     mockito-target-inline-minus-junit4 \
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index f4acc0c..b159b39 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -15,7 +15,6 @@
  */
 package com.android.keyguard;
 
-import android.R.style;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
@@ -27,7 +26,6 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.StatsLog;
-import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
@@ -212,7 +210,7 @@
 
         if (messageId != 0) {
             final String message = mContext.getString(messageId,
-                    KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(userId),
+                    mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
                     timeoutInSeconds);
             showDialog(null, message);
         }
@@ -257,8 +255,8 @@
     }
 
     private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
-        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        final int failedAttempts = monitor.getFailedUnlockAttempts(userId) + 1; // +1 for this time
+        // +1 for this time
+        final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
 
         if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
 
@@ -292,7 +290,6 @@
                 showWipeDialog(failedAttempts, userType);
             }
         }
-        monitor.reportFailedStrongAuthUnlockAttempt(userId);
         mLockPatternUtils.reportFailedPasswordAttempt(userId);
         if (timeoutMs > 0) {
             mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
@@ -436,7 +433,6 @@
             if (success) {
                 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
                     StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
-                monitor.clearFailedUnlockAttempts();
                 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
             } else {
                 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 6517a9d..9603562 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -27,6 +27,7 @@
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Trace;
 import android.provider.Settings;
 import android.text.Layout;
 import android.text.TextUtils;
@@ -148,6 +149,7 @@
     }
 
     private void showSlice() {
+        Trace.beginSection("KeyguardSliceView#showSlice");
         if (mPulsing || mSlice == null) {
             mTitle.setVisibility(GONE);
             mRow.setVisibility(GONE);
@@ -236,6 +238,7 @@
         if (mContentChangeListener != null) {
             mContentChangeListener.run();
         }
+        Trace.endSection();
     }
 
     public void setPulsing(boolean pulsing, boolean animate) {
@@ -383,8 +386,23 @@
     }
 
     public void refresh() {
-        Slice slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
+        Slice slice;
+        Trace.beginSection("KeyguardSliceView#refresh");
+        // We can optimize performance and avoid binder calls when we know that we're bound
+        // to a Slice on the same process.
+        if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
+            KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
+            if (instance != null) {
+                slice = instance.onBindSlice(mKeyguardSliceUri);
+            } else {
+                Log.w(TAG, "Keyguard slice not bound yet?");
+                slice = null;
+            }
+        } else {
+            slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
+        }
         onChanged(slice);
+        Trace.endSection();
     }
 
     public static class Row extends LinearLayout {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index dfd6a18..3e534d1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -215,9 +215,6 @@
     // Battery status
     private BatteryStatus mBatteryStatus;
 
-    // Password attempts
-    private SparseIntArray mFailedAttempts = new SparseIntArray();
-
     private final StrongAuthTracker mStrongAuthTracker;
 
     private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
@@ -2141,22 +2138,10 @@
         return mDeviceProvisioned;
     }
 
-    public void clearFailedUnlockAttempts() {
-        mFailedAttempts.delete(sCurrentUser);
-    }
-
     public ServiceState getServiceState(int subId) {
         return mServiceStates.get(subId);
     }
 
-    public int getFailedUnlockAttempts(int userId) {
-        return mFailedAttempts.get(userId, 0);
-    }
-
-    public void reportFailedStrongAuthUnlockAttempt(int userId) {
-        mFailedAttempts.put(userId, getFailedUnlockAttempts(userId) + 1);
-    }
-
     public void clearBiometricRecognized() {
         mUserFingerprintAuthenticated.clear();
         mUserFaceAuthenticated.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 1cacdb5..51cc4a1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -35,7 +35,7 @@
     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
 
-    private static final int PULSE_REASONS = 6;
+    private static final int PULSE_REASONS = 7;
 
     public static final int PULSE_REASON_NONE = -1;
     public static final int PULSE_REASON_INTENT = 0;
@@ -44,6 +44,7 @@
     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
     public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
     public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
+    public static final int PULSE_REASON_SENSOR_REACH = 6;
 
     private static boolean sRegisterKeyguardCallback = true;
 
@@ -169,6 +170,11 @@
         log("state " + state);
     }
 
+    public static void traceReachWakeUp() {
+        if (!ENABLED) return;
+        log("reachWakeUp");
+    }
+
     public static void traceProximityResult(Context context, boolean near, long millis,
             int pulseReason) {
         if (!ENABLED) return;
@@ -186,6 +192,7 @@
             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
             case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
             case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
+            case PULSE_REASON_SENSOR_REACH: return "reach";
             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 18dffa7..045a98c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -110,6 +110,13 @@
                         DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
                         true /* reports touch coordinates */,
                         true /* touchscreen */),
+                new TriggerSensor(
+                        findSensorWithType(config.reachSensorType()),
+                        Settings.Secure.DOZE_REACH_GESTURE,
+                        true /* configured */,
+                        DozeLog.PULSE_REASON_SENSOR_REACH,
+                        false /* reports touch coordinates */,
+                        false /* touchscreen */),
         };
 
         mProxSensor = new ProxSensor(policy);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 4391a44..73cbd7d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -128,6 +128,7 @@
         boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
         boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
         boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
+        boolean isReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_REACH;
 
         if (isLongPress) {
             requestPulse(pulseReason, sensorPerformedProxCheck);
@@ -140,7 +141,7 @@
                 if (isDoubleTap) {
                     mDozeHost.onDoubleTap(screenX, screenY);
                     mMachine.wakeUp();
-                } else if (isPickup) {
+                } else if (isPickup || isReach) {
                     mMachine.wakeUp();
                 } else {
                     mDozeHost.extendPulse();
@@ -155,6 +156,8 @@
             final boolean withinVibrationThreshold =
                     timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
             DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold);
+        } else if (isReach) {
+            DozeLog.traceReachWakeUp();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index a42191c..76a1acc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -318,7 +318,7 @@
     private CachedBluetoothDevice getCachedBluetoothDevice(BluetoothDevice d) {
         CachedBluetoothDevice cachedDevice = mCachedDeviceManager.findDevice(d);
         if (cachedDevice == null) {
-            cachedDevice = mCachedDeviceManager.addDevice(mLocalBluetoothAdapter, d);
+            cachedDevice = mCachedDeviceManager.addDevice(d);
         }
         return cachedDevice;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index c96aa73..82b79ac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -30,6 +30,7 @@
 import android.icu.text.DisplayContext;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Trace;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 import android.text.TextUtils;
@@ -72,6 +73,8 @@
     @VisibleForTesting
     static final int ALARM_VISIBILITY_HOURS = 12;
 
+    private static KeyguardSliceProvider sInstance;
+
     protected final Uri mSliceUri;
     protected final Uri mDateUri;
     protected final Uri mAlarmUri;
@@ -89,6 +92,7 @@
     protected AlarmManager mAlarmManager;
     protected ContentResolver mContentResolver;
     private AlarmManager.AlarmClockInfo mNextAlarmInfo;
+    private PendingIntent mPendingIntent;
 
     /**
      * Receiver responsible for time ticking and updating the date format.
@@ -117,6 +121,10 @@
         this(new Handler());
     }
 
+    public static KeyguardSliceProvider getAttachedInstance() {
+        return KeyguardSliceProvider.sInstance;
+    }
+
     @VisibleForTesting
     KeyguardSliceProvider(Handler handler) {
         mHandler = handler;
@@ -128,23 +136,24 @@
 
     @Override
     public Slice onBindSlice(Uri sliceUri) {
+        Trace.beginSection("KeyguardSliceProvider#onBindSlice");
         ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
         builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
         addNextAlarm(builder);
         addZenMode(builder);
         addPrimaryAction(builder);
-        return builder.build();
+        Slice slice = builder.build();
+        Trace.endSection();
+        return slice;
     }
 
     protected void addPrimaryAction(ListBuilder builder) {
         // Add simple action because API requires it; Keyguard handles presenting
         // its own slices so this action + icon are actually never used.
-        PendingIntent pi = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
         IconCompat icon = IconCompat.createWithResource(getContext(),
                 R.drawable.ic_access_alarms_big);
-        SliceAction action = SliceAction.createDeeplink(pi, icon,
+        SliceAction action = SliceAction.createDeeplink(mPendingIntent, icon,
                 ListBuilder.ICON_IMAGE, mLastText);
-
         RowBuilder primaryActionRow = new RowBuilder(Uri.parse(KEYGUARD_ACTION_URI))
                 .setPrimaryAction(action);
         builder.addRow(primaryActionRow);
@@ -154,7 +163,6 @@
         if (TextUtils.isEmpty(mNextAlarm)) {
             return;
         }
-
         IconCompat alarmIcon = IconCompat.createWithResource(getContext(),
                 R.drawable.ic_access_alarms_big);
         RowBuilder alarmRowBuilder = new RowBuilder(mAlarmUri)
@@ -198,6 +206,8 @@
         mZenModeController = new ZenModeControllerImpl(getContext(), mHandler);
         mZenModeController.addCallback(this);
         mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
+        mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+        KeyguardSliceProvider.sInstance = this;
         registerClockUpdate();
         updateClock();
         return true;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 4763fa9..4977ff7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1655,7 +1655,6 @@
             resetKeyguardDonePendingLocked();
         }
 
-        mUpdateMonitor.clearFailedUnlockAttempts();
         mUpdateMonitor.clearBiometricRecognized();
 
         if (mGoingToSleep) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0876a5d..3fc258b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -285,9 +285,6 @@
 
         updatePageIndicator();
 
-        for (TileRecord r : mRecords) {
-            r.tile.clearState();
-        }
         if (mListening) {
             refreshAllTiles();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 78e9f36..10b92f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -88,6 +88,7 @@
     private Holder mCurrentDrag;
     private int mAccessibilityAction = ACTION_NONE;
     private int mAccessibilityFromIndex;
+    private CharSequence mAccessibilityFromLabel;
     private QSTileHost mHost;
 
     public TileAdapter(Context context) {
@@ -241,7 +242,8 @@
             holder.mTileView.setVisibility(View.VISIBLE);
             holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
             holder.mTileView.setContentDescription(mContext.getString(
-                    R.string.accessibility_qs_edit_position_label, position + 1));
+                    R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel,
+                    position + 1));
             holder.mTileView.setOnClickListener(new OnClickListener() {
                 @Override
                 public void onClick(View v) {
@@ -270,9 +272,12 @@
         if (position > mEditIndex) {
             info.state.contentDescription = mContext.getString(
                     R.string.accessibility_qs_edit_add_tile_label, info.state.label);
-        } else if (mAccessibilityAction != ACTION_NONE) {
+        } else if (mAccessibilityAction == ACTION_ADD) {
             info.state.contentDescription = mContext.getString(
-                    R.string.accessibility_qs_edit_position_label, position + 1);
+                    R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, position + 1);
+        } else if (mAccessibilityAction == ACTION_MOVE) {
+            info.state.contentDescription = mContext.getString(
+                    R.string.accessibility_qs_edit_tile_move, mAccessibilityFromLabel, position + 1);
         } else {
             info.state.contentDescription = mContext.getString(
                     R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
@@ -351,6 +356,7 @@
 
     private void startAccessibleAdd(int position) {
         mAccessibilityFromIndex = position;
+        mAccessibilityFromLabel = mTiles.get(position).state.label;
         mAccessibilityAction = ACTION_ADD;
         // Add placeholder for last slot.
         mTiles.add(mEditIndex++, null);
@@ -360,6 +366,7 @@
 
     private void startAccessibleMove(int position) {
         mAccessibilityFromIndex = position;
+        mAccessibilityFromLabel = mTiles.get(position).state.label;
         mAccessibilityAction = ACTION_MOVE;
         notifyDataSetChanged();
     }
@@ -385,15 +392,11 @@
                     strip(mTiles.get(to)));
             MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
                     to);
-            v.announceForAccessibility(mContext.getString(R.string.accessibility_qs_edit_tile_added,
-                    fromLabel, (to + 1)));
         } else {
             MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE_SPEC,
                     strip(mTiles.get(to)));
             MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE,
                     to);
-            v.announceForAccessibility(mContext.getString(R.string.accessibility_qs_edit_tile_moved,
-                    fromLabel, (to + 1)));
         }
         saveSpecs(mHost);
         return true;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 53a576d..591e9e0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -95,7 +95,6 @@
                 continue;
             }
             tile.setListening(this, true);
-            tile.clearState();
             tile.refreshState();
             tile.setListening(this, false);
             tile.setTileSpec(spec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 6bc3bee..b6a776f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -211,10 +211,6 @@
         mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
     }
 
-    public void clearState() {
-        mHandler.sendEmptyMessage(H.CLEAR_STATE);
-    }
-
     public void userSwitch(int newUserId) {
         mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
     }
@@ -266,11 +262,6 @@
 
     public abstract Intent getLongClickIntent();
 
-    protected void handleClearState() {
-        mTmpState = newTileState();
-        mState = newTileState();
-    }
-
     protected void handleRefreshState(Object arg) {
         handleUpdateState(mTmpState, arg);
         final boolean changed = mTmpState.copyTo(mState);
@@ -409,11 +400,10 @@
         private static final int TOGGLE_STATE_CHANGED = 8;
         private static final int SCAN_STATE_CHANGED = 9;
         private static final int DESTROY = 10;
-        private static final int CLEAR_STATE = 11;
-        private static final int REMOVE_CALLBACKS = 12;
-        private static final int REMOVE_CALLBACK = 13;
-        private static final int SET_LISTENING = 14;
-        private static final int STALE = 15;
+        private static final int REMOVE_CALLBACKS = 11;
+        private static final int REMOVE_CALLBACK = 12;
+        private static final int SET_LISTENING = 13;
+        private static final int STALE = 14;
 
         @VisibleForTesting
         protected H(Looper looper) {
@@ -467,9 +457,6 @@
                 } else if (msg.what == DESTROY) {
                     name = "handleDestroy";
                     handleDestroy();
-                } else if (msg.what == CLEAR_STATE) {
-                    name = "handleClearState";
-                    handleClearState();
                 } else if (msg.what == SET_LISTENING) {
                     name = "handleSetListeningInternal";
                     handleSetListeningInternal(msg.obj, msg.arg1 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
index d7c4bbf..c97095e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
@@ -21,11 +21,13 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Resources.NotFoundException;
 import android.media.AudioManager;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.WindowManager;
 
+
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 abstract public class SafetyWarningDialog extends SystemUIDialog
@@ -40,12 +42,18 @@
 
     private long mShowTime;
     private boolean mNewVolumeUp;
+    private boolean mDisableOnVolumeUp;
 
     public SafetyWarningDialog(Context context, AudioManager audioManager) {
         super(context);
         mContext = context;
         mAudioManager = audioManager;
-
+        try {
+            mDisableOnVolumeUp = mContext.getResources().getBoolean(
+                  com.android.internal.R.bool.config_safe_media_disable_on_volume_up);
+        } catch (NotFoundException e) {
+            mDisableOnVolumeUp = true;
+        }
         getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
         setShowForAllUsers(true);
         setMessage(mContext.getString(com.android.internal.R.string.safe_media_volume_warning));
@@ -63,7 +71,8 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && event.getRepeatCount() == 0) {
+        if (mDisableOnVolumeUp && keyCode == KeyEvent.KEYCODE_VOLUME_UP
+            && event.getRepeatCount() == 0) {
             mNewVolumeUp = true;
         }
         return super.onKeyDown(keyCode, event);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index a4120c4..9ee5532 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -30,37 +30,17 @@
 LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    $(call all-Iaidl-files-under, src) \
-    $(call all-java-files-under, ../src)
+    $(call all-Iaidl-files-under, src)
 
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
-    frameworks/base/packages/SystemUI/res \
-    frameworks/base/packages/SystemUI/res-keyguard \
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
-    SystemUIPluginLib \
-    SystemUISharedLib \
-    androidx.car_car \
-    androidx.legacy_legacy-support-v4 \
-    androidx.recyclerview_recyclerview \
-    androidx.preference_preference \
-    androidx.appcompat_appcompat \
-    androidx.mediarouter_mediarouter \
-    androidx.palette_palette \
-    androidx.legacy_legacy-preference-v14 \
-    androidx.leanback_leanback \
-    androidx.slice_slice-core \
-    androidx.slice_slice-view \
-    androidx.slice_slice-builders \
-    androidx.arch.core_core-runtime \
-    androidx.lifecycle_lifecycle-extensions \
+    SystemUI-core
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     metrics-helper-lib \
     android-support-test \
     mockito-target-inline-minus-junit4 \
-    SystemUI-proto \
-    SystemUI-tags \
     testables \
     truth-prebuilt \
 
@@ -70,7 +50,6 @@
     libdexmakerjvmtiagent \
     libmultiplejvmtiagentsinterferenceagent
 
-
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
     telephony-common \
@@ -112,8 +91,6 @@
 LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*
 LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.systemui.tests.*,$(jacoco_exclude)
 
-include frameworks/base/packages/SettingsLib/common.mk
-
 ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
     include $(BUILD_PACKAGE)
 endif
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index f95027b..64f96da 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -15,6 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     package="com.android.systemui.tests">
 
@@ -72,6 +73,18 @@
             android:authorities="${applicationId}.lifecycle-tests"
             android:exported="false"
             android:multiprocess="true" />
+        <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider"
+            android:authorities="com.android.systemui.test.keyguard.disabled"
+            android:enabled="false"
+            tools:replace="android:authorities"
+            tools:node="remove" />
+
+        <provider
+            android:name="androidx.core.content.FileProvider"
+            android:authorities="com.android.systemui.test.fileprovider"
+            android:exported="false"
+            tools:replace="android:authorities"
+            android:grantUriPermissions="true" />
     </application>
 
     <instrumentation android:name="android.testing.TestableInstrumentation"
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index cc789e2..a20eece 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2219,6 +2219,7 @@
     // 1: Gesture performed is Nudge
     // 2: Gesture performed is Pickup
     // 4: Gesture performed is Double Tap
+    // 6: Gesture performed is Reach
     ACTION_AMBIENT_GESTURE = 411;
 
     // ---- End N Constants, all N constants go above this line ----
@@ -6440,6 +6441,10 @@
     // OS: Q
     SETTINGS_WIFI_ADD_NETWORK = 1556;
 
+    // OPEN: Settings > System > Input & Gesture > Reach up gesture
+    // OS: Q
+    SETTINGS_GESTURE_REACH = 1557;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/art-profile b/services/art-profile
index cbc00ea..3c60eee 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -13303,7 +13303,7 @@
 PLcom/android/server/notification/NotificationManagerService$10;->deleteNotificationChannel(Ljava/lang/String;Ljava/lang/String;)V
 PLcom/android/server/notification/NotificationManagerService$10;->enforcePolicyAccess(ILjava/lang/String;)V
 PLcom/android/server/notification/NotificationManagerService$10;->enforceSystemOrSystemUI(Ljava/lang/String;)V
-PLcom/android/server/notification/NotificationManagerService$10;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;I)V
+PLcom/android/server/notification/NotificationManagerService$10;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;II)V
 PLcom/android/server/notification/NotificationManagerService$10;->finishToken(Ljava/lang/String;Landroid/app/ITransientNotification;)V
 PLcom/android/server/notification/NotificationManagerService$10;->getAppActiveNotifications(Ljava/lang/String;I)Landroid/content/pm/ParceledListSlice;
 PLcom/android/server/notification/NotificationManagerService$10;->getBackupPayload(I)[B
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 67abedc..628207c 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -705,9 +705,13 @@
         final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null;
         if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
             // Picture-in-picture mode changes also trigger a multi-window mode change as well, so
-            // update that here in order
+            // update that here in order. Set the last reported MW state to the same as the PiP
+            // state since we haven't yet actually resized the task (these callbacks need to
+            // preceed the configuration change from the resiez.
+            // TODO(110009072): Once we move these callbacks to the client, remove all logic related
+            // to forcing the update of the picture-in-picture mode as a part of the PiP animation.
             mLastReportedPictureInPictureMode = inPictureInPictureMode;
-            mLastReportedMultiWindowMode = inMultiWindowMode();
+            mLastReportedMultiWindowMode = inPictureInPictureMode;
             final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
                     targetStackBounds, null);
             schedulePictureInPictureModeChanged(newConfig);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b1b4c4f..f074319 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -628,15 +628,17 @@
         final String pkg;
         final ITransientNotification callback;
         int duration;
+        int displayId;
         Binder token;
 
         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
-                    Binder token) {
+                Binder token, int displayId) {
             this.pid = pid;
             this.pkg = pkg;
             this.callback = callback;
             this.duration = duration;
             this.token = token;
+            this.displayId = displayId;
         }
 
         void update(int duration) {
@@ -1986,11 +1988,12 @@
         // ============================================================================
 
         @Override
-        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
+        public void enqueueToast(String pkg, ITransientNotification callback, int duration,
+                int displayId)
         {
             if (DBG) {
                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
-                        + " duration=" + duration);
+                        + " duration=" + duration + " displayId=" + displayId);
             }
 
             if (pkg == null || callback == null) {
@@ -2042,8 +2045,9 @@
                         }
 
                         Binder token = new Binder();
-                        mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
-                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
+                        mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId);
+                        record = new ToastRecord(callingPid, pkg, callback, duration, token,
+                                displayId);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
                         keepProcessAliveIfNeededLocked(callingPid);
@@ -2094,7 +2098,7 @@
                     int index = indexOfToastLocked(pkg, callback);
                     if (index >= 0) {
                         ToastRecord record = mToastQueue.get(index);
-                        finishTokenLocked(record.token);
+                        finishTokenLocked(record.token, record.displayId);
                     } else {
                         Slog.w(TAG, "Toast already killed. pkg=" + pkg
                                 + " callback=" + callback);
@@ -5231,13 +5235,13 @@
         ToastRecord lastToast = mToastQueue.remove(index);
 
         mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
-                DEFAULT_DISPLAY);
+                lastToast.displayId);
         // We passed 'false' for 'removeWindows' so that the client has time to stop
         // rendering (as hide above is a one-way message), otherwise we could crash
         // a client which was actively using a surface made from the token. However
         // we need to schedule a timeout to make sure the token is eventually killed
         // one way or another.
-        scheduleKillTokenTimeout(lastToast.token);
+        scheduleKillTokenTimeout(lastToast);
 
         keepProcessAliveIfNeededLocked(record.pid);
         if (mToastQueue.size() > 0) {
@@ -5248,14 +5252,13 @@
         }
     }
 
-    void finishTokenLocked(IBinder t) {
+    void finishTokenLocked(IBinder t, int displayId) {
         mHandler.removeCallbacksAndMessages(t);
         // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
         // remaining surfaces as either the client has called finishToken indicating
         // it has successfully removed the views, or the client has timed out
         // at which point anything goes.
-        mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
-                DEFAULT_DISPLAY);
+        mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
     }
 
     @GuardedBy("mToastQueue")
@@ -5279,18 +5282,18 @@
     }
 
     @GuardedBy("mToastQueue")
-    private void scheduleKillTokenTimeout(IBinder token)
+    private void scheduleKillTokenTimeout(ToastRecord r)
     {
-        mHandler.removeCallbacksAndMessages(token);
-        Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
+        mHandler.removeCallbacksAndMessages(r);
+        Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
         mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
     }
 
-    private void handleKillTokenTimeout(IBinder token)
+    private void handleKillTokenTimeout(ToastRecord record)
     {
-        if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
+        if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
         synchronized (mToastQueue) {
-            finishTokenLocked(token);
+            finishTokenLocked(record.token, record.displayId);
         }
     }
 
@@ -5484,7 +5487,7 @@
                     handleDurationReached((ToastRecord)msg.obj);
                     break;
                 case MESSAGE_FINISH_TOKEN_TIMEOUT:
-                    handleKillTokenTimeout((IBinder)msg.obj);
+                    handleKillTokenTimeout((ToastRecord)msg.obj);
                     break;
                 case MESSAGE_SAVE_POLICY_FILE:
                     handleSavePolicyFile();
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index 71cee05..28cee7a 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -117,7 +117,8 @@
     }
 
     public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
-        if (zen == ZEN_MODE_OFF) {
+        // Zen mode is ignored for critical notifications.
+        if (zen == ZEN_MODE_OFF || isCritical(record)) {
             return false;
         }
         // Make an exception to policy for the notification saying that policy has changed
@@ -207,6 +208,19 @@
         }
     }
 
+    /**
+     * Check if the notification is too critical to be suppressed.
+     *
+     * @param record the record to test for criticality
+     * @return {@code true} if notification is considered critical
+     *
+     * @see CriticalNotificationExtractor for criteria
+     */
+    private boolean isCritical(NotificationRecord record) {
+        // 0 is the most critical
+        return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
+    }
+
     private static boolean shouldInterceptAudience(int source, NotificationRecord record) {
         if (!audienceMatches(source, record.getContactAffinity())) {
             ZenLog.traceIntercepted(record, "!audienceMatches");
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 42d6c8e..e18d564 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1365,7 +1365,7 @@
             // UID, otherwise we allow unlimited duration. When a UID looses focus we
             // schedule hiding all of its toast windows.
             if (type == TYPE_TOAST) {
-                if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
+                if (!displayContent.canAddToastWindowForUid(callingUid)) {
                     Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
                     return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 81ac6a4..664a837 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4579,10 +4579,12 @@
         enforceFullCrossUsersPermission(userHandle);
         synchronized (getLockObject()) {
             if (!isCallerWithSystemUid()) {
-                // This API can only be called by an active device admin,
-                // so try to retrieve it to check that the caller is one.
-                getActiveAdminForCallerLocked(
-                        null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+                // This API can be called by an active device admin or by keyguard code.
+                if (mContext.checkCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    getActiveAdminForCallerLocked(
+                            null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+                }
             }
 
             DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 16cc8fd..348e201 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -65,6 +65,7 @@
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.SUSPEND_APPS"/>
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
+    <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 5c449b3..7a96f4c 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -47,6 +47,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
@@ -111,6 +112,7 @@
     @Mock private IAccountManagerResponse mMockAccountManagerResponse;
     @Mock private IBinder mMockBinder;
     @Mock private INotificationManager mMockNotificationManager;
+    @Mock private PackageManagerInternal mMockPackageManagerInternal;
 
     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
     @Captor private ArgumentCaptor<Bundle> mBundleCaptor;
@@ -155,6 +157,9 @@
         when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
                 mMockDevicePolicyManager);
         when(mMockAccountManagerResponse.asBinder()).thenReturn(mMockBinder);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(true);
+        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
 
         Context realTestContext = getContext();
         MyMockContext mockContext = new MyMockContext(realTestContext, mMockContext);
@@ -174,6 +179,7 @@
             cdl.countDown();
         });
         cdl.await(1, TimeUnit.SECONDS);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
         super.tearDown();
     }
 
@@ -607,6 +613,8 @@
                 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
         when(mMockPackageManager.checkSignatures(
                 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
@@ -623,7 +631,7 @@
         waitForLatch(latch);
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
         verify(mMockAccountManagerResponse).onError(
-                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
     }
 
     @SmallTest
@@ -789,6 +797,8 @@
                 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
         when(mMockPackageManager.checkSignatures(
                 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
@@ -805,7 +815,7 @@
         waitForLatch(latch);
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
         verify(mMockAccountManagerResponse).onError(
-                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
     }
 
     @SmallTest
@@ -1089,6 +1099,8 @@
                 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
         when(mMockPackageManager.checkSignatures(
                 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
@@ -1103,7 +1115,7 @@
         waitForLatch(latch);
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
         verify(mMockAccountManagerResponse).onError(
-                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
     }
 
     @SmallTest
@@ -1349,6 +1361,8 @@
         unlockSystemUser();
         when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
                     .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
         try {
             mAms.removeAccountAsUser(
                 mMockAccountManagerResponse, // response
@@ -1685,6 +1699,8 @@
                 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
         when(mMockPackageManager.checkSignatures(
                 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
@@ -1698,7 +1714,7 @@
         waitForLatch(latch);
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
         verify(mMockAccountManagerResponse).onError(
-                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
     }
 
     @SmallTest
@@ -1956,6 +1972,8 @@
                 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
         when(mMockPackageManager.checkSignatures(
                 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
@@ -1971,7 +1989,7 @@
         waitForLatch(latch);
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
         verify(mMockAccountManagerResponse).onError(
-                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
     }
 
     @SmallTest
@@ -2094,6 +2112,8 @@
                 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
         when(mMockPackageManager.checkSignatures(
                 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
@@ -2107,7 +2127,7 @@
 
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
         verify(mMockAccountManagerResponse).onError(
-                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
     }
 
     @SmallTest
@@ -2227,6 +2247,8 @@
                 any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
         when(mMockPackageManager.checkSignatures(
                 anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
@@ -2242,7 +2264,7 @@
 
         verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
         verify(mMockAccountManagerResponse).onError(
-                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), anyString());
     }
 
     @SmallTest
@@ -2329,6 +2351,8 @@
         unlockSystemUser();
         when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
                     .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
         try {
             mAms.editProperties(
                 mMockAccountManagerResponse, // response
@@ -2618,6 +2642,8 @@
                 PackageManager.PERMISSION_DENIED);
         when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
                     .thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+        when(mMockPackageManagerInternal.hasSignatureCapability(anyInt(), anyInt(), anyInt()))
+                .thenReturn(false);
 
         final CountDownLatch latch = new CountDownLatch(1);
         Response response = new Response(latch, mMockAccountManagerResponse);
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
index fa7501d..72c22fd 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
@@ -25,6 +25,7 @@
 import android.accounts.Account;
 import android.content.Context;
 import android.database.Cursor;
+import android.os.Build;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
 
@@ -86,6 +87,12 @@
 
     @Test
     public void testCeNotAvailableInitially() {
+        // If the CE database is not attached to the DE database then any calls that modify the CE
+        // database will result in a Log.wtf call that will crash this process on eng builds. To
+        // allow the test to run through to completion skip this test on eng builds.
+        if (Build.IS_ENG) {
+            return;
+        }
         Account account = new Account("name", "example.com");
         long id = mAccountsDb.insertCeAccount(account, "");
         assertEquals("Insert into CE should fail until CE database is attached", -1, id);
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
index b431af1..3f7c714 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
@@ -143,10 +143,10 @@
         assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, params[1]);
     }
 
-    @Test
     /**
      * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
      */
+    @Test
     public void testTaskChangeCallBacks() throws Exception {
         final Object[] params = new Object[2];
         final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
@@ -218,16 +218,17 @@
     /**
      * Starts the provided activity and returns the started instance.
      */
-    private Activity startTestActivity(Class<?> activityClass) {
+    private TestActivity startTestActivity(Class<?> activityClass) throws InterruptedException {
         final Context context = InstrumentationRegistry.getContext();
         final ActivityMonitor monitor =
                 new ActivityMonitor(activityClass.getName(), null, false);
         InstrumentationRegistry.getInstrumentation().addMonitor(monitor);
         context.startActivity(new Intent(context, activityClass));
-        final Activity activity = monitor.waitForActivityWithTimeout(1000);
+        final TestActivity activity = (TestActivity)monitor.waitForActivityWithTimeout(1000);
         if (activity == null) {
             throw new RuntimeException("Timed out waiting for Activity");
         }
+        activity.waitForResumeStateChange(true);
         return activity;
     }
 
@@ -245,7 +246,43 @@
         }catch (InterruptedException e) {}
     }
 
-    public static class ActivityA extends Activity {
+    public static class TestActivity extends Activity {
+        boolean mIsResumed = false;
+
+        @Override
+        protected void onPostResume() {
+            super.onPostResume();
+            synchronized (this) {
+                mIsResumed = true;
+                notifyAll();
+            }
+        }
+
+        @Override
+        protected void onPause() {
+            super.onPause();
+            synchronized (this) {
+                mIsResumed = false;
+                notifyAll();
+            }
+        }
+
+        /**
+         * If isResumed is {@code true}, sleep the thread until the activity is resumed.
+         * if {@code false}, sleep the thread until the activity is paused.
+         */
+        public void waitForResumeStateChange(boolean isResumed) throws InterruptedException {
+            synchronized (this) {
+                if (mIsResumed == isResumed) {
+                    return;
+                }
+                wait(5000);
+            }
+            assertTrue("The activity resume state change timed out", mIsResumed == isResumed);
+        }
+    }
+
+    public static class ActivityA extends TestActivity {
 
         private boolean mActivityBLaunched = false;
 
@@ -261,7 +298,7 @@
         }
     }
 
-    public static class ActivityB extends Activity {
+    public static class ActivityB extends TestActivity {
 
         @Override
         protected void onPostResume() {
@@ -274,7 +311,7 @@
         }
     }
 
-    public static class ActivityRequestedOrientationChange extends Activity {
+    public static class ActivityRequestedOrientationChange extends TestActivity {
         @Override
         protected void onPostResume() {
             super.onPostResume();
@@ -283,7 +320,7 @@
         }
     }
 
-    public static class ActivityTaskDescriptionChange extends Activity {
+    public static class ActivityTaskDescriptionChange extends TestActivity {
         @Override
         protected void onPostResume() {
             super.onPostResume();
@@ -292,7 +329,7 @@
         }
     }
 
-    public static class ActivityTaskChangeCallbacks extends Activity {
+    public static class ActivityTaskChangeCallbacks extends TestActivity {
         boolean onDetachedFromWindowCalled = false;
         CountDownLatch onDetachedFromWindowCountDownLatch;
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockWeaverService.java b/services/tests/servicestests/src/com/android/server/locksettings/MockWeaverService.java
index 34831cd..7fb1278 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockWeaverService.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockWeaverService.java
@@ -15,7 +15,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 
-public class MockWeaverService implements IWeaver {
+public class MockWeaverService extends IWeaver.Stub {
 
     private static final int MAX_SLOTS = 8;
     private static final int KEY_LENGTH = 256 / 8;
@@ -55,54 +55,4 @@
             cb.onValues(WeaverStatus.FAILED, response);
         }
     }
-
-    @Override
-    public IHwBinder asBinder() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public ArrayList<String> interfaceChain() throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String interfaceDescriptor() throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setHALInstrumentation() throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean linkToDeath(DeathRecipient recipient, long cookie) throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void ping() throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public DebugInfo getDebugInfo() throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void notifySyspropsChanged() throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean unlinkToDeath(DeathRecipient recipient) throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public ArrayList<byte[]> getHashChain() throws RemoteException {
-        throw new UnsupportedOperationException();
-    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index c0bd7cc..d335450 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -171,4 +171,17 @@
 
         assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_OFF, config, r));
     }
+
+    @Test
+    public void testSuppressAnything_bypass_ZenModeOn() {
+        NotificationRecord r = getNotificationRecord();
+        r.setCriticality(CriticalNotificationExtractor.CRITICAL);
+        when(r.sbn.getPackageName()).thenReturn("bananas");
+        ZenModeConfig config = mock(ZenModeConfig.class);
+
+        assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_NO_INTERRUPTIONS, config, r));
+
+        r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW);
+        assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_NO_INTERRUPTIONS, config, r));
+    }
 }
diff --git a/tests/testables/Android.bp b/tests/testables/Android.bp
new file mode 100644
index 0000000..f07f09d
--- /dev/null
+++ b/tests/testables/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 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.
+//
+
+java_library {
+
+    name: "testables",
+    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_MODULE_TAG
+    // LOCAL_MODULE_TAG := tests
+
+    srcs: ["src/**/*.java"],
+
+    libs: [
+        "android.test.runner",
+        "android.test.mock",
+        "android-support-test",
+        "mockito-target-inline-minus-junit4",
+    ],
+
+}
diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk
deleted file mode 100644
index f3cbac0..0000000
--- a/tests/testables/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright (C) 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := testables
-LOCAL_MODULE_TAG := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.mock \
-    android-support-test \
-    mockito-target-inline-minus-junit4
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index f064cb1..0a517ab 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -408,6 +408,41 @@
   }
 }
 
+void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer) {
+  using namespace android;
+  
+  if (pool->getError() == NO_INIT) {
+    printer->Print("String pool is unitialized.\n");
+    return;
+  } else if (pool->getError() != NO_ERROR) {
+    printer->Print("String pool is corrupt/invalid.\n");
+    return;
+  }
+
+  SortedVector<const void*> uniqueStrings;
+  const size_t N = pool->size();
+  for (size_t i=0; i<N; i++) {
+    size_t len;
+    if (pool->isUTF8()) {
+      uniqueStrings.add(pool->string8At(i, &len));
+    } else {
+      uniqueStrings.add(pool->stringAt(i, &len));
+    }
+  }
+
+  printer->Print(StringPrintf("String pool of %zd unique %s %s strings, %zd entries and %zd styles "
+                              "using %zd bytes:\n", uniqueStrings.size(),
+                              pool->isUTF8() ? "UTF-8" : "UTF-16",
+                              pool->isSorted() ? "sorted" : "non-sorted", N, pool->styleCount(),
+                              pool->bytes()));
+
+  const size_t NS = pool->size();
+  for (size_t s=0; s<NS; s++) {
+    String8 str = pool->string8ObjectAt(s);
+    printer->Print(StringPrintf("String #%zd : %s\n", s, str.string()));
+  }
+}
+
 namespace {
 
 class XmlPrinter : public xml::ConstVisitor {
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 382707e..a43197c 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -38,6 +38,7 @@
   static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
   static void DumpHex(const void* data, size_t len);
   static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
+  static void DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer);
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index b32766b..a73d56c 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -184,10 +184,7 @@
   std::unique_ptr<io::IFileCollectionIterator> iterator = apk_->Iterator();
   while (iterator->HasNext()) {
     io::IFile* file = iterator->Next();
-
     std::string path = file->GetSource().path;
-    // The name of the path has the format "<zip-file-name>@<path-to-file>".
-    path = path.substr(path.find('@') + 1);
 
     // Skip resources that are not referenced if requested.
     if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
@@ -257,6 +254,53 @@
   return true;
 }
 
+std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_path,
+                                                     IDiagnostics* diag) {
+  io::IFile* file = apk_->FindFile(file_path);
+  if (file == nullptr) {
+    diag->Error(DiagMessage() << "failed to find file");
+    return nullptr;
+  }
+
+  std::unique_ptr<xml::XmlResource> doc;
+  if (format_ == ApkFormat::kProto) {
+    std::unique_ptr<io::InputStream> in = file->OpenInputStream();
+    if (!in) {
+      diag->Error(DiagMessage() << "failed to open file");
+      return nullptr;
+    }
+
+    io::ZeroCopyInputAdaptor adaptor(in.get());
+    pb::XmlNode pb_node;
+    if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+      diag->Error(DiagMessage() << "failed to parse file as proto XML");
+      return nullptr;
+    }
+
+    std::string err;
+    doc = DeserializeXmlResourceFromPb(pb_node, &err);
+    if (!doc) {
+      diag->Error(DiagMessage() << "failed to deserialize proto XML: " << err);
+      return nullptr;
+    }
+  } else if (format_ == ApkFormat::kBinary) {
+    std::unique_ptr<io::IData> data = file->OpenAsData();
+    if (!data) {
+      diag->Error(DiagMessage() << "failed to open file");
+      return nullptr;
+    }
+
+    std::string err;
+    doc = xml::Inflate(data->data(), data->size(), &err);
+    if (!doc) {
+      diag->Error(DiagMessage() << "failed to parse file as binary XML: " << err);
+      return nullptr;
+    }
+  }
+
+  return doc;
+}
+
 ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) {
   if (apk->FindFile(kApkResourceTablePath) != nullptr) {
     return ApkFormat::kBinary;
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index 41f879d..dcb085a 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -70,6 +70,10 @@
     return apk_.get();
   }
 
+  ApkFormat GetApkFormat() {
+    return format_;
+  }
+
   const ResourceTable* GetResourceTable() const {
     return table_.get();
   }
@@ -106,6 +110,8 @@
                               const TableFlattenerOptions& options, FilterChain* filters,
                               IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
 
+  /** Loads the file as an xml document. */
+  std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedApk);
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 23903c9e..37013c0 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -71,7 +71,7 @@
   explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) {
     AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics));
     AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics));
-    AddOptionalSubcommand(util::make_unique<DumpCommand>());
+    AddOptionalSubcommand(util::make_unique<DumpCommand>(diagnostics));
     AddOptionalSubcommand(util::make_unique<DiffCommand>());
     AddOptionalSubcommand(util::make_unique<OptimizeCommand>());
     AddOptionalSubcommand(util::make_unique<ConvertCommand>());
diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h
index 0f312d6..92934c3 100644
--- a/tools/aapt2/Source.h
+++ b/tools/aapt2/Source.h
@@ -31,12 +31,16 @@
 struct Source {
   std::string path;
   Maybe<size_t> line;
+  Maybe<std::string> archive;
 
   Source() = default;
 
   inline Source(const android::StringPiece& path) : path(path.to_string()) {  // NOLINT(implicit)
   }
 
+  inline Source(const android::StringPiece& path, const android::StringPiece& archive)
+      : path(path.to_string()), archive(archive.to_string()) {}
+
   inline Source(const android::StringPiece& path, size_t line)
       : path(path.to_string()), line(line) {}
 
@@ -45,10 +49,14 @@
   }
 
   std::string to_string() const {
-    if (line) {
-      return ::android::base::StringPrintf("%s:%zd", path.c_str(), line.value());
+    std::string s = path;
+    if (archive) {
+      s = ::android::base::StringPrintf("%s@%s", archive.value().c_str(), s.c_str());
     }
-    return path;
+    if (line) {
+      s = ::android::base::StringPrintf("%s:%zd", s.c_str(), line.value());
+    }
+    return s;
   }
 };
 
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 2ba2cf7..62c19fb 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -41,8 +41,10 @@
 #include "format/proto/ProtoSerialize.h"
 #include "io/BigBufferStream.h"
 #include "io/FileStream.h"
+#include "io/FileSystem.h"
 #include "io/StringStream.h"
 #include "io/Util.h"
+#include "io/ZipArchive.h"
 #include "util/Files.h"
 #include "util/Maybe.h"
 #include "util/Util.h"
@@ -135,81 +137,20 @@
   return name.str();
 }
 
-static bool IsHidden(const StringPiece& filename) {
-  return util::StartsWith(filename, ".");
-}
-
-// Walks the res directory structure, looking for resource files.
-static bool LoadInputFilesFromDir(IAaptContext* context, const CompileOptions& options,
-                                  std::vector<ResourcePathData>* out_path_data) {
-  const std::string& root_dir = options.res_dir.value();
-  std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir);
-  if (!d) {
-    context->GetDiagnostics()->Error(DiagMessage(root_dir) << "failed to open directory: "
-                                                           << SystemErrorCodeToString(errno));
-    return false;
-  }
-
-  while (struct dirent* entry = readdir(d.get())) {
-    if (IsHidden(entry->d_name)) {
-      continue;
-    }
-
-    std::string prefix_path = root_dir;
-    file::AppendPath(&prefix_path, entry->d_name);
-
-    if (file::GetFileType(prefix_path) != file::FileType::kDirectory) {
-      continue;
-    }
-
-    std::unique_ptr<DIR, decltype(closedir)*> subdir(opendir(prefix_path.data()), closedir);
-    if (!subdir) {
-      context->GetDiagnostics()->Error(DiagMessage(prefix_path) << "failed to open directory: "
-                                                                << SystemErrorCodeToString(errno));
-      return false;
-    }
-
-    while (struct dirent* leaf_entry = readdir(subdir.get())) {
-      if (IsHidden(leaf_entry->d_name)) {
-        continue;
-      }
-
-      std::string full_path = prefix_path;
-      file::AppendPath(&full_path, leaf_entry->d_name);
-
-      std::string err_str;
-      Maybe<ResourcePathData> path_data = ExtractResourcePathData(full_path, &err_str);
-      if (!path_data) {
-        context->GetDiagnostics()->Error(DiagMessage(full_path) << err_str);
-        return false;
-      }
-
-      out_path_data->push_back(std::move(path_data.value()));
-    }
-  }
-
-  // File-system directory enumeration order is platform-dependent. Sort the result to remove any
-  // inconsistencies between platforms.
-  std::sort(
-      out_path_data->begin(), out_path_data->end(),
-      [](const ResourcePathData& a, const ResourcePathData& b) { return a.source < b.source; });
-  return true;
-}
-
 static bool CompileTable(IAaptContext* context, const CompileOptions& options,
-                         const ResourcePathData& path_data, IArchiveWriter* writer,
+                         const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer,
                          const std::string& output_path) {
   ResourceTable table;
   {
-    FileInputStream fin(path_data.source.path);
-    if (fin.HadError()) {
+    auto fin = file->OpenInputStream();
+    if (fin->HadError()) {
       context->GetDiagnostics()->Error(DiagMessage(path_data.source)
-                                       << "failed to open file: " << fin.GetError());
+          << "failed to open file: " << fin->GetError());
       return false;
     }
 
     // Parse the values file from XML.
-    xml::XmlPullParser xml_parser(&fin);
+    xml::XmlPullParser xml_parser(fin.get());
 
     ResourceParserOptions parser_options;
     parser_options.error_on_positional_arguments = !options.legacy_mode;
@@ -222,7 +163,7 @@
     parser_options.visibility = options.visibility;
 
     ResourceParser res_parser(context->GetDiagnostics(), &table, path_data.source, path_data.config,
-                              parser_options);
+        parser_options);
     if (!res_parser.Parse(&xml_parser)) {
       return false;
     }
@@ -408,7 +349,7 @@
 }
 
 static bool CompileXml(IAaptContext* context, const CompileOptions& options,
-                       const ResourcePathData& path_data, IArchiveWriter* writer,
+                       const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer,
                        const std::string& output_path) {
   if (context->IsVerbose()) {
     context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling XML");
@@ -416,18 +357,17 @@
 
   std::unique_ptr<xml::XmlResource> xmlres;
   {
-    FileInputStream fin(path_data.source.path);
-    if (fin.HadError()) {
+    auto fin = file->OpenInputStream();
+    if (fin->HadError()) {
       context->GetDiagnostics()->Error(DiagMessage(path_data.source)
-                                       << "failed to open file: " << fin.GetError());
+                                       << "failed to open file: " << fin->GetError());
       return false;
     }
 
-    xmlres = xml::Inflate(&fin, context->GetDiagnostics(), path_data.source);
-  }
-
-  if (!xmlres) {
-    return false;
+    xmlres = xml::Inflate(fin.get(), context->GetDiagnostics(), path_data.source);
+    if (!xmlres) {
+      return false;
+    }
   }
 
   xmlres->file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name);
@@ -508,7 +448,7 @@
 }
 
 static bool CompilePng(IAaptContext* context, const CompileOptions& options,
-                       const ResourcePathData& path_data, IArchiveWriter* writer,
+                       const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer,
                        const std::string& output_path) {
   if (context->IsVerbose()) {
     context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling PNG");
@@ -522,15 +462,17 @@
   res_file.type = ResourceFile::Type::kPng;
 
   {
-    std::string content;
-    if (!android::base::ReadFileToString(path_data.source.path, &content,
-                                         true /*follow_symlinks*/)) {
-      context->GetDiagnostics()->Error(DiagMessage(path_data.source)
-                                       << "failed to open file: "
-                                       << SystemErrorCodeToString(errno));
+    auto data = file->OpenAsData();
+    if (!data) {
+      context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to open file ");
       return false;
     }
 
+    // Read the file as a string
+    char buffer_2[data->size()];
+    memcpy(&buffer_2, data->data(), data->size());
+    StringPiece content(buffer_2, data->size());
+
     BigBuffer crunched_png_buffer(4096);
     io::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer);
 
@@ -598,7 +540,7 @@
     if (context->IsVerbose()) {
       // For debugging only, use the legacy PNG cruncher and compare the resulting file sizes.
       // This will help catch exotic cases where the new code may generate larger PNGs.
-      std::stringstream legacy_stream(content);
+      std::stringstream legacy_stream(content.to_string());
       BigBuffer legacy_buffer(4096);
       Png png(context->GetDiagnostics());
       if (!png.process(path_data.source, &legacy_stream, &legacy_buffer, {})) {
@@ -612,41 +554,31 @@
   }
 
   io::BigBufferInputStream buffer_in(&buffer);
-  if (!WriteHeaderAndDataToWriter(output_path, res_file, &buffer_in, writer,
-                                  context->GetDiagnostics())) {
-    return false;
-  }
-  return true;
+  return WriteHeaderAndDataToWriter(output_path, res_file, &buffer_in, writer,
+      context->GetDiagnostics());
 }
 
 static bool CompileFile(IAaptContext* context, const CompileOptions& options,
-                        const ResourcePathData& path_data, IArchiveWriter* writer,
+                        const ResourcePathData& path_data, io::IFile* file, IArchiveWriter* writer,
                         const std::string& output_path) {
   if (context->IsVerbose()) {
     context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling file");
   }
 
-  BigBuffer buffer(256);
   ResourceFile res_file;
   res_file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name);
   res_file.config = path_data.config;
   res_file.source = path_data.source;
   res_file.type = ResourceFile::Type::kUnknown;
 
-  std::string error_str;
-  Maybe<android::FileMap> f = file::MmapPath(path_data.source.path, &error_str);
-  if (!f) {
-    context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to mmap file: "
-                                     << error_str);
+  auto data = file->OpenAsData();
+  if (!data) {
+    context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to open file ");
     return false;
   }
 
-  io::MmappedData mmapped_in(std::move(f.value()));
-  if (!WriteHeaderAndDataToWriter(output_path, res_file, &mmapped_in, writer,
-                                  context->GetDiagnostics())) {
-    return false;
-  }
-  return true;
+  return WriteHeaderAndDataToWriter(output_path, res_file, data.get(), writer,
+      context->GetDiagnostics());
 }
 
 class CompileContext : public IAaptContext {
@@ -701,6 +633,79 @@
   bool verbose_ = false;
 };
 
+int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer,
+             CompileOptions& options) {
+  bool error = false;
+
+  // Iterate over the input files in a stable, platform-independent manner
+  auto file_iterator  = inputs->Iterator();
+  while (file_iterator->HasNext()) {
+    auto file = file_iterator->Next();
+    std::string path = file->GetSource().path;
+
+    // Skip hidden input files
+    if (file::IsHidden(path)) {
+      continue;
+    }
+
+    if (!options.res_zip && !IsValidFile(context, path)) {
+      error = true;
+      continue;
+    }
+
+    // Extract resource type information from the full path
+    std::string err_str;
+    ResourcePathData path_data;
+    if (auto maybe_path_data = ExtractResourcePathData(path, &err_str)) {
+      path_data = maybe_path_data.value();
+    } else {
+      context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << err_str);
+      error = true;
+      continue;
+    }
+
+    // Determine how to compile the file based on its type.
+    auto compile_func = &CompileFile;
+    if (path_data.resource_dir == "values" && path_data.extension == "xml") {
+      compile_func = &CompileTable;
+      // We use a different extension (not necessary anymore, but avoids altering the existing
+      // build system logic).
+      path_data.extension = "arsc";
+
+    } else if (const ResourceType* type = ParseResourceType(path_data.resource_dir)) {
+      if (*type != ResourceType::kRaw) {
+        if (path_data.extension == "xml") {
+          compile_func = &CompileXml;
+        } else if ((!options.no_png_crunch && path_data.extension == "png")
+                   || path_data.extension == "9.png") {
+          compile_func = &CompilePng;
+        }
+      }
+    } else {
+      context->GetDiagnostics()->Error(DiagMessage()
+          << "invalid file path '" << path_data.source << "'");
+      error = true;
+      continue;
+    }
+
+    // Treat periods as a reserved character that should not be present in a file name
+    // Legacy support for AAPT which did not reserve periods
+    if (compile_func != &CompileFile && !options.legacy_mode
+        && std::count(path_data.name.begin(), path_data.name.end(), '.') != 0) {
+      error = true;
+      context->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+                                                    << "file name cannot contain '.' other than for"
+                                                    << " specifying the extension");
+      continue;
+    }
+
+    const std::string out_path = BuildIntermediateContainerFilename(path_data);
+    error |= !compile_func(context, options, path_data, file, output_writer, out_path);
+  }
+
+  return error ? 1 : 0;
+}
+
 int CompileCommand::Action(const std::vector<std::string>& args) {
   CompileContext context(diagnostic_);
   context.SetVerbose(options_.verbose);
@@ -720,37 +725,55 @@
     }
   }
 
+  std::unique_ptr<io::IFileCollection> file_collection;
   std::unique_ptr<IArchiveWriter> archive_writer;
 
-  std::vector<ResourcePathData> input_data;
-  if (options_.res_dir) {
+  // Collect the resources files to compile
+  if (options_.res_dir && options_.res_zip) {
+    context.GetDiagnostics()->Error(DiagMessage()
+                                        << "only one of --dir and --zip can be specified");
+    return 1;
+  } else if (options_.res_dir) {
     if (!args.empty()) {
-      // Can't have both files and a resource directory.
       context.GetDiagnostics()->Error(DiagMessage() << "files given but --dir specified");
       Usage(&std::cerr);
       return 1;
     }
 
-    if (!LoadInputFilesFromDir(&context, options_, &input_data)) {
+    // Load the files from the res directory
+    std::string err;
+    file_collection = io::FileCollection::Create(options_.res_dir.value(), &err);
+    if (!file_collection) {
+      context.GetDiagnostics()->Error(DiagMessage(options_.res_dir.value()) << err);
       return 1;
     }
 
     archive_writer = CreateZipFileArchiveWriter(context.GetDiagnostics(), options_.output_path);
+  } else if (options_.res_zip) {
+    if (!args.empty()) {
+      context.GetDiagnostics()->Error(DiagMessage() << "files given but --zip specified");
+      Usage(&std::cerr);
+      return 1;
+    }
 
+    // Load a zip file containing a res directory
+    std::string err;
+    file_collection = io::ZipFileCollection::Create(options_.res_zip.value(), &err);
+    if (!file_collection) {
+      context.GetDiagnostics()->Error(DiagMessage(options_.res_zip.value()) << err);
+      return 1;
+    }
+
+    archive_writer = CreateZipFileArchiveWriter(context.GetDiagnostics(), options_.output_path);
   } else {
-    input_data.reserve(args.size());
+    auto collection = util::make_unique<io::FileCollection>();
 
     // Collect data from the path for each input file.
     for (const std::string& arg : args) {
-      std::string error_str;
-      if (Maybe<ResourcePathData> path_data = ExtractResourcePathData(arg, &error_str)) {
-        input_data.push_back(std::move(path_data.value()));
-      } else {
-        context.GetDiagnostics()->Error(DiagMessage() << error_str << " (" << arg << ")");
-        return 1;
-      }
+      collection->InsertFile(arg);
     }
 
+    file_collection = std::move(collection);
     archive_writer = CreateDirectoryArchiveWriter(context.GetDiagnostics(), options_.output_path);
   }
 
@@ -758,57 +781,7 @@
     return 1;
   }
 
-  bool error = false;
-  for (ResourcePathData& path_data : input_data) {
-    if (options_.verbose) {
-      context.GetDiagnostics()->Note(DiagMessage(path_data.source) << "processing");
-    }
-
-    if (!IsValidFile(&context, path_data.source.path)) {
-      error = true;
-      continue;
-    }
-
-    // Determine how to compile the file based on its type.
-    auto compile_func = &CompileFile;
-    if (path_data.resource_dir == "values" && path_data.extension == "xml") {
-      compile_func = &CompileTable;
-      // We use a different extension (not necessary anymore, but avoids altering the existing
-      // build system logic).
-      path_data.extension = "arsc";
-
-    } else if (const ResourceType* type = ParseResourceType(path_data.resource_dir)) {
-      if (*type != ResourceType::kRaw) {
-        if (path_data.extension == "xml") {
-          compile_func = &CompileXml;
-        } else if ((!options_.no_png_crunch && path_data.extension == "png")
-            || path_data.extension == "9.png") {
-          compile_func = &CompilePng;
-        }
-      }
-    } else {
-      context.GetDiagnostics()->Error(DiagMessage()
-          << "invalid file path '" << path_data.source << "'");
-      error = true;
-      continue;
-    }
-
-    // Treat periods as a reserved character that should not be present in a file name
-    // Legacy support for AAPT which did not reserve periods
-    if (compile_func != &CompileFile && !options_.legacy_mode
-        && std::count(path_data.name.begin(), path_data.name.end(), '.') != 0) {
-      error = true;
-      context.GetDiagnostics()->Error(DiagMessage() << "resource file '" << path_data.source.path
-                                                    << "' name cannot contain '.' other than for"
-                                                    << "specifying the extension");
-      continue;
-    }
-
-    // Compile the file.
-    const std::string out_path = BuildIntermediateContainerFilename(path_data);
-    error |= !compile_func(&context, options_, path_data, archive_writer.get(), out_path);
-  }
-  return error ? 1 : 0;
+  return Compile(&context, file_collection.get(), archive_writer.get(), options_);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index 4151952..c429d5f 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -18,7 +18,8 @@
 #define AAPT2_COMPILE_H
 
 #include "androidfw/StringPiece.h"
-
+#include "format/Archive.h"
+#include "process/IResourceTableConsumer.h"
 #include "Command.h"
 #include "Diagnostics.h"
 #include "ResourceTable.h"
@@ -28,6 +29,7 @@
 struct CompileOptions {
   std::string output_path;
   Maybe<std::string> res_dir;
+  Maybe<std::string> res_zip;
   Maybe<std::string> generate_text_symbols_path;
   Maybe<Visibility::Level> visibility;
   bool pseudolocalize = false;
@@ -36,6 +38,7 @@
   bool verbose = false;
 };
 
+/** Parses flags and compiles resources to be used in linking.  */
 class CompileCommand : public Command {
  public:
   explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"),
@@ -43,6 +46,8 @@
     SetDescription("Compiles resources to be linked into an apk.");
     AddRequiredFlag("-o", "Output path", &options_.output_path);
     AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir);
+    AddOptionalFlag("--zip", "Zip file containing the res directory to scan for resources",
+        &options_.res_zip);
     AddOptionalFlag("--output-text-symbols",
         "Generates a text file containing the resource symbols in the\n"
             "specified file", &options_.generate_text_symbols_path);
@@ -51,10 +56,10 @@
     AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch);
     AddOptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
         &options_.legacy_mode);
-    AddOptionalSwitch("-v", "Enables verbose logging", &options_.verbose);
     AddOptionalFlag("--visibility",
         "Sets the visibility of the compiled resources to the specified\n"
             "level. Accepted levels: public, private, default", &visibility_);
+    AddOptionalSwitch("-v", "Enables verbose logging", &options_.verbose);
   }
 
   int Action(const std::vector<std::string>& args) override;
@@ -65,6 +70,8 @@
   Maybe<std::string> visibility_;
 };
 
+int Compile(IAaptContext* context, io::IFileCollection* inputs,
+             IArchiveWriter* output_writer, CompileOptions& options);
 }// namespace aapt
 
 #endif //AAPT2_COMPILE_H
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index d21addf..dd5198c 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -18,6 +18,7 @@
 
 #include "android-base/file.h"
 #include "io/StringStream.h"
+#include "io/ZipArchive.h"
 #include "java/AnnotationProcessor.h"
 #include "test/Test.h"
 
@@ -29,7 +30,6 @@
   args.push_back(path);
   args.push_back("-o");
   args.push_back(outDir);
-  args.push_back("-v");
   if (legacy) {
     args.push_back("--legacy");
   }
@@ -94,4 +94,56 @@
   ASSERT_EQ(remove(path5_out.c_str()), 0);
 }
 
-}
\ No newline at end of file
+TEST(CompilerTest, DirInput) {
+  StdErrDiagnostics diag;
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+  const std::string kResDir = android::base::Dirname(android::base::GetExecutablePath())
+                            + "/integration-tests/CompileTest/DirInput/res";
+  const std::string kOutputFlata = android::base::Dirname(android::base::GetExecutablePath())
+                                 + "/integration-tests/CompileTest/DirInput/compiled.flata";
+  remove(kOutputFlata.c_str());
+
+  std::vector<android::StringPiece> args;
+  args.push_back("--dir");
+  args.push_back(kResDir);
+  args.push_back("-o");
+  args.push_back(kOutputFlata);
+  ASSERT_EQ(CompileCommand(&diag).Execute(args, &std::cerr), 0);
+
+  // Check for the presence of the compiled files
+  std::string err;
+  std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(kOutputFlata, &err);
+  ASSERT_NE(zip, nullptr) << err;
+  ASSERT_NE(zip->FindFile("drawable_image.png.flat"), nullptr);
+  ASSERT_NE(zip->FindFile("layout_layout.xml.flat"), nullptr);
+  ASSERT_NE(zip->FindFile("values_values.arsc.flat"), nullptr);
+  ASSERT_EQ(remove(kOutputFlata.c_str()), 0);
+}
+
+TEST(CompilerTest, ZipInput) {
+  StdErrDiagnostics diag;
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+  const std::string kResZip = android::base::Dirname(android::base::GetExecutablePath())
+                            + "/integration-tests/CompileTest/ZipInput/res.zip";
+  const std::string kOutputFlata = android::base::Dirname(android::base::GetExecutablePath())
+                                 + "/integration-tests/CompileTest/ZipInput/compiled.flata";
+  remove(kOutputFlata.c_str());
+
+  std::vector<android::StringPiece> args;
+  args.push_back("--zip");
+  args.push_back(kResZip);
+  args.push_back("-o");
+  args.push_back(kOutputFlata);
+  ASSERT_EQ(CompileCommand(&diag).Execute(args, &std::cerr), 0);
+
+  // Check for the presence of the compiled files
+  std::string err;
+  std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(kOutputFlata, &err);
+  ASSERT_NE(zip, nullptr) << err;
+  ASSERT_NE(zip->FindFile("drawable_image.png.flat"), nullptr);
+  ASSERT_NE(zip->FindFile("layout_layout.xml.flat"), nullptr);
+  ASSERT_NE(zip->FindFile("values_values.arsc.flat"), nullptr);
+  ASSERT_EQ(remove(kOutputFlata.c_str()), 0);
+}
+
+} // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index d57eaa1..86b1f4c 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -105,10 +105,7 @@
   std::unique_ptr<io::IFileCollectionIterator> iterator = apk->GetFileCollection()->Iterator();
   while (iterator->HasNext()) {
     io::IFile* file = iterator->Next();
-
     std::string path = file->GetSource().path;
-    // The name of the path has the format "<zip-file-name>@<path-to-file>".
-    path = path.substr(path.find('@') + 1);
 
     // Manifest, resource table and resources have already been taken care of.
     if (path == kAndroidManifestPath ||
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 6e9c800..b4311c5 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -24,8 +24,11 @@
 
 #include "Debug.h"
 #include "Diagnostics.h"
+#include "LoadedApk.h"
+#include "Util.h"
 #include "format/Container.h"
 #include "format/binary/BinaryResourceParser.h"
+#include "format/binary/XmlFlattener.h"
 #include "format/proto/ProtoDeserialize.h"
 #include "io/FileStream.h"
 #include "io/ZipArchive.h"
@@ -70,184 +73,6 @@
   printer->Println(StringPrintf("Data:     offset=%" PRIi64 " length=%zd", offset, len));
 }
 
-static bool DumpXmlFile(IAaptContext* context, io::IFile* file, bool proto,
-                        text::Printer* printer) {
-  std::unique_ptr<xml::XmlResource> doc;
-  if (proto) {
-    std::unique_ptr<io::InputStream> in = file->OpenInputStream();
-    if (in == nullptr) {
-      context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
-      return false;
-    }
-
-    io::ZeroCopyInputAdaptor adaptor(in.get());
-    pb::XmlNode pb_node;
-    if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
-      context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as proto XML");
-      return false;
-    }
-
-    std::string err;
-    doc = DeserializeXmlResourceFromPb(pb_node, &err);
-    if (doc == nullptr) {
-      context->GetDiagnostics()->Error(DiagMessage() << "failed to deserialize proto XML");
-      return false;
-    }
-    printer->Println("Proto XML");
-  } else {
-    std::unique_ptr<io::IData> data = file->OpenAsData();
-    if (data == nullptr) {
-      context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
-      return false;
-    }
-
-    std::string err;
-    doc = xml::Inflate(data->data(), data->size(), &err);
-    if (doc == nullptr) {
-      context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as binary XML");
-      return false;
-    }
-    printer->Println("Binary XML");
-  }
-
-  Debug::DumpXml(*doc, printer);
-  return true;
-}
-
-static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
-                        const DumpOptions& options) {
-  // Use a smaller buffer so that there is less latency for dumping to stdout.
-  constexpr size_t kStdOutBufferSize = 1024u;
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
-
-  std::string err;
-  std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
-  if (zip) {
-    ResourceTable table(/** validate_resources **/ false);
-    bool proto = false;
-    if (io::IFile* file = zip->FindFile("resources.pb")) {
-      proto = true;
-
-      std::unique_ptr<io::IData> data = file->OpenAsData();
-      if (data == nullptr) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
-        return false;
-      }
-
-      pb::ResourceTable pb_table;
-      if (!pb_table.ParseFromArray(data->data(), data->size())) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb");
-        return false;
-      }
-
-      if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                         << "failed to parse table: " << err);
-        return false;
-      }
-    } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
-      std::unique_ptr<io::IData> data = file->OpenAsData();
-      if (!data) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc");
-        return false;
-      }
-
-      BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path),
-                                  data->data(), data->size());
-      if (!parser.Parse()) {
-        return false;
-      }
-    }
-
-    if (!options.file_to_dump_path) {
-      if (proto) {
-        printer.Println("Proto APK");
-      } else {
-        printer.Println("Binary APK");
-      }
-      Debug::PrintTable(table, options.print_options, &printer);
-      return true;
-    }
-
-    io::IFile* file = zip->FindFile(options.file_to_dump_path.value());
-    if (file == nullptr) {
-      context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                       << "file '" << options.file_to_dump_path.value()
-                                       << "' not found in APK");
-      return false;
-    }
-    return DumpXmlFile(context, file, proto, &printer);
-  }
-
-  err.clear();
-
-  io::FileInputStream input(file_path);
-  if (input.HadError()) {
-    context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                     << "failed to open file: " << input.GetError());
-    return false;
-  }
-
-  // Try as a compiled file.
-  ContainerReader reader(&input);
-  if (reader.HadError()) {
-    context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                     << "failed to read container: " << reader.GetError());
-    return false;
-  }
-
-  printer.Println("AAPT2 Container (APC)");
-  ContainerReaderEntry* entry;
-  while ((entry = reader.Next()) != nullptr) {
-    if (entry->Type() == ContainerEntryType::kResTable) {
-      printer.Println("kResTable");
-
-      pb::ResourceTable pb_table;
-      if (!entry->GetResTable(&pb_table)) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                         << "failed to parse proto table: " << entry->GetError());
-        continue;
-      }
-
-      ResourceTable table;
-      err.clear();
-      if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                         << "failed to parse table: " << err);
-        continue;
-      }
-
-      printer.Indent();
-      Debug::PrintTable(table, options.print_options, &printer);
-      printer.Undent();
-    } else if (entry->Type() == ContainerEntryType::kResFile) {
-      printer.Println("kResFile");
-      pb::internal::CompiledFile pb_compiled_file;
-      off64_t offset;
-      size_t length;
-      if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
-        context->GetDiagnostics()->Error(
-            DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError());
-        continue;
-      }
-
-      ResourceFile file;
-      std::string error;
-      if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
-        context->GetDiagnostics()->Warn(DiagMessage(file_path)
-                                        << "failed to parse compiled file: " << error);
-        continue;
-      }
-
-      printer.Indent();
-      DumpCompiledFile(file, Source(file_path), offset, length, &printer);
-      printer.Undent();
-    }
-  }
-  return true;
-}
-
 namespace {
 
 class DumpContext : public IAaptContext {
@@ -299,17 +124,290 @@
 
 }  // namespace
 
-int DumpCommand::Action(const std::vector<std::string>& args) {
+// Use a smaller buffer so that there is less latency for dumping to stdout.
+constexpr size_t kStdOutBufferSize = 1024u;
+
+int DumpAPCCommand::Action(const std::vector<std::string>& args) {
   DumpContext context;
-  context.SetVerbose(verbose_);
-  options_.print_options.show_sources = true;
-  options_.print_options.show_values = !no_values_;
-  for (const std::string& arg : args) {
-    if (!TryDumpFile(&context, arg, options_)) {
-      return 1;
+  DebugPrintTableOptions print_options;
+  print_options.show_sources = true;
+  print_options.show_values = !no_values_;
+
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump container specified.");
+    return 1;
+  }
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  Printer printer(&fout);
+
+  for (auto container : args) {
+    io::FileInputStream input(container);
+    if (input.HadError()) {
+      context.GetDiagnostics()->Error(DiagMessage(container)
+                                          << "failed to open file: " << input.GetError());
+      return false;
+    }
+
+    // Try as a compiled file.
+    ContainerReader reader(&input);
+    if (reader.HadError()) {
+      context.GetDiagnostics()->Error(DiagMessage(container)
+                                           << "failed to read container: " << reader.GetError());
+      return false;
+    }
+
+    printer.Println("AAPT2 Container (APC)");
+    ContainerReaderEntry* entry;
+    std::string error;
+    while ((entry = reader.Next()) != nullptr) {
+      if (entry->Type() == ContainerEntryType::kResTable) {
+        printer.Println("kResTable");
+
+        pb::ResourceTable pb_table;
+        if (!entry->GetResTable(&pb_table)) {
+          context.GetDiagnostics()->Error(DiagMessage(container)
+                                               << "failed to parse proto table: "
+                                               << entry->GetError());
+          continue;
+        }
+
+        ResourceTable table;
+        error.clear();
+        if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
+          context.GetDiagnostics()->Error(DiagMessage(container)
+                                               << "failed to parse table: " << error);
+          continue;
+        }
+
+        printer.Indent();
+        Debug::PrintTable(table, print_options, &printer);
+        printer.Undent();
+      } else if (entry->Type() == ContainerEntryType::kResFile) {
+        printer.Println("kResFile");
+        pb::internal::CompiledFile pb_compiled_file;
+        off64_t offset;
+        size_t length;
+        if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
+          context.GetDiagnostics()->Error(
+              DiagMessage(container) << "failed to parse compiled proto file: "
+                                     << entry->GetError());
+          continue;
+        }
+
+        ResourceFile file;
+        if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
+          context.GetDiagnostics()->Warn(DiagMessage(container)
+                                              << "failed to parse compiled file: " << error);
+          continue;
+        }
+
+        printer.Indent();
+        DumpCompiledFile(file, Source(container), offset, length, &printer);
+        printer.Undent();
+      }
     }
   }
+
   return 0;
 }
 
+int DumpConfigsCommand::Action(const std::vector<std::string>& args) {
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump apk specified.");
+    return 1;
+  }
+
+  auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
+  if (!loaded_apk) {
+    return 1;
+  }
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  Printer printer(&fout);
+
+  // Comparison function used to order configurations
+  auto compare = [](ConfigDescription c1, ConfigDescription c2) -> bool {
+      return c1.compare(c2) < 0;
+  };
+
+  // Insert the configurations into a set in order to keep every configuarion seen
+  std::set<ConfigDescription, decltype(compare)> configs(compare);
+  for (auto& package : loaded_apk->GetResourceTable()->packages) {
+    for (auto& type : package->types) {
+      for (auto& entry : type->entries) {
+        for (auto& value : entry->values) {
+          configs.insert(value->config);
+        }
+      }
+    }
+  }
+
+  // Print the configurations in order
+  for (auto& config : configs) {
+    printer.Print(StringPrintf("%s\n", config.to_string().data()));
+  }
+
+  return 0;
+}
+
+int DumpStringsCommand::Action(const std::vector<std::string>& args) {
+  DumpContext context;
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump apk specified.");
+    return 1;
+  }
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  Printer printer(&fout);
+
+  for (auto apk : args) {
+    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+    if (!loaded_apk) {
+      return 1;
+    }
+
+    // Load the run-time xml string pool using the flattened data
+    BigBuffer buffer(4096);
+    StringPool::FlattenUtf8(&buffer, loaded_apk->GetResourceTable()->string_pool,
+                            context.GetDiagnostics());
+    auto data = buffer.to_string();
+    android::ResStringPool pool(data.data(), data.size(), false);
+    Debug::DumpResStringPool(&pool, &printer);
+  }
+
+  return 0;
+}
+
+int DumpTableCommand::Action(const std::vector<std::string>& args) {
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump apk specified.");
+    return 1;
+  }
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  Printer printer(&fout);
+
+  DebugPrintTableOptions print_options;
+  print_options.show_sources = true;
+  print_options.show_values = !no_values_;
+
+  for (auto apk : args) {
+    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+    if (!loaded_apk) {
+      return 1;
+    }
+
+    if (loaded_apk->GetApkFormat()) {
+      printer.Println("Proto APK");
+    } else {
+      printer.Println("Binary APK");
+    }
+
+    Debug::PrintTable(*loaded_apk->GetResourceTable(), print_options, &printer);
+  }
+
+  return 0;
+}
+
+int DumpXmlTreeCommand::Action(const std::vector<std::string>& args) {
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump apk specified");
+    return 1;
+  }
+
+  auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
+  if (!loaded_apk) {
+    return 1;
+  }
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  Printer printer(&fout);
+
+  // Dump the xml tree of every passed in file
+  for (auto file : files_) {
+    auto xml = loaded_apk->LoadXml(file, diag_);
+    if (!xml) {
+      return 1;
+    }
+
+    Debug::DumpXml(*xml, &printer);
+  }
+
+  return 0;
+}
+
+int DumpXmlStringsCommand::Action(const std::vector<std::string>& args) {
+  DumpContext context;
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump apk specified.");
+    return 1;
+  }
+
+  auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
+  if (!loaded_apk) {
+    return 1;
+  }
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  Printer printer(&fout);
+
+  // Dump the xml strings of every passed in file
+  for (auto xml_file : files_) {
+    android::ResXMLTree tree;
+
+    if (loaded_apk->GetApkFormat() == kProto) {
+      auto xml = loaded_apk->LoadXml(xml_file, diag_);
+      if (!xml) {
+        return 1;
+      }
+
+      // Flatten the xml document to get a binary representation of the proto xml file
+      BigBuffer buffer(4096);
+      XmlFlattenerOptions options = {};
+      options.keep_raw_values = true;
+      XmlFlattener flattener(&buffer, options);
+      if (!flattener.Consume(&context, xml.get())) {
+        return 1;
+      }
+
+      // Load the run-time xml tree using the flattened data
+      std::string data = buffer.to_string();
+      tree.setTo(data.data(), data.size(), /** copyData */ true);
+
+    } else if (loaded_apk->GetApkFormat() == kBinary) {
+      io::IFile* file = loaded_apk->GetFileCollection()->FindFile(xml_file);
+      if (!file) {
+        diag_->Error(DiagMessage(xml_file) << "file '" << xml_file << "' not found in APK");
+        return 1;
+      }
+
+      std::unique_ptr<io::IData> data = file->OpenAsData();
+      if (!data) {
+        diag_->Error(DiagMessage() << "failed to open file");
+        return 1;
+      }
+
+      // Load the run-time xml tree from the file data
+      tree.setTo(data->data(), data->size(), /** copyData */ true);
+    }
+
+    Debug::DumpResStringPool(&tree.getStrings(), &printer);
+  }
+
+  return 0;
+}
+
+/** Preform no action because a subcommand is required. */
+int DumpCommand::Action(const std::vector<std::string>& args) {
+  if (args.size() == 0) {
+    diag_->Error(DiagMessage() << "no subcommand specified");
+  } else {
+    diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+  }
+
+  Usage(&std::cerr);
+  return 1;
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 4893c8b..03a4fba 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -22,33 +22,117 @@
 
 namespace aapt {
 
-struct DumpOptions {
-  DebugPrintTableOptions print_options;
-
-  // The path to a file within an APK to dump.
-  Maybe<std::string> file_to_dump_path;
-};
-
-class DumpCommand : public Command {
+/** Command the contents of files generated from the compilation stage. */
+class DumpAPCCommand : public Command {
  public:
-  DumpCommand() : Command("dump", "d") {
-    SetDescription("Prints resource and manifest information.");
+  explicit DumpAPCCommand(IDiagnostics* diag) : Command("apc"), diag_(diag) {
+    SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation.");
     AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
-        &no_values_);
-    AddOptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
-        &options_.file_to_dump_path);
-    AddOptionalSwitch("-v", "increase verbosity of output", &verbose_);
+                      &no_values_);
+    AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
   }
 
   int Action(const std::vector<std::string>& args) override;
 
  private:
-  DumpOptions options_;
-
+  IDiagnostics* diag_;
   bool verbose_ = false;
   bool no_values_ = false;
 };
 
+/** Prints every configuration used by a resource in an APK. */
+class DumpConfigsCommand : public Command {
+ public:
+  explicit DumpConfigsCommand(IDiagnostics* diag) : Command("configurations"), diag_(diag) {
+    SetDescription("Print every configuration used by a resource in the APK.");
+  }
+
+  int Action(const std::vector<std::string>& args) override;
+
+ private:
+  IDiagnostics* diag_;
+};
+
+/** Prints the contents of the resource table string pool in the APK. */
+class DumpStringsCommand : public Command {
+  public:
+    explicit DumpStringsCommand(IDiagnostics* diag) : Command("strings"), diag_(diag) {
+      SetDescription("Print the contents of the resource table string pool in the APK.");
+    }
+
+    int Action(const std::vector<std::string>& args) override;
+
+  private:
+    IDiagnostics* diag_;
+};
+
+/** Prints the contents of the resource table from the APK. */
+class DumpTableCommand : public Command {
+ public:
+  explicit DumpTableCommand(IDiagnostics* diag) : Command("resources"), diag_(diag) {
+    SetDescription("Print the contents of the resource table from the APK.");
+    AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
+                      &no_values_);
+    AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
+  }
+
+  int Action(const std::vector<std::string>& args) override;
+
+ private:
+  IDiagnostics* diag_;
+  bool verbose_ = false;
+  bool no_values_ = false;
+};
+
+/** Prints the string pool of a compiled xml in an APK. */
+class DumpXmlStringsCommand : public Command {
+public:
+    explicit DumpXmlStringsCommand(IDiagnostics* diag) : Command("xmlstrings"), diag_(diag) {
+      SetDescription("Print the string pool of a compiled xml in an APK.");
+      AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
+    }
+
+    int Action(const std::vector<std::string>& args) override;
+
+private:
+    IDiagnostics* diag_;
+    std::vector<std::string> files_;
+};
+
+
+/** Prints the tree of a compiled xml in an APK. */
+class DumpXmlTreeCommand : public Command {
+ public:
+  explicit DumpXmlTreeCommand(IDiagnostics* diag) : Command("xmltree"), diag_(diag) {
+    SetDescription("Print the tree of a compiled xml in an APK.");
+    AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
+  }
+
+  int Action(const std::vector<std::string>& args) override;
+
+ private:
+  IDiagnostics* diag_;
+  std::vector<std::string> files_;
+};
+
+/** The default dump command. Preforms no action because a subcommand is required. */
+class DumpCommand : public Command {
+ public:
+  explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) {
+    AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(diag_));
+    AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(diag_));
+    AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(diag_));
+    AddOptionalSubcommand(util::make_unique<DumpTableCommand>(diag_));
+    AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(diag_));
+    AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(diag_));
+  }
+
+  int Action(const std::vector<std::string>& args) override;
+
+ private:
+  IDiagnostics* diag_;
+};
+
 }// namespace aapt
 
 #endif //AAPT2_DUMP_H
diff --git a/tools/aapt2/integration-tests/CompileTest/DirInput/res/drawable/image.png b/tools/aapt2/integration-tests/CompileTest/DirInput/res/drawable/image.png
new file mode 100644
index 0000000..1a3731b
--- /dev/null
+++ b/tools/aapt2/integration-tests/CompileTest/DirInput/res/drawable/image.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/CompileTest/DirInput/res/layout/layout.xml b/tools/aapt2/integration-tests/CompileTest/DirInput/res/layout/layout.xml
new file mode 100644
index 0000000..e5835ed
--- /dev/null
+++ b/tools/aapt2/integration-tests/CompileTest/DirInput/res/layout/layout.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
diff --git a/tools/aapt2/integration-tests/CompileTest/DirInput/res/values/values.xml b/tools/aapt2/integration-tests/CompileTest/DirInput/res/values/values.xml
new file mode 100644
index 0000000..62ab652
--- /dev/null
+++ b/tools/aapt2/integration-tests/CompileTest/DirInput/res/values/values.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+
+<resources>
+</resources>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/CompileTest/ZipInput/res.zip b/tools/aapt2/integration-tests/CompileTest/ZipInput/res.zip
new file mode 100644
index 0000000..00e396d
--- /dev/null
+++ b/tools/aapt2/integration-tests/CompileTest/ZipInput/res.zip
Binary files differ
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 1387d22..16a20f4c 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -16,6 +16,9 @@
 
 #include "io/FileSystem.h"
 
+#include <dirent.h>
+
+#include "android-base/errors.h"
 #include "androidfw/StringPiece.h"
 #include "utils/FileMap.h"
 
@@ -26,6 +29,7 @@
 #include "util/Util.h"
 
 using ::android::StringPiece;
+using ::android::base::SystemErrorCodeToString;
 
 namespace aapt {
 namespace io {
@@ -64,6 +68,50 @@
   return result;
 }
 
+std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiece& root,
+                                                        std::string* outError) {
+  std::unique_ptr<FileCollection> collection =
+      std::unique_ptr<FileCollection>(new FileCollection());
+
+  std::unique_ptr<DIR, decltype(closedir) *> d(opendir(root.data()), closedir);
+  if (!d) {
+    *outError = "failed to open directory: " + SystemErrorCodeToString(errno);
+    return nullptr;
+  }
+
+  while (struct dirent *entry = readdir(d.get())) {
+    std::string prefix_path = root.to_string();
+    file::AppendPath(&prefix_path, entry->d_name);
+
+    // The directory to iterate over looking for files
+    if (file::GetFileType(prefix_path) != file::FileType::kDirectory
+        || file::IsHidden(prefix_path)) {
+      continue;
+    }
+
+    std::unique_ptr<DIR, decltype(closedir)*> subdir(opendir(prefix_path.data()), closedir);
+    if (!subdir) {
+      *outError = "failed to open directory: " + SystemErrorCodeToString(errno);
+      return nullptr;
+    }
+
+    while (struct dirent* leaf_entry = readdir(subdir.get())) {
+      std::string full_path = prefix_path;
+      file::AppendPath(&full_path, leaf_entry->d_name);
+
+      // Do not add folders to the file collection
+      if (file::GetFileType(full_path) == file::FileType::kDirectory
+          || file::IsHidden(full_path)) {
+        continue;
+      }
+
+      collection->InsertFile(full_path);
+    }
+  }
+
+  return collection;
+}
+
 IFile* FileCollection::InsertFile(const StringPiece& path) {
   return (files_[path.to_string()] = util::make_unique<RegularFile>(Source(path))).get();
 }
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index 6be8807..fb6bf6e 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -59,6 +59,10 @@
  public:
   FileCollection() = default;
 
+  /** Creates a file collection containing all files contained in the specified root directory. */
+  static std::unique_ptr<FileCollection> Create(const android::StringPiece& path,
+                                                std::string* outError);
+
   // Adds a file located at path. Returns the IFile representation of that file.
   IFile* InsertFile(const android::StringPiece& path);
   IFile* FindFile(const android::StringPiece& path) override;
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 269b6c5..8e6d713 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -20,6 +20,7 @@
 #include "ziparchive/zip_archive.h"
 
 #include "Source.h"
+#include "util/Files.h"
 #include "util/Util.h"
 
 using ::android::StringPiece;
@@ -121,9 +122,14 @@
     std::string zip_entry_path =
         std::string(reinterpret_cast<const char*>(zip_entry_name.name),
                     zip_entry_name.name_length);
-    std::string nested_path = path.to_string() + "@" + zip_entry_path;
-    std::unique_ptr<IFile> file =
-        util::make_unique<ZipFile>(collection->handle_, zip_data, Source(nested_path));
+
+    // Do not add folders to the file collection
+    if (util::EndsWith(zip_entry_path, "/")) {
+      continue;
+    }
+
+    std::unique_ptr<IFile> file = util::make_unique<ZipFile>(collection->handle_, zip_data,
+        Source(zip_entry_path, path.to_string()));
     collection->files_by_name_[zip_entry_path] = file.get();
     collection->files_.push_back(std::move(file));
   }
@@ -132,6 +138,7 @@
     if (out_error) *out_error = ErrorCodeString(result);
     return {};
   }
+
   return collection;
 }
 
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5a8ff09..7cd023b 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -149,6 +149,10 @@
   return {};
 }
 
+bool IsHidden(const android::StringPiece& path) {
+  return util::StartsWith(GetFilename(path), ".");
+}
+
 void AppendPath(std::string* base, StringPiece part) {
   CHECK(base != nullptr);
   const bool base_has_trailing_sep = (!base->empty() && *(base->end() - 1) == sDirSep);
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index b26e4fa..219e1a0 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -70,6 +70,9 @@
 // of the path.
 android::StringPiece GetExtension(const android::StringPiece& path);
 
+// Returns whether or not the name of the file or directory is a hidden file name
+bool IsHidden(const android::StringPiece& path);
+
 // Converts a package name (com.android.app) to a path: com/android/app
 std::string PackageToPath(const android::StringPiece& package);