Merge "Media: Eliminate NPE from race conditions"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a040520f..318c7ac 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2157,6 +2157,14 @@
     }
 
     @Override
+    public boolean canLoadUnsafeResources() {
+        if (getPackageName().equals(getOpPackageName())) {
+            return true;
+        }
+        return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0;
+    }
+
+    @Override
     public Display getDisplay() {
         if (mDisplay == null) {
             return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY,
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
index 33f4e80..7d6ad21 100644
--- a/core/java/android/app/timezone/RulesState.java
+++ b/core/java/android/app/timezone/RulesState.java
@@ -174,29 +174,14 @@
     }
 
     /**
-     * Returns true if the distro IANA rules version supplied is newer or the same as the version in
-     * the system image data files.
+     * Returns true if the system image data files contain IANA rules data that are newer than the
+     * distro IANA rules version supplied, i.e. true when the version specified would be "worse"
+     * than the one that is in the system image. Returns false if the system image version is the
+     * same or older, i.e. false when the version specified would be "better" than the one that is
+     * in the system image.
      */
-    public boolean isSystemVersionOlderThan(DistroRulesVersion distroRulesVersion) {
-        return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) < 0;
-    }
-
-    public boolean isDistroInstalled() {
-        return mDistroStatus == DISTRO_STATUS_INSTALLED;
-    }
-
-    /**
-     * Returns true if the rules version supplied is newer than the one currently installed. If
-     * there is no installed distro this method throws IllegalStateException.
-     */
-    public boolean isInstalledDistroOlderThan(DistroRulesVersion distroRulesVersion) {
-        if (mOperationInProgress) {
-            throw new IllegalStateException("Distro state not known: operation in progress.");
-        }
-        if (!isDistroInstalled()) {
-            throw new IllegalStateException("No distro installed.");
-        }
-        return mInstalledDistroRulesVersion.isOlderThan(distroRulesVersion);
+    public boolean isSystemVersionNewerThan(DistroRulesVersion distroRulesVersion) {
+        return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0;
     }
 
     public static final Parcelable.Creator<RulesState> CREATOR =
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5929aca..128d195 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3913,7 +3913,7 @@
      * @see #getSystemService
      * @hide
      */
-    public static final String RADIO_SERVICE = "radio";
+    public static final String RADIO_SERVICE = "broadcastradio";
 
     /**
      * Use with {@link #getSystemService} to retrieve a
@@ -4681,6 +4681,12 @@
     public abstract boolean isCredentialProtectedStorage();
 
     /**
+     * Returns true if the context can load unsafe resources, e.g. fonts.
+     * @hide
+     */
+    public abstract boolean canLoadUnsafeResources();
+
+    /**
      * @hide
      */
     public IBinder getActivityToken() {
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index c719c64..a9fd58b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -925,6 +925,12 @@
         return mBase.isCredentialProtectedStorage();
     }
 
+    /** {@hide} */
+    @Override
+    public boolean canLoadUnsafeResources() {
+        return mBase.canLoadUnsafeResources();
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 0045308..d73d3d8 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -654,6 +654,7 @@
         Preconditions.checkNotNull(port, "port must not be null");
         UsbPort.checkRoles(powerRole, dataRole);
 
+        Log.d(TAG, "setPortRoles Package:" + mContext.getPackageName());
         try {
             mService.setPortRoles(port.getId(), powerRole, dataRole);
         } catch (RemoteException e) {
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 394bd0a..a80ef03 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -19,24 +19,230 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
+import android.provider.Settings;
+
 import com.android.internal.os.HandlerCaller;
 import android.annotation.SdkConstant;
-import android.app.Activity;
-import android.app.Service;
-import android.content.Intent;
+import android.app.Service;import android.content.Intent;
 import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillValue;
 
 import com.android.internal.os.SomeArgs;
 
 /**
- * Top-level service of the current autofill service for a given user.
+ * An {@code AutofillService} is a service used to automatically fill the contents of the screen
+ * on behalf of a given user - for more information about autofill, read
+ * <a href="{@docRoot}preview/features/autofill.html">Autofill Framework</a>.
  *
- * <p>Apps providing autofill capabilities must extend this service.
+ * <p>An {@code AutofillService} is only bound to the Android System for autofill purposes if:
+ * <ol>
+ *   <li>It requires the {@code android.permission.BIND_AUTOFILL_SERVICE} permission in its
+ *       manifest.
+ *   <li>The user explicitly enables it using Android Settings (the
+ *       {@link Settings#ACTION_REQUEST_SET_AUTOFILL_SERVICE} intent can be used to launch such
+ *       Settings screen).
+ * </ol>
+ *
+ * <h3>Basic usage</h3>
+ *
+ * <p>The basic autofill process is defined by the workflow below:
+ * <ol>
+ *   <li>User focus an editable {@link View}.
+ *   <li>View calls {@link AutofillManager#notifyViewEntered(android.view.View)}.
+ *   <li>A {@link ViewStructure} representing all views in the screen is created.
+ *   <li>The Android System binds to the service and calls {@link #onConnected()}.
+ *   <li>The service receives the view structure through the
+ *       {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)}.
+ *   <li>The service replies through {@link FillCallback#onSuccess(FillResponse)}.
+ *   <li>The Android System calls {@link #onDisconnected()} and unbinds from the
+ *       {@code AutofillService}.
+ *   <li>The Android System displays an UI affordance with the options sent by the service.
+ *   <li>The user picks an option.
+ *   <li>The proper views are autofilled.
+ * </ol>
+ *
+ * <p>This workflow was designed to minimize the time the Android System is bound to the service;
+ * for each call, it: binds to service, waits for the reply, and unbinds right away. Furthermore,
+ * those calls are considered stateless: if the service needs to keep state between calls, it must
+ * do its own state management (keeping in mind that the service's process might be killed by the
+ * Android System when unbound; for example, if the device is running low in memory).
+ *
+ * <p>Typically, the
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} will:
+ * <ol>
+ *   <li>Parse the view structure looking for autofillable views (for example, using
+ *       {@link android.app.assist.AssistStructure.ViewNode#getAutofillHints()}.
+ *   <li>Match the autofillable views with the user's data.
+ *   <li>Create a {@link Dataset} for each set of user's data that match those fields.
+ *   <li>Fill the dataset(s) with the proper {@link AutofillId}s and {@link AutofillValue}s.
+ *   <li>Add the dataset(s) to the {@link FillResponse} passed to
+ *       {@link FillCallback#onSuccess(FillResponse)}.
+ * </ol>
+ *
+ * <p>For example, for a login screen with username and password views where the user only has one
+ * account in the service, the response could be:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder()
+ *         .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer"))
+ *         .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer"))
+ *         .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>But if the user had 2 accounts instead, the response could be:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder()
+ *         .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer"))
+ *         .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer"))
+ *         .build())
+ *     .addDataset(new Dataset.Builder()
+ *         .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders"))
+ *         .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders"))
+ *         .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>If the service does not find any autofillable view in the view structure, it should pass
+ * {@code null} to {@link FillCallback#onSuccess(FillResponse)}; if the service encountered an error
+ * processing the request, it should call {@link FillCallback#onFailure(CharSequence)}. For
+ * performance reasons, it's paramount that the service calls either
+ * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} for
+ * each {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} received - if it
+ * doesn't, the request will eventually time out and be discarded by the Android System.
+ *
+ * <h3>Saving user data</h3>
+ *
+ * <p>If the service is also interested on saving the data filled by the user, it must set a
+ * {@link SaveInfo} object in the {@link FillResponse}. See {@link SaveInfo} for more details and
+ * examples.
+ *
+ * <h3>User authentication</h3>
+ *
+ * <p>The service can provide an extra degree of security by requiring the user to authenticate
+ * before an app can be autofilled. The authentication is typically required in 2 scenarios:
+ * <ul>
+ *   <li>To unlock the user data (for example, using a master password or fingerprint
+ *       authentication) - see
+ * {@link FillResponse.Builder#setAuthentication(AutofillId[], android.content.IntentSender, android.widget.RemoteViews)}.
+ *   <li>To unlock a specific dataset (for example, by providing a CVC for a credit card) - see
+ *       {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}.
+ * </ul>
+ *
+ * <p>When using authentication, it is recommended to encrypt only the sensitive data and leave
+ * labels unencrypted, so they can be used on presentation views. For example, if the user has a
+ * home and a work address, the {@code Home} and {@code Work} labels should be stored unencrypted
+ * (since they don't have any sensitive data) while the address data per se could be stored in an
+ * encrypted storage. Then when the user chooses the {@code Home} dataset, the platform starts
+ * the authentication flow, and the service can decrypt the sensitive data.
+ *
+ * <p>The authentication mechanism can also be used in scenarios where the service needs multiple
+ * steps to determine the datasets that can fill a screen. For example, when autofilling a financial
+ * app where the user has accounts for multiple banks, the workflow could be:
+ *
+ * <ol>
+ *   <li>The first {@link FillResponse} contains datasets with the credentials for the financial
+ *       app, plus a "fake" dataset whose presentation says "Tap here for banking apps credentials".
+ *   <li>When the user selects the fake dataset, the service displays a dialog with available
+ *       banking apps.
+ *   <li>When the user select a banking app, the service replies with a new {@link FillResponse}
+ *       containing the datasets for that bank.
+ * </ol>
+ *
+ * <p>Another example of multiple-steps dataset selection is when the service stores the user
+ * credentials in "vaults": the first response would contain fake datasets with the vault names,
+ * and the subsequent response would contain the app credentials stored in that vault.
+ *
+ * <h3>Data partitioning</h3>
+ *
+ * <p>The autofillable views in a screen should be grouped in logical groups called "partitions".
+ * Typical partitions are:
+ * <ul>
+ *   <li>Credentials (username/email address, password).
+ *   <li>Address (street, city, state, zip code, etc).
+ *   <li>Payment info (credit card number, expiration date, and verification code).
+ * </ul>
+ * <p>For security reasons, when a screen has more than one partition, it's paramount that the
+ * contents of a dataset do not spawn multiple partitions, specially when one of the partitions
+ * contains data that is not specific to the application being autofilled. For example, a dataset
+ * should not contain fields for username, password, and credit card information. The reason for
+ * this rule is that a malicious app could draft a view structure where the credit card fields
+ * are not visible, so when the user selects a dataset from the username UI, the credit card info is
+ * released to the application without the user knowledge. Similar, it's recommended to always
+ * protect a dataset that contains sensitive information by requiring dataset authentication
+ * (see {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}).
+ *
+ * <p>When the service detects that a screen have multiple partitions, it should return a
+ * {@link FillResponse} with just the datasets for the partition that originated the request (i.e.,
+ * the partition that has the {@link android.app.assist.AssistStructure.ViewNode} whose
+ * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} returns {@code true}); then if
+ * the user selects a field from a different partition, the Android System will make another
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call for that partition,
+ * and so on.
+ *
+ * <p>Notice that when the user autofill a partition with the data provided by the service and the
+ * user did not change these fields, the autofilled value is sent back to the service in the
+ * subsequent calls (and can be obtained by calling
+ * {@link android.app.assist.AssistStructure.ViewNode#getAutofillValue()}). This is useful in the
+ * cases where the service must create datasets for a partition based on the choice made in a
+ * previous partition. For example, the 1st response for a screen that have credentials and address
+ * partitions could be:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder() // partition 1 (credentials)
+ *         .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer"))
+ *         .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer"))
+ *         .build())
+ *     .addDataset(new Dataset.Builder() // partition 1 (credentials)
+ *         .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders"))
+ *         .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders"))
+ *         .build())
+ *     .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD,
+ *         new AutofillId[] { id1, id2 })
+ *             .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>Then if the user selected {@code flanders}, the service would get a new
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call, with the values of
+ * the fields {@code id1} and {@code id2} prepopulated, so the service could then fetch the address
+ * for the Flanders account and return the following {@link FillResponse} for the address partition:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder() // partition 2 (address)
+ *         .setValue(id3, AutofillValue.forText("744 Evergreen Terrace"), createPresentation("744 Evergreen Terrace")) // street
+ *         .setValue(id4, AutofillValue.forText("Springfield"), createPresentation("Springfield")) // city
+ *         .build())
+ *     .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD | SaveInfo.SAVE_DATA_TYPE_ADDRESS,
+ *         new AutofillId[] { id1, id2 }) // username and password
+ *              .setOptionalIds(new AutofillId[] { id3, id4 }) // state and zipcode
+ *             .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>When the service returns multiple {@link FillResponse}, the last one overrides the previous;
+ * that's why the {@link SaveInfo} in the 2nd request above has the info for both partitions.
+ *
+ * <h3>Ignoring views</h3>
+ *
+ * <p>If the service find views that cannot be autofilled (for example, a text field representing
+ * the response to a Captcha challenge), it should mark those views as ignored by
+ * calling {@link FillResponse.Builder#setIgnoredIds(AutofillId...)} so the system does not trigger
+ * a new {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} when these views are
+ * focused.
  */
 public abstract class AutofillService extends Service {
     private static final String TAG = "AutofillService";
@@ -132,11 +338,6 @@
 
     private HandlerCaller mHandlerCaller;
 
-    /**
-     * {@inheritDoc}
-     *
-     * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}.
-     */
     @CallSuper
     @Override
     public void onCreate() {
@@ -162,8 +363,7 @@
     }
 
     /**
-     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
-     * service.
+     * Called by the Android system do decide if a screen can be autofilled by the service.
      *
      * <p>Service must call one of the {@link FillCallback} methods (like
      * {@link FillCallback#onSuccess(FillResponse)}
@@ -181,7 +381,7 @@
             @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
 
     /**
-     * Called when user requests service to save the fields of an {@link Activity}.
+     * Called when user requests service to save the fields of a screen.
      *
      * <p>Service must call one of the {@link SaveCallback} methods (like
      * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
@@ -226,7 +426,7 @@
      * @return The history or {@code null} if there are no events.
      */
     @Nullable public final FillEventHistory getFillEventHistory() {
-        AutofillManager afm = getSystemService(AutofillManager.class);
+        final AutofillManager afm = getSystemService(AutofillManager.class);
 
         if (afm == null) {
             return null;
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index af2eb34..a2ec099 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -31,17 +31,23 @@
 import java.util.ArrayList;
 
 /**
- * A set of data that can be used to autofill an {@link android.app.Activity}.
+ * A dataset object represents a group of key/value pairs used to autofill parts of a screen.
  *
- * <p>It contains:
+ * <p>In its simplest form, a dataset contains one or more key / value pairs (comprised of
+ * {@link AutofillId} and {@link AutofillValue} respectively); and one or more
+ * {@link RemoteViews presentation} for these pairs (a pair could have its own
+ * {@link RemoteViews presentation}, or use the default {@link RemoteViews presentation} associated
+ * with the whole dataset). When an autofill service returns datasets in a {@link FillResponse}
+ * and the screen input is focused in a view that is present in at least one of these datasets,
+ * the Android System displays a UI affordance containing the {@link RemoteViews presentation} of
+ * all datasets pairs that have that view's {@link AutofillId}. Then, when the user selects a
+ * dataset from the affordance, all views in that dataset are autofilled.
  *
- * <ol>
- *   <li>A list of values for input fields.
- *   <li>A presentation view to visualize.
- *   <li>An optional intent to authenticate.
- * </ol>
+ * <p>In a more sophisticated form, the dataset value can be protected until the user authenticates
+ * the dataset - see {@link Dataset.Builder#setAuthentication(IntentSender)}.
  *
- * @see android.service.autofill.FillResponse for examples.
+ * @see android.service.autofill.AutofillService for more information and examples about the
+ * role of datasets in the autofill workflow.
  */
 public final class Dataset implements Parcelable {
 
@@ -113,7 +119,7 @@
     }
 
     /**
-     * A builder for {@link Dataset} objects. You must to provide at least
+     * A builder for {@link Dataset} objects. You must provide at least
      * one value for a field or set an authentication intent.
      */
     public static final class Builder {
@@ -175,9 +181,9 @@
          * credit card information without the CVV for the data set in the {@link FillResponse
          * response} then the returned data set should contain the CVV entry.
          *
-         * <p></><strong>Note:</strong> Do not make the provided pending intent
+         * <p><b>NOTE:</b> Do not make the provided pending intent
          * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
-         * platform needs to fill in the authentication arguments.</p>
+         * platform needs to fill in the authentication arguments.
          *
          * @param authentication Intent to an activity with your authentication flow.
          * @return This builder.
@@ -191,7 +197,7 @@
         }
 
         /**
-         * Sets the id for the dataset.
+         * Sets the id for the dataset so its usage history can be retrieved later.
          *
          * <p>The id of the last selected dataset can be read from
          * {@link AutofillService#getFillEventHistory()}. If the id is not set it will not be clear
@@ -214,13 +220,12 @@
          *
          * @param id id returned by {@link
          *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
-         * @param value value to be auto filled. Pass {@code null} if you do not have the value
+         * @param value value to be autofilled. Pass {@code null} if you do not have the value
          *        but the target view is a logical part of the dataset. For example, if
          *        the dataset needs an authentication and you have no access to the value.
-         *        Filtering matches any user typed string to {@code null} values.
          * @return This builder.
-         * @throws IllegalStateException if the builder was constructed without a presentation
-         * ({@link RemoteViews}).
+         * @throws IllegalStateException if the builder was constructed without a
+         * {@link RemoteViews presentation}.
          */
         public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) {
             throwIfDestroyed();
@@ -232,7 +237,8 @@
         }
 
         /**
-         * Sets the value of a field, using a custom presentation to visualize it.
+         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
+         * visualize it.
          *
          * @param id id returned by {@link
          *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
@@ -272,10 +278,12 @@
         }
 
         /**
-         * Creates a new {@link Dataset} instance. You should not interact
-         * with this builder once this method is called. It is required
-         * that you specified at least one field. Also it is mandatory to
-         * provide a presentation view to visualize the data set in the UI.
+         * Creates a new {@link Dataset} instance.
+         *
+         * <p>You should not interact with this builder once this method is called.
+         *
+         * <p>It is required that you specify at least one field before calling this method. It's
+         * also mandatory to provide a presentation view to visualize the data set in the UI.
          *
          * @return The built dataset.
          */
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index f8a8751..cda2f4a 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -30,7 +30,6 @@
 import android.util.SparseIntArray;
 import android.view.autofill.AutofillId;
 
-import java.util.ArrayList;
 import java.util.LinkedList;
 
 /**
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index b1145ee..fd6da05a 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -23,6 +23,7 @@
 import android.os.CancellationSignal;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.View;
 
 import com.android.internal.util.Preconditions;
 
@@ -32,7 +33,7 @@
 import java.util.List;
 
 /**
- * This class represents a request to an {@link AutofillService autofill provider}
+ * This class represents a request to an autofill service
  * to interpret the screen and provide information to the system which views are
  * interesting for saving and what are the possible ways to fill the inputs on
  * the screen if applicable.
@@ -40,8 +41,29 @@
  * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
  */
 public final class FillRequest implements Parcelable {
+
     /**
      * Indicates autofill was explicitly requested by the user.
+     *
+     * <p>Users typically make an explicit request to autofill a screen in two situations:
+     * <ul>
+     *   <li>The app disabled autofill (using {@link View#setImportantForAutofill(int)}.
+     *   <li>The service could not figure out how to autofill a screen (but the user knows the
+     *       service has data for that app).
+     * </ul>
+     *
+     * <p>This flag is particularly useful for the second case. For example, the service could offer
+     * a complex UI where the user can map which screen views belong to each user data, or it could
+     * offer a simpler UI where the user picks the data for just the view used to trigger the
+     * request (that would be the view whose
+     * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} method returns {@code true}).
+     *
+     * <p>An explicit autofill request is triggered when the
+     * {@link android.view.autofill.AutofillManager#requestAutofill(View)} or
+     * {@link android.view.autofill.AutofillManager#requestAutofill(View, int, android.graphics.Rect)}
+     * is called. For example, standard {@link android.widget.TextView} views that use
+     * an {@link android.widget.Editor} shows an {@code AUTOFILL} option in the overflow menu that
+     * triggers such request.
      */
     public static final int FLAG_MANUAL_REQUEST = 0x1;
 
@@ -79,14 +101,14 @@
     }
 
     /**
-     * @return The unique id of this request.
+     * Gets the unique id of this request.
      */
     public int getId() {
         return mId;
     }
 
     /**
-     * @return The flags associated with this request.
+     * Gets the flags associated with this request.
      *
      * @see #FLAG_MANUAL_REQUEST
      */
@@ -95,7 +117,7 @@
     }
 
     /**
-     * @return The contexts associated with each previous fill request.
+     * Gets the contexts associated with each previous fill request.
      */
     public @NonNull List<FillContext> getFillContexts() {
         return mContexts;
@@ -104,10 +126,10 @@
     /**
      * Gets the extra client state returned from the last {@link
      * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
-     * fill request}.
-     * <p>
-     * Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
-     * save request} is made the client state is cleared.
+     * fill request}, so the service can use it for state management.
+     *
+     * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
+     * save request} is made, the client state is cleared.
      *
      * @return The client state.
      */
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index fcf18eb..e13fdf6 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -21,6 +21,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -36,100 +37,7 @@
  * Response for a {@link
  * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}.
  *
- * <p>The response typically contains one or more {@link Dataset}s, each representing a set of
- * fields that can be autofilled together, and the Android system displays a dataset picker UI
- * affordance that the user must use before the {@link android.app.Activity} is filled with
- * the dataset.
- *
- * <p>For example, for a login page with username/password where the user only has one account in
- * the response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createPresentation())
- *          .setValue(id1, AutofillValue.forText("homer"))
- *          .setValue(id2, AutofillValue.forText("D'OH!"))
- *          .build())
- *      .build();
- * </pre>
- *
- * <p>If the user had 2 accounts, each with its own user-provided names, the response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createFirstPresentation())
- *          .setValue(id1, AutofillValue.forText("homer"))
- *          .setValue(id2, AutofillValue.forText("D'OH!"))
- *          .build())
- *      .add(new Dataset.Builder(createSecondPresentation())
- *          .setValue(id1, AutofillValue.forText("elbarto")
- *          .setValue(id2, AutofillValue.forText("cowabonga")
- *          .build())
- *      .build();
- * </pre>
- *
- * If the service is interested on saving the user-edited data back, it must set a {@link SaveInfo}
- * in the {@link FillResponse}. Typically, the {@link SaveInfo} contains the same ids as the
- * {@link Dataset}, but other combinations are possible - see {@link SaveInfo} for more details
- *
- * <p>If the service has multiple {@link Dataset}s for different sections of the activity,
- * for example, a user section for which there are two datasets followed by an address
- * section for which there are two datasets for each user user, then it should "partition"
- * the activity in sections and populate the response with just a subset of the data that would
- * fulfill the first section (the name in our example); then once the user fills the first
- * section and taps a field from the next section (the address in our example), the Android
- * system would issue another request for that section, and so on. Note that if the user
- * chooses to populate the first section with a service provided dataset, the subsequent request
- * would contain the populated values so you don't try to provide suggestions for the first
- * section but ony for the second one based on the context of what was already filled. For
- * example, the first response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createFirstPresentation())
- *          .setValue(id1, AutofillValue.forText("Homer"))
- *          .setValue(id2, AutofillValue.forText("Simpson"))
- *          .build())
- *      .add(new Dataset.Builder(createSecondPresentation())
- *          .setValue(id1, AutofillValue.forText("Bart"))
- *          .setValue(id2, AutofillValue.forText("Simpson"))
- *          .build())
- *      .build();
- * </pre>
- *
- * <p>Then after the user picks the second dataset and taps the street field to
- * trigger another autofill request, the second response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createThirdPresentation())
- *          .setValue(id3, AutofillValue.forText("742 Evergreen Terrace"))
- *          .setValue(id4, AutofillValue.forText("Springfield"))
- *          .build())
- *      .add(new Dataset.Builder(createFourthPresentation())
- *          .setValue(id3, AutofillValue.forText("Springfield Power Plant"))
- *          .setValue(id4, AutofillValue.forText("Springfield"))
- *          .build())
- *      .build();
- * </pre>
- *
- * <p>The service could require user authentication at the {@link FillResponse} or the
- * {@link Dataset} level, prior to autofilling an activity - see
- * {@link FillResponse.Builder#setAuthentication(AutofillId[], IntentSender, RemoteViews)} and
- * {@link Dataset.Builder#setAuthentication(IntentSender)}.
- *
- * <p>It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
- * which would allow you to provide a dataset presentation views with labels and if the user
- * chooses one of them challenge the user to authenticate. For example, if the user has a
- * home and a work address the Home and Work labels could be stored unencrypted as they don't
- * have any sensitive data while the address data is in an encrypted storage. If the user
- * chooses Home, then the platform will start your authentication flow. If you encrypt all
- * data and require auth at the response level the user will have to interact with the fill
- * UI to trigger a request for the datasets (as they don't see the presentation views for the
- * possible options) which will start your auth flow and after successfully authenticating
- * the user will be presented with the Home and Work options to pick one. Hence, you have
- * flexibility how to implement your auth while storing labels non-encrypted and data
- * encrypted provides a better user experience.
+ * <p>See the main {@link AutofillService} documentation for more details and examples.
  */
 public final class FillResponse implements Parcelable {
 
@@ -221,7 +129,7 @@
         private boolean mDestroyed;
 
         /**
-         * Requires a fill response authentication before autofilling the activity with
+         * Requires a fill response authentication before autofilling the screen with
          * any data set in this response.
          *
          * <p>This is typically useful when a user interaction is required to unlock their
@@ -230,16 +138,16 @@
          * auth on the data set level leading to a better user experience. Note that if you
          * use sensitive data as a label, for example an email address, then it should also
          * be encrypted. The provided {@link android.app.PendingIntent intent} must be an
-         * activity which implements your authentication flow. Also if you provide an auth
+         * {@link Activity} which implements your authentication flow. Also if you provide an auth
          * intent you also need to specify the presentation view to be shown in the fill UI
          * for the user to trigger your authentication flow.
          *
          * <p>When a user triggers autofill, the system launches the provided intent
          * whose extras will have the {@link AutofillManager#EXTRA_ASSIST_STRUCTURE screen
          * content} and your {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE
-         * client state}. Once you complete your authentication flow you should set the activity
-         * result to {@link android.app.Activity#RESULT_OK} and provide the fully populated
-         * {@link FillResponse response} by setting it to the {@link
+         * client state}. Once you complete your authentication flow you should set the
+         * {@link Activity} result to {@link android.app.Activity#RESULT_OK} and provide the fully
+         * populated {@link FillResponse response} by setting it to the {@link
          * AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra.
          * For example, if you provided an empty {@link FillResponse resppnse} because the
          * user's data was locked and marked that the response needs an authentication then
@@ -286,8 +194,8 @@
          * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
          * FillCallback)} requests.
          *
-         * <p>This is typically used when the service cannot autofill the view; for example, an
-         * {@code EditText} representing a captcha.
+         * <p>This is typically used when the service cannot autofill the view; for example, a
+         * text field representing the result of a Captcha challenge.
          */
         public Builder setIgnoredIds(AutofillId...ids) {
             mIgnoredIds = ids;
@@ -316,8 +224,6 @@
         /**
          * Sets the {@link SaveInfo} associated with this response.
          *
-         * <p>See {@link FillResponse} for more info.
-         *
          * @return This builder.
          */
         public @NonNull Builder setSaveInfo(@NonNull SaveInfo saveInfo) {
@@ -335,7 +241,7 @@
          * fill requests and the subsequent save request.
          *
          * <p>If this method is called on multiple {@link FillResponse} objects for the same
-         * activity, just the latest bundle is passed back to the service.
+         * screen, just the latest bundle is passed back to the service.
          *
          * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
          * save request} is made the client state is cleared.
@@ -350,9 +256,10 @@
         }
 
         /**
-         * Builds a new {@link FillResponse} instance. You must provide at least
-         * one dataset or some savable ids or an authentication with a presentation
-         * view.
+         * Builds a new {@link FillResponse} instance.
+         *
+         * <p>You must provide at least one dataset or some savable ids or an authentication with a
+         * presentation view.
          *
          * @return A built response.
          */
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 6ea7d5e..95d393b 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.content.IntentSender;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -45,70 +46,91 @@
  * two pieces of information:
  *
  * <ol>
- *   <li>The type of user data that would be saved (like passoword or credit card info).
+ *   <li>The type(s) of user data (like password or credit card info) that would be saved.
  *   <li>The minimum set of views (represented by their {@link AutofillId}) that need to be changed
  *       to trigger a save request.
  * </ol>
  *
- *  Typically, the {@link SaveInfo} contains the same {@code id}s as the {@link Dataset}:
+ * <p>Typically, the {@link SaveInfo} contains the same {@code id}s as the {@link Dataset}:
  *
  * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createPresentation())
- *          .setValue(id1, AutofillValue.forText("homer"))
- *          .setValue(id2, AutofillValue.forText("D'OH!"))
- *          .build())
- *      .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_PASSWORD, new int[] {id1, id2})
- *                  .build())
- *      .build();
+ *   new FillResponse.Builder()
+ *       .addDataset(new Dataset.Builder()
+ *           .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) // username
+ *           .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) // password
+ *           .build())
+ *       .setSaveInfo(new SaveInfo.Builder(
+ *           SaveInfo.SAVE_DATA_TYPE_USERNAME | SaveInfo.SAVE_DATA_TYPE_PASSWORD,
+ *           new AutofillId[] { id1, id2 }).build())
+ *       .build();
  * </pre>
  *
- * There might be cases where the {@link AutofillService} knows how to fill the
- * {@link android.app.Activity}, but the user has no data for it. In that case, the
- * {@link FillResponse} should contain just the {@link SaveInfo}, but no {@link Dataset}s:
+ * <p>The save type flags are used to display the appropriate strings in the save UI affordance.
+ * You can pass multiple values, but try to keep it short if possible. In the above example, just
+ * {@code SaveInfo.SAVE_DATA_TYPE_PASSWORD} would be enough.
+ *
+ * <p>There might be cases where the {@link AutofillService} knows how to fill the screen,
+ * but the user has no data for it. In that case, the {@link FillResponse} should contain just the
+ * {@link SaveInfo}, but no {@link Dataset Datasets}:
  *
  * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_PASSWORD, new int[] {id1, id2})
- *                  .build())
- *      .build();
+ *   new FillResponse.Builder()
+ *       .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD,
+ *           new AutofillId[] { id1, id2 }).build())
+ *       .build();
  * </pre>
  *
  * <p>There might be cases where the user data in the {@link AutofillService} is enough
  * to populate some fields but not all, and the service would still be interested on saving the
- * other fields. In this scenario, the service could set the
+ * other fields. In that case, the service could set the
  * {@link SaveInfo.Builder#setOptionalIds(AutofillId[])} as well:
  *
  * <pre class="prettyprint">
  *   new FillResponse.Builder()
- *       .add(new Dataset.Builder(createPresentation())
- *          .setValue(id1, AutofillValue.forText("742 Evergreen Terrace"))  // street
- *          .setValue(id2, AutofillValue.forText("Springfield"))            // city
- *          .build())
- *       .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_ADDRESS, new int[] {id1, id2})
- *                   .setOptionalIds(new int[] {id3, id4}) // state and zipcode
- *                   .build())
+ *       .addDataset(new Dataset.Builder()
+ *           .setValue(id1, AutofillValue.forText("742 Evergreen Terrace"),
+ *               createPresentation("742 Evergreen Terrace")) // street
+ *           .setValue(id2, AutofillValue.forText("Springfield"),
+ *               createPresentation("Springfield")) // city
+ *           .build())
+ *       .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_ADDRESS,
+ *           new AutofillId[] { id1, id2 }) // street and  city
+ *           .setOptionalIds(new AutofillId[] { id3, id4 }) // state and zipcode
+ *           .build())
  *       .build();
  * </pre>
  *
- * The
- * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}
- * is triggered after a call to {@link AutofillManager#commit()}, but only when all conditions
- * below are met:
+ * <p>The {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} can be triggered after
+ * any of the following events:
+ * <ul>
+ *   <li>The {@link Activity} finishes.
+ *   <li>The app explicitly called {@link AutofillManager#commit()}.
+ *   <li>All required views became invisible (if the {@link SaveInfo} was created with the
+ *       {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} flag).
+ * </ul>
  *
- * <ol>
+ * <p>But it is only triggered when all conditions below are met:
+ * <ul>
  *   <li>The {@link SaveInfo} associated with the {@link FillResponse} is not {@code null}.
- *   <li>The {@link AutofillValue} of all required views (as set by the {@code requiredIds} passed
- *       to {@link SaveInfo.Builder} constructor are not empty.
+ *   <li>The {@link AutofillValue}s of all required views (as set by the {@code requiredIds} passed
+ *       to the {@link SaveInfo.Builder} constructor are not empty.
  *   <li>The {@link AutofillValue} of at least one view (be it required or optional) has changed
- *       (i.e., it's not the same value passed in a {@link Dataset}).
- *   <li>The user explicitly tapped the affordance asking to save data for autofill.
- * </ol>
+ *       (i.e., it's neither the same value passed in a {@link Dataset}, nor the initial value
+ *       presented in the view).
+ *   <li>The user explicitly tapped the UI affordance asking to save data for autofill.
+ * </ul>
+ *
+ * <p>The service can also customize some aspects of the save UI affordance:
+ * <ul>
+ *   <li>Add a subtitle by calling {@link Builder#setDescription(CharSequence)}.
+ *   <li>Customize the button used to reject the save request by calling
+ *       {@link Builder#setNegativeAction(int, IntentSender)}.
+ * </ul>
  */
 public final class SaveInfo implements Parcelable {
 
     /**
-     * Type used on when the service can save the contents of an activity, but cannot describe what
+     * Type used when the service can save the contents of a screen, but cannot describe what
      * the content is for.
      */
     public static final int SAVE_DATA_TYPE_GENERIC = 0x0;
@@ -181,8 +203,8 @@
 
     /**
      * Usually {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}
-     * is called once the activity finishes. If this flag is set it is called once all saved views
-     * become invisible.
+     * is called once the {@link Activity} finishes. If this flag is set it is called once all
+     * saved views become invisible.
      */
     public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 0x1;
 
@@ -294,9 +316,9 @@
         }
 
         /**
-         * Set flags changing the save behavior.
+         * Sets flags changing the save behavior.
          *
-         * @param flags {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} or 0.
+         * @param flags {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} or {@code 0}.
          * @return This builder.
          */
         public @NonNull Builder setFlags(@SaveInfoFlags int flags) {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 2e8faee..0d67615 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -25,6 +25,7 @@
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -532,8 +533,14 @@
     public void setHeight(int height) {
         if (height < 0 && ViewGroup.LayoutParams.WRAP_CONTENT != height
                 && ViewGroup.LayoutParams.MATCH_PARENT != height) {
-            throw new IllegalArgumentException(
-                   "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT.");
+            if (mContext.getApplicationInfo().targetSdkVersion
+                    < Build.VERSION_CODES.O) {
+                Log.e(TAG, "Negative value " + height + " passed to ListPopupWindow#setHeight"
+                        + " produces undefined results");
+            } else {
+                throw new IllegalArgumentException(
+                        "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT.");
+            }
         }
         mDropDownHeight = height;
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6b328ea..9a92489 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -913,7 +913,7 @@
                         break;
 
                     case com.android.internal.R.styleable.TextAppearance_fontFamily:
-                        if (!context.isRestricted()) {
+                        if (!context.isRestricted() && context.canLoadUnsafeResources()) {
                             try {
                                 fontTypeface = appearance.getFont(attr);
                             } catch (UnsupportedOperationException
@@ -1233,7 +1233,7 @@
                     break;
 
                 case com.android.internal.R.styleable.TextView_fontFamily:
-                    if (!context.isRestricted()) {
+                    if (!context.isRestricted() && context.canLoadUnsafeResources()) {
                         try {
                             fontTypeface = a.getFont(attr);
                         } catch (UnsupportedOperationException | Resources.NotFoundException e) {
@@ -3417,7 +3417,7 @@
 
         Typeface fontTypeface = null;
         String fontFamily = null;
-        if (!context.isRestricted()) {
+        if (!context.isRestricted() && context.canLoadUnsafeResources()) {
             try {
                 fontTypeface = ta.getFont(R.styleable.TextAppearance_fontFamily);
             } catch (UnsupportedOperationException | Resources.NotFoundException e) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 7e71ce9..c5279e1 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -215,7 +215,6 @@
         "libgif",
         "libseccomp_policy",
         "libselinux",
-        "libcrypto",
         "libgrallocusage",
     ],
 
@@ -224,6 +223,7 @@
         "libandroidfw",
         "libappfuse",
         "libbase",
+        "libcrypto",
         "libnativehelper",
         "liblog",
         "libcutils",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 1779ada..e8f6074 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -396,7 +396,7 @@
 }
 
 static void
-android_media_AudioSystem_recording_callback(int event, audio_session_t session, int source,
+android_media_AudioSystem_recording_callback(int event, const record_client_info_t *clientInfo,
         const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
         audio_patch_handle_t patchHandle)
 {
@@ -404,8 +404,8 @@
     if (env == NULL) {
         return;
     }
-    if (clientConfig == NULL || deviceConfig == NULL) {
-        ALOGE("Unexpected null client/device configurations in recording callback");
+    if (clientInfo == NULL || clientConfig == NULL || deviceConfig == NULL) {
+        ALOGE("Unexpected null client/device info or configurations in recording callback");
         return;
     }
 
@@ -433,7 +433,7 @@
     jclass clazz = env->FindClass(kClassPathName);
     env->CallStaticVoidMethod(clazz,
             gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
-            event, session, source, recParamArray);
+            event, (jint) clientInfo->uid, clientInfo->session, clientInfo->source, recParamArray);
     env->DeleteLocalRef(clazz);
 
     env->DeleteLocalRef(recParamArray);
@@ -1930,7 +1930,7 @@
                     "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
     gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
             GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
-                    "recordingCallbackFromNative", "(III[I)V");
+                    "recordingCallbackFromNative", "(IIII[I)V");
 
     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4d254c2..4ee9d54 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3003,6 +3003,21 @@
         <item quantity="other">Open Wi-Fi networks available</item>
     </plurals>
 
+    <!-- Notification title for a nearby open wireless network.-->
+    <string name="wifi_available_title">Connect to open Wi\u2011Fi network</string>
+    <!-- Notification title when the system is connecting to the specified open network. The network name is specified in the notification content. -->
+    <string name="wifi_available_title_connecting">Connecting to open Wi\u2011Fi network</string>
+    <!-- Notification title when the system has connected to the open network. The network name is specified in the notification content. -->
+    <string name="wifi_available_title_connected">Connected to Wi\u2011Fi network</string>
+    <!-- Notification title when the system failed to connect to the specified open network. -->
+    <string name="wifi_available_title_failed_to_connect">Could not connect to Wi\u2011Fi network</string>
+    <!-- Notification content when the system failed to connect to the specified open network. This informs the user that tapping on this notification will open the wifi picker. -->
+    <string name="wifi_available_content_failed_to_connect">Tap to see all networks</string>
+    <!-- Notification action name for connecting to the network specified in the notification body. -->
+    <string name="wifi_available_action_connect">Connect</string>
+    <!-- Notification action name for opening the wifi picker, showing the user all the nearby networks. -->
+    <string name="wifi_available_action_all_networks">All Networks</string>
+
     <!-- A notification is shown when a wifi captive portal network is detected.  This is the notification's title. -->
     <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4e634b7..6cbf11f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1869,6 +1869,13 @@
   <java-symbol type="layout" name="app_error_dialog" />
   <java-symbol type="plurals" name="wifi_available" />
   <java-symbol type="plurals" name="wifi_available_detailed" />
+  <java-symbol type="string" name="wifi_available_title" />
+  <java-symbol type="string" name="wifi_available_title_connecting" />
+  <java-symbol type="string" name="wifi_available_title_connected" />
+  <java-symbol type="string" name="wifi_available_title_failed_to_connect" />
+  <java-symbol type="string" name="wifi_available_content_failed_to_connect" />
+  <java-symbol type="string" name="wifi_available_action_connect" />
+  <java-symbol type="string" name="wifi_available_action_all_networks" />
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
index a9357c9..7f4819b 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -107,7 +107,7 @@
                 "2016a", formatVersion(1, 1), true /* operationInProgress */,
                 RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
                 RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
-        checkParcelableRoundTrip(rulesStateWithNulls);
+        checkParcelableRoundTrip(rulesStateWithUnknowns);
     }
 
     private static void checkParcelableRoundTrip(RulesState rulesState) {
@@ -121,55 +121,14 @@
     }
 
     @Test
-    public void isSystemVersionOlderThan() {
+    public void isSystemVersionNewerThan() {
         RulesState rulesState = new RulesState(
                 "2016b", formatVersion(1, 1), false /* operationInProgress */,
                 RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
                 RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
-        assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016a", 1)));
-        assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016b", 1)));
-        assertTrue(rulesState.isSystemVersionOlderThan(rulesVersion("2016c", 1)));
-    }
-
-    @Test
-    public void isInstalledDistroOlderThan() {
-        RulesState operationInProgress = new RulesState(
-                "2016b", formatVersion(1, 1), true /* operationInProgress */,
-                RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
-                RulesState.STAGED_OPERATION_UNKNOWN, null /* installedDistroRulesVersion */);
-        try {
-            operationInProgress.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-
-        RulesState nothingInstalled = new RulesState(
-                "2016b", formatVersion(1, 1), false /* operationInProgress */,
-                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
-                RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
-        try {
-            nothingInstalled.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-
-        DistroRulesVersion installedVersion = rulesVersion("2016b", 3);
-        RulesState rulesStateWithInstalledVersion = new RulesState(
-                "2016b", formatVersion(1, 1), false /* operationInProgress */,
-                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
-                RulesState.DISTRO_STATUS_INSTALLED, installedVersion);
-
-        DistroRulesVersion olderRules = rulesVersion("2016a", 1);
-        assertEquals(installedVersion.isOlderThan(olderRules),
-                rulesStateWithInstalledVersion.isInstalledDistroOlderThan(olderRules));
-
-        DistroRulesVersion sameRules = rulesVersion("2016b", 1);
-        assertEquals(installedVersion.isOlderThan(sameRules),
-                rulesStateWithInstalledVersion.isInstalledDistroOlderThan(sameRules));
-
-        DistroRulesVersion newerRules = rulesVersion("2016c", 1);
-        assertEquals(installedVersion.isOlderThan(newerRules),
-                rulesStateWithInstalledVersion.isInstalledDistroOlderThan(newerRules));
+        assertTrue(rulesState.isSystemVersionNewerThan(rulesVersion("2016a", 1)));
+        assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016b", 1)));
+        assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016c", 1)));
     }
 
     private static void assertEqualsContract(RulesState one, RulesState two) {
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 81cc93d..93fc3da 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -267,6 +267,42 @@
      **/
     public static final int ENCODING_DOLBY_TRUEHD = 14;
 
+    /** @hide */
+    public static String toLogFriendlyEncoding(int enc) {
+        switch(enc) {
+            case ENCODING_INVALID:
+                return "ENCODING_INVALID";
+            case ENCODING_PCM_16BIT:
+                return "ENCODING_PCM_16BIT";
+            case ENCODING_PCM_8BIT:
+                return "ENCODING_PCM_8BIT";
+            case ENCODING_PCM_FLOAT:
+                return "ENCODING_PCM_FLOAT";
+            case ENCODING_AC3:
+                return "ENCODING_AC3";
+            case ENCODING_E_AC3:
+                return "ENCODING_E_AC3";
+            case ENCODING_DTS:
+                return "ENCODING_DTS";
+            case ENCODING_DTS_HD:
+                return "ENCODING_DTS_HD";
+            case ENCODING_MP3:
+                return "ENCODING_MP3";
+            case ENCODING_AAC_LC:
+                return "ENCODING_AAC_LC";
+            case ENCODING_AAC_HE_V1:
+                return "ENCODING_AAC_HE_V1";
+            case ENCODING_AAC_HE_V2:
+                return "ENCODING_AAC_HE_V2";
+            case ENCODING_IEC61937:
+                return "ENCODING_IEC61937";
+            case ENCODING_DOLBY_TRUEHD:
+                return "ENCODING_DOLBY_TRUEHD";
+            default :
+                return "invalid encoding " + enc;
+        }
+    }
+
     /** Invalid audio channel configuration */
     /** @deprecated Use {@link #CHANNEL_INVALID} instead.  */
     @Deprecated    public static final int CHANNEL_CONFIGURATION_INVALID   = 0;
@@ -693,6 +729,12 @@
         return mPropertySetMask;
     }
 
+    /** @hide */
+    public String toLogFriendlyString() {
+        return String.format("%dch %dHz %s",
+                getChannelCount(), mSampleRate, toLogFriendlyEncoding(mEncoding));
+    }
+
     /**
      * Builder class for {@link AudioFormat} objects.
      * Use this class to configure and create an AudioFormat instance. By setting format
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index 50dbd03..984c554 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -17,10 +17,12 @@
 package android.media;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
 
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -52,18 +54,59 @@
     private final AudioFormat mDeviceFormat;
     private final AudioFormat mClientFormat;
 
+    @NonNull private final String mClientPackageName;
+    private final int mClientUid;
+
     private final int mPatchHandle;
 
     /**
      * @hide
      */
-    public AudioRecordingConfiguration(int session, int source, AudioFormat clientFormat,
-            AudioFormat devFormat, int patchHandle) {
+    public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat,
+            AudioFormat devFormat, int patchHandle, String packageName) {
+        mClientUid = uid;
         mSessionId = session;
         mClientSource = source;
         mClientFormat = clientFormat;
         mDeviceFormat = devFormat;
         mPatchHandle = patchHandle;
+        mClientPackageName = packageName;
+    }
+
+    /**
+     * @hide
+     * For AudioService dump
+     * @param pw
+     */
+    public void dump(PrintWriter pw) {
+        pw.println("  " + toLogFriendlyString(this));
+    }
+
+    /**
+     * @hide
+     */
+    public static String toLogFriendlyString(AudioRecordingConfiguration arc) {
+        return new String("session:" + arc.mSessionId
+                + " -- source:" + MediaRecorder.toLogFriendlyAudioSource(arc.mClientSource)
+                + " -- uid:" + arc.mClientUid
+                + " -- patch:" + arc.mPatchHandle
+                + " -- pack:" + arc.mClientPackageName
+                + " -- format client=" + arc.mClientFormat.toLogFriendlyString()
+                    + ", dev=" + arc.mDeviceFormat.toLogFriendlyString());
+    }
+
+    // Note that this method is called server side, so no "privileged" information is ever sent
+    // to a client that is not supposed to have access to it.
+    /**
+     * @hide
+     * Creates a copy of the recording configuration that is stripped of any data enabling
+     * identification of which application it is associated with ("anonymized").
+     * @param in
+     */
+    public static AudioRecordingConfiguration anonymizedCopy(AudioRecordingConfiguration in) {
+        return new AudioRecordingConfiguration( /*anonymized uid*/ -1,
+                in.mSessionId, in.mClientSource, in.mClientFormat,
+                in.mDeviceFormat, in.mPatchHandle, "" /*empty package name*/);
     }
 
     // matches the sources that return false in MediaRecorder.isSystemOnlyAudioSource(source)
@@ -120,6 +163,30 @@
     public AudioFormat getClientFormat() { return mClientFormat; }
 
     /**
+     * @pending for SystemApi
+     * Returns the package name of the application performing the recording.
+     * Where there are multiple packages sharing the same user id through the "sharedUserId"
+     * mechanism, only the first one with that id will be returned
+     * (see {@link PackageManager#getPackagesForUid(int)}).
+     * <p>This information is only available if the caller has the
+     * {@link android.Manifest.permission.MODIFY_AUDIO_ROUTING} permission.
+     * <br>When called without the permission, the result is an empty string.
+     * @return the package name
+     */
+    public String getClientPackageName() { return mClientPackageName; }
+
+    /**
+     * @pending for SystemApi
+     * Returns the user id of the application performing the recording.
+     * <p>This information is only available if the caller has the
+     * {@link android.Manifest.permission.MODIFY_AUDIO_ROUTING}
+     * permission.
+     * <br>The result is -1 without the permission.
+     * @return the user id
+     */
+    public int getClientUid() { return mClientUid; }
+
+    /**
      * Returns information about the audio input device used for this recording.
      * @return the audio recording device or null if this information cannot be retrieved
      */
@@ -185,6 +252,8 @@
         mClientFormat.writeToParcel(dest, 0);
         mDeviceFormat.writeToParcel(dest, 0);
         dest.writeInt(mPatchHandle);
+        dest.writeString(mClientPackageName);
+        dest.writeInt(mClientUid);
     }
 
     private AudioRecordingConfiguration(Parcel in) {
@@ -193,6 +262,8 @@
         mClientFormat = AudioFormat.CREATOR.createFromParcel(in);
         mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in);
         mPatchHandle = in.readInt();
+        mClientPackageName = in.readString();
+        mClientUid = in.readInt();
     }
 
     @Override
@@ -202,10 +273,12 @@
 
         AudioRecordingConfiguration that = (AudioRecordingConfiguration) o;
 
-        return ((mSessionId == that.mSessionId)
+        return ((mClientUid == that.mClientUid)
+                && (mSessionId == that.mSessionId)
                 && (mClientSource == that.mClientSource)
                 && (mPatchHandle == that.mPatchHandle)
                 && (mClientFormat.equals(that.mClientFormat))
-                && (mDeviceFormat.equals(that.mDeviceFormat)));
+                && (mDeviceFormat.equals(that.mDeviceFormat))
+                && (mClientPackageName.equals(that.mClientPackageName)));
     }
 }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 6ef3091..c7c2dd8 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -287,6 +287,7 @@
         /**
          * Callback for recording activity notifications events
          * @param event
+         * @param uid uid of the client app performing the recording
          * @param session
          * @param source
          * @param recordingFormat an array of ints containing respectively the client and device
@@ -298,9 +299,10 @@
          *          4: device channel mask
          *          5: device sample rate
          *          6: patch handle
+         * @param packName package name of the client app performing the recording. NOT SUPPORTED
          */
-        void onRecordingConfigurationChanged(int event, int session, int source,
-                int[] recordingFormat);
+        void onRecordingConfigurationChanged(int event, int uid, int session, int source,
+                int[] recordingFormat, String packName);
     }
 
     private static AudioRecordingCallback sRecordingCallback;
@@ -318,17 +320,18 @@
      * @param session
      * @param source
      * @param recordingFormat see
-     *     {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])} for
-     *     the description of the record format.
+     *     {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int[])}
+     *     for the description of the record format.
      */
-    private static void recordingCallbackFromNative(int event, int session, int source,
+    private static void recordingCallbackFromNative(int event, int uid, int session, int source,
             int[] recordingFormat) {
         AudioRecordingCallback cb = null;
         synchronized (AudioSystem.class) {
             cb = sRecordingCallback;
         }
         if (cb != null) {
-            cb.onRecordingConfigurationChanged(event, session, source, recordingFormat);
+            // TODO receive package name from native
+            cb.onRecordingConfigurationChanged(event, uid, session, source, recordingFormat, "");
         }
     }
 
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 33a7c83..59a124f 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -324,6 +324,40 @@
         }
     }
 
+    /** @hide */
+    public static final String toLogFriendlyAudioSource(int source) {
+        switch(source) {
+        case AudioSource.DEFAULT:
+            return "DEFAULT";
+        case AudioSource.MIC:
+            return "MIC";
+        case AudioSource.VOICE_UPLINK:
+            return "VOICE_UPLINK";
+        case AudioSource.VOICE_DOWNLINK:
+            return "VOICE_DOWNLINK";
+        case AudioSource.VOICE_CALL:
+            return "VOICE_CALL";
+        case AudioSource.CAMCORDER:
+            return "CAMCORDER";
+        case AudioSource.VOICE_RECOGNITION:
+            return "VOICE_RECOGNITION";
+        case AudioSource.VOICE_COMMUNICATION:
+            return "VOICE_COMMUNICATION";
+        case AudioSource.REMOTE_SUBMIX:
+            return "REMOTE_SUBMIX";
+        case AudioSource.UNPROCESSED:
+            return "UNPROCESSED";
+        case AudioSource.RADIO_TUNER:
+            return "RADIO_TUNER";
+        case AudioSource.HOTWORD:
+            return "HOTWORD";
+        case AudioSource.AUDIO_SOURCE_INVALID:
+            return "AUDIO_SOURCE_INVALID";
+        default:
+            return "unknown source " + source;
+        }
+    }
+
     /**
      * Defines the video source. These constants are used with
      * {@link MediaRecorder#setVideoSource(int)}.
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index 5a1e603..f1d43bf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -51,6 +51,12 @@
     public Icon icon;
 
     /**
+     * Whether the icon can be tinted. This should be set to true for monochrome (single-color)
+     * icons that can be tinted to match the design.
+     */
+    public boolean isIconTintable;
+
+    /**
      * Intent to launch when the preference is selected.
      */
     public Intent intent;
@@ -126,6 +132,7 @@
         dest.writeBundle(metaData);
         dest.writeString(key);
         dest.writeParcelable(remoteViews, flags);
+        dest.writeBoolean(isIconTintable);
     }
 
     public void readFromParcel(Parcel in) {
@@ -147,6 +154,7 @@
         metaData = in.readBundle();
         key = in.readString();
         remoteViews = in.readParcelable(RemoteViews.class.getClassLoader());
+        isIconTintable = in.readBoolean();
     }
 
     Tile(Parcel in) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 04a3d1f..9620a91 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -133,15 +133,25 @@
 
     /**
      * Name of the meta-data item that should be set in the AndroidManifest.xml
-     * to specify the title that should be displayed for the preference.
+     * to specify whether the icon is tintable. This should be a boolean value {@code true} or
+     * {@code false}, set using {@code android:value}
      */
-    @Deprecated
-    public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";
+    public static final String META_DATA_PREFERENCE_ICON_TINTABLE =
+            "com.android.settings.icon_tintable";
 
     /**
      * Name of the meta-data item that should be set in the AndroidManifest.xml
      * to specify the title that should be displayed for the preference.
+     *
+     * <p>Note: It is preferred to provide this value using {@code android:resource} with a string
+     * resource for localization.
      */
+    public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";
+
+    /**
+     * @deprecated Use {@link #META_DATA_PREFERENCE_TITLE} with {@code android:resource}
+     */
+    @Deprecated
     public static final String META_DATA_PREFERENCE_TITLE_RES_ID =
             "com.android.settings.title.resid";
 
@@ -309,12 +319,13 @@
             intent.setPackage(settingPkg);
         }
         getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
-                usePriority, true);
+                usePriority, true, true);
     }
 
-    public static void getTilesForIntent(Context context, UserHandle user, Intent intent,
+    public static void getTilesForIntent(
+            Context context, UserHandle user, Intent intent,
             Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
-            boolean usePriority, boolean checkCategory) {
+            boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon) {
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                 PackageManager.GET_META_DATA, user.getIdentifier());
@@ -350,7 +361,7 @@
                 tile.priority = usePriority ? resolved.priority : 0;
                 tile.metaData = activityInfo.metaData;
                 updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
-                        pm, providerMap);
+                        pm, providerMap, forceTintExternalIcon);
                 if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
 
                 addedCache.put(key, tile);
@@ -366,25 +377,40 @@
 
     private static boolean updateTileData(Context context, Tile tile,
             ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm,
-            Map<String, IContentProvider> providerMap) {
+            Map<String, IContentProvider> providerMap, boolean forceTintExternalIcon) {
         if (applicationInfo.isSystemApp()) {
+            boolean forceTintIcon = false;
             int icon = 0;
             Pair<String, Integer> iconFromUri = null;
             CharSequence title = null;
             String summary = null;
             String keyHint = null;
+            boolean isIconTintable = false;
             RemoteViews remoteViews = null;
 
             // Get the activity's meta-data
             try {
-                Resources res = pm.getResourcesForApplication(
-                        applicationInfo.packageName);
+                Resources res = pm.getResourcesForApplication(applicationInfo.packageName);
                 Bundle metaData = activityInfo.metaData;
 
+                if (forceTintExternalIcon
+                        && !context.getPackageName().equals(applicationInfo.packageName)) {
+                    isIconTintable = true;
+                    forceTintIcon = true;
+                }
+
                 if (res != null && metaData != null) {
                     if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
                         icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
                     }
+                    if (metaData.containsKey(META_DATA_PREFERENCE_ICON_TINTABLE)) {
+                        if (forceTintIcon) {
+                            Log.w(LOG_TAG, "Ignoring icon tintable for " + activityInfo);
+                        } else {
+                            isIconTintable =
+                                    metaData.getBoolean(META_DATA_PREFERENCE_ICON_TINTABLE);
+                        }
+                    }
                     int resId = 0;
                     if (metaData.containsKey(META_DATA_PREFERENCE_TITLE_RES_ID)) {
                         resId = metaData.getInt(META_DATA_PREFERENCE_TITLE_RES_ID);
@@ -392,8 +418,6 @@
                             title = res.getString(resId);
                         }
                     }
-                    // Fallback to legacy title extraction if we couldn't get the title through
-                    // res id.
                     if ((resId == 0) && metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
                         if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) {
                             title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
@@ -457,6 +481,7 @@
                     activityInfo.name);
             // Suggest a key for this tile
             tile.key = keyHint;
+            tile.isIconTintable = isIconTintable;
             tile.remoteViews = remoteViews;
 
             return true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index a28bece..167ffe6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -208,7 +208,7 @@
             intent.setPackage(category.pkg);
         }
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
-                mAddCache, null, suggestions, true, false);
+                mAddCache, null, suggestions, true, false, false);
         filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
         if (!category.multiple && suggestions.size() > (countBefore + 1)) {
             // If there are too many, remove them all and only re-add the one with the highest
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
index 22fd83c..31abecd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
@@ -19,5 +19,5 @@
 public class TestConfig {
     public static final int SDK_VERSION = 23;
     public static final String MANIFEST_PATH =
-            "frameworks/base/packages/SettingsLib/robotests/AndroidManifest.xml";
+            "frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml";
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 7cfb32d..0364418 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -16,6 +16,19 @@
 
 package com.android.settingslib.drawer;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.RuntimeEnvironment.application;
+
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -50,8 +63,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 import org.robolectric.internal.ShadowExtractor;
 
 import java.util.ArrayList;
@@ -59,20 +73,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH,
         sdk = TestConfig.SDK_VERSION,
@@ -100,8 +100,11 @@
         MockitoAnnotations.initMocks(this);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
-        mContentResolver = spy(RuntimeEnvironment.application.getContentResolver());
+        when(mPackageManager.getApplicationInfo(eq("abc"), anyInt()))
+                .thenReturn(application.getApplicationInfo());
+        mContentResolver = spy(application.getContentResolver());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getPackageName()).thenReturn("com.android.settings");
     }
 
     @Test
@@ -118,7 +121,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).category).isEqualTo(testCategory);
@@ -139,7 +142,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).key).isEqualTo(keyHint);
@@ -159,7 +162,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.isEmpty()).isTrue();
     }
@@ -182,7 +185,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         SuggestionParser parser = new SuggestionParser(
@@ -255,7 +258,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).title).isEqualTo("my title");
@@ -279,10 +282,60 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).title).isEqualTo("my localized title");
+
+        // Icon should be tintable because the tile is not from settings package, and
+        // "forceTintExternalIcon" is set
+        assertThat(outTiles.get(0).isIconTintable).isTrue();
+    }
+
+    @Test
+    public void getTilesForIntent_shouldNotTintIconIfInSettingsPackage() {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+                URI_GET_SUMMARY, null, 123);
+        resolveInfo.activityInfo.packageName = "com.android.settings";
+        resolveInfo.activityInfo.applicationInfo.packageName = "com.android.settings";
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, true /* forceTintExternalIcon */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        assertThat(outTiles.get(0).isIconTintable).isFalse();
+    }
+
+    @Test
+    public void getTilesForIntent_shouldMarkIconTintableIfMetadataSet() {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+                URI_GET_SUMMARY, null, 123);
+        resolveInfo.activityInfo.metaData
+                .putBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE, true);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, false /* forceTintExternalIcon */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        assertThat(outTiles.get(0).isIconTintable).isTrue();
     }
 
     @Test
@@ -301,7 +354,7 @@
         // Case 1: No provider associated with the uri specified.
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
@@ -319,7 +372,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
@@ -341,7 +394,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
     }
