Merge "Emergency SUPL when location is disabled" into oc-dev
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index c4f17fa..e5c2466 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -216,5 +216,5 @@
     }
 
     // b/36066697: Avoid running static destructors.
-    _exit(1);
+    _exit(0);
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1b25e65..3ea0c83 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2138,6 +2138,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/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index f3f0ae5..1eac395 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -136,6 +136,11 @@
      * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via
      * the PendingIntent. Use this method of scanning if your process is not always running and it
      * should be started when scan results are available.
+     * <p>
+     * When the PendingIntent is delivered, the Intent passed to the receiver or activity
+     * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE},
+     * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of
+     * the scan.
      *
      * @param filters Optional list of ScanFilters for finding exact BLE devices.
      * @param settings Optional settings for the scan.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2303a38..0f94065 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4658,6 +4658,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 3b27905..df59f0e 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -920,6 +920,12 @@
         return mBase.isCredentialProtectedStorage();
     }
 
+    /** {@hide} */
+    @Override
+    public boolean canLoadUnsafeResources() {
+        return mBase.canLoadUnsafeResources();
+    }
+
     /**
      * @hide
      */
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..fd6da05 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/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 236c185..0431217 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -471,7 +471,7 @@
     <string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicació de camp proper (NFC)"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet que l\'aplicació es comuniqui amb les etiquetes, les targetes i els lectors de Comunicació de camp proper (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivació del bloqueig de pantalla"</string>
-    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet que l\'aplicació desactivi el bloqueig del teclat i qualsevol element de seguretat de contrasenyes associat. Per exemple, el telèfon desactiva el bloqueig del teclat en rebre una trucada telefònica entrant i, a continuació, reactiva el bloqueig del teclat quan finalitza la trucada."</string>
+    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet que l\'aplicació desactivi el bloqueig del teclat i qualsevol element de seguretat de contrasenyes associat. Per exemple, el telèfon desactiva el bloqueig del teclat en rebre una trucada entrant i, a continuació, reactiva el bloqueig del teclat quan finalitza la trucada."</string>
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Gestionar el maquinari d\'empremtes digitals"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permet que l\'aplicació invoqui mètodes per afegir i suprimir plantilles d\'empremtes digitals que es puguin fer servir."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utilitzar el maquinari d\'empremtes digitals"</string>
@@ -788,13 +788,13 @@
     <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ha finalitzat la reorganització del widget."</string>
     <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"S\'ha suprimit el widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
     <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Desplega l\'àrea de desbloqueig."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueig lliscant el dit"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueig lliscant"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueig mitjançant patró"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueig facial"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueig mitjançant PIN"</string>
     <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueig mitjançant contrasenya"</string>
     <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Àrea de patró"</string>
-    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Àrea per lliscar el dit"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Àrea per lliscar"</string>
     <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
     <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
     <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1075,7 +1075,7 @@
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ha superat el límit de memòria"</string>
     <string name="dump_heap_notification_detail" msgid="6901391084243999274">"S\'ha recopilat un procés \"heap dump\"; toca per compartir-lo"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Vols compartir el \"heap dump\"?"</string>
-    <string name="dump_heap_text" msgid="4809417337240334941">"El procés <xliff:g id="PROC">%1$s</xliff:g> ha superat el límit de <xliff:g id="SIZE">%2$s</xliff:g> de memòria del procés. Hi ha un procés \"heap dump\" disponible perquè el comparteixis amb el desenvolupador. Vés amb compte: aquest \"heap dump\" pot contenir les dades personals a les quals l\'aplicació tingui accés."</string>
+    <string name="dump_heap_text" msgid="4809417337240334941">"El procés <xliff:g id="PROC">%1$s</xliff:g> ha superat el límit de <xliff:g id="SIZE">%2$s</xliff:g> de memòria del procés. Hi ha un procés \"heap dump\" disponible perquè el comparteixis amb el desenvolupador. Ves amb compte: aquest \"heap dump\" pot contenir les dades personals a les quals l\'aplicació tingui accés."</string>
     <string name="sendText" msgid="5209874571959469142">"Tria una acció per al text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volum del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volum de multimèdia"</string>
@@ -1257,7 +1257,7 @@
     <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permet que una aplicació demani permís per ignorar les optimitzacions de bateria per a l\'aplicació."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Piqueu dos cops per controlar el zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No s\'ha pogut afegir el widget."</string>
-    <string name="ime_action_go" msgid="8320845651737369027">"Vés"</string>
+    <string name="ime_action_go" msgid="8320845651737369027">"Ves"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Cerca"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"Envia"</string>
     <string name="ime_action_next" msgid="3138843904009813834">"Següent"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d308c70..a0f5358 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1138,7 +1138,7 @@
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Gonbidapena bidali da"</string>
     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Konektatzeko gonbidapena"</string>
     <string name="wifi_p2p_from_message" msgid="570389174731951769">"Igorlea:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Nori:"</string>
+    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Hartzailea:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Idatzi beharrezko PINa:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PINa:"</string>
     <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableta Wi-Fi saretik deskonektatuko da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b999489..69ec07b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -90,7 +90,7 @@
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"A szolgáltatás nincs biztosítva."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nem tudja módosítani a hívó fél azonosítója beállítást."</string>
     <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"Adatszolgáltatás letiltva"</string>