@@ -362,7 +415,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         Tile tile = outTiles.get(0);
@@ -399,7 +452,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         Tile tile = outTiles.get(0);
@@ -437,7 +490,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         Tile tile = outTiles.get(0);
@@ -484,7 +537,9 @@
         if (summaryUri != null) {
             info.activityInfo.metaData.putString("com.android.settings.summary_uri", summaryUri);
         }
-        if (title != null) {
+        if (titleResId != 0) {
+            info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
+        } else if (title != null) {
             info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
         }
         if (titleResId != 0) {
diff --git a/packages/SystemUI/res/drawable/pip_icon.xml b/packages/SystemUI/res/drawable/pip_icon.xml
new file mode 100644
index 0000000..bd92ccd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_icon.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="36dp"
+    android:height="36dp"
+    android:viewportWidth="25"
+    android:viewportHeight="25">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19,7h-8v6h8L19,7zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.98h18v14.03z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 9076199..18ffd0f 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -16,12 +16,12 @@
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/volume_dialog"
-    android:layout_width="@dimen/volume_dialog_panel_width"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
-    android:layout_gravity="center_vertical|end"
+    android:background="@drawable/volume_dialog_background"
     android:paddingTop="@dimen/volume_dialog_padding_top"
-    android:translationZ="8dp" >
+    android:translationZ="4dp" >
 
     <LinearLayout
         android:id="@+id/volume_dialog_content"
@@ -57,7 +57,6 @@
             android:layout_height="wrap_content"
             android:ellipsize="end"
             android:maxLines="1"
-            android:visibility="gone"
             android:textAppearance="@style/TextAppearance.Volume.Header" />
         <com.android.keyguard.AlphaOptimizedImageButton
             xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SystemUI/res/layout/volume_dialog_wrapped.xml b/packages/SystemUI/res/layout/volume_dialog_wrapped.xml
deleted file mode 100644
index 57489fd..0000000
--- a/packages/SystemUI/res/layout/volume_dialog_wrapped.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.android.systemui.HardwareUiLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginTop="@dimen/top_padding"
-    android:layout_marginBottom="@dimen/bottom_padding">
-
-    <include layout="@layout/volume_dialog"/>
-
-</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9395e5a..93d2072 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -216,6 +216,8 @@
     <!-- The width of the panel that holds the quick settings. -->
     <dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
 
+    <dimen name="volume_dialog_panel_width">@dimen/standard_notification_panel_width</dimen>
+
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
 
@@ -800,7 +802,6 @@
 
     <dimen name="hwui_edge_margin">16dp</dimen>
 
-    <dimen name="volume_dialog_panel_width">315dp</dimen>
     <dimen name="global_actions_panel_width">125dp</dimen>
 
     <dimen name="global_actions_top_padding">100dp</dimen>
@@ -819,7 +820,7 @@
     <dimen name="edge_margin">16dp</dimen>
 
     <dimen name="rounded_corner_radius">0dp</dimen>
-    <dimen name="rounded_corner_content_padding">0dp</dimen>
+    <dimen name="rounded_corner_content_padding">8dp</dimen>
 
     <!-- Intended corner radius when drawing the mobile signal -->
     <dimen name="stat_sys_mobile_signal_corner_radius">0.75dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
index 7af4a90..14e15ec 100644
--- a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
+++ b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
@@ -55,11 +55,17 @@
     public void start() {
         mRoundedDefault = mContext.getResources().getDimensionPixelSize(
                 R.dimen.rounded_corner_radius);
-        if (mRoundedDefault == 0) {
-            // No rounded corners on this device.
-            return;
+        if (mRoundedDefault != 0) {
+            setupRounding();
         }
+        int padding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.rounded_corner_content_padding);
+        if (padding != 0) {
+            setupPadding(padding);
+        }
+    }
 
+    private void setupRounding() {
         mOverlay = LayoutInflater.from(mContext)
                 .inflate(R.layout.rounded_corners, null);
         mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -82,10 +88,10 @@
         mDensity = metrics.density;
 
         Dependency.get(TunerService.class).addTunable(this, SIZE);
+    }
 
+    private void setupPadding(int padding) {
         // Add some padding to all the content near the edge of the screen.
-        int padding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_content_padding);
         StatusBar sb = getComponent(StatusBar.class);
         View statusBar = sb.getStatusBarWindow();
 
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 699fdef..6777ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -25,6 +25,7 @@
 import android.content.res.Resources;
 import android.graphics.RectF;
 import android.os.Handler;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -37,8 +38,6 @@
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
-import java.util.HashMap;
-
 public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
     private static final boolean DEBUG = false;
@@ -51,10 +50,10 @@
     public static final int X = 0;
     public static final int Y = 1;
 
-    private float SWIPE_ESCAPE_VELOCITY = 500f; // dp/sec
-    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
-    private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
-    private int MAX_DISMISS_VELOCITY = 4000; // dp/sec
+    private static final float SWIPE_ESCAPE_VELOCITY = 500f; // dp/sec
+    private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
+    private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
+    private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
     private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
 
     static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
@@ -65,13 +64,13 @@
     private float mMinSwipeProgress = 0f;
     private float mMaxSwipeProgress = 1f;
 
-    private FlingAnimationUtils mFlingAnimationUtils;
+    private final FlingAnimationUtils mFlingAnimationUtils;
     private float mPagingTouchSlop;
-    private Callback mCallback;
-    private Handler mHandler;
-    private int mSwipeDirection;
-    private VelocityTracker mVelocityTracker;
-    private FalsingManager mFalsingManager;
+    private final Callback mCallback;
+    private final Handler mHandler;
+    private final int mSwipeDirection;
+    private final VelocityTracker mVelocityTracker;
+    private final FalsingManager mFalsingManager;
 
     private float mInitialTouchPos;
     private float mPerpendicularInitialTouchPos;
@@ -86,16 +85,16 @@
     private boolean mLongPressSent;
     private LongPressListener mLongPressListener;
     private Runnable mWatchLongPress;
-    private long mLongPressTimeout;
+    private final long mLongPressTimeout;
 
     final private int[] mTmpPos = new int[2];
-    private int mFalsingThreshold;
+    private final int mFalsingThreshold;
     private boolean mTouchAboveFalsingThreshold;
     private boolean mDisableHwLayers;
-    private boolean mFadeDependingOnAmountSwiped;
-    private Context mContext;
+    private final boolean mFadeDependingOnAmountSwiped;
+    private final Context mContext;
 
-    private HashMap<View, Animator> mDismissPendingMap = new HashMap<>();
+    private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
 
     public SwipeHelper(int swipeDirection, Callback callback, Context context) {
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index f0745a0..ac41b75 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -174,7 +174,7 @@
     void onConfigurationChanged(Context context) {
         Resources res = context.getResources();
         mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
-        mDefaultIconResId = R.drawable.pip_expand;
+        mDefaultIconResId = R.drawable.pip_icon;
         if (mNotified) {
             // update notification
             notifyPipNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 2742fdd..2b2ad69 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -18,7 +18,6 @@
 
 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.animation.ObjectAnimator;
@@ -32,10 +31,12 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -48,9 +49,11 @@
 import android.transition.AutoTransition;
 import android.transition.Transition;
 import android.transition.TransitionManager;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
@@ -71,7 +74,6 @@
 import android.widget.TextView;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -96,8 +98,7 @@
  *
  * Methods ending in "H" must be called on the (ui) handler.
  */
-public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable,
-        ColorExtractor.OnColorsChangedListener {
+public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
     private static final String TAG = Util.logTag(VolumeDialogImpl.class);
 
     public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
@@ -107,8 +108,6 @@
 
     private final Context mContext;
     private final H mHandler = new H();
-    private final GradientDrawable mGradientDrawable;
-    private final ColorExtractor mColorExtractor;
     private final VolumeDialogController mController;
 
     private Window mWindow;
@@ -163,9 +162,6 @@
                 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
         mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
         mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
-        mGradientDrawable = new GradientDrawable(mContext);
-        mGradientDrawable.setAlpha((int) (ScrimController.GRADIENT_SCRIM_ALPHA * 255));
-        mColorExtractor = Dependency.get(SysuiColorExtractor.class);
     }
 
     public void init(int windowType, Callback callback) {
@@ -187,7 +183,6 @@
     @Override
     public void destroy() {
         mController.removeCallback(mControllerCallbackH);
-        mColorExtractor.removeOnColorsChangedListener(this);
     }
 
     private void initDialog() {
@@ -198,52 +193,64 @@
         mShowing = false;
         mWindow = mDialog.getWindow();
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
-        mWindow.setBackgroundDrawable(mGradientDrawable);
+        mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
-                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
-        Point displaySize = new Point();
-        mContext.getDisplay().getRealSize(displaySize);
+                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
         mDialog.setCanceledOnTouchOutside(true);
         final Resources res = mContext.getResources();
+        final WindowManager.LayoutParams lp = mWindow.getAttributes();
+        lp.type = mWindowType;
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.setTitle(VolumeDialogImpl.class.getSimpleName());
+        lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+        lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top);
+        lp.gravity = Gravity.TOP;
+        lp.windowAnimations = -1;
+        mWindow.setAttributes(lp);
         mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
 
-        mDialog.setContentView(R.layout.volume_dialog_wrapped);
-        mDialogView = mDialog.findViewById(R.id.volume_dialog);
-        mDialogView.setOnHoverListener((v, event) -> {
-            int action = event.getActionMasked();
-            mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
-                    || (action == MotionEvent.ACTION_HOVER_MOVE);
-            rescheduleTimeoutH();
-            return true;
+        mDialog.setContentView(R.layout.volume_dialog);
+        mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
+        mDialogView.setOnHoverListener(new View.OnHoverListener() {
+            @Override
+            public boolean onHover(View v, MotionEvent event) {
+                int action = event.getActionMasked();
+                mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
+                        || (action == MotionEvent.ACTION_HOVER_MOVE);
+                rescheduleTimeoutH();
+                return true;
+            }
         });
 
-        mColorExtractor.addOnColorsChangedListener(this);
-        mGradientDrawable.setScreenSize(displaySize.x, displaySize.y);
-
         mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
         mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
         mExpanded = false;
-        mExpandButton = mDialogView.findViewById(R.id.volume_expand_button);
+        mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
         mExpandButton.setOnClickListener(mClickExpand);
 
         mExpandButton.setVisibility(
                 AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE);
+        updateWindowWidthH();
         updateExpandButtonH();
 
-        mMotion = new VolumeDialogMotion(mDialog, (View) mDialogView.getParent(),
-                mDialogContentView, mExpandButton, mGradientDrawable, animating -> {
-                    if (animating) return;
-                    if (mPendingStateChanged) {
-                        mHandler.sendEmptyMessage(H.STATE_CHANGED);
-                        mPendingStateChanged = false;
-                    }
-                    if (mPendingRecheckAll) {
-                        mHandler.sendEmptyMessage(H.RECHECK_ALL);
-                        mPendingRecheckAll = false;
+        mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton,
+                new VolumeDialogMotion.Callback() {
+                    @Override
+                    public void onAnimatingChanged(boolean animating) {
+                        if (animating) return;
+                        if (mPendingStateChanged) {
+                            mHandler.sendEmptyMessage(H.STATE_CHANGED);
+                            mPendingStateChanged = false;
+                        }
+                        if (mPendingRecheckAll) {
+                            mHandler.sendEmptyMessage(H.RECHECK_ALL);
+                            mPendingRecheckAll = false;
+                        }
                     }
                 });
 
@@ -268,20 +275,11 @@
             addExistingRows();
         }
         mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
-        mZenFooter = mDialog.findViewById(R.id.volume_zen_footer);
+        mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
         mZenFooter.init(mZenModeController);
-        mZenPanel = mDialog.findViewById(R.id.tuner_zen_mode_panel);
+        mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
         mZenPanel.init(mZenModeController);
         mZenPanel.setCallback(mZenPanelCallback);
-
-        final WindowManager.LayoutParams lp = mWindow.getAttributes();
-        lp.width = MATCH_PARENT;
-        lp.height = MATCH_PARENT;
-        lp.type = mWindowType;
-        lp.format = PixelFormat.TRANSLUCENT;
-        lp.setTitle(VolumeDialogImpl.class.getSimpleName());
-        lp.windowAnimations = -1;
-        mWindow.setAttributes(lp);
     }
 
     @Override
@@ -295,6 +293,20 @@
         return ColorStateList.valueOf(mContext.getColor(colorResId));
     }
 
+    private void updateWindowWidthH() {
+        final ViewGroup.LayoutParams lp = mDialogView.getLayoutParams();
+        final DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+        if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels);
+        int w = dm.widthPixels;
+        final int max = mContext.getResources()
+                .getDimensionPixelSize(R.dimen.volume_dialog_panel_width);
+        if (w > max) {
+            w = max;
+        }
+        lp.width = w;
+        mDialogView.setLayoutParams(lp);
+    }
+
     public void setStreamImportant(int stream, boolean important) {
         mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
     }
@@ -478,10 +490,6 @@
         rescheduleTimeoutH();
         if (mShowing) return;
         mShowing = true;
-        ColorExtractor.GradientColors colors = mColorExtractor.getColors(
-                mKeyguard.isKeyguardLocked() ? WallpaperManager.FLAG_LOCK
-                        : WallpaperManager.FLAG_SYSTEM);
-        mGradientDrawable.setColors(colors, false);
         mMotion.startShow();
         Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
         mController.notifyVisible(true);
@@ -539,8 +547,10 @@
     }
 
     private void updateDialogBottomMarginH() {
+        final long diff = System.currentTimeMillis() - mCollapseTime;
+        final boolean collapsing = mCollapseTime != 0 && diff < getConservativeCollapseDuration();
         final ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams();
-        final int bottomMargin =
+        final int bottomMargin = collapsing ? mDialogContentView.getHeight() :
                 mContext.getResources().getDimensionPixelSize(R.dimen.volume_dialog_margin_bottom);
         if (bottomMargin != mlp.bottomMargin) {
             if (D.BUG) Log.d(TAG, "bottomMargin " + mlp.bottomMargin + " -> " + bottomMargin);
@@ -570,7 +580,7 @@
         TransitionManager.endTransitions(mDialogView);
         final VolumeRow activeRow = getActiveRow();
         if (!dismissing) {
-            mWindow.setLayout(mWindow.getAttributes().width, MATCH_PARENT);
+            mWindow.setLayout(mWindow.getAttributes().width, ViewGroup.LayoutParams.MATCH_PARENT);
             TransitionManager.beginDelayedTransition(mDialogView, getTransition());
         }
         updateRowsH(activeRow);
@@ -632,7 +642,7 @@
             final boolean isActive = row == activeRow;
             final boolean shouldBeVisible = shouldBeVisibleH(row, isActive);
             Util.setVisOrGone(row.view, shouldBeVisible);
-            Util.setVisOrGone(row.header, shouldBeVisible && mExpanded);
+            Util.setVisOrGone(row.header, shouldBeVisible);
             if (row.view.isShown()) {
                 updateVolumeRowSliderTintH(row, isActive);
             }
@@ -689,18 +699,12 @@
         final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
                 && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
                 && !mZenPanel.isEditing();
-
-        if (wasVisible != visible) {
-            mZenFooter.update();
-            if (visible) {
-                HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter);
-            } else {
-                mHandler.postDelayed(() ->
-                                HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter),
-                        mExpandButtonAnimationDuration);
-            }
-            Util.setVisOrGone(mZenFooter, visible);
+        TransitionManager.beginDelayedTransition(mDialogView, getTransition());
+        if (wasVisible != visible && !visible) {
+            prepareForCollapse();
         }
+        Util.setVisOrGone(mZenFooter, visible);
+        mZenFooter.update();
 
         final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
         final boolean fullVisible = mShowFullZen && !visible;
@@ -960,7 +964,8 @@
 
             @Override
             public void onTransitionEnd(Transition transition) {
-                mWindow.setLayout(MATCH_PARENT, MATCH_PARENT);
+                mWindow.setLayout(
+                        mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
             }
 
             @Override
@@ -969,7 +974,8 @@
 
             @Override
             public void onTransitionPause(Transition transition) {
-                mWindow.setLayout(MATCH_PARENT, MATCH_PARENT);
+                mWindow.setLayout(
+                        mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
             }
 
             @Override
@@ -1021,6 +1027,7 @@
                 initDialog();
                 mDensity = density;
             }
+            updateWindowWidthH();
             mConfigurableTexts.update();
             mZenFooter.onConfigurationChanged();
         }
@@ -1076,26 +1083,10 @@
             if (mExpandButtonAnimationRunning) return;
             final boolean newExpand = !mExpanded;
             Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand);
-            if (!newExpand) {
-                HardwareUiLayout.get(mDialogContentView).setCollapse();
-            }
             updateExpandedH(newExpand, false /* dismissing */);
         }
     };
 
-    @Override
-    public void onColorsChanged(ColorExtractor extractor, int which) {
-        if (mKeyguard.isKeyguardLocked()) {
-            if ((WallpaperManager.FLAG_LOCK & which) != 0) {
-                mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_LOCK));
-            }
-        } else {
-            if ((WallpaperManager.FLAG_SYSTEM & which) != 0) {
-                mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM));
-            }
-        }
-    }
-
     private final class H extends Handler {
         private static final int SHOW = 1;
         private static final int DISMISS = 2;
@@ -1167,8 +1158,8 @@
             event.setPackageName(mContext.getPackageName());
 
             ViewGroup.LayoutParams params = getWindow().getAttributes();
-            boolean isFullScreen = (params.width == MATCH_PARENT) &&
-                    (params.height == MATCH_PARENT);
+            boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
+                    (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
             event.setFullScreen(isFullScreen);
 
             if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
index 2df2227..01d31e2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.systemui.volume;
 
 import android.animation.Animator;
@@ -41,10 +42,8 @@
     private final View mDialogView;
     private final ViewGroup mContents;  // volume rows + zen footer
     private final View mChevron;
-    private final Drawable mBackground;
     private final Handler mHandler = new Handler();
     private final Callback mCallback;
-    private final int mBackgroundTargetAlpha;
 
     private boolean mAnimating;  // show or dismiss animation is running
     private boolean mShowing;  // show animation is running
@@ -53,14 +52,12 @@
     private ValueAnimator mContentsPositionAnimator;
 
     public VolumeDialogMotion(Dialog dialog, View dialogView, ViewGroup contents, View chevron,
-            Drawable background, Callback callback) {
+            Callback callback) {
         mDialog = dialog;
         mDialogView = dialogView;
         mContents = contents;
         mChevron = chevron;
         mCallback = callback;
-        mBackground = background;
-        mBackgroundTargetAlpha = mBackground.getAlpha();
         mDialog.setOnDismissListener(new OnDismissListener() {
             @Override
             public void onDismiss(DialogInterface dialog) {
@@ -71,9 +68,8 @@
             @Override
             public void onShow(DialogInterface dialog) {
                 if (D.BUG) Log.d(TAG, "mDialog.onShow");
-                final int w = mDialogView.getWidth() / 4;
-                mDialogView.setTranslationX(w);
-                mBackground.setAlpha(0);
+                final int h = mDialogView.getHeight();
+                mDialogView.setTranslationY(-h);
                 startShowAnimation();
             }
         });
@@ -122,7 +118,7 @@
     }
 
     private int chevronDistance() {
-        return 0;
+        return mChevron.getHeight() / 6;
     }
 
     private int chevronPosY() {
@@ -133,29 +129,26 @@
     private void startShowAnimation() {
         if (D.BUG) Log.d(TAG, "startShowAnimation");
         mDialogView.animate()
-                .translationX(0)
                 .translationY(0)
-                .alpha(1)
                 .setDuration(scaledDuration(300))
                 .setInterpolator(new LogDecelerateInterpolator())
                 .setListener(null)
                 .setUpdateListener(animation -> {
-                    mBackground.setAlpha(
-                            (int) (animation.getAnimatedFraction() * mBackgroundTargetAlpha));
                     if (mChevronPositionAnimator != null) {
                         final float v = (Float) mChevronPositionAnimator.getAnimatedValue();
                         if (mChevronPositionAnimator == null) return;
                         // reposition chevron
                         final int posY = chevronPosY();
+                        mChevron.setTranslationY(posY + v + -mDialogView.getTranslationY());
                     }
                 })
                 .withEndAction(new Runnable() {
                     @Override
                     public void run() {
-                        mBackground.setAlpha(mBackgroundTargetAlpha);
                         if (mChevronPositionAnimator == null) return;
                         // reposition chevron
                         final int posY = chevronPosY();
+                        mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
                     }
                 })
                 .start();
@@ -171,13 +164,19 @@
                 if (D.BUG) Log.d(TAG, "show.onAnimationEnd");
                 setShowing(false);
             }
-
             @Override
             public void onAnimationCancel(Animator animation) {
                 if (D.BUG) Log.d(TAG, "show.onAnimationCancel");
                 mCancelled = true;
             }
         });
+        mContentsPositionAnimator.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float v = (Float) animation.getAnimatedValue();
+                mContents.setTranslationY(v + -mDialogView.getTranslationY());
+            }
+        });
         mContentsPositionAnimator.setInterpolator(new LogDecelerateInterpolator());
         mContentsPositionAnimator.start();
 
@@ -219,30 +218,34 @@
             setShowing(false);
         }
         mDialogView.animate()
-                .translationX(mDialogView.getWidth() / 4)
-                .alpha(0)
+                .translationY(-mDialogView.getHeight())
                 .setDuration(scaledDuration(250))
                 .setInterpolator(new LogAccelerateInterpolator())
-                .setUpdateListener(animation -> {
-                    final float v = 1 - mChevronPositionAnimator.getAnimatedFraction();
-                    mBackground.setAlpha((int) (v * mBackgroundTargetAlpha));
+                .setUpdateListener(new AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        mContents.setTranslationY(-mDialogView.getTranslationY());
+                        final int posY = chevronPosY();
+                        mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
+                    }
                 })
                 .setListener(new AnimatorListenerAdapter() {
                     private boolean mCancelled;
-
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         if (mCancelled) return;
                         if (D.BUG) Log.d(TAG, "dismiss.onAnimationEnd");
-                        mHandler.postDelayed(() -> {
-                            if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
-                            mDialog.dismiss();
-                            onComplete.run();
-                            setDismissing(false);
+                        mHandler.postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
+                                mDialog.dismiss();
+                                onComplete.run();
+                                setDismissing(false);
+                            }
                         }, PRE_DISMISS_DELAY);
 
                     }
-
                     @Override
                     public void onAnimationCancel(Animator animation) {
                         if (D.BUG) Log.d(TAG, "dismiss.onAnimationCancel");
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index b3a4007..2edcd71 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4134,6 +4134,31 @@
     // OS: O DR
     ACTION_APP_LOCATION_CHECK = 1021;
 
+    // Device headset status
+    // CATEGORY: OTHER
+    //  SUBTYPE: 1 is DON, 2 is DOFF
+    // OS: O DR
+    ACTION_HEADSET_STATUS = 1022;
+
+    // Device Headset Plug status
+    // CATEGORY: OTHER
+    //  SUBTYPE: 1 is AC power, 2 is USB power, 3 is Unplug
+    // OS: O DR
+    ACTION_HEADSET_PLUG = 1023;
+
+    // Device Headset battery level on Plug
+    // CATEGORY: OTHER
+    // FIELD - The battery percentage when the user decided to plug in
+    // Type: integer
+    // OS: O DR
+    FIELD_PLUG_BATTERY_PERCENTAGE = 1024;
+
+    // Device Headset Pose status
+    // CATEGORY: OTHER
+    //  SUBTYPE: 1 is 6DOF, 2 is 3DOF
+    // OS: O DR
+    ACTION_HEADSET_POSE_STATUS = 1025;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 7275461..eda283e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -324,58 +324,13 @@
             ActivityManager.OnUidImportanceListener uidImportanceListener
                     = new ActivityManager.OnUidImportanceListener() {
                 @Override
-                public void onUidImportance(int uid, int importance) {
-                    boolean foreground = isImportanceForeground(importance);
-                    HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
-                    synchronized (mLock) {
-                        for (Entry<String, ArrayList<UpdateRecord>> entry
-                                : mRecordsByProvider.entrySet()) {
-                            String provider = entry.getKey();
-                            for (UpdateRecord record : entry.getValue()) {
-                                if (record.mReceiver.mIdentity.mUid == uid
-                                        && record.mIsForegroundUid != foreground) {
-                                    if (D) Log.d(TAG, "request from uid " + uid + " is now "
-                                            + (foreground ? "foreground" : "background)"));
-                                    record.mIsForegroundUid = foreground;
-
-                                    if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
-                                        affectedProviders.add(provider);
-                                    }
-                                }
-                            }
+                public void onUidImportance(final int uid, final int importance) {
+                    mLocationHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            onUidImportanceChanged(uid, importance);
                         }
-                        for (String provider : affectedProviders) {
-                            applyRequirementsLocked(provider);
-                        }
-
-                        for (Entry<IGnssMeasurementsListener, Identity> entry
-                                : mGnssMeasurementsListeners.entrySet()) {
-                            if (entry.getValue().mUid == uid) {
-                                if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
-                                    + " is now " + (foreground ? "foreground" : "background)"));
-                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                                    mGnssMeasurementsProvider.addListener(entry.getKey());
-                                } else {
-                                    mGnssMeasurementsProvider.removeListener(entry.getKey());
-                                }
-                            }
-                        }
-
-                        for (Entry<IGnssNavigationMessageListener, Identity> entry
-                            : mGnssNavigationMessageListeners.entrySet()) {
-                            if (entry.getValue().mUid == uid) {
-                                if (D) Log.d(TAG, "gnss navigation message listener from uid "
-                                    + uid + " is now "
-                                    + (foreground ? "foreground" : "background)"));
-                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                                    mGnssNavigationMessageProvider.addListener(entry.getKey());
-                                } else {
-                                    mGnssNavigationMessageProvider.removeListener(entry.getKey());
-                                }
-                            }
-                        }
-                    }
-
+                    });
                 }
             };
             mActivityManager.addOnUidImportanceListener(uidImportanceListener,
@@ -455,6 +410,59 @@
         }, UserHandle.ALL, intentFilter, null, mLocationHandler);
     }
 
+    private void onUidImportanceChanged(int uid, int importance) {
+        boolean foreground = isImportanceForeground(importance);
+        HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
+        synchronized (mLock) {
+            for (Entry<String, ArrayList<UpdateRecord>> entry
+                : mRecordsByProvider.entrySet()) {
+                String provider = entry.getKey();
+                for (UpdateRecord record : entry.getValue()) {
+                    if (record.mReceiver.mIdentity.mUid == uid
+                        && record.mIsForegroundUid != foreground) {
+                        if (D) Log.d(TAG, "request from uid " + uid + " is now "
+                            + (foreground ? "foreground" : "background)"));
+                        record.mIsForegroundUid = foreground;
+
+                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
+                            affectedProviders.add(provider);
+                        }
+                    }
+                }
+            }
+            for (String provider : affectedProviders) {
+                applyRequirementsLocked(provider);
+            }
+
+            for (Entry<IGnssMeasurementsListener, Identity> entry
+                : mGnssMeasurementsListeners.entrySet()) {
+                if (entry.getValue().mUid == uid) {
+                    if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
+                        + " is now " + (foreground ? "foreground" : "background)"));
+                    if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                        mGnssMeasurementsProvider.addListener(entry.getKey());
+                    } else {
+                        mGnssMeasurementsProvider.removeListener(entry.getKey());
+                    }
+                }
+            }
+
+            for (Entry<IGnssNavigationMessageListener, Identity> entry
+                : mGnssNavigationMessageListeners.entrySet()) {
+                if (entry.getValue().mUid == uid) {
+                    if (D) Log.d(TAG, "gnss navigation message listener from uid "
+                        + uid + " is now "
+                        + (foreground ? "foreground" : "background)"));
+                    if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                        mGnssNavigationMessageProvider.addListener(entry.getKey());
+                    } else {
+                        mGnssNavigationMessageProvider.removeListener(entry.getKey());
+                    }
+                }
+            }
+        }
+    }
+
     private static boolean isImportanceForeground(int importance) {
         return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
     }
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 1810823..21aeee2 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -49,6 +49,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -797,12 +798,13 @@
                     pw.println(
                             "        " + "mScLocale=" + req.mLocale + " mUid=" + req.mUserId);
                 }
-                final int N = grp.mListeners.size();
+                final int N = grp.mListeners.getRegisteredCallbackCount();
                 for (int i = 0; i < N; i++) {
-                    final InternalDeathRecipient listener = grp.mListeners.get(i);
+                    final ISpellCheckerSessionListener mScListener =
+                            grp.mListeners.getRegisteredCallbackItem(i);
                     pw.println("      " + "Listener #" + i + ":");
-                    pw.println("        " + "mScListener=" + listener.mScListener);
-                    pw.println("        " + "mGroup=" + listener.mGroup);
+                    pw.println("        " + "mScListener=" + mScListener);
+                    pw.println("        " + "mGroup=" + grp);
                 }
             }
             pw.println("");
@@ -840,7 +842,7 @@
     private final class SpellCheckerBindGroup {
         private final String TAG = SpellCheckerBindGroup.class.getSimpleName();
         private final InternalServiceConnection mInternalConnection;
-        private final ArrayList<InternalDeathRecipient> mListeners = new ArrayList<>();
+        private final InternalDeathRecipients mListeners;
         private boolean mUnbindCalled;
         private ISpellCheckerService mSpellChecker;
         private boolean mConnected;
@@ -849,6 +851,7 @@
 
         public SpellCheckerBindGroup(InternalServiceConnection connection) {
             mInternalConnection = connection;
+            mListeners = new InternalDeathRecipients(this);
         }
 
         public void onServiceConnected(ISpellCheckerService spellChecker) {
@@ -881,26 +884,7 @@
                 Slog.w(TAG, "remove listener: " + listener.hashCode());
             }
             synchronized(mSpellCheckerMap) {
-                final int size = mListeners.size();
-                final ArrayList<InternalDeathRecipient> removeList = new ArrayList<>();
-                for (int i = 0; i < size; ++i) {
-                    final InternalDeathRecipient tempRecipient = mListeners.get(i);
-                    if(tempRecipient.hasSpellCheckerListener(listener)) {
-                        if (DBG) {
-                            Slog.w(TAG, "found existing listener.");
-                        }
-                        removeList.add(tempRecipient);
-                    }
-                }
-                final int removeSize = removeList.size();
-                for (int i = 0; i < removeSize; ++i) {
-                    if (DBG) {
-                        Slog.w(TAG, "Remove " + removeList.get(i));
-                    }
-                    final InternalDeathRecipient idr = removeList.get(i);
-                    idr.mScListener.asBinder().unlinkToDeath(idr, 0);
-                    mListeners.remove(idr);
-                }
+                mListeners.unregister(listener);
                 cleanLocked();
             }
         }
@@ -914,7 +898,7 @@
                 return;
             }
             // If there are no more active listeners, clean up.  Only do this once.
-            if (!mListeners.isEmpty()) {
+            if (mListeners.getRegisteredCallbackCount() > 0) {
                 return;
             }
             if (!mPendingSessionRequests.isEmpty()) {
@@ -938,12 +922,10 @@
         public void removeAll() {
             Slog.e(TAG, "Remove the spell checker bind unexpectedly.");
             synchronized(mSpellCheckerMap) {
-                final int size = mListeners.size();
+                final int size = mListeners.getRegisteredCallbackCount();
                 for (int i = 0; i < size; ++i) {
-                    final InternalDeathRecipient idr = mListeners.get(i);
-                    idr.mScListener.asBinder().unlinkToDeath(idr, 0);
+                    mListeners.unregister(mListeners.getRegisteredCallbackItem(i));
                 }
-                mListeners.clear();
                 mPendingSessionRequests.clear();
                 mOnGoingSessionRequests.clear();
                 cleanLocked();
@@ -984,12 +966,9 @@
                     return;
                 }
                 if (mOnGoingSessionRequests.remove(request)) {
-                    final InternalDeathRecipient recipient =
-                            new InternalDeathRecipient(this, request.mScListener);
                     try {
                         request.mTsListener.onServiceConnected(newSession);
-                        request.mScListener.asBinder().linkToDeath(recipient, 0);
-                        mListeners.add(recipient);
+                        mListeners.register(request.mScListener);
                     } catch (RemoteException e) {
                         // Technically this can happen if the spell checker client app is already
                         // dead.  We can just forget about this request; the request is already
@@ -1045,24 +1024,21 @@
         }
     }
 
-    private static final class InternalDeathRecipient implements IBinder.DeathRecipient {
-        public final ISpellCheckerSessionListener mScListener;
+    private final class InternalDeathRecipients extends
+            RemoteCallbackList<ISpellCheckerSessionListener> {
         private final SpellCheckerBindGroup mGroup;
 
-        public InternalDeathRecipient(SpellCheckerBindGroup group,
-                ISpellCheckerSessionListener scListener) {
-            mScListener = scListener;
+        public InternalDeathRecipients(SpellCheckerBindGroup group) {
             mGroup = group;
         }
 
-        public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) {
-            return listener.asBinder().equals(mScListener.asBinder());
+        @Override
+        public void onCallbackDied(ISpellCheckerSessionListener listener) {
+            synchronized(mSpellCheckerMap) {
+                mGroup.removeListener(listener);
+            }
         }
 
-        @Override
-        public void binderDied() {
-            mGroup.removeListener(mScListener);
-        }
     }
 
     private static final class ISpellCheckerServiceCallbackBinder
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5bffe1e..de853df 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4044,7 +4044,11 @@
                     aInfo.applicationInfo.uid, true);
             if (app == null || app.instr == null) {
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
+                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
+                // For ANR debugging to verify if the user activity is the one that actually
+                // launched.
+                final String myReason = reason + ":" + userId + ":" + resolvedUserId;
+                mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
             }
         } else {
             Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index be30d5a..a145435 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -2308,6 +2308,7 @@
         pw.println(prefix + "ActivityStarter:");
         prefix = prefix + "  ";
 
+        pw.println(prefix + "mCurrentUser=" + mSupervisor.mCurrentUser);
         pw.println(prefix + "mLastStartReason=" + mLastStartReason);
         pw.println(prefix + "mLastStartActivityTimeMs="
                 + DateFormat.getDateTimeInstance().format(new Date(mLastStartActivityTimeMs)));
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e5ab784..c6307a7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -706,6 +706,8 @@
 
         mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
 
+        mRecordMonitor = new RecordingActivityMonitor(mContext);
+
         readAndSetLowRamDevice();
 
         // Call setRingerModeInt() to apply correct mute
@@ -6309,6 +6311,8 @@
         dumpAudioPolicies(pw);
 
         mPlaybackMonitor.dump(pw);
+
+        mRecordMonitor.dump(pw);
     }
 
     private static String safeMediaVolumeStateToString(Integer state) {
@@ -6730,10 +6734,13 @@
     //======================
     // Audio policy callbacks from AudioSystem for recording configuration updates
     //======================
-    private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
+    private final RecordingActivityMonitor mRecordMonitor;
 
     public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
-        mRecordMonitor.registerRecordingCallback(rcdb);
+        final boolean isPrivileged =
+                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
+                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
+        mRecordMonitor.registerRecordingCallback(rcdb, isPrivileged);
     }
 
     public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
@@ -6741,7 +6748,10 @@
     }
 
     public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
-        return mRecordMonitor.getActiveRecordingConfigurations();
+        final boolean isPrivileged =
+                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
+                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
+        return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged);
     }
 
     public void disableRingtoneSync(final int userId) {
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 57d55de..34309b6 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -16,8 +16,11 @@
 
 package com.android.server.audio;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.AudioFormat;
 import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
 import android.media.AudioRecordingConfiguration;
 import android.media.AudioSystem;
 import android.media.IRecordingConfigDispatcher;
@@ -26,7 +29,10 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.io.PrintWriter;
+import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -39,31 +45,47 @@
     public final static String TAG = "AudioService.RecordingActivityMonitor";
 
     private ArrayList<RecMonitorClient> mClients = new ArrayList<RecMonitorClient>();
+    // a public client is one that needs an anonymized version of the playback configurations, we
+    // keep track of whether there is at least one to know when we need to create the list of
+    // playback configurations that do not contain uid/package name information.
+    private boolean mHasPublicClients = false;
 
     private HashMap<Integer, AudioRecordingConfiguration> mRecordConfigs =
             new HashMap<Integer, AudioRecordingConfiguration>();
 
-    RecordingActivityMonitor() {
+    private final PackageManager mPackMan;
+
+    RecordingActivityMonitor(Context ctxt) {
         RecMonitorClient.sMonitor = this;
+        mPackMan = ctxt.getPackageManager();
     }
 
     /**
      * Implementation of android.media.AudioSystem.AudioRecordingCallback
      */
-    public void onRecordingConfigurationChanged(int event, int session, int source,
-            int[] recordingInfo) {
+    public void onRecordingConfigurationChanged(int event, int uid, int session, int source,
+            int[] recordingInfo, String packName) {
         if (MediaRecorder.isSystemOnlyAudioSource(source)) {
             return;
         }
-        final List<AudioRecordingConfiguration> configs =
-                updateSnapshot(event, session, source, recordingInfo);
-        if (configs != null){
-            synchronized(mClients) {
+        final List<AudioRecordingConfiguration> configsSystem =
+                updateSnapshot(event, uid, session, source, recordingInfo);
+        if (configsSystem != null){
+            synchronized (mClients) {
+                // list of recording configurations for "public consumption". It is only computed if
+                // there are non-system recording activity listeners.
+                final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients ?
+                        anonymizeForPublicConsumption(configsSystem) :
+                            new ArrayList<AudioRecordingConfiguration>();
                 final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
                 while (clientIterator.hasNext()) {
+                    final RecMonitorClient rmc = clientIterator.next();
                     try {
-                        clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange(
-                                configs);
+                        if (rmc.mIsPrivileged) {
+                            rmc.mDispatcherCb.dispatchRecordingConfigChange(configsSystem);
+                        } else {
+                            rmc.mDispatcherCb.dispatchRecordingConfigChange(configsPublic);
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
                     }
@@ -72,17 +94,42 @@
         }
     }
 
+    protected void dump(PrintWriter pw) {
+        // players
+        pw.println("\nRecordActivityMonitor dump time: "
+                + DateFormat.getTimeInstance().format(new Date()));
+        synchronized(mRecordConfigs) {
+            for (AudioRecordingConfiguration conf : mRecordConfigs.values()) {
+                conf.dump(pw);
+            }
+        }
+    }
+
+    private ArrayList<AudioRecordingConfiguration> anonymizeForPublicConsumption(
+            List<AudioRecordingConfiguration> sysConfigs) {
+        ArrayList<AudioRecordingConfiguration> publicConfigs =
+                new ArrayList<AudioRecordingConfiguration>();
+        // only add active anonymized configurations,
+        for (AudioRecordingConfiguration config : sysConfigs) {
+            publicConfigs.add(AudioRecordingConfiguration.anonymizedCopy(config));
+        }
+        return publicConfigs;
+    }
+
     void initMonitor() {
         AudioSystem.setRecordingCallback(this);
     }
 
-    void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
+    void registerRecordingCallback(IRecordingConfigDispatcher rcdb, boolean isPrivileged) {
         if (rcdb == null) {
             return;
         }
-        synchronized(mClients) {
-            final RecMonitorClient rmc = new RecMonitorClient(rcdb);
+        synchronized (mClients) {
+            final RecMonitorClient rmc = new RecMonitorClient(rcdb, isPrivileged);
             if (rmc.init()) {
+                if (!isPrivileged) {
+                    mHasPublicClients = true;
+                }
                 mClients.add(rmc);
             }
         }
@@ -92,22 +139,34 @@
         if (rcdb == null) {
             return;
         }
-        synchronized(mClients) {
+        synchronized (mClients) {
             final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+            boolean hasPublicClients = false;
             while (clientIterator.hasNext()) {
                 RecMonitorClient rmc = clientIterator.next();
                 if (rcdb.equals(rmc.mDispatcherCb)) {
                     rmc.release();
                     clientIterator.remove();
-                    break;
+                } else {
+                    if (!rmc.mIsPrivileged) {
+                        hasPublicClients = true;
+                    }
                 }
             }
+            mHasPublicClients = hasPublicClients;
         }
     }
 
-    List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
+    List<AudioRecordingConfiguration> getActiveRecordingConfigurations(boolean isPrivileged) {
         synchronized(mRecordConfigs) {
-            return new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values());
+            if (isPrivileged) {
+                return new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values());
+            } else {
+                final List<AudioRecordingConfiguration> configsPublic =
+                        anonymizeForPublicConsumption(
+                            new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values()));
+                return configsPublic;
+            }
         }
     }
 
@@ -122,8 +181,8 @@
      * @return null if the list of active recording sessions has not been modified, a list
      *     with the current active configurations otherwise.
      */
-    private List<AudioRecordingConfiguration> updateSnapshot(int event, int session, int source,
-            int[] recordingInfo) {
+    private List<AudioRecordingConfiguration> updateSnapshot(int event, int uid, int session,
+            int source, int[] recordingInfo) {
         final boolean configChanged;
         final ArrayList<AudioRecordingConfiguration> configs;
         synchronized(mRecordConfigs) {
@@ -147,10 +206,19 @@
                         .build();
                 final int patchHandle = recordingInfo[6];
                 final Integer sessionKey = new Integer(session);
+
+                final String[] packages = mPackMan.getPackagesForUid(uid);
+                final String packageName;
+                if (packages != null && packages.length > 0) {
+                    packageName = packages[0];
+                } else {
+                    packageName = "";
+                }
+                final AudioRecordingConfiguration updatedConfig =
+                        new AudioRecordingConfiguration(uid, session, source,
+                                clientFormat, deviceFormat, patchHandle, packageName);
+
                 if (mRecordConfigs.containsKey(sessionKey)) {
-                    final AudioRecordingConfiguration updatedConfig =
-                            new AudioRecordingConfiguration(session, source,
-                                    clientFormat, deviceFormat, patchHandle);
                     if (updatedConfig.equals(mRecordConfigs.get(sessionKey))) {
                         configChanged = false;
                     } else {
@@ -160,9 +228,7 @@
                         configChanged = true;
                     }
                 } else {
-                    mRecordConfigs.put(sessionKey,
-                            new AudioRecordingConfiguration(session, source,
-                                    clientFormat, deviceFormat, patchHandle));
+                    mRecordConfigs.put(sessionKey, updatedConfig);
                     configChanged = true;
                 }
                 break;
@@ -189,9 +255,11 @@
         static RecordingActivityMonitor sMonitor;
 
         final IRecordingConfigDispatcher mDispatcherCb;
+        final boolean mIsPrivileged;
 
-        RecMonitorClient(IRecordingConfigDispatcher rcdb) {
+        RecMonitorClient(IRecordingConfigDispatcher rcdb, boolean isPrivileged) {
             mDispatcherCb = rcdb;
+            mIsPrivileged = isPrivileged;
         }
 
         public void binderDied() {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index da75722..4511aa9 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -789,6 +789,18 @@
             }
         };
         mGnssMetrics = new GnssMetrics();
+
+        /*
+        * A cycle of native_init() and native_cleanup() is needed so that callbacks are registered
+        * after bootup even when location is disabled. This will allow Emergency SUPL to work even
+        * when location is disabled before device restart.
+        * */
+        boolean isInitialized = native_init();
+        if(!isInitialized) {
+            Log.d(TAG, "Failed to initialize at bootup");
+        } else {
+            native_cleanup();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0c854c2..c1c14e8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7175,16 +7175,13 @@
      */
     private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
             String ephemeralPkgName) {
-        // TODO: When adding on-demand split support for non-instant apps, remove this check
-        // and always apply post filtering
-        if (ephemeralPkgName == null) {
-            return resolveInfos;
-        }
         for (int i = resolveInfos.size() - 1; i >= 0; i--) {
             final ResolveInfo info = resolveInfos.get(i);
             final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
+            // TODO: When adding on-demand split support for non-instant apps, remove this check
+            // and always apply post filtering
             // allow activities that are defined in the provided package
-            if (isEphemeralApp && ephemeralPkgName.equals(info.activityInfo.packageName)) {
+            if (isEphemeralApp) {
                 if (info.activityInfo.splitName != null
                         && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
                                 info.activityInfo.splitName)) {
@@ -7209,6 +7206,10 @@
                 }
                 continue;
             }
+            // caller is a full app, don't need to apply any other filtering
+            if (ephemeralPkgName == null) {
+                continue;
+            }
             // allow activities that have been explicitly exposed to ephemeral apps
             if (!isEphemeralApp
                     && ((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) {
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index ebad81c..5e5ba46 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -816,6 +816,12 @@
 
     /** {@hide} */
     @Override
+    public boolean canLoadUnsafeResources() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
     public IBinder getActivityToken() {
         throw new UnsupportedOperationException();
     }