-    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Nincs vészhívás"</string>
+    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Nincs segélyhívás"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Hangszolgáltatás letiltva"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Hang- és segélyszolgáltatás letiltva"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"Az Ön tartózkodási helyén ideiglenesen nem áll rendelkezésre a mobilhálózaton"</string>
@@ -223,7 +223,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonbeállítások"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Képernyő lezárása"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Kikapcsolás"</string>
-    <string name="global_action_emergency" msgid="7112311161137421166">"Vészhívás"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Segélyhívás"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
@@ -714,7 +714,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"A feloldáshoz vagy segélyhívás kezdeményezéséhez nyomja meg a Menü gombot."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"A feloldáshoz nyomja meg a Menü gombot."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Rajzolja le a mintát a feloldáshoz"</string>
-    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Vészhívás"</string>
+    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Segélyhívás"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Hívás folytatása"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Helyes!"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Próbálja újra"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 6cd7ba0..ab0b6da 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -398,7 +398,7 @@
     <string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"Այս հավելվածը կարող է ստանալ ձեր տեղադրության տվյալները ցանցային տարբեր աղբյուրներից, օրինակ՝ բջջային աշտարակներից և Wi-Fi ցանցերից: Այս տեղորոշման ծառայությունները պետք է միացված և հասանելի լինեն ձեր հեռախոսում, որպեսզի հավելվածը կարողանա օգտագործել դրանք:"</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"փոխել ձեր աուդիո կարգավորումները"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Թույլ է տալիս հավելվածին փոփոխել ձայնանյութի գլոբալ կարգավորումները, ինչպես օրինակ` ձայնը և թե որ խոսափողն է օգտագործված արտածման համար:"</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"ձայնագրել ձայնանյութ"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"ձայնագրել աուդիո ֆայլ"</string>
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"Այս հավելվածը ցանկացած պահի կարող է ձայնագրել խոսափողի օգնությամբ:"</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"ուղարկել հրամաններ SIM քարտին"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Թույլ է տալիս հավելվածին հրամաններ ուղարկել SIM-ին: Սա շատ վտանգավոր է:"</string>
@@ -1418,7 +1418,7 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Համակցված բարձրախոսներ"</string>
     <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Համակարգ"</string>
-    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի ձայնանյութ"</string>
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի աուդիո ֆայլ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Անլար էկրան"</string>
     <string name="media_route_button_content_description" msgid="591703006349356016">"Հեռարձակում"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Միանալ սարքին"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 474cdc0..688e639 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1041,7 +1041,7 @@
     <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> не реагира"</string>
     <string name="anr_process" msgid="6156880875555921105">"Процесот <xliff:g id="PROCESS">%1$s</xliff:g> не реагира"</string>
     <string name="force_close" msgid="8346072094521265605">"Во ред"</string>
-    <string name="report" msgid="4060218260984795706">"Извештај"</string>
+    <string name="report" msgid="4060218260984795706">"Пријави"</string>
     <string name="wait" msgid="7147118217226317732">"Почекај"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"Страницата не реагира.\n\nДали сакате да ја затворите?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Пренасочена апликација"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 5fd500a..312916c 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1621,7 +1621,7 @@
     <string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado pelo seu administrador"</string>
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros aplicativos que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho do dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros apps que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode significar que as imagens não serão exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 5fd500a..312916c 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1621,7 +1621,7 @@
     <string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado pelo seu administrador"</string>
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros aplicativos que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho do dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros apps que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode significar que as imagens não serão exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 38573c1..ea9a180 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -210,7 +210,7 @@
     <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Подготовка обновлений…"</string>
     <string name="reboot_to_update_package" msgid="3871302324500927291">"Обработка обновлений…"</string>
     <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Перезагрузка…"</string>
-    <string name="reboot_to_reset_title" msgid="4142355915340627490">"Сброс к заводским настройкам"</string>
+    <string name="reboot_to_reset_title" msgid="4142355915340627490">"Сбросить к заводским настройкам"</string>
     <string name="reboot_to_reset_message" msgid="2432077491101416345">"Перезагрузка…"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Выключение..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшетный ПК будет отключен."</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index f5d5140..f34e7b4 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -364,6 +364,6 @@
     <string name="active_input_method_subtypes" msgid="3596398805424733238">"Mètodes d\'introducció actius"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Utilitza els idiomes del sistema"</string>
     <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"No s\'ha pogut obrir la configuració de: <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string>
-    <string name="ime_security_warning" msgid="4135828934735934248">"Pot ser que aquest mètode d\'entrada pugui recopilar tot el que escriviu, incloses dades personals, com ara contrasenyes i números de targetes de crèdit. Ve de l\'aplicació <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Voleu utilitzar aquest mètode d\'entrada?"</string>
+    <string name="ime_security_warning" msgid="4135828934735934248">"Pot ser que aquest mètode d\'introducció pugui recopilar tot el que escriviu, incloses dades personals, com ara contrasenyes i números de targetes de crèdit. Ve de l\'aplicació <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Voleu utilitzar aquest mètode d\'introducció?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"Nota: després de reiniciar, l\'aplicació no s\'iniciarà fins que no desbloquegis el telèfon"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 1b75574..0f4224a 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -77,7 +77,7 @@
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"페어링"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"페어링"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"취소"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"페어링하면 연결 시 주소록 및 통화 기록에 액세스할 수 있습니다."</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"페어링하면 연결 시 연락처 및 통화 기록에 액세스할 수 있습니다."</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 페어링하지 못했습니다."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN 또는 패스키가 잘못되어 <xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 페어링하지 못했습니다."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 통신할 수 없습니다."</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 98ef4cb..e0683a8 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -81,7 +81,7 @@
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pareamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 98ef4cb..e0683a8 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -81,7 +81,7 @@
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pareamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index a4006f9..7a50c47 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -50,7 +50,7 @@
     <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Профиль HSP/HFP"</string>
     <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Профиль OPP"</string>
     <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Профиль HID"</string>
-    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Интернет-доступ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Доступ к Интернету"</string>
     <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Обмен контактами"</string>
     <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Использовать для обмена контактами"</string>
     <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Профиль PAN"</string>
@@ -74,12 +74,12 @@
     <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Использовать для аудиоустройства телефона"</string>
     <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Используется для передачи файлов"</string>
     <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Использовать для ввода"</string>
-    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Подключить"</string>
-    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ПОДКЛЮЧИТЬ"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Добавить"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ДОБАВИТЬ"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Отмена"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Сопряжение обеспечивает доступ к вашим контактам и журналу звонков при подключении."</string>
-    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не удалось подключиться к устройству \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
-    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не удалось подключиться к устройству \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", так как введен неверный PIN-код или пароль."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не удалось установить сопряжение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не удалось установить сопряжение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", так как введен неверный PIN-код или пароль."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не удается установить соединение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> не разрешает сопряжение."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi выключен"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 6a92562..5316357 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -41,7 +41,7 @@
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Bağlantı kesiliyor…"</string>
     <string name="bluetooth_connecting" msgid="8555009514614320497">"Bağlanıyor…"</string>
     <string name="bluetooth_connected" msgid="6038755206916626419">"Bağlandı"</string>
-    <string name="bluetooth_pairing" msgid="1426882272690346242">"Eşleştiriliyor…"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Eşleniyor…"</string>
     <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Bağlandı (telefon yok)"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Bağlandı (medya yok)"</string>
     <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Bağlı (mesaj erişimi yok)"</string>
@@ -74,14 +74,14 @@
     <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Telefon sesi için kullan"</string>
     <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Dosya aktarımı için kullan"</string>
     <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Giriş için kullan"</string>
-    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Eşleştir"</string>
-    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"EŞLEŞTİR"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Eşle"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"EŞLE"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"İptal"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Eşleme işlemi, bağlantı kurulduğunda kişilerinize ve çağrı geçmişine erişim izni verir."</string>
-    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşleştirilemedi."</string>
-    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN veya parola yanlış olduğundan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşleştirilemedi"</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşlenemedi."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN veya parola yanlış olduğundan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşlenemedi"</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile iletişim kurulamıyor."</string>
-    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Eşleştirme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tarafından reddedildi."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Eşleme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tarafından reddedildi."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Kablosuz kapalı."</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"Kablosuz bağlantı kesildi."</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Kablosuz sinyal gücü tek çubuk."</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
index a8f6f02..8fc9fa6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
@@ -54,6 +54,10 @@
                 mStorageStatsManager.queryStatsForPackage(volumeUuid, packageName, user));
     }
 
+    public long getCacheQuotaBytes(String volumeUuid, int uid) {
+        return mStorageStatsManager.getCacheQuotaBytes(volumeUuid, uid);
+    }
+
     /**
      * Static class that provides methods for querying the amount of external storage available as
      * well as breaking it up into several media types.
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/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4245b11..f66a09e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -776,4 +776,7 @@
 
     <dimen name="qs_gutter_height">6dp</dimen>
 
+    <!-- Width of the hollow triangle for empty signal state -->
+    <dimen name="mobile_signal_empty_strokewidth">2dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index 32b5862..af2b767 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -38,6 +38,7 @@
 import android.view.View;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
 
 /**
  * Bouncer between work activities and the activity used to confirm credentials before unlocking
@@ -83,6 +84,7 @@
         // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
         // redaction switched on.
         final View blankView = new View(this);
+        blankView.setContentDescription(getString(R.string.accessibility_desc_work_lock));
         blankView.setBackgroundColor(getPrimaryColor());
         setContentView(blankView);
     }
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/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index b52414e..fbcdf1a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -140,7 +140,11 @@
         state.value = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
         state.icon = new SignalIcon(cb.mobileSignalIconId);
-        state.state = Tile.STATE_ACTIVE;
+        if (cb.airplaneModeEnabled) {
+            state.state = Tile.STATE_INACTIVE;
+        } else {
+            state.state = Tile.STATE_ACTIVE;
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 93033ea..80c44a3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -71,6 +71,7 @@
 
     Context mContext;
 
+    int mPreloadedUserId;
     List<ActivityManager.RecentTaskInfo> mRawTasks;
     TaskStack mStack;
     ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>();
@@ -83,9 +84,6 @@
     private void updateCurrentQuietProfilesCache(int currentUserId) {
         mCurrentQuietProfiles.clear();
 
-        if (currentUserId == UserHandle.USER_CURRENT) {
-            currentUserId = SystemServicesProxy.getInstance(mContext).getCurrentUser();
-        }
         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         List<UserInfo> profiles = userManager.getProfiles(currentUserId);
         if (profiles != null) {
@@ -105,9 +103,10 @@
      * Note: Do not lock, callers should synchronize on the loader before making this call.
      */
     void preloadRawTasks(boolean includeFrontMostExcludedTask) {
-        int currentUserId = UserHandle.USER_CURRENT;
-        updateCurrentQuietProfilesCache(currentUserId);
         SystemServicesProxy ssp = Recents.getSystemServices();
+        int currentUserId = ssp.getCurrentUser();
+        updateCurrentQuietProfilesCache(currentUserId);
+        mPreloadedUserId = currentUserId;
         mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                 currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles);
 
@@ -135,7 +134,6 @@
             preloadRawTasks(includeFrontMostExcludedTask);
         }
 
-        SystemServicesProxy ssp = SystemServicesProxy.getInstance(mContext);
         SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
         SparseIntArray affiliatedTaskCounts = new SparseIntArray();
         SparseBooleanArray lockedUsers = new SparseBooleanArray();
@@ -143,7 +141,7 @@
                 R.string.accessibility_recents_item_will_be_dismissed);
         String appInfoDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_open_app_info);
-        int currentUserId = ssp.getCurrentUser();
+        int currentUserId = mPreloadedUserId;
         long legacyLastStackActiveTime = migrateLegacyLastStackActiveTime(currentUserId);
         long lastStackActiveTime = Settings.Secure.getLongForUser(mContext.getContentResolver(),
                 Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime, currentUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index bbcbfd6..1a99636 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -454,7 +454,8 @@
                     || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
                 iconState.hidden = true;
             }
-            int shelfColor = icon.getStaticDrawableColor();
+            int backgroundColor = getBackgroundColorWithoutTint();
+            int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor);
             if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) {
                 int iconColor = row.getVisibleNotificationHeader().getOriginalIconColor();
                 shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3c7ddb5..1a47e44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -35,6 +35,7 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
+import android.support.v4.graphics.ColorUtils;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
@@ -46,6 +47,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
@@ -127,6 +129,8 @@
         setColorInternal(newColor);
     };
     private final NotificationIconDozeHelper mDozer;
+    private int mContrastedDrawableColor;
+    private int mCachedContrastBackgroundColor = NO_COLOR;
 
     public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
         this(context, slot, sbn, false);
@@ -528,6 +532,7 @@
     public void setStaticDrawableColor(int color) {
         mDrawableColor = color;
         setColorInternal(color);
+        updateContrastedStaticColor();
         mIconColor = color;
         mDozer.setColor(color);
     }
@@ -580,6 +585,42 @@
         return mDrawableColor;
     }
 
+    /**
+     * A drawable color that passes GAR on a specific background.
+     * This value is cached.
+     *
+     * @param backgroundColor Background to test against.
+     * @return GAR safe version of {@link StatusBarIconView#getStaticDrawableColor()}.
+     */
+    int getContrastedStaticDrawableColor(int backgroundColor) {
+        if (mCachedContrastBackgroundColor != backgroundColor) {
+            mCachedContrastBackgroundColor = backgroundColor;
+            updateContrastedStaticColor();
+        }
+        return mContrastedDrawableColor;
+    }
+
+    private void updateContrastedStaticColor() {
+        if (mCachedContrastBackgroundColor == NO_COLOR) {
+            return;
+        }
+        // We'll modify the color if it doesn't pass GAR
+        int contrastedColor = mDrawableColor;
+        if (!NotificationColorUtil.satisfiesTextContrast(mCachedContrastBackgroundColor,
+                contrastedColor)) {
+            float[] hsl = new float[3];
+            ColorUtils.colorToHSL(mDrawableColor, hsl);
+            // This is basically a light grey, pushing the color will only distort it.
+            // Best thing to do in here is to fallback to the default color.
+            if (hsl[1] < 0.2f) {
+                contrastedColor = Notification.COLOR_DEFAULT;
+            }
+            contrastedColor = NotificationColorUtil.resolveContrastColor(mContext,
+                    contrastedColor, mCachedContrastBackgroundColor);
+        }
+        mContrastedDrawableColor = contrastedColor;
+    }
+
     public void setVisibleState(int state) {
         setVisibleState(state, true /* animate */, null /* endRunnable */);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 0b46c21..1ef784e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -303,10 +303,10 @@
                 trackMovement(event);
                 if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
                         || mPeekAnimator != null) {
-                    cancelHeightAnimator();
-                    cancelPeek();
                     mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
                             || mPeekAnimator != null;
+                    cancelHeightAnimator();
+                    cancelPeek();
                     onTrackingStarted();
                 }
                 if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
@@ -611,6 +611,9 @@
 
     protected void cancelHeightAnimator() {
         if (mHeightAnimator != null) {
+            if (mHeightAnimator.isRunning()) {
+                mPanelUpdateWhenAnimatorEnds = false;
+            }
             mHeightAnimator.cancel();
         }
         endClosing();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
index 0a638d8..983a796 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Path;
@@ -28,6 +29,7 @@
 import android.graphics.Path.FillType;
 import android.graphics.Path.Op;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.util.LayoutDirection;
@@ -64,6 +66,7 @@
     private static final int STATE_EMPTY = 1;
     private static final int STATE_CUT = 2;
     private static final int STATE_CARRIER_CHANGE = 3;
+    private static final int STATE_AIRPLANE = 4;
 
     private static final long DOT_DELAY = 1000;
 
@@ -82,6 +85,13 @@
             {-1.9f / VIEWPORT, -1.9f / VIEWPORT},
     };
 
+    // The easiest way to understand this is as if we set Style.STROKE and draw the triangle,
+    // but that is only theoretically right. Instead, draw the triangle and clip out a smaller
+    // one inset by this amount.
+    private final float mEmptyStrokeWidth;
+    private static final float INV_TAN = 1f / (float) Math.tan(Math.PI / 8f);
+    private final float mEmptyDiagInset;  // == mEmptyStrokeWidth * INV_TAN
+
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final int mDarkModeBackgroundColor;
@@ -91,6 +101,10 @@
     private final Path mFullPath = new Path();
     private final Path mForegroundPath = new Path();
     private final Path mXPath = new Path();
+    // Cut out when STATE_EMPTY
+    private final Path mCutPath = new Path();
+    // Draws the slash when in airplane mode
+    private final SlashArtist mSlash = new SlashArtist();
     private final Handler mHandler;
     private float mOldDarkIntensity = -1;
     private float mNumLevels = 1;
@@ -111,6 +125,12 @@
         mLightModeFillColor =
                 Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill);
         mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size);
+
+        // mCutPath parameters
+        mEmptyStrokeWidth = context.getResources()
+                .getDimensionPixelSize(R.dimen.mobile_signal_empty_strokewidth);
+        mEmptyDiagInset = mEmptyStrokeWidth * INV_TAN;
+
         mHandler = new Handler();
         setDarkIntensity(0);
     }
@@ -208,7 +228,7 @@
         mFullPath.setFillType(FillType.WINDING);
         float width = getBounds().width();
         float height = getBounds().height();
-        float padding = (PAD * width);
+        float padding = Math.round(PAD * width);
         mFullPath.moveTo(width - padding, height - padding);
         mFullPath.lineTo(width - padding, padding);
         mFullPath.lineTo(padding, height - padding);
@@ -241,10 +261,27 @@
             mFullPath.rLineTo(0, cut);
         }
 
-        mPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL);
-        mForegroundPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL);
+        if (mState == STATE_EMPTY) {
+            // Cut out a smaller triangle from the center of mFullPath
+            mCutPath.reset();
+            mCutPath.setFillType(FillType.WINDING);
+            mCutPath.moveTo(width - padding - mEmptyStrokeWidth,
+                    height - padding - mEmptyStrokeWidth);
+            mCutPath.lineTo(width - padding - mEmptyStrokeWidth, padding + mEmptyDiagInset);
+            mCutPath.lineTo(padding + mEmptyDiagInset, height - padding - mEmptyStrokeWidth);
+            mCutPath.lineTo(width - padding - mEmptyStrokeWidth,
+                    height - padding - mEmptyStrokeWidth);
 
-        if (mState != STATE_CARRIER_CHANGE) {
+            // In empty state, draw the full path as the foreground paint
+            mForegroundPath.set(mFullPath);
+            mFullPath.reset();
+            mForegroundPath.op(mCutPath, Path.Op.DIFFERENCE);
+        } else if (mState == STATE_AIRPLANE) {
+            // Airplane mode is slashed, full-signal
+            mForegroundPath.set(mFullPath);
+            mFullPath.reset();
+            mSlash.draw((int) height, (int) width, canvas, mForegroundPaint);
+        } else if (mState != STATE_CARRIER_CHANGE) {
             mForegroundPath.reset();
             int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding));
             mForegroundPath.addRect(padding, padding, padding + sigWidth, height - padding,
@@ -354,4 +391,65 @@
     public static int getEmptyState(int numLevels) {
         return (STATE_EMPTY << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
     }
+
+    public static int getAirplaneModeState(int numLevels) {
+        return (STATE_AIRPLANE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
+    }
+
+    private final class SlashArtist {
+        // These values are derived in un-rotated (vertical) orientation
+        private static final float SLASH_WIDTH = 1.8384776f;
+        private static final float SLASH_HEIGHT = 22f;
+        private static final float CENTER_X = 10.65f;
+        private static final float CENTER_Y = 15.869239f;
+        private static final float SCALE = 24f;
+
+        // Bottom is derived during animation
+        private static final float LEFT = (CENTER_X - (SLASH_WIDTH / 2)) / SCALE;
+        private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE;
+        private static final float RIGHT = (CENTER_X + (SLASH_WIDTH / 2)) / SCALE;
+        private static final float BOTTOM = (CENTER_Y + (SLASH_HEIGHT / 2)) / SCALE;
+        // Draw the slash washington-monument style; rotate to no-u-turn style
+        private static final float ROTATION = -45f;
+
+        private final Path mPath = new Path();
+        private final RectF mSlashRect = new RectF();
+
+        void draw(int height, int width, @NonNull Canvas canvas, Paint paint) {
+            Matrix m = new Matrix();
+            updateRect(
+                    scale(LEFT, width),
+                    scale(TOP, height),
+                    scale(RIGHT, width),
+                    scale(BOTTOM, height));
+
+            mPath.reset();
+            // Draw the slash vertically
+            mPath.addRect(mSlashRect, Direction.CW);
+            m.setRotate(ROTATION, width / 2, height / 2);
+            mPath.transform(m);
+            canvas.drawPath(mPath, paint);
+
+            // Rotate back to vertical, and draw the cut-out rect next to this one
+            m.setRotate(-ROTATION, width / 2, height / 2);
+            mPath.transform(m);
+            m.setTranslate(mSlashRect.width(), 0);
+            mPath.transform(m);
+            mPath.addRect(mSlashRect, Direction.CW);
+            m.setRotate(ROTATION, width / 2, height / 2);
+            mPath.transform(m);
+            canvas.clipOutPath(mPath);
+        }
+
+        void updateRect(float left, float top, float right, float bottom) {
+            mSlashRect.left = left;
+            mSlashRect.top = top;
+            mSlashRect.right = right;
+            mSlashRect.bottom = bottom;
+        }
+
+        private float scale(float frac, int width) {
+            return frac * width;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 3f5f5a0..874f0d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -31,8 +31,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 
 import com.android.systemui.R;
+import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -141,7 +143,8 @@
     /**
      * Returns true if there currently exist active high power location requests.
      */
-    private boolean areActiveHighPowerLocationRequests() {
+    @VisibleForTesting
+    protected boolean areActiveHighPowerLocationRequests() {
         List<AppOpsManager.PackageOps> packages
             = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
         // AppOpsManager can return null when there is no requested data.
@@ -205,16 +208,14 @@
         }
 
         private void locationActiveChanged() {
-            for (LocationChangeCallback cb : mSettingsChangeCallbacks) {
-                cb.onLocationActiveChanged(mAreActiveLocationRequests);
-            }
+            Utils.safeForeach(mSettingsChangeCallbacks,
+                    cb -> cb.onLocationActiveChanged(mAreActiveLocationRequests));
         }
 
         private void locationSettingsChanged() {
             boolean isEnabled = isLocationEnabled();
-            for (LocationChangeCallback cb : mSettingsChangeCallbacks) {
-                cb.onLocationSettingsChanged(isEnabled);
-            }
+            Utils.safeForeach(mSettingsChangeCallbacks,
+                    cb -> cb.onLocationSettingsChanged(isEnabled));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 67b5596..efce871 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -254,6 +254,10 @@
 
     @Override
     public int getQsCurrentIconId() {
+        if (mCurrentState.airplaneMode) {
+            return SignalDrawable.getAirplaneModeState(getNumLevels());
+        }
+
         return getCurrentIconId();
     }
 
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 612a54a..b12fd1c 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -37,6 +37,7 @@
     <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 68f9cb05..8e7ffdf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.statusbar;
 
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -33,12 +35,14 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
@@ -100,4 +104,17 @@
 
         assertFalse(mIconView.set(mStatusBarIcon));
     }
+
+    @Test
+    public void testGetContrastedStaticDrawableColor() {
+        mIconView.setStaticDrawableColor(Color.DKGRAY);
+        int color = mIconView.getContrastedStaticDrawableColor(Color.WHITE);
+        assertEquals("Color should not change when we have enough contrast",
+                Color.DKGRAY, color);
+
+        mIconView.setStaticDrawableColor(Color.WHITE);
+        color = mIconView.getContrastedStaticDrawableColor(Color.WHITE);
+        assertTrue("Similar colors should be shifted to satisfy contrast",
+                NotificationColorUtil.satisfiesTextContrast(Color.WHITE, color));
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
new file mode 100644
index 0000000..a10bebf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.location.LocationManager;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class LocationControllerImplTest extends SysuiTestCase {
+
+    private LocationControllerImpl mLocationController;
+
+    @Before
+    public void setup() {
+        mLocationController = spy(new LocationControllerImpl(mContext,
+                TestableLooper.get(this).getLooper()));
+    }
+
+    @Test
+    public void testRemoveSelfActive_DoesNotCrash() {
+        LocationController.LocationChangeCallback callback = new LocationChangeCallback() {
+            @Override
+            public void onLocationActiveChanged(boolean active) {
+                mLocationController.removeCallback(this);
+            }
+        };
+        mLocationController.addCallback(callback);
+        mLocationController.addCallback(mock(LocationChangeCallback.class));
+
+        when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(false);
+        mLocationController.onReceive(mContext, new Intent(
+                LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
+        when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(true);
+        mLocationController.onReceive(mContext, new Intent(
+                LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
+
+        TestableLooper.get(this).processAllMessages();
+    }
+
+    @Test
+    public void testRemoveSelfSettings_DoesNotCrash() {
+        LocationController.LocationChangeCallback callback = new LocationChangeCallback() {
+            @Override
+            public void onLocationSettingsChanged(boolean isEnabled) {
+                mLocationController.removeCallback(this);
+            }
+        };
+        mLocationController.addCallback(callback);
+        mLocationController.addCallback(mock(LocationChangeCallback.class));
+
+        TestableLooper.get(this).processAllMessages();
+    }
+}
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e85f96b..cb91f93 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -270,6 +270,12 @@
     }
 
     @Override
+    public void onSwitchUser(int userHandle) {
+        if (sDebug) Slog.d(TAG, "Hiding UI when user switched");
+        mUi.hideAll(null);
+    }
+
+    @Override
     public void onCleanupUser(int userId) {
         synchronized (mLock) {
             removeCachedServiceLocked(userId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1a02e8d..751c054 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -360,8 +360,7 @@
     }
 
     void disableOwnedAutofillServicesLocked(int uid) {
-        if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid
-                != UserHandle.getAppId(uid)) {
+        if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid != uid) {
             return;
         }
         final long identity = Binder.clearCallingIdentity();
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index d1fbbf9..c9e2a92 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -191,6 +191,7 @@
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+        window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS);
         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
         window.setGravity(Gravity.BOTTOM | Gravity.CENTER);
         window.setCloseOnTouchOutside(true);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6c3a8a4..607b84c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4064,7 +4064,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/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 3f825c5..d820f3d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -243,21 +243,11 @@
         // See NetlinkHandler.cpp:71.
         if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
         synchronized (mPublicSync) {
-            int interfaceType = ifaceNameToType(iface);
-            if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
-                return;
-            }
-
-            TetherState tetherState = mTetherStates.get(iface);
             if (up) {
-                if (tetherState == null) {
-                    trackNewTetherableInterface(iface, interfaceType);
-                }
+                maybeTrackNewInterfaceLocked(iface);
             } else {
-                if (interfaceType == ConnectivityManager.TETHERING_BLUETOOTH) {
-                    tetherState.stateMachine.sendMessage(
-                            TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-                    mTetherStates.remove(iface);
+                if (ifaceNameToType(iface) == ConnectivityManager.TETHERING_BLUETOOTH) {
+                    stopTrackingInterfaceLocked(iface);
                 } else {
                     // Ignore usb0 down after enabling RNDIS.
                     // We will handle disconnect in interfaceRemoved.
@@ -291,18 +281,7 @@
     public void interfaceAdded(String iface) {
         if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
         synchronized (mPublicSync) {
-            int interfaceType = ifaceNameToType(iface);
-            if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
-                if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
-                return;
-            }
-
-            TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState == null) {
-                trackNewTetherableInterface(iface, interfaceType);
-            } else {
-                if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
-            }
+            maybeTrackNewInterfaceLocked(iface);
         }
     }
 
@@ -310,15 +289,7 @@
     public void interfaceRemoved(String iface) {
         if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
         synchronized (mPublicSync) {
-            TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState == null) {
-                if (VDBG) {
-                    Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
-                }
-                return;
-            }
-            tetherState.stateMachine.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-            mTetherStates.remove(iface);
+            stopTrackingInterfaceLocked(iface);
         }
     }
 
@@ -821,30 +792,41 @@
                     case WifiManager.WIFI_AP_STATE_DISABLING:
                     case WifiManager.WIFI_AP_STATE_FAILED:
                     default:
-                        disableWifiIpServingLocked(curState);
+                        disableWifiIpServingLocked(ifname, curState);
                         break;
                 }
             }
         }
     }
 
-    // TODO: Pass in the interface name and, if non-empty, only turn down IP
-    // serving on that one interface.
-    private void disableWifiIpServingLocked(int apState) {
-        if (DBG) Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" + apState);
+    private void disableWifiIpServingLocked(String ifname, int apState) {
+        mLog.log("Canceling WiFi tethering request - AP_STATE=" + apState);
 
-        // Tell appropriate interface state machines that they should tear
-        // themselves down.
+        // Regardless of whether we requested this transition, the AP has gone
+        // down.  Don't try to tether again unless we're requested to do so.
+        // TODO: Remove this altogether, once Wi-Fi reliably gives us an
+        // interface name with every broadcast.
+        mWifiTetherRequested = false;
+
+        if (!TextUtils.isEmpty(ifname)) {
+            final TetherState ts = mTetherStates.get(ifname);
+            if (ts != null) {
+                ts.stateMachine.unwanted();
+                return;
+            }
+        }
+
         for (int i = 0; i < mTetherStates.size(); i++) {
             TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
             if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
-                tism.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-                break;  // There should be at most one of these.
+                tism.unwanted();
+                return;
             }
         }
-        // Regardless of whether we requested this transition, the AP has gone
-        // down.  Don't try to tether again unless we're requested to do so.
-        mWifiTetherRequested = false;
+
+        mLog.log("Error disabling Wi-Fi IP serving; " +
+                (TextUtils.isEmpty(ifname) ? "no interface name specified"
+                                           : "specified interface: " + ifname));
     }
 
     private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
@@ -864,6 +846,7 @@
         }
 
         if (!TextUtils.isEmpty(ifname)) {
+            maybeTrackNewInterfaceLocked(ifname, ConnectivityManager.TETHERING_WIFI);
             changeInterfaceState(ifname, ipServingMode);
         } else {
             mLog.e(String.format(
@@ -1887,15 +1870,43 @@
         sendTetherStateChangedBroadcast();
     }
 
-    private void trackNewTetherableInterface(String iface, int interfaceType) {
-        TetherState tetherState;
-        tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
-                interfaceType, mLog, mNMService, mStatsService, this,
-                new IPv6TetheringInterfaceServices(iface, mNMService, mLog)));
+    private void maybeTrackNewInterfaceLocked(final String iface) {
+        // If we don't care about this type of interface, ignore.
+        final int interfaceType = ifaceNameToType(iface);
+        if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
+            mLog.log(iface + " is not a tetherable iface, ignoring");
+            return;
+        }
+        maybeTrackNewInterfaceLocked(iface, interfaceType);
+    }
+
+    private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
+        // If we have already started a TISM for this interface, skip.
+        if (mTetherStates.containsKey(iface)) {
+            mLog.log("active iface (" + iface + ") reported as added, ignoring");
+            return;
+        }
+
+        mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
+        final TetherState tetherState = new TetherState(
+                new TetherInterfaceStateMachine(
+                    iface, mLooper, interfaceType, mLog, mNMService, mStatsService, this,
+                    new IPv6TetheringInterfaceServices(iface, mNMService, mLog)));
         mTetherStates.put(iface, tetherState);
         tetherState.stateMachine.start();
     }
 
+    private void stopTrackingInterfaceLocked(final String iface) {
+        final TetherState tetherState = mTetherStates.get(iface);
+        if (tetherState == null) {
+            mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
+            return;
+        }
+        tetherState.stateMachine.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
+        mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
+        mTetherStates.remove(iface);
+    }
+
     private static String[] copy(String[] strarray) {
         return Arrays.copyOf(strarray, strarray.length);
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 4a1d405..ffd71ca 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -127,6 +127,10 @@
 
     public int lastError() { return mLastError; }
 
+    public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
+
+    public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
+
     // configured when we start tethering and unconfig'd on error or conclusion
     private boolean configureIfaceIp(boolean enabled) {
         if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 27602d3..70f6a04 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7179,16 +7179,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)) {
@@ -7213,6 +7210,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/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8b28df1..8112f99 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -23,6 +23,7 @@
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.AppOpsManager.OP_TOAST_WINDOW;
+import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.content.Context.DISPLAY_SERVICE;
 import static android.content.Context.WINDOW_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
@@ -2843,7 +2844,7 @@
 
             if (theme != context.getThemeResId() || labelRes != 0) {
                 try {
-                    context = context.createPackageContext(packageName, 0);
+                    context = context.createPackageContext(packageName, CONTEXT_RESTRICTED);
                     context.setTheme(theme);
                 } catch (PackageManager.NameNotFoundException e) {
                     // Ignore
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 6a7123c..7e575bf 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
@@ -37,6 +38,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.MergedConfiguration;
 import android.util.Slog;
@@ -85,6 +87,7 @@
     private boolean mClientDead = false;
     private float mLastReportedAnimatorScale;
     private String mPackageName;
+    private String mRelayoutTag;
 
     public Session(WindowManagerService service, IWindowSessionCallback callback,
             IInputMethodClient client, IInputContext inputContext) {
@@ -221,10 +224,12 @@
             MergedConfiguration mergedConfiguration, Surface outSurface) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags,
                 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                 outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
         return res;
@@ -550,6 +555,7 @@
 
     void windowAddedLocked(String packageName) {
         mPackageName = packageName;
+        mRelayoutTag = "relayoutWindow: " + mPackageName;
         if (mSurfaceSession == null) {
             if (WindowManagerService.localLOGV) Slog.v(
                 TAG_WM, "First window added to " + this + ", creating SurfaceSession");
@@ -673,6 +679,7 @@
                 pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces);
                 pw.print(" mClientDead="); pw.print(mClientDead);
                 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
+        pw.print(prefix); pw.print("mPackageName="); pw.println(mPackageName);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ec7ab23..30027d5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -30,6 +30,7 @@
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
 import static android.os.Process.myPid;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -884,11 +885,16 @@
     }
 
     void openSurfaceTransaction() {
-        synchronized (mWindowMap) {
-            if (mRoot.mSurfaceTraceEnabled) {
-                mRoot.mRemoteEventTrace.openSurfaceTransaction();
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
+            synchronized (mWindowMap) {
+                if (mRoot.mSurfaceTraceEnabled) {
+                    mRoot.mRemoteEventTrace.openSurfaceTransaction();
+                }
+                SurfaceControl.openTransaction();
             }
-            SurfaceControl.openTransaction();
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -904,16 +910,21 @@
      *                     blocks and we call it repeatedly, like we do for animations.
      */
     void closeSurfaceTransaction(boolean withLockHeld) {
-        synchronized (mWindowMap) {
-            if (mRoot.mSurfaceTraceEnabled) {
-                mRoot.mRemoteEventTrace.closeSurfaceTransaction();
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
+            synchronized (mWindowMap) {
+                if (mRoot.mSurfaceTraceEnabled) {
+                    mRoot.mRemoteEventTrace.closeSurfaceTransaction();
+                }
+                if (withLockHeld) {
+                    SurfaceControl.closeTransaction();
+                }
             }
-            if (withLockHeld) {
+            if (!withLockHeld) {
                 SurfaceControl.closeTransaction();
             }
-        }
-        if (!withLockHeld) {
-            SurfaceControl.closeTransaction();
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -1988,6 +1999,8 @@
                     (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
                             || !win.mAppToken.isClientHidden())) {
 
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
+
                 // We are about to create a surface, but we didn't run a layout yet. So better run
                 // a layout now that we already know the right size, as a resize call will make the
                 // surface transaction blocking until next vsync and slow us down.
@@ -1999,6 +2012,7 @@
                 }
                 result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
                         oldVisibility);
+
                 try {
                     result = createSurfaceControl(outSurface, result, win, winAnimator);
                 } catch (Exception e) {
@@ -2018,7 +2032,10 @@
                     imMayMove = true;
                 }
                 win.adjustStartingWindowFlags();
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             } else {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_2");
+
                 winAnimator.mEnterAnimationPending = false;
                 winAnimator.mEnteringAnimation = false;
                 final boolean usingSavedSurfaceBeforeVisible =
@@ -2053,18 +2070,22 @@
                     // We already told the client to go invisible, but the message may not be
                     // handled yet, or it might want to draw a last frame. If we already have a
                     // surface, let the client use that, but don't create new surface at this point.
+                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
                     winAnimator.mSurfaceController.getSurface(outSurface);
+                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 } else {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
 
                     try {
-                        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
+                        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
                                 + win.mAttrs.getTitle());
                         outSurface.release();
                     } finally {
-                        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+                        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                     }
                 }
+
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
 
             if (focusMayChange) {
@@ -2101,8 +2122,11 @@
             }
 
             win.setDisplayLayoutNeeded();
-            win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
+            win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+                    "relayoutWindow: updateOrientationFromAppTokens");
             configChanged = updateOrientationFromAppTokensLocked(false, displayId);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
             // We may be deferring layout passes at the moment, but since the client is interested
             // in the new out values right now we need to force a layout.
@@ -2155,7 +2179,9 @@
         }
 
         if (configChanged) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: sendNewConfiguration");
             sendNewConfiguration(displayId);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
         Binder.restoreCallingIdentity(origId);
         return result;
@@ -2216,8 +2242,14 @@
         if (!win.mHasSurface) {
             result |= RELAYOUT_RES_SURFACE_CHANGED;
         }
-        WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked(
-            win.mAttrs.type, win.mOwnerUid);
+
+        WindowSurfaceController surfaceController;
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
+            surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
         if (surfaceController != null) {
             surfaceController.getSurface(outSurface);
             if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurface + ": copied");
@@ -2227,6 +2259,7 @@
             Slog.w(TAG_WM, "Failed to create surface control for " + win);
             outSurface.release();
         }
+
         return result;
     }
 
@@ -2273,7 +2306,7 @@
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
         // is running.
-        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
         if (okToDisplay()) {
             final DisplayContent displayContent = atoken.getTask().getDisplayContent();
             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
@@ -2329,7 +2362,7 @@
         } else {
             atoken.mAppAnimator.clearAnimation();
         }
-        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
         return atoken.mAppAnimator.animation != null;
     }
@@ -3412,7 +3445,7 @@
 
             if (!mBootAnimationStopped) {
                 // Do this one time.
-                Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
+                Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
                 try {
                     IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                     if (surfaceFlinger != null) {
@@ -3435,7 +3468,7 @@
             }
 
             EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
-            Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
+            Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
             mDisplayEnabled = true;
             if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******************** ENABLING SCREEN!");
 
@@ -3666,12 +3699,12 @@
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
         try {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
             return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
                     -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */,
                     Bitmap.Config.ARGB_8888, true /* wallpaperOnly */, false /* includeDecor */);
         } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -3857,6 +3890,8 @@
                 + " alwaysSendConfiguration=" + alwaysSendConfiguration
                 + " forceRelayout=" + forceRelayout);
 
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation");
+
         long origId = Binder.clearCallingIdentity();
 
         try {
@@ -3865,20 +3900,28 @@
             final int displayId;
             synchronized (mWindowMap) {
                 final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");
                 rotationChanged = displayContent.updateRotationUnchecked(
                         false /* inTransaction */);
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 if (!rotationChanged || forceRelayout) {
                     displayContent.setLayoutNeeded();
+                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+                            "updateRotation: performSurfacePlacement");
                     mWindowPlacerLocked.performSurfacePlacement();
+                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 }
                 displayId = displayContent.getDisplayId();
             }
 
             if (rotationChanged || alwaysSendConfiguration) {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: sendNewConfiguration");
                 sendNewConfiguration(displayId);
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -5806,7 +5849,7 @@
     boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
         WindowState newFocus = mRoot.computeFocusedWindow();
         if (mCurrentFocus != newFocus) {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
             // This check makes sure that we don't already have the focus
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
@@ -5882,7 +5925,7 @@
             // other apps' UI.
             displayContent.scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);
 
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index edbdf8b..27927e6 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -33,6 +34,7 @@
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.Debug;
+import android.os.Trace;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -101,8 +103,10 @@
             mSurfaceControl = new SurfaceTrace(
                     s, name, w, h, format, flags, windowType, ownerUid);
         } else {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
             mSurfaceControl = new SurfaceControl(
                     s, name, w, h, format, flags, windowType, ownerUid);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
         if (mService.mRoot.mSurfaceTraceEnabled) {
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index bfc2d72..24e7bff 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -810,6 +810,12 @@
 
     /** {@hide} */
     @Override
+    public boolean canLoadUnsafeResources() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
     public IBinder getActivityToken() {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 281223e..0c45cf1 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -235,32 +235,51 @@
         mIntents.remove(bcast);
     }
 
-    @Test
-    public void failingLocalOnlyHotspotLegacyApBroadcast() throws Exception {
+    public void failingLocalOnlyHotspotLegacyApBroadcast(
+            boolean emulateInterfaceStatusChanged) throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
 
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
-        mTethering.interfaceStatusChanged(mTestIfname, true);
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(mTestIfname, true);
+        }
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        // If, and only if, Tethering received an interface status changed
+        // then it creates a TetherInterfaceStateMachine and sends out a
+        // broadcast indicating that the interface is "available".
+        if (emulateInterfaceStatusChanged) {
+            verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
+            verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        }
         verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
         verifyNoMoreInteractions(mWifiManager);
     }
 
     @Test
-    public void workingLocalOnlyHotspotEnrichedApBroadcast() throws Exception {
+    public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
+        failingLocalOnlyHotspotLegacyApBroadcast(true);
+    }
+
+    @Test
+    public void failingLocalOnlyHotspotLegacyApBroadcastSansIfaceStatusChanged() throws Exception {
+        failingLocalOnlyHotspotLegacyApBroadcast(false);
+    }
+
+    public void workingLocalOnlyHotspotEnrichedApBroadcast(
+            boolean emulateInterfaceStatusChanged) throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
 
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
-        mTethering.interfaceStatusChanged(mTestIfname, true);
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(mTestIfname, true);
+        }
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
         mLooper.dispatchAll();
 
@@ -305,6 +324,17 @@
     }
 
     @Test
+    public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
+        workingLocalOnlyHotspotEnrichedApBroadcast(true);
+    }
+
+    @Test
+    public void workingLocalOnlyHotspotEnrichedApBroadcastSansIfaceChanged() throws Exception {
+        workingLocalOnlyHotspotEnrichedApBroadcast(false);
+    }
+
+    // TODO: Test with and without interfaceStatusChanged().
+    @Test
     public void failingWifiTetheringLegacyApBroadcast() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
@@ -331,6 +361,7 @@
         verifyNoMoreInteractions(mWifiManager);
     }
 
+    // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
@@ -412,6 +443,7 @@
                 mTethering.getLastTetherError(mTestIfname));
     }
 
+    // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void failureEnablingIpForwarding() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 8bd924e..1fc5d72 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -2008,6 +2008,11 @@
         return false;
     }
 
+    @Override
+    public boolean canLoadUnsafeResources() {
+        return false;
+    }
+
     /**
      * The cached value depends on
      * <ol>
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 18f30f8..bb3af3c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -156,9 +156,20 @@
 
     }
 
-    /** Copy constructor */
-    public WifiEnterpriseConfig(WifiEnterpriseConfig source) {
+    /**
+     * Copy over the contents of the source WifiEnterpriseConfig object over to this object.
+     *
+     * @param source Source WifiEnterpriseConfig object.
+     * @param ignoreMaskedPassword Set to true to ignore masked password field, false otherwise.
+     * @param mask if |ignoreMaskedPassword| is set, check if the incoming password field is set
+     *             to this value.
+     */
+    private void copyFrom(WifiEnterpriseConfig source, boolean ignoreMaskedPassword, String mask) {
         for (String key : source.mFields.keySet()) {
+            if (ignoreMaskedPassword && key.equals(PASSWORD_KEY)
+                    && TextUtils.equals(source.mFields.get(key), mask)) {
+                continue;
+            }
             mFields.put(key, source.mFields.get(key));
         }
         if (source.mCaCerts != null) {
@@ -178,6 +189,29 @@
         mPhase2Method = source.mPhase2Method;
     }
 
+    /**
+     * Copy constructor.
+     * This copies over all the fields verbatim (does not ignore masked password fields).
+     *
+     * @param source Source WifiEnterpriseConfig object.
+     */
+    public WifiEnterpriseConfig(WifiEnterpriseConfig source) {
+        copyFrom(source, false, "");
+    }
+
+    /**
+     * Copy fields from the provided external WifiEnterpriseConfig.
+     * This is needed to handle the WifiEnterpriseConfig objects which were sent by apps with the
+     * password field masked.
+     *
+     * @param externalConfig External WifiEnterpriseConfig object.
+     * @param mask String mask to compare against.
+     * @hide
+     */
+    public void copyFromExternal(WifiEnterpriseConfig externalConfig, String mask) {
+        copyFrom(externalConfig, true, convertToQuotedString(mask));
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index d0aedba..1a7dd13 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -316,15 +317,37 @@
         assertEquals("\"auth=AKA'\"", getSupplicantPhase2Method());
     }
 
-    /** Verfies that the copy constructor preseves the inner method information. */
+    /**
+     * Verifies that the copy constructor preseves both the masked password and inner method
+     * information.
+     */
     @Test
     public void copyConstructor() {
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setPassword("*");
         enterpriseConfig.setEapMethod(Eap.TTLS);
         enterpriseConfig.setPhase2Method(Phase2.GTC);
         mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
         assertEquals("TTLS", getSupplicantEapMethod());
         assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+        assertEquals("*", mEnterpriseConfig.getPassword());
+    }
+
+    /**
+     * Verifies that the copy from external ignores masked passwords and preserves the
+     * inner method information.
+     */
+    @Test
+    public void copyFromExternal() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setPassword("*");
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        mEnterpriseConfig = new WifiEnterpriseConfig();
+        mEnterpriseConfig.copyFromExternal(enterpriseConfig, "*");
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+        assertNotEquals("*", mEnterpriseConfig.getPassword());
     }
 
     /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */