Merge "Fix anchor overlap handling in ListPopupWindow" into oc-dev
diff --git a/Android.mk b/Android.mk
index ee7d471..01fb73e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -224,6 +224,7 @@
 	core/java/android/net/IEthernetManager.aidl \
 	core/java/android/net/IEthernetServiceListener.aidl \
 	core/java/android/net/INetdEventCallback.aidl \
+	core/java/android/net/IIpSecService.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
 	core/java/android/net/INetworkPolicyListener.aidl \
 	core/java/android/net/INetworkPolicyManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index c5f4816..48f57b4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4771,7 +4771,7 @@
     method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
     method public abstract int getBackStackEntryCount();
     method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
-    method public abstract java.util.Collection<android.app.Fragment> getFragments();
+    method public abstract java.util.List<android.app.Fragment> getFragments();
     method public abstract android.app.Fragment getPrimaryNavigationFragment();
     method public void invalidateOptionsMenu();
     method public abstract boolean isDestroyed();
@@ -25557,7 +25557,7 @@
     method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
     method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
     field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
@@ -25591,7 +25591,6 @@
     method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
-    method public android.net.IpSecTransform.Builder setSpi(int, int);
     method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
   }
 
@@ -37052,7 +37051,7 @@
     ctor public FillResponse.Builder();
     method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
     method public android.service.autofill.FillResponse build();
-    method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
+    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
     method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
@@ -37068,8 +37067,10 @@
     field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
     field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
     field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+    field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5; // 0x5
     field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
     field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+    field public static final int SAVE_DATA_TYPE_USERNAME = 4; // 0x4
   }
 
   public static final class SaveInfo.Builder {
diff --git a/api/system-current.txt b/api/system-current.txt
index 9b295bf..bc063b5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4931,7 +4931,7 @@
     method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
     method public abstract int getBackStackEntryCount();
     method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
-    method public abstract java.util.Collection<android.app.Fragment> getFragments();
+    method public abstract java.util.List<android.app.Fragment> getFragments();
     method public abstract android.app.Fragment getPrimaryNavigationFragment();
     method public void invalidateOptionsMenu();
     method public abstract boolean isDestroyed();
@@ -27718,13 +27718,11 @@
   public final class IpSecManager {
     method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
     method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
     method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
     method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public void removeTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
     field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
@@ -27755,12 +27753,10 @@
   public static class IpSecTransform.Builder {
     ctor public IpSecTransform.Builder(android.content.Context);
     method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method public android.net.IpSecTransform buildTunnelModeTransform(java.net.InetAddress, java.net.InetAddress);
     method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
     method public android.net.IpSecTransform.Builder setNattKeepalive(int);
-    method public android.net.IpSecTransform.Builder setSpi(int, int);
     method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
     method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
   }
@@ -40117,7 +40113,7 @@
     ctor public FillResponse.Builder();
     method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
     method public android.service.autofill.FillResponse build();
-    method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
+    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
     method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
@@ -40133,8 +40129,10 @@
     field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
     field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
     field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+    field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5; // 0x5
     field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
     field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+    field public static final int SAVE_DATA_TYPE_USERNAME = 4; // 0x4
   }
 
   public static final class SaveInfo.Builder {
diff --git a/api/test-current.txt b/api/test-current.txt
index 6db91be..8ea1dde 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4783,7 +4783,7 @@
     method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
     method public abstract int getBackStackEntryCount();
     method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
-    method public abstract java.util.Collection<android.app.Fragment> getFragments();
+    method public abstract java.util.List<android.app.Fragment> getFragments();
     method public abstract android.app.Fragment getPrimaryNavigationFragment();
     method public void invalidateOptionsMenu();
     method public abstract boolean isDestroyed();
@@ -25670,7 +25670,7 @@
     method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
     method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
     field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
@@ -25704,7 +25704,6 @@
     method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
-    method public android.net.IpSecTransform.Builder setSpi(int, int);
     method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
   }
 
@@ -37210,7 +37209,7 @@
     ctor public FillResponse.Builder();
     method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
     method public android.service.autofill.FillResponse build();
-    method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
+    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
     method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
@@ -37226,8 +37225,10 @@
     field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
     field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
     field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+    field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5; // 0x5
     field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
     field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+    field public static final int SAVE_DATA_TYPE_USERNAME = 4; // 0x4
   }
 
   public static final class SaveInfo.Builder {
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 35011b5..8442585 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -40,8 +40,8 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -98,11 +98,10 @@
             "alwaysPromptForAccount";
 
     /**
-     * If set then this string willb e used as the description rather than
+     * If set then this string will be used as the description rather than
      * the default.
      */
-    public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =
-            "descriptionTextOverride";
+    public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE = "descriptionTextOverride";
 
     public static final int REQUEST_NULL = 0;
     public static final int REQUEST_CHOOSE_TYPE = 1;
@@ -112,7 +111,8 @@
     private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
     private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
     private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
-    private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountAndVisibilityList";
+    private static final String KEY_INSTANCE_STATE_ACCOUNTS_LIST = "accountsList";
+    private static final String KEY_INSTANCE_STATE_VISIBILITY_LIST = "visibilityList";
 
     private static final int SELECTED_ITEM_NONE = -1;
 
@@ -122,7 +122,7 @@
     private boolean mSelectedAddNewAccount = false;
     private String mDescriptionOverride;
 
-    private Map<Account, Integer> mAccounts;
+    private LinkedHashMap<Account, Integer> mAccounts;
     // TODO Redesign flow to show NOT_VISIBLE accounts
     // and display a warning if they are selected.
     // Currently NOT_VISBILE accounts are not shown at all.
@@ -164,6 +164,10 @@
         // save some items we use frequently
         final Intent intent = getIntent();
 
+        mSetOfAllowableAccounts = getAllowableAccountSet(intent);
+        mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
+        mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
+
         if (savedInstanceState != null) {
             mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
             mExistingAccounts =
@@ -174,8 +178,15 @@
                     savedInstanceState.getString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
             mSelectedAddNewAccount =
                     savedInstanceState.getBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
-            mAccounts = (Map<Account, Integer>) savedInstanceState
-                    .getSerializable(KEY_INSTANCE_STATE_ACCOUNT_LIST);
+            // restore mAccounts
+            Parcelable[] accounts =
+                savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_ACCOUNTS_LIST);
+            ArrayList<Integer> visibility =
+                savedInstanceState.getIntegerArrayList(KEY_INSTANCE_STATE_VISIBILITY_LIST);
+            mAccounts = new LinkedHashMap<>();
+            for (int i = 0; i < accounts.length; i++) {
+                mAccounts.put((Account) accounts[i], visibility.get(i));
+            }
         } else {
             mPendingRequest = REQUEST_NULL;
             mExistingAccounts = null;
@@ -185,20 +196,21 @@
             if (selectedAccount != null) {
                 mSelectedAccountName = selectedAccount.name;
             }
+            mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
         }
 
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "selected account name is " + mSelectedAccountName);
         }
 
+        mPossiblyVisibleAccounts = new ArrayList<>(mAccounts.size());
+        for (Map.Entry<Account, Integer> entry : mAccounts.entrySet()) {
+            if (AccountManager.VISIBILITY_NOT_VISIBLE != entry.getValue()) {
+                mPossiblyVisibleAccounts.add(entry.getKey());
+            }
+        }
 
-        mSetOfAllowableAccounts = getAllowableAccountSet(intent);
-        mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
-        mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
-
-        mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
-        if (mAccounts.isEmpty()
-                && mDisallowAddAccounts) {
+        if (mPossiblyVisibleAccounts.isEmpty() && mDisallowAddAccounts) {
             requestWindowFeature(Window.FEATURE_NO_TITLE);
             setContentView(R.layout.app_not_authorized);
             mDontShowPicker = true;
@@ -216,7 +228,7 @@
         if (mPendingRequest == REQUEST_NULL) {
             // If there are no relevant accounts and only one relevant account type go directly to
             // add account. Otherwise let the user choose.
-            if (mAccounts.isEmpty()) {
+            if (mPossiblyVisibleAccounts.isEmpty()) {
                 setNonLabelThemeAndCallSuperCreate(savedInstanceState);
                 if (mSetOfRelevantAccountTypes.size() == 1) {
                     runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
@@ -226,12 +238,6 @@
             }
         }
 
-        mPossiblyVisibleAccounts = new ArrayList<>(mAccounts.size());
-        for (Map.Entry<Account, Integer> entry : mAccounts.entrySet()) {
-            if (AccountManager.VISIBILITY_NOT_VISIBLE != entry.getValue()) {
-                mPossiblyVisibleAccounts.add(entry.getKey());
-            }
-        }
         String[] listItems = getListOfDisplayableOptions(mPossiblyVisibleAccounts);
         mSelectedItemIndex = getItemIndexToSelect(mPossiblyVisibleAccounts, mSelectedAccountName,
                 mSelectedAddNewAccount);
@@ -270,10 +276,16 @@
                         mPossiblyVisibleAccounts.get(mSelectedItemIndex).name);
             }
         }
-        // should be HashMap by default.
-        HashMap<Account, Integer> accountsHashMap = (mAccounts instanceof HashMap)
-                ? (HashMap) mAccounts : new HashMap<Account, Integer>(mAccounts);
-        outState.putSerializable(KEY_INSTANCE_STATE_ACCOUNT_LIST, accountsHashMap);
+        // save mAccounts
+        Parcelable[] accounts = new Parcelable[mAccounts.size()];
+        ArrayList<Integer> visibility = new ArrayList<>(mAccounts.size());
+        int i = 0;
+        for (Map.Entry<Account, Integer> e : mAccounts.entrySet()) {
+            accounts[i++] = e.getKey();
+            visibility.add(e.getValue());
+        }
+        outState.putParcelableArray(KEY_INSTANCE_STATE_ACCOUNTS_LIST, accounts);
+        outState.putIntegerArrayList(KEY_INSTANCE_STATE_VISIBILITY_LIST, visibility);
     }
 
     public void onCancelButtonClicked(View view) {
@@ -308,7 +320,7 @@
         if (resultCode == RESULT_CANCELED) {
             // if canceling out of addAccount and the original state caused us to skip this,
             // finish this activity
-            if (mAccounts.isEmpty()) {
+            if (mPossiblyVisibleAccounts.isEmpty()) {
                 setResult(Activity.RESULT_CANCELED);
                 finish();
             }
@@ -428,18 +440,20 @@
     private void setResultAndFinish(final String accountName, final String accountType) {
         // Mark account as visible since user chose it.
         Account account = new Account(accountName, accountType);
-        Integer oldVisibility = mAccounts.get(account);
-        // oldVisibility is null if new account was added
-        if (oldVisibility == null) {
-            Map<Account, Integer> accountsAndVisibility = AccountManager.get(this)
-                    .getAccountsAndVisibilityForPackage(mCallingPackage, null /* type */);
-            oldVisibility = accountsAndVisibility.get(account);
-        }
+        Integer oldVisibility =
+            AccountManager.get(this).getAccountVisibility(account, mCallingPackage);
         if (oldVisibility != null
                 && oldVisibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) {
             AccountManager.get(this).setAccountVisibility(account, mCallingPackage,
                     AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
         }
+
+        if (oldVisibility != null && oldVisibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
+            // Added account is not visible to caller.
+            setResult(Activity.RESULT_CANCELED);
+            finish();
+            return;
+        }
         Bundle bundle = new Bundle();
         bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
         bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
@@ -448,6 +462,7 @@
             Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: selected account "
                     + accountName + ", " + accountType);
         }
+
         finish();
     }
 
@@ -509,22 +524,24 @@
      * that don't match the allowable types, if provided, or that don't match the allowable
      * accounts, if provided.
      */
-    private Map<Account, Integer> getAcceptableAccountChoices(AccountManager accountManager) {
-        Map<Account, Integer> accountsAndVisibility =
-                accountManager.getAccountsAndVisibilityForPackage(mCallingPackage, null /* type */);
-
-        Map<Account, Integer> accountsToPopulate =
-                new HashMap<Account, Integer>(accountsAndVisibility.size());
-        for (Map.Entry<Account, Integer> entry : accountsAndVisibility.entrySet()) {
+    private LinkedHashMap<Account, Integer> getAcceptableAccountChoices(AccountManager accountManager) {
+        Map<Account, Integer> accountsAndVisibilityForCaller =
+                accountManager.getAccountsAndVisibilityForPackage(mCallingPackage, null);
+        Account[] allAccounts = accountManager.getAccounts();
+        LinkedHashMap<Account, Integer> accountsToPopulate =
+                new LinkedHashMap<>(accountsAndVisibilityForCaller.size());
+        for (Account account : allAccounts) {
             if (mSetOfAllowableAccounts != null
-                    && !mSetOfAllowableAccounts.contains(entry.getKey())) {
+                    && !mSetOfAllowableAccounts.contains(account)) {
                 continue;
             }
             if (mSetOfRelevantAccountTypes != null
-                    && !mSetOfRelevantAccountTypes.contains(entry.getKey().type)) {
+                    && !mSetOfRelevantAccountTypes.contains(account.type)) {
                 continue;
             }
-            accountsToPopulate.put(entry.getKey(), entry.getValue());
+            if (accountsAndVisibilityForCaller.get(account) != null) {
+                accountsToPopulate.put(account, accountsAndVisibilityForCaller.get(account));
+            }
         }
         return accountsToPopulate;
     }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 3102a93..a3c123f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -2608,6 +2608,12 @@
         }
     }
 
+    void noteStateNotSaved() {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+        }
+    }
+
     @Deprecated
     void performMultiWindowModeChanged(boolean isInMultiWindowMode) {
         onMultiWindowModeChanged(isInMultiWindowMode);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 399987f..75d6295 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -314,14 +314,17 @@
     public abstract Fragment getFragment(Bundle bundle, String key);
 
     /**
-     * Get a collection of all fragments that are currently added to the FragmentManager.
+     * Get a list of all fragments that are currently added to the FragmentManager.
      * This may include those that are hidden as well as those that are shown.
      * This will not include any fragments only in the back stack, or fragments that
      * are detached or removed.
+     * <p>
+     * The order of the fragments in the list is the order in which they were
+     * added or attached.
      *
-     * @return A collection of all fragments that are added to the FragmentManager.
+     * @return A list of all fragments that are added to the FragmentManager.
      */
-    public abstract Collection<Fragment> getFragments();
+    public abstract List<Fragment> getFragments();
 
     /**
      * Save the current instance state of the given Fragment.  This can be
@@ -695,6 +698,9 @@
     // This is dangerous, but we want to keep from breaking old applications.
     boolean mAllowOldReentrantBehavior;
 
+    // Saved FragmentManagerNonConfig during saveAllState() and cleared in noteStateNotSaved()
+    FragmentManagerNonConfig mSavedNonConfig;
+
     Runnable mExecCommit = new Runnable() {
         @Override
         public void run() {
@@ -907,12 +913,12 @@
     }
 
     @Override
-    public Collection<Fragment> getFragments() {
+    public List<Fragment> getFragments() {
         if (mAdded == null) {
             return Collections.EMPTY_LIST;
         }
         synchronized (mAdded) {
-            return (Collection<Fragment>) mAdded.clone();
+            return (List<Fragment>) mAdded.clone();
         }
     }
 
@@ -2518,6 +2524,35 @@
     }
 
     FragmentManagerNonConfig retainNonConfig() {
+        setRetaining(mSavedNonConfig);
+        return mSavedNonConfig;
+    }
+
+    /**
+     * Recurse the FragmentManagerNonConfig fragments and set the mRetaining to true. This
+     * was previously done while saving the non-config state, but that has been moved to
+     * {@link #saveNonConfig()} called from {@link #saveAllState()}. If mRetaining is set too
+     * early, the fragment won't be destroyed when the FragmentManager is destroyed.
+     */
+    private static void setRetaining(FragmentManagerNonConfig nonConfig) {
+        if (nonConfig == null) {
+            return;
+        }
+        List<Fragment> fragments = nonConfig.getFragments();
+        if (fragments != null) {
+            for (Fragment fragment : fragments) {
+                fragment.mRetaining = true;
+            }
+        }
+        List<FragmentManagerNonConfig> children = nonConfig.getChildNonConfigs();
+        if (children != null) {
+            for (FragmentManagerNonConfig child : children) {
+                setRetaining(child);
+            }
+        }
+    }
+
+    void saveNonConfig() {
         ArrayList<Fragment> fragments = null;
         ArrayList<FragmentManagerNonConfig> childFragments = null;
         if (mActive != null) {
@@ -2529,13 +2564,13 @@
                             fragments = new ArrayList<>();
                         }
                         fragments.add(f);
-                        f.mRetaining = true;
                         f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
                         if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
                     }
                     boolean addedChild = false;
                     if (f.mChildFragmentManager != null) {
-                        FragmentManagerNonConfig child = f.mChildFragmentManager.retainNonConfig();
+                        f.mChildFragmentManager.saveNonConfig();
+                        FragmentManagerNonConfig child = f.mChildFragmentManager.mSavedNonConfig;
                         if (child != null) {
                             if (childFragments == null) {
                                 childFragments = new ArrayList<>();
@@ -2554,9 +2589,10 @@
             }
         }
         if (fragments == null && childFragments == null) {
-            return null;
+            mSavedNonConfig = null;
+        } else {
+            mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments);
         }
-        return new FragmentManagerNonConfig(fragments, childFragments);
     }
     
     void saveFragmentViewState(Fragment f) {
@@ -2617,6 +2653,7 @@
         execPendingActions();
 
         mStateSaved = true;
+        mSavedNonConfig = null;
 
         if (mActive == null || mActive.size() <= 0) {
             return null;
@@ -2717,6 +2754,7 @@
         if (mPrimaryNav != null) {
             fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
         }
+        saveNonConfig();
         return fms;
     }
     
@@ -2892,9 +2930,17 @@
     }
 
     public void noteStateNotSaved() {
+        mSavedNonConfig = null;
         mStateSaved = false;
+        final int addedCount = mAdded == null ? 0 : mAdded.size();
+        for (int i = 0; i < addedCount; i++) {
+            Fragment fragment = mAdded.get(i);
+            if (fragment != null) {
+                fragment.noteStateNotSaved();
+            }
+        }
     }
-    
+
     public void dispatchCreate() {
         mStateSaved = false;
         dispatchMoveToState(Fragment.CREATED);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6b05bdf..4572578 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -74,7 +74,9 @@
 import android.net.EthernetManager;
 import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
+import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
 import android.net.nsd.INsdManager;
@@ -261,6 +263,15 @@
                 return new ConnectivityManager(context, service);
             }});
 
+        registerService(Context.IPSEC_SERVICE, IpSecManager.class,
+                new StaticServiceFetcher<IpSecManager>() {
+            @Override
+            public IpSecManager createService() {
+                IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
+                IIpSecService service = IIpSecService.Stub.asInterface(b);
+                return new IpSecManager(service);
+            }});
+
         registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
                 new StaticServiceFetcher<CountryDetector>() {
             @Override
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index fe51633..545aef5 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -599,6 +599,10 @@
         boolean mSanitized;
         HtmlInfo mHtmlInfo;
 
+        // POJO used to override some autofill-related values when the node is parcelized.
+        // Not written to parcel.
+        AutofillOverlay mAutofillOverlay;
+
         int mX;
         int mY;
         int mScrollX;
@@ -756,6 +760,7 @@
             boolean writeSensitive = true;
 
             int flags = mFlags & ~FLAGS_ALL_CONTROL;
+
             if (mId != View.NO_ID) {
                 flags |= FLAGS_HAS_ID;
             }
@@ -810,6 +815,13 @@
                 // Remove 'checked' from sanitized autofill request.
                 writtenFlags = flags & ~FLAGS_CHECKED;
             }
+            if (mAutofillOverlay != null) {
+                if (mAutofillOverlay.focused) {
+                    writtenFlags |= ViewNode.FLAGS_FOCUSED;
+                } else {
+                    writtenFlags &= ~ViewNode.FLAGS_FOCUSED;
+                }
+            }
 
             out.writeInt(writtenFlags);
             if ((flags&FLAGS_HAS_ID) != 0) {
@@ -829,7 +841,14 @@
                 out.writeParcelable(mAutofillId, 0);
                 out.writeInt(mAutofillType);
                 out.writeStringArray(mAutofillHints);
-                final AutofillValue sanitizedValue = writeSensitive ? mAutofillValue : null;
+                final AutofillValue sanitizedValue;
+                if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
+                    sanitizedValue = mAutofillOverlay.value;
+                } else if (writeSensitive) {
+                    sanitizedValue = mAutofillValue;
+                } else {
+                    sanitizedValue = null;
+                }
                 out.writeParcelable(sanitizedValue,  0);
                 out.writeStringArray(mAutofillOptions);
                 if (mHtmlInfo instanceof Parcelable) {
@@ -959,6 +978,11 @@
             return mAutofillValue;
         }
 
+        /** @hide **/
+        public void setAutofillOverlay(AutofillOverlay overlay) {
+            mAutofillOverlay = overlay;
+        }
+
         /**
          * Gets the options that can be used to autofill this structure.
          *
@@ -1340,6 +1364,16 @@
         }
     }
 
+    /**
+     * POJO used to override some autofill-related values when the node is parcelized.
+     *
+     * @hide
+     */
+    static public class AutofillOverlay {
+        public boolean focused;
+        public AutofillValue value;
+    }
+
     static class ViewNodeBuilder extends ViewStructure {
         final AssistStructure mAssist;
         final ViewNode mNode;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9457d15..2dfb45f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6172,6 +6172,7 @@
             cpuAbiOverride = dest.readString();
             use32bitAbi = (dest.readInt() == 1);
             restrictUpdateHash = dest.createByteArray();
+            visibleToInstantApps = dest.readInt() == 1;
         }
 
         private static void internStringArrayList(List<String> list) {
@@ -6286,6 +6287,7 @@
             dest.writeString(cpuAbiOverride);
             dest.writeInt(use32bitAbi ? 1 : 0);
             dest.writeByteArray(restrictUpdateHash);
+            dest.writeInt(visibleToInstantApps ? 1 : 0);
         }
 
 
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 572a287..ea1d01b 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -131,6 +131,64 @@
      */
     public static final int TYPE_SAMPLING = 0x10004;
 
+    /**
+     * Local geo-magnetic Field.
+     *
+     * Additional into to sensor hardware.  Local geomagnetic field information based on
+     * device geo location. This type is primarily for for magnetic field calibration and rotation
+     * vector sensor fusion.
+     *
+     * float[3]: strength (uT), declination and inclination angle (rad).
+     * @hide
+     */
+    public static final int TYPE_LOCAL_GEOMAGNETIC_FIELD = 0x30000;
+
+    /**
+     * Local gravity acceleration strength.
+     *
+     * Additional info to sensor hardware for accelerometer calibration.
+     *
+     * float: gravitational acceleration norm in m/s^2.
+     * @hide
+     */
+    public static final int TYPE_LOCAL_GRAVITY = 0x30001;
+
+    /**
+     * Device dock state.
+     *
+     * Additional info to sensor hardware indicating dock states of device.
+     *
+     * int32_t: dock state following definition of {@link android.content.Intent#EXTRA_DOCK_STATE}.
+     *          Undefined values are ignored.
+     * @hide
+     */
+    public static final int TYPE_DOCK_STATE = 0x30002;
+
+    /**
+     * High performance mode.
+     *
+     * Additional info to sensor hardware. Device is able to use up more power and take more
+     * resources to improve throughput and latency in high performance mode. One possible use case
+     * is virtual reality, when sensor latency need to be carefully controlled.
+     *
+     * int32_t: 1 or 0, denoting device is in or out of high performance mode, respectively.
+     *          Other values are ignored.
+     * @hide
+     */
+    public static final int TYPE_HIGH_PERFORMANCE_MODE = 0x30003;
+
+    /**
+     * Magnetic field calibration hint.
+     *
+     * Additional info to sensor hardware. Device is notified when manually triggered magnetic field
+     * calibration procedure is started or stopped. The calibration procedure is assumed timed out
+     * after 1 minute from start, even if an explicit stop is not received.
+     *
+     * int32_t: 1 for calibration start, 0 for stop, other values are ignored.
+     * @hide
+     */
+    public static final int TYPE_MAGNETIC_FIELD_CALIBRATION = 0x30004;
+
     SensorAdditionalInfo(
             Sensor aSensor, int aType, int aSerial, int [] aIntValues, float [] aFloatValues) {
         sensor = aSensor;
@@ -139,4 +197,18 @@
         intValues = aIntValues;
         floatValues = aFloatValues;
     }
+
+    /** @hide */
+    public static SensorAdditionalInfo createLocalGeomagneticField(
+            float strength, float declination, float inclination) {
+        if (strength < 10 || strength > 100 // much beyond extreme values on earth
+                || declination < 0 || declination > Math.PI
+                || inclination < -Math.PI / 2 || inclination > Math.PI / 2) {
+            throw new IllegalArgumentException("Geomagnetic field info out of range");
+        }
+
+        return new SensorAdditionalInfo(
+                null, TYPE_LOCAL_GEOMAGNETIC_FIELD, 0,
+                null, new float[] { strength, declination, inclination});
+    }
 }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index a6930b0..1dc6478 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1927,4 +1927,12 @@
         }
         return delay;
     }
+
+    /** @hide */
+    public boolean setOperationParameter(SensorAdditionalInfo parameter) {
+        return setOperationParameterImpl(parameter);
+    }
+
+    /** @hide */
+    protected abstract boolean setOperationParameterImpl(SensorAdditionalInfo parameter);
 }
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 7029847..0677179 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -67,6 +67,9 @@
     private static native int nativeConfigDirectChannel(
             long nativeInstance, int channelHandle, int sensorHandle, int rate);
 
+    private static native int nativeSetOperationParameter(
+            long nativeInstance, int type, float[] floatValues, int[] intValues);
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static boolean sNativeClassInited = false;
@@ -928,4 +931,9 @@
 
         }
     }
+
+    protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
+        return nativeSetOperationParameter(
+                mNativeInstance, parameter.type, parameter.floatValues, parameter.intValues) == 0;
+    }
 }
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
new file mode 100644
index 0000000..0aa3ce6
--- /dev/null
+++ b/core/java/android/net/IIpSecService.aidl
@@ -0,0 +1,46 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+import android.net.Network;
+import android.net.IpSecConfig;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IIpSecService
+{
+    Bundle reserveSecurityParameterIndex(
+            int direction, in String remoteAddress, int requestedSpi, in IBinder binder);
+
+    void releaseSecurityParameterIndex(int resourceId);
+
+    Bundle openUdpEncapsulationSocket(int port, in IBinder binder);
+
+    void closeUdpEncapsulationSocket(in ParcelFileDescriptor socket);
+
+    Bundle createTransportModeTransform(in IpSecConfig c, in IBinder binder);
+
+    void deleteTransportModeTransform(int transformId);
+
+    void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId);
+
+    void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId);
+}
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index da5cb37..7fea4a2 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -164,6 +164,8 @@
 
     private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
         switch (algo) {
+            case ALGO_CRYPT_AES_CBC:
+                return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256);
             case ALGO_AUTH_HMAC_MD5:
                 return (truncLenBits >= 96 && truncLenBits <= 128);
             case ALGO_AUTH_HMAC_SHA1:
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index b58bf42..13dc19f 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -23,7 +23,7 @@
 
 /** @hide */
 public final class IpSecConfig implements Parcelable {
-    private static final String TAG = IpSecConfig.class.getSimpleName();
+    private static final String TAG = "IpSecConfig";
 
     //MODE_TRANSPORT or MODE_TUNNEL
     int mode;
@@ -43,13 +43,13 @@
         int spi;
 
         // Encryption Algorithm
-        IpSecAlgorithm encryptionAlgo;
+        IpSecAlgorithm encryption;
 
         // Authentication Algorithm
-        IpSecAlgorithm authenticationAlgo;
+        IpSecAlgorithm authentication;
     }
 
-    Flow[] flow = new Flow[2];
+    Flow[] flow = new Flow[] {new Flow(), new Flow()};
 
     // For tunnel mode IPv4 UDP Encapsulation
     // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
@@ -57,17 +57,15 @@
     int encapLocalPort;
     int encapRemotePort;
 
-    // An optional protocol to match with the selector
-    int selectorProto;
-
-    // A bitmask of FEATURE_* indicating which of the fields
-    // of this class are valid.
-    long features;
-
     // An interval, in seconds between the NattKeepalive packets
     int nattKeepaliveInterval;
 
-    public InetAddress getLocalIp() {
+    // Transport or Tunnel
+    public int getMode() {
+        return mode;
+    }
+
+    public InetAddress getLocalAddress() {
         return localAddress;
     }
 
@@ -75,19 +73,19 @@
         return flow[direction].spi;
     }
 
-    public InetAddress getRemoteIp() {
+    public InetAddress getRemoteAddress() {
         return remoteAddress;
     }
 
-    public IpSecAlgorithm getEncryptionAlgo(int direction) {
-        return flow[direction].encryptionAlgo;
+    public IpSecAlgorithm getEncryption(int direction) {
+        return flow[direction].encryption;
     }
 
-    public IpSecAlgorithm getAuthenticationAlgo(int direction) {
-        return flow[direction].authenticationAlgo;
+    public IpSecAlgorithm getAuthentication(int direction) {
+        return flow[direction].authentication;
     }
 
-    Network getNetwork() {
+    public Network getNetwork() {
         return network;
     }
 
@@ -103,18 +101,10 @@
         return encapRemotePort;
     }
 
-    public int getSelectorProto() {
-        return selectorProto;
-    }
-
-    int getNattKeepaliveInterval() {
+    public int getNattKeepaliveInterval() {
         return nattKeepaliveInterval;
     }
 
-    public boolean hasProperty(int featureBits) {
-        return (features & featureBits) == featureBits;
-    }
-
     // Parcelable Methods
 
     @Override
@@ -124,31 +114,25 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeLong(features);
         // TODO: Use a byte array or other better method for storing IPs that can also include scope
         out.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
         // TODO: Use a byte array or other better method for storing IPs that can also include scope
         out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
         out.writeParcelable(network, flags);
         out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi);
-        out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags);
-        out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags);
+        out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags);
+        out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags);
         out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi);
-        out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags);
-        out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags);
+        out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags);
+        out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags);
         out.writeInt(encapType);
         out.writeInt(encapLocalPort);
         out.writeInt(encapRemotePort);
-        out.writeInt(selectorProto);
     }
 
     // Package Private: Used by the IpSecTransform.Builder;
     // there should be no public constructor for this object
-    IpSecConfig() {
-        flow[IpSecTransform.DIRECTION_IN].spi = 0;
-        flow[IpSecTransform.DIRECTION_OUT].spi = 0;
-        nattKeepaliveInterval = 0; //FIXME constant
-    }
+    IpSecConfig() {}
 
     private static InetAddress readInetAddressFromParcel(Parcel in) {
         String addrString = in.readString();
@@ -164,24 +148,22 @@
     }
 
     private IpSecConfig(Parcel in) {
-        features = in.readLong();
         localAddress = readInetAddressFromParcel(in);
         remoteAddress = readInetAddressFromParcel(in);
         network = (Network) in.readParcelable(Network.class.getClassLoader());
         flow[IpSecTransform.DIRECTION_IN].spi = in.readInt();
-        flow[IpSecTransform.DIRECTION_IN].encryptionAlgo =
+        flow[IpSecTransform.DIRECTION_IN].encryption =
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
-        flow[IpSecTransform.DIRECTION_IN].authenticationAlgo =
+        flow[IpSecTransform.DIRECTION_IN].authentication =
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt();
-        flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo =
+        flow[IpSecTransform.DIRECTION_OUT].encryption =
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
-        flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo =
+        flow[IpSecTransform.DIRECTION_OUT].authentication =
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         encapType = in.readInt();
         encapLocalPort = in.readInt();
         encapRemotePort = in.readInt();
-        selectorProto = in.readInt();
     }
 
     public static final Parcelable.Creator<IpSecConfig> CREATOR =
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 2c544e9..6852beb 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -17,10 +17,11 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.INetworkManagementService;
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.util.AndroidException;
 import dalvik.system.CloseGuard;
 import java.io.FileDescriptor;
@@ -41,6 +42,29 @@
     private static final String TAG = "IpSecManager";
 
     /**
+     * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+     *
+     * <p>No IPsec packet may contain an SPI of 0.
+     */
+    public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
+
+    /** @hide */
+    public interface Status {
+        public static final int OK = 0;
+        public static final int RESOURCE_UNAVAILABLE = 1;
+        public static final int SPI_UNAVAILABLE = 2;
+    }
+
+    /** @hide */
+    public static final String KEY_STATUS = "status";
+    /** @hide */
+    public static final String KEY_RESOURCE_ID = "resourceId";
+    /** @hide */
+    public static final String KEY_SPI = "spi";
+    /** @hide */
+    public static final int INVALID_RESOURCE_ID = 0;
+
+    /**
      * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
      * request. If encountered, selection of a new SPI is required before a transform may be
      * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
@@ -79,42 +103,30 @@
         }
     }
 
-    private final Context mContext;
-    private final INetworkManagementService mService;
+    private final IIpSecService mService;
 
     public static final class SecurityParameterIndex implements AutoCloseable {
-        private final Context mContext;
-        private final InetAddress mDestinationAddress;
+        private final IIpSecService mService;
+        private final InetAddress mRemoteAddress;
         private final CloseGuard mCloseGuard = CloseGuard.get();
-        private int mSpi;
+        private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
+        private int mResourceId;
 
         /** Return the underlying SPI held by this object */
         public int getSpi() {
             return mSpi;
         }
 
-        private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
-                throws ResourceUnavailableException, SpiUnavailableException {
-            mContext = context;
-            mDestinationAddress = destinationAddress;
-            mSpi = spi;
-            mCloseGuard.open("open");
-        }
-
         /**
          * Release an SPI that was previously reserved.
          *
-         * <p>Release an SPI for use by other users in the system. This will fail if the SPI is
-         * currently in use by an IpSecTransform.
-         *
-         * @param destinationAddress SPIs must be unique for each combination of SPI and destination
-         *     address. Thus, the destinationAddress to which the SPI will communicate must be
-         *     supplied.
-         * @param spi the previously reserved SPI to be freed.
+         * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
+         * applied to an IpSecTransform, it will become unusable for future transforms but should
+         * still be closed to ensure system resources are released.
          */
         @Override
         public void close() {
-            mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI
+            mSpi = INVALID_SECURITY_PARAMETER_INDEX;
             mCloseGuard.close();
         }
 
@@ -126,23 +138,61 @@
 
             close();
         }
+
+        private SecurityParameterIndex(
+                @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi)
+                throws ResourceUnavailableException, SpiUnavailableException {
+            mService = service;
+            mRemoteAddress = remoteAddress;
+            try {
+                Bundle result =
+                        mService.reserveSecurityParameterIndex(
+                                direction, remoteAddress.getHostAddress(), spi, new Binder());
+
+                if (result == null) {
+                    throw new NullPointerException("Received null response from IpSecService");
+                }
+
+                int status = result.getInt(KEY_STATUS);
+                switch (status) {
+                    case Status.OK:
+                        break;
+                    case Status.RESOURCE_UNAVAILABLE:
+                        throw new ResourceUnavailableException(
+                                "No more SPIs may be allocated by this requester.");
+                    case Status.SPI_UNAVAILABLE:
+                        throw new SpiUnavailableException("Requested SPI is unavailable", spi);
+                    default:
+                        throw new RuntimeException(
+                                "Unknown status returned by IpSecService: " + status);
+                }
+                mSpi = result.getInt(KEY_SPI);
+                mResourceId = result.getInt(KEY_RESOURCE_ID);
+
+                if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
+                    throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
+                }
+
+                if (mResourceId == INVALID_RESOURCE_ID) {
+                    throw new RuntimeException(
+                            "Invalid Resource ID returned by IpSecService: " + status);
+                }
+
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mCloseGuard.open("open");
+        }
     }
 
     /**
-     * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
-     *
-     * <p>No IPsec packet may contain an SPI of 0.
-     */
-    public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
-
-    /**
-     * Reserve an SPI for traffic bound towards the specified destination address.
+     * Reserve an SPI for traffic bound towards the specified remote address.
      *
      * <p>If successful, this SPI is guaranteed available until released by a call to {@link
      * SecurityParameterIndex#close()}.
      *
-     * @param destinationAddress SPIs must be unique for each combination of SPI and destination
-     *     address.
+     * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
+     * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
      * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
      * @return the reserved SecurityParameterIndex
      * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
@@ -150,9 +200,9 @@
      * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
      */
     public SecurityParameterIndex reserveSecurityParameterIndex(
-            InetAddress destinationAddress, int requestedSpi)
+            int direction, InetAddress remoteAddress, int requestedSpi)
             throws SpiUnavailableException, ResourceUnavailableException {
-        return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
+        return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi);
     }
 
     /**
@@ -190,7 +240,13 @@
     }
 
     /* Call down to activate a transform */
-    private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+    private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
+        try {
+            mService.applyTransportModeTransform(pfd, transform.getResourceId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
     /**
      * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
@@ -203,7 +259,6 @@
      * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
      * @hide
      */
-    @SystemApi
     public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
 
     /**
@@ -235,7 +290,13 @@
     }
 
     /* Call down to activate a transform */
-    private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+    private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
+        try {
+            mService.removeTransportModeTransform(pfd, transform.getResourceId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
     /**
      * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
@@ -248,7 +309,6 @@
      *     network
      * @hide
      */
-    @SystemApi
     public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
 
     /**
@@ -260,19 +320,19 @@
      */
     public static final class UdpEncapsulationSocket implements AutoCloseable {
         private final FileDescriptor mFd;
-        private final Context mContext;
+        private final IIpSecService mService;
         private final CloseGuard mCloseGuard = CloseGuard.get();
 
-        private UdpEncapsulationSocket(Context context, int port)
+        private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
                 throws ResourceUnavailableException {
-            mContext = context;
+            mService = service;
             mCloseGuard.open("constructor");
             // TODO: go down to the kernel and get a socket on the specified
             mFd = new FileDescriptor();
         }
 
-        private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
-            mContext = context;
+        private UdpEncapsulationSocket(IIpSecService service) throws ResourceUnavailableException {
+            mService = service;
             mCloseGuard.open("constructor");
             // TODO: go get a random socket on a random port
             mFd = new FileDescriptor();
@@ -339,7 +399,7 @@
     public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
             throws IOException, ResourceUnavailableException {
         // Temporary code
-        return new UdpEncapsulationSocket(mContext, port);
+        return new UdpEncapsulationSocket(mService, port);
     }
 
     /**
@@ -363,7 +423,7 @@
     public UdpEncapsulationSocket openUdpEncapsulationSocket()
             throws IOException, ResourceUnavailableException {
         // Temporary code
-        return new UdpEncapsulationSocket(mContext);
+        return new UdpEncapsulationSocket(mService);
     }
 
     /**
@@ -372,8 +432,7 @@
      * @param context the application context for this manager
      * @hide
      */
-    public IpSecManager(Context context, INetworkManagementService service) {
-        mContext = checkNotNull(context, "missing context");
+    public IpSecManager(IIpSecService service) {
         mService = checkNotNull(service, "missing service");
     }
 }
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index d6dd28be..801e98c 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -15,11 +15,21 @@
  */
 package android.net;
 
+import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_STATUS;
+
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.system.ErrnoException;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
+import com.android.internal.util.Preconditions;
 import dalvik.system.CloseGuard;
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -86,39 +96,64 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface EncapType {}
 
-    /**
-     * Sentinel for an invalid transform (means that this transform is inactive).
-     *
-     * @hide
-     */
-    public static final int INVALID_TRANSFORM_ID = -1;
-
     private IpSecTransform(Context context, IpSecConfig config) {
         mContext = context;
         mConfig = config;
-        mTransformId = INVALID_TRANSFORM_ID;
+        mResourceId = INVALID_RESOURCE_ID;
+    }
+
+    private IIpSecService getIpSecService() {
+        IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE);
+        if (b == null) {
+            throw new RemoteException("Failed to connect to IpSecService")
+                    .rethrowAsRuntimeException();
+        }
+
+        return IIpSecService.Stub.asInterface(b);
+    }
+
+    private void checkResultStatusAndThrow(int status)
+            throws IOException, IpSecManager.ResourceUnavailableException,
+                    IpSecManager.SpiUnavailableException {
+        switch (status) {
+            case IpSecManager.Status.OK:
+                return;
+                // TODO: Pass Error string back from bundle so that errors can be more specific
+            case IpSecManager.Status.RESOURCE_UNAVAILABLE:
+                throw new IpSecManager.ResourceUnavailableException(
+                        "Failed to allocate a new IpSecTransform");
+            case IpSecManager.Status.SPI_UNAVAILABLE:
+                Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved");
+                // Fall through
+            default:
+                throw new IllegalStateException(
+                        "Failed to Create a Transform with status code " + status);
+        }
     }
 
     private IpSecTransform activate()
             throws IOException, IpSecManager.ResourceUnavailableException,
                     IpSecManager.SpiUnavailableException {
-        int transformId;
         synchronized (this) {
-            //try {
-            transformId = INVALID_TRANSFORM_ID;
-            //} catch (RemoteException e) {
-            //    throw e.rethrowFromSystemServer();
-            //}
+            try {
+                IIpSecService svc = getIpSecService();
+                Bundle result = svc.createTransportModeTransform(mConfig, new Binder());
+                int status = result.getInt(KEY_STATUS);
+                checkResultStatusAndThrow(status);
+                mResourceId = result.getInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID);
 
-            if (transformId < 0) {
-                throw new ErrnoException("addTransform", -transformId).rethrowAsIOException();
+                /* Keepalive will silently fail if not needed by the config; but, if needed and
+                 * it fails to start, we need to bail because a transform will not be reliable
+                 * to use if keepalive is expected to offload and fails.
+                 */
+                // FIXME: if keepalive fails, we need to fail spectacularly
+                startKeepalive(mContext);
+                Log.d(TAG, "Added Transform with Id " + mResourceId);
+                mCloseGuard.open("build");
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
             }
-
-            startKeepalive(mContext); // Will silently fail if not required
-            mTransformId = transformId;
-            Log.d(TAG, "Added Transform with Id " + transformId);
         }
-        mCloseGuard.open("build");
 
         return this;
     }
@@ -133,21 +168,27 @@
      * transform is no longer needed.
      */
     public void close() {
-        Log.d(TAG, "Removing Transform with Id " + mTransformId);
+        Log.d(TAG, "Removing Transform with Id " + mResourceId);
 
         // Always safe to attempt cleanup
-        if (mTransformId == INVALID_TRANSFORM_ID) {
+        if (mResourceId == INVALID_RESOURCE_ID) {
+            mCloseGuard.close();
             return;
         }
-        //try {
-        stopKeepalive();
-        //} catch (RemoteException e) {
-        //    transform.setTransformId(transformId);
-        //    throw e.rethrowFromSystemServer();
-        //} finally {
-        mTransformId = INVALID_TRANSFORM_ID;
-        //}
-        mCloseGuard.close();
+        try {
+            /* Order matters here because the keepalive is best-effort but could fail in some
+             * horrible way to be removed if the wifi (or cell) subsystem has crashed, and we
+             * still want to clear out the transform.
+             */
+            IIpSecService svc = getIpSecService();
+            svc.deleteTransportModeTransform(mResourceId);
+            stopKeepalive();
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        } finally {
+            mResourceId = INVALID_RESOURCE_ID;
+            mCloseGuard.close();
+        }
     }
 
     @Override
@@ -164,7 +205,7 @@
     }
 
     private final IpSecConfig mConfig;
-    private int mTransformId;
+    private int mResourceId;
     private final Context mContext;
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private ConnectivityManager.PacketKeepalive mKeepalive;
@@ -200,6 +241,7 @@
 
     /* Package */
     void startKeepalive(Context c) {
+        // FIXME: NO_KEEPALIVE needs to be a constant
         if (mConfig.getNattKeepaliveInterval() == 0) {
             return;
         }
@@ -208,7 +250,7 @@
                 (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
 
         if (mKeepalive != null) {
-            Log.e(TAG, "Keepalive already started for this IpSecTransform.");
+            Log.wtf(TAG, "Keepalive already started for this IpSecTransform.");
             return;
         }
 
@@ -218,10 +260,11 @@
                             mConfig.getNetwork(),
                             mConfig.getNattKeepaliveInterval(),
                             mKeepaliveCallback,
-                            mConfig.getLocalIp(),
+                            mConfig.getLocalAddress(),
                             mConfig.getEncapLocalPort(),
-                            mConfig.getRemoteIp());
+                            mConfig.getRemoteAddress());
             try {
+                // FIXME: this is still a horrible way to fudge the synchronous callback
                 mKeepaliveSyncLock.wait(2000);
             } catch (InterruptedException e) {
             }
@@ -232,6 +275,11 @@
     }
 
     /* Package */
+    int getResourceId() {
+        return mResourceId;
+    }
+
+    /* Package */
     void stopKeepalive() {
         if (mKeepalive == null) {
             return;
@@ -247,16 +295,6 @@
         }
     }
 
-    /* Package */
-    void setTransformId(int transformId) {
-        mTransformId = transformId;
-    }
-
-    /* Package */
-    int getTransformId() {
-        return mTransformId;
-    }
-
     /**
      * Builder object to facilitate the creation of IpSecTransform objects.
      *
@@ -280,7 +318,7 @@
          */
         public IpSecTransform.Builder setEncryption(
                 @TransformDirection int direction, IpSecAlgorithm algo) {
-            mConfig.flow[direction].encryptionAlgo = algo;
+            mConfig.flow[direction].encryption = algo;
             return this;
         }
 
@@ -295,7 +333,7 @@
          */
         public IpSecTransform.Builder setAuthentication(
                 @TransformDirection int direction, IpSecAlgorithm algo) {
-            mConfig.flow[direction].authenticationAlgo = algo;
+            mConfig.flow[direction].authentication = algo;
             return this;
         }
 
@@ -305,32 +343,9 @@
          * given destination address.
          *
          * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
-         * possible. Random number generation is a reasonable approach to selecting an SPI. For
-         * outbound SPIs, they must be reserved by calling {@link
-         * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
-         * fail to build.
-         *
-         * <p>Unless an SPI is set for a given direction, traffic in that direction will be
-         * sent/received without any IPsec applied.
-         *
-         * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
-         * @param spi a unique 32-bit integer to identify transformed traffic
-         */
-        public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) {
-            mConfig.flow[direction].spi = spi;
-            return this;
-        }
-
-        /**
-         * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
-         * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
-         * given destination address.
-         *
-         * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
-         * possible. Random number generation is a reasonable approach to selecting an SPI. For
-         * outbound SPIs, they must be reserved by calling {@link
-         * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
-         * fail to activate.
+         * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int,
+         * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being
+         * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}.
          *
          * <p>Unless an SPI is set for a given direction, traffic in that direction will be
          * sent/received without any IPsec applied.
@@ -341,6 +356,8 @@
          */
         public IpSecTransform.Builder setSpi(
                 @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
+            // TODO: convert to using the resource Id of the SPI. Then build() can validate
+            // the owner in the IpSecService
             mConfig.flow[direction].spi = spi.getSpi();
             return this;
         }
@@ -447,7 +464,6 @@
          *     properties is invalid.
          * @hide
          */
-        @SystemApi
         public IpSecTransform buildTunnelModeTransform(
                 InetAddress localAddress, InetAddress remoteAddress) {
             //FIXME: argument validation here
@@ -463,7 +479,8 @@
          *
          * @param context current Context
          */
-        public Builder(Context context) {
+        public Builder(@NonNull Context context) {
+            Preconditions.checkNotNull(context);
             mContext = context;
             mConfig = new IpSecConfig();
         }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8349510..4c6d22a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3313,16 +3313,17 @@
             final int wifiScanCount = u.getWifiScanCount(which);
             final int wifiScanCountBg = u.getWifiScanBackgroundCount(which);
             // Note that 'ActualTime' are unpooled and always since reset (regardless of 'which')
-            final long wifiScanActualTime = u.getWifiScanActualTime(rawRealtime);
-            final long wifiScanActualTimeBg = u.getWifiScanBackgroundTime(rawRealtime);
+            final long wifiScanActualTimeMs = (u.getWifiScanActualTime(rawRealtime) + 500) / 1000;
+            final long wifiScanActualTimeMsBg = (u.getWifiScanBackgroundTime(rawRealtime) + 500)
+                    / 1000;
             final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
             if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
-                    || wifiScanCountBg != 0 || wifiScanActualTime != 0 || wifiScanActualTimeBg != 0
-                    || uidWifiRunningTime != 0) {
+                    || wifiScanCountBg != 0 || wifiScanActualTimeMs != 0
+                    || wifiScanActualTimeMsBg != 0 || uidWifiRunningTime != 0) {
                 dumpLine(pw, uid, category, WIFI_DATA, fullWifiLockOnTime, wifiScanTime,
                         uidWifiRunningTime, wifiScanCount,
                         /* legacy fields follow, keep at 0 */ 0, 0, 0,
-                        wifiScanCountBg, wifiScanActualTime, wifiScanActualTimeBg);
+                        wifiScanCountBg, wifiScanActualTimeMs, wifiScanActualTimeMsBg);
             }
 
             dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index c43019d..717312b 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.service.autofill;
 
 import static android.view.autofill.Helper.DEBUG;
@@ -23,6 +24,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.widget.RemoteViews;
 
@@ -112,7 +114,7 @@
  *
  * <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(IntentSender, RemoteViews)} and
+ * {@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
@@ -126,7 +128,7 @@
  * 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>
+ * encrypted provides a better user experience.
  */
 public final class FillResponse implements Parcelable {
 
@@ -135,6 +137,7 @@
     private final Bundle mExtras;
     private final RemoteViews mPresentation;
     private final IntentSender mAuthentication;
+    private AutofillId[] mAuthenticationIds;
 
     private FillResponse(@NonNull Builder builder) {
         mDatasets = builder.mDatasets;
@@ -142,6 +145,7 @@
         mExtras = builder.mExtras;
         mPresentation = builder.mPresentation;
         mAuthentication = builder.mAuthentication;
+        mAuthenticationIds = builder.mAuthenticationIds;
     }
 
     /** @hide */
@@ -169,6 +173,11 @@
         return mAuthentication;
     }
 
+    /** @hide */
+    public @Nullable AutofillId[] getAuthenticationIds() {
+        return mAuthenticationIds;
+    }
+
     /**
      * Builder for {@link FillResponse} objects. You must to provide at least
      * one dataset or set an authentication intent with a presentation view.
@@ -179,6 +188,7 @@
         private Bundle mExtras;
         private RemoteViews mPresentation;
         private IntentSender mAuthentication;
+        private AutofillId[] mAuthenticationIds;
         private boolean mDestroyed;
 
         /**
@@ -193,7 +203,7 @@
          * be encrypted. The provided {@link android.app.PendingIntent intent} must be an
          * 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>
+         * 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
@@ -205,40 +215,54 @@
          * user's data was locked and marked that the response needs an authentication then
          * in the response returned if authentication succeeds you need to provide all
          * available data sets some of which may need to be further authenticated, for
-         * example a credit card whose CVV needs to be entered.</p>
+         * example a credit card whose CVV needs to be entered.
          *
          * <p>If you provide an authentication intent you must also provide a presentation
          * which is used to visualize visualize the response for triggering the authentication
-         * flow.</p>
+         * flow.
          *
          * <p></><strong>Note:</strong> 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.
          * @param presentation The presentation to visualize the response.
-         * @return This builder.
+         * @param ids id of Views that when focused will display the authentication UI affordance.
          *
+         * @return This builder.
          * @see android.app.PendingIntent#getIntentSender()
          */
-        public @NonNull Builder setAuthentication(@Nullable IntentSender authentication,
-                @Nullable RemoteViews presentation) {
+        public @NonNull Builder setAuthentication(@NonNull AutofillId[] ids,
+                @Nullable IntentSender authentication, @Nullable RemoteViews presentation) {
             throwIfDestroyed();
+            // TODO(b/33197203): assert ids is not null nor empty once old version is removed
             if (authentication == null ^ presentation == null) {
                 throw new IllegalArgumentException("authentication and presentation"
                         + " must be both non-null or null");
             }
             mAuthentication = authentication;
             mPresentation = presentation;
+            mAuthenticationIds = ids;
             return this;
         }
 
         /**
+         * TODO(b/33197203): will be removed once clients use the version that takes ids
+         * @hide
+         * @deprecated
+         */
+        @Deprecated
+        public @NonNull Builder setAuthentication(@Nullable IntentSender authentication,
+                @Nullable RemoteViews presentation) {
+            return setAuthentication(null, authentication, presentation);
+        }
+
+        /**
          * Adds a new {@link Dataset} to this response.
          *
          * @return This builder.
          */
-        public@NonNull Builder addDataset(@Nullable Dataset dataset) {
+        public @NonNull Builder addDataset(@Nullable Dataset dataset) {
             throwIfDestroyed();
             if (dataset == null) {
                 return this;
@@ -282,6 +306,7 @@
             return this;
         }
 
+
         /**
          * Builds a new {@link FillResponse} instance. You must provide at least
          * one dataset or some savable ids or an authentication with a presentation
@@ -308,7 +333,7 @@
     }
 
     /////////////////////////////////////
-    //  Object "contract" methods. //
+    // Object "contract" methods. //
     /////////////////////////////////////
     @Override
     public String toString() {
@@ -320,11 +345,13 @@
                 .append(", hasExtras=").append(mExtras != null)
                 .append(", hasPresentation=").append(mPresentation != null)
                 .append(", hasAuthentication=").append(mAuthentication != null)
+                .append(", authenticationSize=").append(mAuthenticationIds != null
+                        ? mAuthenticationIds.length : "N/A")
                 .toString();
     }
 
     /////////////////////////////////////
-    //  Parcelable "contract" methods. //
+    // Parcelable "contract" methods. //
     /////////////////////////////////////
 
     @Override
@@ -337,6 +364,7 @@
         parcel.writeTypedArrayList(mDatasets, flags);
         parcel.writeParcelable(mSaveInfo, flags);
         parcel.writeParcelable(mExtras, flags);
+        parcel.writeParcelableArray(mAuthenticationIds, flags);
         parcel.writeParcelable(mAuthentication, flags);
         parcel.writeParcelable(mPresentation, flags);
     }
@@ -356,8 +384,8 @@
             }
             builder.setSaveInfo(parcel.readParcelable(null));
             builder.setExtras(parcel.readParcelable(null));
-            builder.setAuthentication(parcel.readParcelable(null),
-                    parcel.readParcelable(null));
+            builder.setAuthentication(parcel.readParcelableArray(null, AutofillId.class),
+                    parcel.readParcelable(null), parcel.readParcelable(null));
             return builder.build();
         }
 
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 95608a5..f75b7af 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -129,6 +129,16 @@
      */
     public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3;
 
+    /**
+     * Type used when the {@link FillResponse} represents just an username, without a password.
+     */
+    public static final int SAVE_DATA_TYPE_USERNAME = 4;
+
+    /**
+     * Type used when the {@link FillResponse} represents just an email address, without a password.
+     */
+    public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 5;
+
     private final @SaveDataType int mType;
     private final CharSequence mNegativeActionTitle;
     private final IntentSender mNegativeActionListener;
@@ -222,6 +232,8 @@
                 case SAVE_DATA_TYPE_PASSWORD:
                 case SAVE_DATA_TYPE_ADDRESS:
                 case SAVE_DATA_TYPE_CREDIT_CARD:
+                case SAVE_DATA_TYPE_USERNAME:
+                case SAVE_DATA_TYPE_EMAIL_ADDRESS:
                     mType = type;
                     break;
                 default:
diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java
index e14cd2c..0accbf6 100644
--- a/core/java/android/text/method/DateKeyListener.java
+++ b/core/java/android/text/method/DateKeyListener.java
@@ -22,6 +22,7 @@
 import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 
 import java.util.HashMap;
 import java.util.LinkedHashSet;
@@ -37,8 +38,11 @@
 public class DateKeyListener extends NumberKeyListener
 {
     public int getInputType() {
-        return InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_DATE;
+        if (mNeedsAdvancedInput) {
+            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        } else {
+            return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
+        }
     }
 
     @Override
@@ -65,7 +69,13 @@
         final boolean success = NumberKeyListener.addDigits(chars, locale)
                                 && NumberKeyListener.addFormatCharsFromSkeletons(
                                         chars, locale, SKELETONS, SYMBOLS_TO_IGNORE);
-        mCharacters = success ? NumberKeyListener.collectionToArray(chars) : CHARACTERS;
+        if (success) {
+            mCharacters = NumberKeyListener.collectionToArray(chars);
+            mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters);
+        } else {
+            mCharacters = CHARACTERS;
+            mNeedsAdvancedInput = false;
+        }
     }
 
     /**
@@ -110,6 +120,7 @@
         };
 
     private final char[] mCharacters;
+    private final boolean mNeedsAdvancedInput;
 
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java
index 62e3ade..551db55 100644
--- a/core/java/android/text/method/DateTimeKeyListener.java
+++ b/core/java/android/text/method/DateTimeKeyListener.java
@@ -22,6 +22,7 @@
 import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 
 import java.util.HashMap;
 import java.util.LinkedHashSet;
@@ -37,10 +38,13 @@
 public class DateTimeKeyListener extends NumberKeyListener
 {
     public int getInputType() {
-        return InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_NORMAL;
+        if (mNeedsAdvancedInput) {
+            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        } else {
+            return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_NORMAL;
+        }
     }
-    
+
     @Override
     @NonNull
     protected char[] getAcceptedChars()
@@ -70,7 +74,13 @@
                               chars, locale, SKELETON_12HOUR, SYMBOLS_TO_IGNORE)
                           && NumberKeyListener.addFormatCharsFromSkeleton(
                               chars, locale, SKELETON_24HOUR, SYMBOLS_TO_IGNORE);
-        mCharacters = success ? NumberKeyListener.collectionToArray(chars) : CHARACTERS;
+        if (success) {
+            mCharacters = NumberKeyListener.collectionToArray(chars);
+            mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters);
+        } else {
+            mCharacters = CHARACTERS;
+            mNeedsAdvancedInput = false;
+        }
     }
 
     /**
@@ -114,6 +124,7 @@
         };
 
     private final char[] mCharacters;
+    private final boolean mNeedsAdvancedInput;
 
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java
index 26c69ab..d9f2dcf 100644
--- a/core/java/android/text/method/DigitsKeyListener.java
+++ b/core/java/android/text/method/DigitsKeyListener.java
@@ -27,6 +27,7 @@
 import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 
 import java.util.HashMap;
 import java.util.LinkedHashSet;
@@ -42,8 +43,12 @@
 public class DigitsKeyListener extends NumberKeyListener
 {
     private char[] mAccepted;
+    private boolean mNeedsAdvancedInput;
     private final boolean mSign;
     private final boolean mDecimal;
+    private final boolean mStringMode;
+    @Nullable
+    private final Locale mLocale;
 
     private static final String DEFAULT_DECIMAL_POINT_CHARS = ".";
     private static final String DEFAULT_SIGN_CHARS = "-+";
@@ -112,11 +117,17 @@
         this(locale, false, false);
     }
 
-    private void setToCompat(boolean sign, boolean decimal) {
+    private void setToCompat() {
         mDecimalPointChars = DEFAULT_DECIMAL_POINT_CHARS;
         mSignChars = DEFAULT_SIGN_CHARS;
-        final int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0);
+        final int kind = (mSign ? SIGN : 0) | (mDecimal ? DECIMAL : 0);
         mAccepted = COMPATIBILITY_CHARACTERS[kind];
+        mNeedsAdvancedInput = false;
+    }
+
+    private void calculateNeedForAdvancedInput() {
+        final int kind = (mSign ? SIGN : 0) | (mDecimal ? DECIMAL : 0);
+        mNeedsAdvancedInput = !ArrayUtils.containsAll(COMPATIBILITY_CHARACTERS[kind], mAccepted);
     }
 
     // Takes a sign string and strips off its bidi controls, if any.
@@ -144,14 +155,16 @@
     public DigitsKeyListener(@Nullable Locale locale, boolean sign, boolean decimal) {
         mSign = sign;
         mDecimal = decimal;
+        mStringMode = false;
+        mLocale = locale;
         if (locale == null) {
-            setToCompat(sign, decimal);
+            setToCompat();
             return;
         }
         LinkedHashSet<Character> chars = new LinkedHashSet<>();
         final boolean success = NumberKeyListener.addDigits(chars, locale);
         if (!success) {
-            setToCompat(sign, decimal);
+            setToCompat();
             return;
         }
         if (sign || decimal) {
@@ -161,7 +174,7 @@
                 final String plusString = stripBidiControls(symbols.getPlusSignString());
                 if (minusString.length() > 1 || plusString.length() > 1) {
                     // non-BMP and multi-character signs are not supported.
-                    setToCompat(sign, decimal);
+                    setToCompat();
                     return;
                 }
                 final char minus = minusString.charAt(0);
@@ -181,7 +194,7 @@
                 final String separatorString = symbols.getDecimalSeparatorString();
                 if (separatorString.length() > 1) {
                     // non-BMP and multi-character decimal separators are not supported.
-                    setToCompat(sign, decimal);
+                    setToCompat();
                     return;
                 }
                 final Character separatorChar = Character.valueOf(separatorString.charAt(0));
@@ -190,13 +203,19 @@
             }
         }
         mAccepted = NumberKeyListener.collectionToArray(chars);
+        calculateNeedForAdvancedInput();
     }
 
     private DigitsKeyListener(@NonNull final String accepted) {
         mSign = false;
         mDecimal = false;
+        mStringMode = true;
+        mLocale = null;
         mAccepted = new char[accepted.length()];
         accepted.getChars(0, accepted.length(), mAccepted, 0);
+        // Theoretically we may need advanced input, but for backward compatibility, we don't change
+        // the input type.
+        mNeedsAdvancedInput = false;
     }
 
     /**
@@ -280,13 +299,38 @@
         return result;
     }
 
-    public int getInputType() {
-        int contentType = InputType.TYPE_CLASS_NUMBER;
-        if (mSign) {
-            contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
+    /**
+     * Returns a DigitsKeyListener based on an the settings of a existing DigitsKeyListener, with
+     * the locale modified.
+     *
+     * @hide
+     */
+    @NonNull
+    public static DigitsKeyListener getInstance(
+            @Nullable Locale locale,
+            @NonNull DigitsKeyListener listener) {
+        if (listener.mStringMode) {
+            return listener; // string-mode DigitsKeyListeners have no locale.
+        } else {
+            return getInstance(locale, listener.mSign, listener.mDecimal);
         }
-        if (mDecimal) {
-            contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
+    }
+
+    /**
+     * Returns the input type for the listener.
+     */
+    public int getInputType() {
+        int contentType;
+        if (mNeedsAdvancedInput) {
+            contentType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        } else {
+            contentType = InputType.TYPE_CLASS_NUMBER;
+            if (mSign) {
+                contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
+            }
+            if (mDecimal) {
+                contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
+            }
         }
         return contentType;
     }
diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java
index c9f9f9f..5b1db11 100644
--- a/core/java/android/text/method/TimeKeyListener.java
+++ b/core/java/android/text/method/TimeKeyListener.java
@@ -22,6 +22,7 @@
 import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 
 import java.util.HashMap;
 import java.util.LinkedHashSet;
@@ -37,8 +38,11 @@
 public class TimeKeyListener extends NumberKeyListener
 {
     public int getInputType() {
-        return InputType.TYPE_CLASS_DATETIME
-        | InputType.TYPE_DATETIME_VARIATION_TIME;
+        if (mNeedsAdvancedInput) {
+            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        } else {
+            return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME;
+        }
     }
 
     @Override
@@ -70,7 +74,13 @@
                               chars, locale, SKELETON_12HOUR, SYMBOLS_TO_IGNORE)
                           && NumberKeyListener.addFormatCharsFromSkeleton(
                               chars, locale, SKELETON_24HOUR, SYMBOLS_TO_IGNORE);
-        mCharacters = success ? NumberKeyListener.collectionToArray(chars) : CHARACTERS;
+        if (success) {
+            mCharacters = NumberKeyListener.collectionToArray(chars);
+            mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters);
+        } else {
+            mCharacters = CHARACTERS;
+            mNeedsAdvancedInput = false;
+        }
     }
 
     /**
@@ -114,6 +124,7 @@
         };
 
     private final char[] mCharacters;
+    private final boolean mNeedsAdvancedInput;
 
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1b60ebc..7d9253b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -598,6 +598,11 @@
     private Layout mLayout;
     private boolean mLocalesChanged = false;
 
+    // True if setKeyListener() has been explicitly called
+    private boolean mListenerChanged = false;
+    // True if internationalized input should be used for numbers and date and time.
+    private final boolean mUseInternationalizedInput;
+
     @ViewDebug.ExportedProperty(category = "text")
     private int mGravity = Gravity.TOP | Gravity.START;
     private boolean mHorizontallyScrolling;
@@ -1356,6 +1361,9 @@
         final boolean numberPasswordInputType = variation
                 == (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD);
 
+        mUseInternationalizedInput =
+                context.getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O;
+
         if (inputMethod != null) {
             Class<?> c;
 
@@ -1398,15 +1406,11 @@
             mEditor.mInputType = inputType = EditorInfo.TYPE_CLASS_PHONE;
         } else if (numeric != 0) {
             createEditorIfNeeded();
-            mEditor.mKeyListener = DigitsKeyListener.getInstance((numeric & SIGNED) != 0,
-                                                   (numeric & DECIMAL) != 0);
-            inputType = EditorInfo.TYPE_CLASS_NUMBER;
-            if ((numeric & SIGNED) != 0) {
-                inputType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED;
-            }
-            if ((numeric & DECIMAL) != 0) {
-                inputType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL;
-            }
+            mEditor.mKeyListener = DigitsKeyListener.getInstance(
+                    mUseInternationalizedInput ? getTextLocale() : null,
+                    (numeric & SIGNED) != 0,
+                    (numeric & DECIMAL) != 0);
+            inputType = mEditor.mKeyListener.getInputType();
             mEditor.mInputType = inputType;
         } else if (autotext || autocap != -1) {
             TextKeyListener.Capitalize cap;
@@ -2308,19 +2312,13 @@
      * @attr ref android.R.styleable#TextView_autoText
      */
     public void setKeyListener(KeyListener input) {
+        mListenerChanged = true;
         setKeyListenerOnly(input);
         fixFocusableAndClickableSettings();
 
         if (input != null) {
             createEditorIfNeeded();
-            try {
-                mEditor.mInputType = mEditor.mKeyListener.getInputType();
-            } catch (IncompatibleClassChangeError e) {
-                mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
-            }
-            // Change inputType, without affecting transformation.
-            // No need to applySingleLine since mSingleLine is unchanged.
-            setInputTypeSingleLine(mSingleLine);
+            setInputTypeFromEditor();
         } else {
             if (mEditor != null) mEditor.mInputType = EditorInfo.TYPE_NULL;
         }
@@ -2329,6 +2327,17 @@
         if (imm != null) imm.restartInput(this);
     }
 
+    private void setInputTypeFromEditor() {
+        try {
+            mEditor.mInputType = mEditor.mKeyListener.getInputType();
+        } catch (IncompatibleClassChangeError e) {
+            mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
+        }
+        // Change inputType, without affecting transformation.
+        // No need to applySingleLine since mSingleLine is unchanged.
+        setInputTypeSingleLine(mSingleLine);
+    }
+
     private void setKeyListenerOnly(KeyListener input) {
         if (mEditor == null && input == null) return; // null is the default value
 
@@ -3390,6 +3399,29 @@
         return mTextPaint.getTextLocales();
     }
 
+    private void changeListenerLocaleTo(@NonNull Locale locale) {
+        if (mListenerChanged) {
+            // If a listener has been explicitly set, don't change it. We may break something.
+            return;
+        }
+        if (mEditor != null) {
+            KeyListener listener = mEditor.mKeyListener;
+            if (listener instanceof DigitsKeyListener) {
+                listener = DigitsKeyListener.getInstance(locale, (DigitsKeyListener) listener);
+            } else if (listener instanceof DateKeyListener) {
+                listener = DateKeyListener.getInstance(locale);
+            } else if (listener instanceof TimeKeyListener) {
+                listener = TimeKeyListener.getInstance(locale);
+            } else if (listener instanceof DateTimeKeyListener) {
+                listener = DateTimeKeyListener.getInstance(locale);
+            } else {
+                return;
+            }
+            setKeyListenerOnly(listener);
+            setInputTypeFromEditor();
+        }
+    }
+
     /**
      * Set the default {@link LocaleList} of the text in this TextView to a one-member list
      * containing just the given value.
@@ -3401,6 +3433,7 @@
     public void setTextLocale(@NonNull Locale locale) {
         mLocalesChanged = true;
         mTextPaint.setTextLocale(locale);
+        changeListenerLocaleTo(locale);
         if (mLayout != null) {
             nullLayouts();
             requestLayout();
@@ -3422,6 +3455,7 @@
     public void setTextLocales(@NonNull @Size(min = 1) LocaleList locales) {
         mLocalesChanged = true;
         mTextPaint.setTextLocales(locales);
+        changeListenerLocaleTo(locales.get(0));
         if (mLayout != null) {
             nullLayouts();
             requestLayout();
@@ -3433,7 +3467,9 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         if (!mLocalesChanged) {
-            mTextPaint.setTextLocales(LocaleList.getDefault());
+            final LocaleList locales = LocaleList.getDefault();
+            mTextPaint.setTextLocales(locales);
+            changeListenerLocaleTo(locales.get(0));
             if (mLayout != null) {
                 nullLayouts();
                 requestLayout();
@@ -5567,26 +5603,35 @@
             input = TextKeyListener.getInstance(autotext, cap);
         } else if (cls == EditorInfo.TYPE_CLASS_NUMBER) {
             input = DigitsKeyListener.getInstance(
+                    mUseInternationalizedInput ? getTextLocale() : null,
                     (type & EditorInfo.TYPE_NUMBER_FLAG_SIGNED) != 0,
                     (type & EditorInfo.TYPE_NUMBER_FLAG_DECIMAL) != 0);
+            if (mUseInternationalizedInput) {
+                type = input.getInputType(); // Override type, if necessary for i18n.
+            }
         } else if (cls == EditorInfo.TYPE_CLASS_DATETIME) {
+            final Locale locale = mUseInternationalizedInput ? getTextLocale() : null;
             switch (type & EditorInfo.TYPE_MASK_VARIATION) {
                 case EditorInfo.TYPE_DATETIME_VARIATION_DATE:
-                    input = DateKeyListener.getInstance();
+                    input = DateKeyListener.getInstance(locale);
                     break;
                 case EditorInfo.TYPE_DATETIME_VARIATION_TIME:
-                    input = TimeKeyListener.getInstance();
+                    input = TimeKeyListener.getInstance(locale);
                     break;
                 default:
-                    input = DateTimeKeyListener.getInstance();
+                    input = DateTimeKeyListener.getInstance(locale);
                     break;
             }
+            if (mUseInternationalizedInput) {
+                type = input.getInputType(); // Override type, if necessary for i18n.
+            }
         } else if (cls == EditorInfo.TYPE_CLASS_PHONE) {
             input = DialerKeyListener.getInstance();
         } else {
             input = TextKeyListener.getInstance();
         }
         setRawInputType(type);
+        mListenerChanged = false;
         if (direct) {
             createEditorIfNeeded();
             mEditor.mKeyListener = input;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index f4dd5a6..2c8e4e0 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -236,6 +236,29 @@
         return false;
     }
 
+    public static boolean contains(@Nullable char[] array, char value) {
+        if (array == null) return false;
+        for (char element : array) {
+            if (element == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Test if all {@code check} items are contained in {@code array}.
+     */
+    public static <T> boolean containsAll(@Nullable char[] array, char[] check) {
+        if (check == null) return true;
+        for (char checkItem : check) {
+            if (!contains(array, checkItem)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public static long total(@Nullable long[] array) {
         long total = 0;
         if (array != null) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index dae4310..520302e 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -282,6 +282,25 @@
     return mgr->configureDirectChannel(channelHandle, sensorHandle, rate);
 }
 
+static jint nativeSetOperationParameter(JNIEnv *_env, jclass _this, jlong sensorManager,
+        jint type, jfloatArray floats, jintArray ints) {
+    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+    Vector<float> floatVector;
+    Vector<int32_t> int32Vector;
+
+    if (floats != nullptr) {
+        floatVector.resize(_env->GetArrayLength(floats));
+        _env->GetFloatArrayRegion(floats, 0, _env->GetArrayLength(floats), floatVector.editArray());
+    }
+
+    if (ints != nullptr) {
+        int32Vector.resize(_env->GetArrayLength(ints));
+        _env->GetIntArrayRegion(ints, 0, _env->GetArrayLength(ints), int32Vector.editArray());
+    }
+
+    return mgr->setOperationParameter(type, floatVector, int32Vector);
+}
+
 //----------------------------------------------------------------------------
 
 class Receiver : public LooperCallback {
@@ -499,6 +518,10 @@
     {"nativeConfigDirectChannel",
             "(JIII)I",
             (void*)nativeConfigDirectChannel },
+
+    {"nativeSetOperationParameter",
+            "(JI[F[I)I",
+            (void*)nativeSetOperationParameter },
 };
 
 static const JNINativeMethod gBaseEventQueueMethods[] = {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bf2f355..459b48f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4602,6 +4602,10 @@
     <string name="autofill_save_type_address">address</string>
     <!-- Label for the type of data being saved for autofill when it represents a credit card [CHAR LIMIT=NONE] -->
     <string name="autofill_save_type_credit_card">credit card</string>
+    <!-- Label for the type of data being saved for autofill when it represents an username [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_type_username">username</string>
+    <!-- Label for the type of data being saved for autofill when it represents an email address [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_type_email_address">email address</string>
 
     <!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for earthquake -->
     <string name="etws_primary_default_message_earthquake">Stay calm and seek shelter nearby.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c12116a..fa13fbf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2883,6 +2883,8 @@
   <java-symbol type="string" name="autofill_save_type_password" />
   <java-symbol type="string" name="autofill_save_type_address" />
   <java-symbol type="string" name="autofill_save_type_credit_card" />
+  <java-symbol type="string" name="autofill_save_type_username" />
+  <java-symbol type="string" name="autofill_save_type_email_address" />
 
   <!-- Accessibility fingerprint gestures -->
   <java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 23bf3d6..431d5d8 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -34,6 +34,7 @@
     libutils \
     libbinder \
     libmedia \
+    libmediametrics \
     libmediadrm \
     libmidi \
     libskia \
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 2e6ed69b..63850ae 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -149,6 +149,12 @@
     <!-- Description of printer info icon. [CHAR LIMIT=50] -->
     <string name="printer_info_desc">More information about this printer</string>
 
+    <!-- Label for the notification channel that contains print jobs without problems. [CHAR LIMIT=40] -->
+    <string name="notification_channel_progress">Running print jobs</string>
+
+    <!-- Label for the notification channel that contains print jobs with problems. [CHAR LIMIT=40] -->
+    <string name="notification_channel_failure">Failed print jobs</string>
+
     <!-- Notification that we could not create a file name for the printed PDF. [CHAR LIMIT=50] -->
     <string name="could_not_create_file">Could not create file</string>
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index cd1d540..9d737e0 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -20,13 +20,12 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.Notification.Action;
-import android.app.Notification.InboxStyle;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -57,14 +56,14 @@
 
     public static final String LOG_TAG = "NotificationController";
 
+    private static final String NOTIFICATION_CHANNEL_PROGRESS = "PRINT_PROGRESS";
+    private static final String NOTIFICATION_CHANNEL_FAILURES = "PRINT_FAILURES";
+
     private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
     private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
 
     private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
 
-    private static final String PRINT_JOB_NOTIFICATION_GROUP_KEY = "PRINT_JOB_NOTIFICATIONS";
-    private static final String PRINT_JOB_NOTIFICATION_SUMMARY = "PRINT_JOB_NOTIFICATIONS_SUMMARY";
-
     private final Context mContext;
     private final NotificationManager mNotificationManager;
 
@@ -78,6 +77,15 @@
         mNotificationManager = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mNotifications = new ArraySet<>(0);
+
+        mNotificationManager.createNotificationChannel(
+                new NotificationChannel(NOTIFICATION_CHANNEL_PROGRESS,
+                        context.getString(R.string.notification_channel_progress),
+                        NotificationManager.IMPORTANCE_LOW));
+        mNotificationManager.createNotificationChannel(
+                new NotificationChannel(NOTIFICATION_CHANNEL_FAILURES,
+                        context.getString(R.string.notification_channel_failure),
+                        NotificationManager.IMPORTANCE_DEFAULT));
     }
 
     public void onUpdateNotifications(List<PrintJobInfo> printJobs) {
@@ -104,13 +112,6 @@
 
         final int numPrintJobs = printJobs.size();
 
-        // Create summary notification
-        if (numPrintJobs > 1) {
-            createStackedNotification(printJobs);
-        } else {
-            mNotificationManager.cancel(PRINT_JOB_NOTIFICATION_SUMMARY, 0);
-        }
-
         // Create per print job notification
         for (int i = 0; i < numPrintJobs; i++) {
             PrintJobInfo printJob = printJobs.get(i);
@@ -178,16 +179,16 @@
      */
     private void createNotification(@NonNull PrintJobInfo printJob, @Nullable Action firstAction,
             @Nullable Action secondAction) {
-        Notification.Builder builder = new Notification.Builder(mContext)
+        Notification.Builder builder = new Notification.Builder(mContext, computeChannel(printJob))
                 .setContentIntent(createContentIntent(printJob.getId()))
                 .setSmallIcon(computeNotificationIcon(printJob))
                 .setContentTitle(computeNotificationTitle(printJob))
                 .setWhen(System.currentTimeMillis())
                 .setOngoing(true)
                 .setShowWhen(true)
+                .setOnlyAlertOnce(true)
                 .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
-                .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY);
+                        com.android.internal.R.color.system_notification_accent_color));
 
         if (firstAction != null) {
             builder.addAction(firstAction);
@@ -238,43 +239,6 @@
         createNotification(printJob, null, null);
     }
 
-    private void createStackedNotification(List<PrintJobInfo> printJobs) {
-        Notification.Builder builder = new Notification.Builder(mContext)
-                .setContentIntent(createContentIntent(null))
-                .setWhen(System.currentTimeMillis())
-                .setOngoing(true)
-                .setShowWhen(true)
-                .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY)
-                .setGroupSummary(true);
-
-        final int printJobCount = printJobs.size();
-
-        InboxStyle inboxStyle = new InboxStyle();
-
-        int icon = com.android.internal.R.drawable.ic_print;
-        for (int i = printJobCount - 1; i>= 0; i--) {
-            PrintJobInfo printJob = printJobs.get(i);
-
-            inboxStyle.addLine(computeNotificationTitle(printJob));
-
-            // if any print job is in an error state show an error icon for the summary
-            if (printJob.getState() == PrintJobInfo.STATE_FAILED
-                    || printJob.getState() == PrintJobInfo.STATE_BLOCKED) {
-                icon = com.android.internal.R.drawable.ic_print_error;
-            }
-        }
-
-        builder.setSmallIcon(icon);
-        builder.setLargeIcon(
-                ((BitmapDrawable) mContext.getResources().getDrawable(icon, null)).getBitmap());
-        builder.setNumber(printJobCount);
-        builder.setStyle(inboxStyle);
-        builder.setColor(mContext.getColor(
-                com.android.internal.R.color.system_notification_accent_color));
-
-        mNotificationManager.notify(PRINT_JOB_NOTIFICATION_SUMMARY, 0, builder.build());
-    }
-
     private String computeNotificationTitle(PrintJobInfo printJob) {
         switch (printJob.getState()) {
             case PrintJobInfo.STATE_FAILED: {
@@ -359,6 +323,22 @@
         }
     }
 
+    private static String computeChannel(PrintJobInfo printJob) {
+        if (printJob.isCancelling()) {
+            return NOTIFICATION_CHANNEL_PROGRESS;
+        }
+
+        switch (printJob.getState()) {
+            case PrintJobInfo.STATE_FAILED:
+            case PrintJobInfo.STATE_BLOCKED: {
+                return NOTIFICATION_CHANNEL_FAILURES;
+            }
+            default: {
+                return NOTIFICATION_CHANNEL_PROGRESS;
+            }
+        }
+    }
+
     public static final class NotificationBroadcastReceiver extends BroadcastReceiver {
         @SuppressWarnings("hiding")
         private static final String LOG_TAG = "NotificationBroadcastReceiver";
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 1ea4183..901848a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -149,6 +149,7 @@
 
     private int mRankingScore = Integer.MIN_VALUE;
     private int mBadge = NetworkBadging.BADGING_NONE;
+    private boolean mIsScoredNetworkMetered = false;
 
     // used to co-relate internal vs returned accesspoint.
     int mId;
@@ -248,6 +249,7 @@
         this.mScanResultCache.putAll(that.mScanResultCache);
         this.mId = that.mId;
         this.mBadge = that.mBadge;
+        this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered;
         this.mRankingScore = that.mRankingScore;
     }
 
@@ -336,16 +338,32 @@
         builder.append(",level=").append(getLevel());
         builder.append(",rankingScore=").append(mRankingScore);
         builder.append(",badge=").append(mBadge);
+        builder.append(",metered=").append(isMetered());
 
         return builder.append(')').toString();
     }
 
     /**
+     * Updates the AccessPoint rankingScore, metering, and badge, returning true if the data has
+     * changed.
+     *
+     * @param scoreCache The score cache to use to retrieve scores.
+     * @param scoringUiEnabled Whether to show scoring and badging UI.
+     */
+    boolean update(WifiNetworkScoreCache scoreCache, boolean scoringUiEnabled) {
+        boolean scoreChanged = false;
+        if (scoringUiEnabled) {
+            scoreChanged = updateScores(scoreCache);
+        }
+        return updateMetered(scoreCache) || scoreChanged;
+    }
+
+    /**
      * Updates the AccessPoint rankingScore and badge, returning true if the data has changed.
      *
      * @param scoreCache The score cache to use to retrieve scores.
      */
-    boolean updateScores(WifiNetworkScoreCache scoreCache) {
+    private boolean updateScores(WifiNetworkScoreCache scoreCache) {
         int oldBadge = mBadge;
         int oldRankingScore = mRankingScore;
         mBadge = NetworkBadging.BADGING_NONE;
@@ -366,6 +384,23 @@
         return (oldBadge != mBadge || oldRankingScore != mRankingScore);
     }
 
+    /**
+     * Updates the AccessPoint's metering based on {@link ScoredNetwork#meteredHint}, returning
+     * true if the metering changed.
+     */
+    private boolean updateMetered(WifiNetworkScoreCache scoreCache) {
+        boolean oldMetering = mIsScoredNetworkMetered;
+        mIsScoredNetworkMetered = false;
+        for (ScanResult result : mScanResultCache.values()) {
+            ScoredNetwork score = scoreCache.getScoredNetwork(result);
+            if (score == null) {
+                continue;
+            }
+            mIsScoredNetworkMetered |= score.meteredHint;
+        }
+        return oldMetering == mIsScoredNetworkMetered;
+    }
+
     private void evictOldScanResults() {
         long nowMs = SystemClock.elapsedRealtime();
         for (Iterator<ScanResult> iter = mScanResultCache.values().iterator(); iter.hasNext(); ) {
@@ -474,6 +509,17 @@
         mSeen = seen;
     }
 
+    /**
+     * Returns if the network is marked metered. Metering can be marked through its config in
+     * {@link WifiConfiguration}, after connection in {@link WifiInfo}, or from a score config in
+     * {@link ScoredNetwork}.
+     */
+    public boolean isMetered() {
+        return mIsScoredNetworkMetered
+                || (mConfig != null && mConfig.meteredHint)
+                || (mInfo != null && mInfo.getMeteredHint());
+    }
+
     public NetworkInfo getNetworkInfo() {
         return mNetworkInfo;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 8f8167e..e82bf81 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -183,7 +183,7 @@
         }
         if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
             mFrictionSld.setState(STATE_SECURED);
-        } else if (mAccessPoint.getConfig() != null && mAccessPoint.getConfig().meteredHint) {
+        } else if (mAccessPoint.isMetered()) {
             mFrictionSld.setState(STATE_METERED);
         }
         Drawable drawable = mFrictionSld.getCurrent();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 50f294c..fc8c42c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -543,11 +543,9 @@
             }
         }
 
-        if (mNetworkScoringUiEnabled) {
-            requestScoresForNetworkKeys(scoresToRequest);
-            for (AccessPoint ap : accessPoints) {
-                ap.updateScores(mScoreCache);
-            }
+        requestScoresForNetworkKeys(scoresToRequest);
+        for (AccessPoint ap : accessPoints) {
+            ap.update(mScoreCache, mNetworkScoringUiEnabled);
         }
 
         // Pre-sort accessPoints to speed preference insertion
@@ -648,7 +646,7 @@
             if (ap.update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
                 reorder = true;
             }
-            if (mNetworkScoringUiEnabled && ap.updateScores(mScoreCache)) {
+            if (ap.update(mScoreCache, mNetworkScoringUiEnabled)) {
                 reorder = true;
             }
         }
@@ -659,15 +657,11 @@
     }
 
     /**
-     * Update all the internal access points rankingScores and badge.
+     * Update all the internal access points rankingScores, badge and metering.
      *
      * <p>Will trigger a resort and notify listeners of changes if applicable.
      */
     private void updateNetworkScores() {
-        if (!mNetworkScoringUiEnabled) {
-            return;
-        }
-
         // Lock required to prevent accidental copying of AccessPoint states while the modification
         // is in progress. see #copyAndNotifyListeners
         long before = System.currentTimeMillis();
@@ -679,7 +673,7 @@
 
         boolean reorder = false;
         for (int i = 0; i < mInternalAccessPoints.size(); i++) {
-            if (mInternalAccessPoints.get(i).updateScores(mScoreCache)) {
+            if (mInternalAccessPoints.get(i).update(mScoreCache, mNetworkScoringUiEnabled)) {
                 reorder = true;
             }
         }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 762d9f8..3e01b34 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -17,15 +17,19 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
-
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
+import android.net.NetworkKey;
+import android.net.ScoredNetwork;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiNetworkScoreCache;
 import android.net.wifi.WifiSsid;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.pps.HomeSp;
@@ -36,10 +40,11 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannableString;
 import android.text.style.TtsSpan;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -50,9 +55,11 @@
 
     private static final String TEST_SSID = "test_ssid";
     private Context mContext;
+    @Mock private WifiNetworkScoreCache mWifiNetworkScoreCache;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getTargetContext();
     }
 
@@ -74,6 +81,7 @@
     @Test
     public void testCopyAccessPoint_dataShouldMatch() {
         WifiConfiguration configuration = createWifiConfiguration();
+        configuration.meteredHint = true;
 
         NetworkInfo networkInfo =
                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
@@ -88,6 +96,7 @@
         assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
         assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
         assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
+        assertThat(originalAccessPoint.isMetered()).isEqualTo(copy.isMetered());
         assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
     }
 
@@ -230,6 +239,55 @@
         assertTrue(ap.isPasspointConfig());
     }
 
+    @Test
+    public void testIsMetered_returnTrueWhenWifiConfigurationIsMetered() {
+        WifiConfiguration configuration = createWifiConfiguration();
+        configuration.meteredHint = true;
+
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
+        AccessPoint accessPoint = new AccessPoint(mContext, configuration);
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
+        wifiInfo.setBSSID(configuration.BSSID);
+        wifiInfo.setNetworkId(configuration.networkId);
+        accessPoint.update(configuration, wifiInfo, networkInfo);
+
+        assertTrue(accessPoint.isMetered());
+    };
+
+    @Test
+    public void testIsMetered_returnTrueWhenWifiInfoIsMetered() {
+        WifiConfiguration configuration = createWifiConfiguration();
+
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
+        AccessPoint accessPoint = new AccessPoint(mContext, configuration);
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
+        wifiInfo.setBSSID(configuration.BSSID);
+        wifiInfo.setNetworkId(configuration.networkId);
+        wifiInfo.setMeteredHint(true);
+        accessPoint.update(configuration, wifiInfo, networkInfo);
+
+        assertTrue(accessPoint.isMetered());
+    };
+
+    @Test
+    public void testIsMetered_returnTrueWhenScoredNetworkIsMetered() {
+        AccessPoint ap = createAccessPointWithScanResultCache();
+
+        when(mWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
+                .thenReturn(
+                        new ScoredNetwork(
+                                null /* NetworkKey */,
+                                null /* rssiCurve */,
+                                true /* metered */));
+        ap.update(mWifiNetworkScoreCache, false /* scoringUiEnabled */);
+
+        assertTrue(ap.isMetered());
+    };
+
     private AccessPoint createAccessPointWithScanResultCache() {
         Bundle bundle = new Bundle();
         ArrayList<ScanResult> scanResults = new ArrayList<>();
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 02deb44..b71915f 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import static org.mockito.Mockito.any;
@@ -302,7 +303,7 @@
                 new ScoredNetwork(
                         NETWORK_KEY_2,
                         mockCurve2,
-                        false /* meteredHint */,
+                        true /* meteredHint */,
                         attr2);
 
         WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
@@ -515,6 +516,23 @@
     }
 
     @Test
+    public void scoreCacheUpdateMeteredShouldUpdateAccessPointMetering()
+            throws InterruptedException {
+        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
+        updateScoresAndWaitForAccessPointsChangedCallback();
+
+        List<AccessPoint> aps = tracker.getAccessPoints();
+
+        for (AccessPoint ap : aps) {
+            if (ap.getSsidStr().equals(SSID_1)) {
+                assertFalse(ap.isMetered());
+            } else if (ap.getSsidStr().equals(SSID_2)) {
+                assertTrue(ap.isMetered());
+            }
+        }
+    }
+
+    @Test
     public void noBadgesShouldBeInsertedIntoAccessPointWhenScoringUiDisabled()
             throws InterruptedException {
         Settings.Global.putInt(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1f559e4..169a034 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -994,6 +994,15 @@
         return false;
     }
 
+    private PackageInfo getCallingPackageInfo(int userId) {
+        try {
+            return mPackageManager.getPackageInfo(getCallingPackage(),
+                    PackageManager.GET_SIGNATURES, userId);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Package " + getCallingPackage() + " doesn't exist");
+        }
+    }
+
     private Cursor getAllSecureSettings(int userId, String[] projection) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
@@ -1002,6 +1011,13 @@
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
+        // The relevant "calling package" userId will be the owning userId for some
+        // profiles, and we can't do the lookup inside our [lock held] loop, so work out
+        // up front who the effective "new SSAID" user ID for that settings name will be.
+        final int ssaidUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
+                Settings.Secure.ANDROID_ID);
+        final PackageInfo ssaidCallingPkg = getCallingPackageInfo(ssaidUserId);
+
         synchronized (mLock) {
             List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SECURE, callingUserId);
 
@@ -1026,7 +1042,7 @@
                 // SETTINGS_FILE_SSAID, unless accessed by a system process.
                 final Setting setting;
                 if (isNewSsaidSetting(name)) {
-                    setting = getSsaidSettingLocked(owningUserId);
+                    setting = getSsaidSettingLocked(ssaidCallingPkg, owningUserId);
                 } else {
                     setting = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE, owningUserId,
                             name);
@@ -1060,14 +1076,17 @@
             return settings != null ? settings.getNullSetting() : null;
         }
 
-        // Get the value.
-        synchronized (mLock) {
-            // As of Android O, the SSAID is read from an app-specific entry in table
-            // SETTINGS_FILE_SSAID, unless accessed by a system process.
-            if (isNewSsaidSetting(name)) {
-                return getSsaidSettingLocked(owningUserId);
+        // As of Android O, the SSAID is read from an app-specific entry in table
+        // SETTINGS_FILE_SSAID, unless accessed by a system process.
+        if (isNewSsaidSetting(name)) {
+            PackageInfo callingPkg = getCallingPackageInfo(owningUserId);
+            synchronized (mLock) {
+                return getSsaidSettingLocked(callingPkg, owningUserId);
             }
+        }
 
+        // Not the SSAID; do a straight lookup
+        synchronized (mLock) {
             return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE,
                     owningUserId, name);
         }
@@ -1078,7 +1097,7 @@
                 && UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID;
     }
 
-    private Setting getSsaidSettingLocked(int owningUserId) {
+    private Setting getSsaidSettingLocked(PackageInfo callingPkg, int owningUserId) {
         // Get uid of caller (key) used to store ssaid value
         String name = Integer.toString(
                 UserHandle.getUid(owningUserId, UserHandle.getAppId(Binder.getCallingUid())));
@@ -1093,7 +1112,7 @@
 
         // Lazy initialize ssaid if not yet present in ssaid table.
         if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {
-            return mSettingsRegistry.generateSsaidLocked(getCallingPackage(), owningUserId);
+            return mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
         }
 
         return ssaid;
@@ -2070,15 +2089,7 @@
             return ByteBuffer.allocate(4).putInt(data.length).array();
         }
 
-        public Setting generateSsaidLocked(String packageName, int userId) {
-            final PackageInfo packageInfo;
-            try {
-                packageInfo = mPackageManager.getPackageInfo(packageName,
-                        PackageManager.GET_SIGNATURES, userId);
-            } catch (RemoteException e) {
-                throw new IllegalStateException("Package info doesn't exist");
-            }
-
+        public Setting generateSsaidLocked(PackageInfo callingPkg, int userId) {
             // Read the user's key from the ssaid table.
             Setting userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);
             if (userKeySetting == null || userKeySetting.isNull()
@@ -2113,11 +2124,12 @@
             }
 
             // Mac the package name and each of the signatures.
-            byte[] packageNameBytes = packageInfo.packageName.getBytes(StandardCharsets.UTF_8);
+            final String packageName = callingPkg.packageName;
+            byte[] packageNameBytes = packageName.getBytes(StandardCharsets.UTF_8);
             m.update(getLengthPrefix(packageNameBytes), 0, 4);
             m.update(packageNameBytes);
-            for (int i = 0; i < packageInfo.signatures.length; i++) {
-                byte[] sig = packageInfo.signatures[i].toByteArray();
+            for (int i = 0; i < callingPkg.signatures.length; i++) {
+                byte[] sig = callingPkg.signatures[i].toByteArray();
                 m.update(getLengthPrefix(sig), 0, 4);
                 m.update(sig);
             }
@@ -2127,7 +2139,7 @@
                     .toLowerCase(Locale.US);
 
             // Save the ssaid in the ssaid table.
-            final String uid = Integer.toString(packageInfo.applicationInfo.uid);
+            final String uid = Integer.toString(callingPkg.applicationInfo.uid);
             final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
             final boolean success = ssaidSettings.insertSettingLocked(uid, ssaid, null, true,
                     packageName);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index fbd9f0c..4e7cf72 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -87,7 +87,9 @@
 
     private boolean mMenuVisible;
     private boolean mAllowMenuTimeout = true;
+
     private final List<RemoteAction> mActions = new ArrayList<>();
+
     private View mViewRoot;
     private Drawable mBackgroundDrawable;
     private View mMenuContainer;
@@ -266,7 +268,6 @@
             }
             notifyMenuVisibility(true);
             updateExpandButtonFromBounds(stackBounds, movementBounds);
-            setDecorViewVisibility(true);
             mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                     mMenuContainer.getAlpha(), 1f);
             mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
@@ -311,11 +312,15 @@
                     if (animationFinishedRunnable != null) {
                         animationFinishedRunnable.run();
                     }
-                    setDecorViewVisibility(false);
+
+                    finish();
                 }
             });
             mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
             mMenuContainerAnimator.start();
+        } else {
+            // If the menu is not visible, just finish now
+            finish();
         }
     }
 
@@ -431,7 +436,6 @@
             alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
         }
         mBackgroundDrawable.setAlpha(alpha);
-        setDecorViewVisibility(alpha > 0);
     }
 
     private void notifyRegisterInputConsumer() {
@@ -508,16 +512,4 @@
         v.removeCallbacks(mFinishRunnable);
         v.postDelayed(mFinishRunnable, delay);
     }
-
-    /**
-     * Sets the visibility of the root view of the window to disable drawing and touches for the
-     * activity.  This differs from {@link Activity#setVisible(boolean)} in that it does not set
-     * the internal mVisibleFromClient state.
-     */
-    private void setDecorViewVisibility(boolean visible) {
-        final View decorView = getWindow().getDecorView();
-        if (decorView != null) {
-            decorView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index bcaa395..875fb14 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -50,6 +50,7 @@
 public class PipMenuActivityController {
 
     private static final String TAG = "PipMenuActController";
+    private static final boolean DEBUG = false;
 
     public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
     public static final String EXTRA_ACTIONS = "actions";
@@ -195,6 +196,10 @@
      * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
      */
     public void setDismissFraction(float fraction) {
+        if (DEBUG) {
+            Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
+                    + " fraction=" + fraction);
+        }
         if (mToActivityMessenger != null) {
             mTmpDismissFractionData.clear();
             mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
@@ -216,6 +221,9 @@
      * Shows the menu activity.
      */
     public void showMenu(Rect stackBounds, Rect movementBounds, boolean allowMenuTimeout) {
+        if (DEBUG) {
+            Log.d(TAG, "showMenu() hasActivity=" + (mToActivityMessenger != null));
+        }
         if (mToActivityMessenger != null) {
             Bundle data = new Bundle();
             data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
@@ -238,6 +246,9 @@
      * Pokes the menu, indicating that the user is interacting with it.
      */
     public void pokeMenu() {
+        if (DEBUG) {
+            Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
+        }
         if (mToActivityMessenger != null) {
             Message m = Message.obtain();
             m.what = PipMenuActivity.MESSAGE_POKE_MENU;
@@ -253,6 +264,9 @@
      * Hides the menu activity.
      */
     public void hideMenu() {
+        if (DEBUG) {
+            Log.d(TAG, "hideMenu() hasActivity=" + (mToActivityMessenger != null));
+        }
         if (mToActivityMessenger != null) {
             Message m = Message.obtain();
             m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
@@ -365,6 +379,10 @@
      * Handles changes in menu visibility.
      */
     private void onMenuVisibilityChanged(boolean visible, boolean resize) {
+        if (DEBUG) {
+            Log.d(TAG, "onMenuVisibilityChanged() mMenuVisible=" + mMenuVisible
+                    + " menuVisible=" + visible + " resize=" + resize);
+        }
         if (visible) {
             mInputConsumerController.unregisterInputConsumer();
         } else {
@@ -389,6 +407,7 @@
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
         pw.println(innerPrefix + "mMenuVisible=" + mMenuVisible);
+        pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
         pw.println(innerPrefix + "mListeners=" + mListeners.size());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index a14a712..fb8574d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
 
 import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.RectEvaluator;
 import android.animation.ValueAnimator;
@@ -253,7 +254,7 @@
      * Flings the PiP to the closest snap target.
      */
     Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
-            AnimatorUpdateListener listener) {
+            AnimatorUpdateListener updateListener, AnimatorListener listener) {
         cancelAnimations();
         Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
                 velocityX, velocityY);
@@ -263,8 +264,11 @@
             mFlingAnimationUtils.apply(mBoundsAnimator, 0,
                     distanceBetweenRectOffsets(mBounds, toBounds),
                     velocity);
-            if (listener != null) {
-                mBoundsAnimator.addUpdateListener(listener);
+            if (updateListener != null) {
+                mBoundsAnimator.addUpdateListener(updateListener);
+            }
+            if (listener != null){
+                mBoundsAnimator.addListener(listener);
             }
             mBoundsAnimator.start();
         }
@@ -274,14 +278,18 @@
     /**
      * Animates the PiP to the closest snap target.
      */
-    Rect animateToClosestSnapTarget(Rect movementBounds, AnimatorUpdateListener listener) {
+    Rect animateToClosestSnapTarget(Rect movementBounds, AnimatorUpdateListener updateListener,
+            AnimatorListener listener) {
         cancelAnimations();
         Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
         if (!mBounds.equals(toBounds)) {
             mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
                     FAST_OUT_SLOW_IN, mUpdateBoundsListener);
-            if (listener != null) {
-                mBoundsAnimator.addUpdateListener(listener);
+            if (updateListener != null) {
+                mBoundsAnimator.addUpdateListener(updateListener);
+            }
+            if (listener != null){
+                mBoundsAnimator.addListener(listener);
             }
             mBoundsAnimator.start();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index d68836c..161bdac 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.pip.phone;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.IActivityManager;
@@ -391,7 +393,10 @@
                 final float distance = bounds.bottom - target;
                 fraction = Math.min(distance / bounds.height(), 1f);
             }
-            mMenuController.setDismissFraction(fraction);
+            if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuVisible()) {
+                // Update if the fraction > 0, or if fraction == 0 and the menu was already visible
+                mMenuController.setDismissFraction(fraction);
+            }
         }
     }
 
@@ -611,22 +616,34 @@
                     setMinimizedStateInternal(false);
                 }
 
-                // If the menu is still visible, and we aren't minimized, then just poke the menu
-                // so that it will timeout after the user stops touching it
+                AnimatorListenerAdapter postAnimationCallback = null;
                 if (mMenuController.isMenuVisible()) {
+                    // If the menu is still visible, and we aren't minimized, then just poke the
+                    // menu so that it will timeout after the user stops touching it
                     mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
                             true /* allowMenuTimeout */);
+                } else {
+                    // If the menu is not visible, then we can still be showing the activity for the
+                    // dismiss overlay, so just finish it after the animation completes
+                    postAnimationCallback = new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mMenuController.hideMenu();
+                        }
+                    };
                 }
 
                 if (isFling) {
                     mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
-                            mUpdateScrimListener);
+                            mUpdateScrimListener, postAnimationCallback);
                 } else {
-                    mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener);
+                    mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener,
+                            postAnimationCallback);
                 }
             } else if (mIsMinimized) {
                 // This was a tap, so no longer minimized
-                mMotionHelper.animateToClosestSnapTarget(mMovementBounds, null /* listener */);
+                mMotionHelper.animateToClosestSnapTarget(mMovementBounds, null /* updateListener */,
+                        null /* animatorListener */);
                 setMinimizedStateInternal(false);
             } else if (!mIsMenuVisible) {
                 mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 8042321..715dc82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -434,7 +434,8 @@
                 iconState.scaleY = 1.0f;
                 iconState.hidden = false;
             }
-            if (row.isAboveShelf() || (!row.isInShelf() && isLastChild && row.areGutsExposed())) {
+            if (row.isAboveShelf() || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
+                    || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
                 iconState.hidden = true;
             }
             int shelfColor = icon.getStaticDrawableColor();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index c8659fb..5b594be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -190,7 +190,9 @@
             view.setScaleY(scaleY);
         }
 
-        boolean becomesInvisible = this.alpha == 0.0f || (this.hidden && !isAnimating(view));
+        int oldVisibility = view.getVisibility();
+        boolean becomesInvisible = this.alpha == 0.0f
+                || (this.hidden && (!isAnimating(view) || oldVisibility != View.VISIBLE));
         boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA);
         if (animatingAlpha) {
             updateAlphaAnimation(view);
@@ -212,7 +214,6 @@
         }
 
         // apply visibility
-        int oldVisibility = view.getVisibility();
         int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
         if (newVisibility != oldVisibility) {
             if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 15ec98f..f8b8e76 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -194,13 +194,17 @@
         }
     }
 
+    private String getComponentNameFromSettings() {
+        return Settings.Secure.getStringForUser(
+                mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
+    }
+
     void updateLocked(boolean disabled) {
         final boolean wasEnabled = isEnabled();
         mDisabled = disabled;
         ComponentName serviceComponent = null;
         ServiceInfo serviceInfo = null;
-        final String componentName = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
+        final String componentName = getComponentNameFromSettings();
         if (!TextUtils.isEmpty(componentName)) {
             try {
                 serviceComponent = ComponentName.unflattenFromString(componentName);
@@ -413,8 +417,7 @@
     void disableSelf() {
         final long identity = Binder.clearCallingIdentity();
         try {
-            final String autoFillService = Settings.Secure.getStringForUser(
-                    mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
+            final String autoFillService = getComponentNameFromSettings();
             if (mInfo.getServiceInfo().getComponentName().equals(
                     ComponentName.unflattenFromString(autoFillService))) {
                 Settings.Secure.putStringForUser(mContext.getContentResolver(),
@@ -432,12 +435,14 @@
     void dumpLocked(String prefix, PrintWriter pw) {
         final String prefix2 = prefix + "  ";
 
-        pw.print(prefix); pw.print("User :"); pw.println(mUserId);
-        pw.print(prefix); pw.print("Component:"); pw.println(mInfo != null
+        pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+        pw.print(prefix); pw.print("Component: "); pw.println(mInfo != null
                 ? mInfo.getServiceInfo().getComponentName() : null);
+        pw.print(prefix); pw.print("Component from settings: ");
+            pw.println(getComponentNameFromSettings());
         pw.print(prefix); pw.print("Default component: ");
             pw.println(mContext.getString(R.string.config_defaultAutofillService));
-        pw.print(prefix); pw.print("Disabled:"); pw.println(mDisabled);
+        pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
 
         if (VERBOSE && mInfo != null) {
             // ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 801769c..1ffc82f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -29,6 +29,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.AutofillOverlay;
 import android.app.assist.AssistStructure.ViewNode;
 import android.app.assist.AssistStructure.WindowNode;
 import android.content.ComponentName;
@@ -100,7 +101,7 @@
     @NonNull private final String mPackageName;
 
     @GuardedBy("mLock")
-    private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>();
+    private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
 
     /**
      * Id of the View currently being displayed.
@@ -517,10 +518,10 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Creating viewState for " + id + " on " + getFlagAsString(flags));
                 }
-                viewState = new ViewState(this, id, this, ViewState.STATE_INITIAL);
+                viewState = new ViewState(this, id, value, this, ViewState.STATE_INITIAL);
                 mViewStates.put(id, viewState);
             } else if ((flags & FLAG_VIEW_ENTERED) != 0) {
-                viewState = startPartitionLocked(id);
+                viewState = startPartitionLocked(id, value);
             } else {
                 if (VERBOSE) Slog.v(TAG, "Ignored " + getFlagAsString(flags) + " for " + id);
                 return;
@@ -584,25 +585,45 @@
         Slog.w(TAG, "updateLocked(): unknown flags " + flags + ": " + getFlagAsString(flags));
     }
 
-    private ViewState startPartitionLocked(AutofillId id) {
+    private ViewState startPartitionLocked(AutofillId id, AutofillValue value) {
         if (DEBUG) {
             Slog.d(TAG, "Starting partition for view id " + id);
         }
-        final ViewState viewState =
-                new ViewState(this, id, this,ViewState.STATE_STARTED_PARTITION);
-        mViewStates.put(id, viewState);
+        final ViewState newViewState =
+                new ViewState(this, id, value, this,ViewState.STATE_STARTED_PARTITION);
+        mViewStates.put(id, newViewState);
 
         /*
          * TODO(b/33197203 , b/35707731): when start a new partition, it should
          *
-         * - add autofilled fields as sanitized
-         * - set focus on ViewStructure that triggered it
          * - pass the first onFillRequest() bundle
          * - optional: perhaps add a new flag onFilLRequest() to indicate it's a new partition?
          */
+
+        // Must update value of nodes so:
+        // - proper node is focused
+        // - autofillValue is sent back to service when it was previously autofilled
+        for (int i = 0; i < mViewStates.size(); i++) {
+            final ViewState viewState = mViewStates.valueAt(i);
+
+            final ViewNode node = findViewNodeByIdLocked(viewState.id);
+            if (node == null) {
+                Slog.w(TAG, "startPartitionLocked(): no node for " + viewState.id);
+                continue;
+            }
+
+            final AutofillValue initialValue = viewState.getInitialValue();
+            final AutofillValue filledValue = viewState.getAutofilledValue();
+            final AutofillOverlay overlay = new AutofillOverlay();
+            if (filledValue != null && !filledValue.equals(initialValue)) {
+                overlay.value = filledValue;
+            }
+            overlay.focused = id.equals(viewState.id);
+            node.setAutofillOverlay(overlay);
+        }
         mRemoteFillService.onFillRequest(mStructure, null, 0);
 
-        return viewState;
+        return newViewState;
     }
 
     @Override
@@ -695,7 +716,7 @@
             if (viewState != null)  {
                 viewState.setState(state);
             } else {
-                viewState = new ViewState(this, id, this, state);
+                viewState = new ViewState(this, id, null, this, state);
                 if (DEBUG) { // TODO(b/33197203): change to VERBOSE once stable
                     Slog.d(TAG, "Adding autofillable view with id " + id + " and state " + state);
                 }
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 549f231..f8919ee 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -67,15 +67,17 @@
     private final Session mSession;
     private FillResponse mResponse;
 
+    private AutofillValue mInitialValue;
     private AutofillValue mCurrentValue;
     private AutofillValue mAutofilledValue;
     private Rect mVirtualBounds;
 
     private int mState;
 
-    ViewState(Session session, AutofillId id, Listener listener, int state) {
+    ViewState(Session session, AutofillId id, AutofillValue value, Listener listener, int state) {
         mSession = session;
         this.id = id;
+        mInitialValue = value;
         mListener = listener;
         mState = state;
     }
@@ -110,6 +112,11 @@
     }
 
     @Nullable
+    AutofillValue getInitialValue() {
+        return mInitialValue;
+    }
+
+    @Nullable
     FillResponse getResponse() {
         return mResponse;
     }
@@ -184,14 +191,16 @@
 
     @Override
     public String toString() {
-        return "ViewState: [id=" + id + ", currentValue=" + mCurrentValue
-                + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() +"]";
+        return "ViewState: [id=" + id + ", initialValue=" + mInitialValue
+                + ", currentValue=" + mCurrentValue + ", autofilledValue=" + mAutofilledValue
+                + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]";
     }
 
     void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("id:" ); pw.println(this.id);
         pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString());
         pw.print(prefix); pw.print("has response:" ); pw.println(mResponse != null);
+        pw.print(prefix); pw.print("initialValue:" ); pw.println(mInitialValue);
         pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
         pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
         pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
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 509351b..2c08afa 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -117,6 +117,12 @@
             case SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD:
                 type = context.getString(R.string.autofill_save_type_credit_card);
                 break;
+            case SaveInfo.SAVE_DATA_TYPE_USERNAME:
+                type = context.getString(R.string.autofill_save_type_username);
+                break;
+            case SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS:
+                type = context.getString(R.string.autofill_save_type_email_address);
+                break;
             default:
                 type = null;
         }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
new file mode 100644
index 0000000..a7ce95b
--- /dev/null
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -0,0 +1,494 @@
+/*
+ * 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.server;
+
+import static android.Manifest.permission.DUMP;
+import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_RESOURCE_ID;
+import static android.net.IpSecManager.KEY_SPI;
+import static android.net.IpSecManager.KEY_STATUS;
+
+import android.content.Context;
+import android.net.IIpSecService;
+import android.net.INetd;
+import android.net.IpSecAlgorithm;
+import android.net.IpSecConfig;
+import android.net.IpSecManager;
+import android.net.IpSecTransform;
+import android.net.util.NetdService;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** @hide */
+public class IpSecService extends IIpSecService.Stub {
+    private static final String TAG = "IpSecService";
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final String NETD_SERVICE_NAME = "netd";
+    private static final int[] DIRECTIONS =
+            new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN};
+
+    /** Binder context for this service */
+    private final Context mContext;
+
+    private Object mLock = new Object();
+
+    private static final int NETD_FETCH_TIMEOUT = 5000; //ms
+
+    private AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0);
+
+    private abstract class ManagedResource implements IBinder.DeathRecipient {
+        final int pid;
+        final int uid;
+        private IBinder mBinder;
+
+        ManagedResource(IBinder binder) {
+            super();
+            mBinder = binder;
+            pid = Binder.getCallingPid();
+            uid = Binder.getCallingUid();
+
+            try {
+                mBinder.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                binderDied();
+            }
+        }
+
+        /**
+         * When this record is no longer needed for managing system resources this function should
+         * unlink all references held by the record to allow efficient garbage collection.
+         */
+        public final void release() {
+            //Release all the underlying system resources first
+            releaseResources();
+
+            if (mBinder != null) {
+                mBinder.unlinkToDeath(this, 0);
+            }
+            mBinder = null;
+
+            //remove this record so that it can be cleaned up
+            nullifyRecord();
+        }
+
+        /**
+         * If the Binder object dies, this function is called to free the system resources that are
+         * being managed by this record and to subsequently release this record for garbage
+         * collection
+         */
+        public final void binderDied() {
+            release();
+        }
+
+        /**
+         * Implement this method to release all object references contained in the subclass to allow
+         * efficient garbage collection of the record. This should remove any references to the
+         * record from all other locations that hold a reference as the record is no longer valid.
+         */
+        protected abstract void nullifyRecord();
+
+        /**
+         * Implement this method to release all system resources that are being protected by this
+         * record. Once the resources are released, the record should be invalidated and no longer
+         * used by calling releaseRecord()
+         */
+        protected abstract void releaseResources();
+    };
+
+    private final class TransformRecord extends ManagedResource {
+        private IpSecConfig mConfig;
+        private int mResourceId;
+
+        TransformRecord(IpSecConfig config, int resourceId, IBinder binder) {
+            super(binder);
+            mConfig = config;
+            mResourceId = resourceId;
+        }
+
+        public IpSecConfig getConfig() {
+            return mConfig;
+        }
+
+        @Override
+        protected void releaseResources() {
+            for (int direction : DIRECTIONS) {
+                try {
+                    getNetdInstance()
+                            .ipSecDeleteSecurityAssociation(
+                                    mResourceId,
+                                    direction,
+                                    (mConfig.getLocalAddress() != null)
+                                            ? mConfig.getLocalAddress().getHostAddress()
+                                            : "",
+                                    (mConfig.getRemoteAddress() != null)
+                                            ? mConfig.getRemoteAddress().getHostAddress()
+                                            : "",
+                                    mConfig.getSpi(direction));
+                } catch (ServiceSpecificException e) {
+                    // FIXME: get the error code and throw is at an IOException from Errno Exception
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
+                }
+            }
+        }
+
+        @Override
+        protected void nullifyRecord() {
+            mConfig = null;
+            mResourceId = INVALID_RESOURCE_ID;
+        }
+    }
+
+    private final class SpiRecord extends ManagedResource {
+        private final int mDirection;
+        private final String mLocalAddress;
+        private final String mRemoteAddress;
+        private final IBinder mBinder;
+        private int mSpi;
+        private int mResourceId;
+
+        SpiRecord(
+                int resourceId,
+                int direction,
+                String localAddress,
+                String remoteAddress,
+                int spi,
+                IBinder binder) {
+            super(binder);
+            mResourceId = resourceId;
+            mDirection = direction;
+            mLocalAddress = localAddress;
+            mRemoteAddress = remoteAddress;
+            mSpi = spi;
+            mBinder = binder;
+        }
+
+        protected void releaseResources() {
+            try {
+                getNetdInstance()
+                        .ipSecDeleteSecurityAssociation(
+                                mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi);
+            } catch (ServiceSpecificException e) {
+                // FIXME: get the error code and throw is at an IOException from Errno Exception
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId);
+            }
+        }
+
+        protected void nullifyRecord() {
+            mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
+            mResourceId = INVALID_RESOURCE_ID;
+        }
+    }
+
+    @GuardedBy("mSpiRecords")
+    private final SparseArray<SpiRecord> mSpiRecords = new SparseArray<>();
+
+    @GuardedBy("mTransformRecords")
+    private final SparseArray<TransformRecord> mTransformRecords = new SparseArray<>();
+
+    /**
+     * Constructs a new IpSecService instance
+     *
+     * @param context Binder context for this service
+     */
+    private IpSecService(Context context) {
+        mContext = context;
+    }
+
+    static IpSecService create(Context context) throws InterruptedException {
+        final IpSecService service = new IpSecService(context);
+        service.connectNativeNetdService();
+        return service;
+    }
+
+    public void systemReady() {
+        if (isNetdAlive()) {
+            Slog.d(TAG, "IpSecService is ready");
+        } else {
+            Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
+        }
+    }
+
+    private void connectNativeNetdService() {
+        // Avoid blocking the system server to do this
+        Thread t =
+                new Thread(
+                        new Runnable() {
+                            @Override
+                            public void run() {
+                                synchronized (mLock) {
+                                    NetdService.get(NETD_FETCH_TIMEOUT);
+                                }
+                            }
+                        });
+        t.run();
+    }
+
+    INetd getNetdInstance() throws RemoteException {
+        final INetd netd = NetdService.getInstance();
+        if (netd == null) {
+            throw new RemoteException("Failed to Get Netd Instance");
+        }
+        return netd;
+    }
+
+    boolean isNetdAlive() {
+        synchronized (mLock) {
+            try {
+                final INetd netd = getNetdInstance();
+                if (netd == null) {
+                    return false;
+                }
+                return netd.isAlive();
+            } catch (RemoteException re) {
+                return false;
+            }
+        }
+    }
+
+    @Override
+    /** Get a new SPI and maintain the reservation in the system server */
+    public Bundle reserveSecurityParameterIndex(
+            int direction, String remoteAddress, int requestedSpi, IBinder binder)
+            throws RemoteException {
+        int resourceId = mNextResourceId.getAndIncrement();
+
+        int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
+        String localAddress = "";
+        Bundle retBundle = new Bundle(3);
+        try {
+            spi =
+                    getNetdInstance()
+                            .ipSecAllocateSpi(
+                                    resourceId,
+                                    direction,
+                                    localAddress,
+                                    remoteAddress,
+                                    requestedSpi);
+            Log.d(TAG, "Allocated SPI " + spi);
+            retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK);
+            retBundle.putInt(KEY_RESOURCE_ID, resourceId);
+            retBundle.putInt(KEY_SPI, spi);
+            synchronized (mSpiRecords) {
+                mSpiRecords.put(
+                        resourceId,
+                        new SpiRecord(
+                                resourceId, direction, localAddress, remoteAddress, spi, binder));
+            }
+        } catch (ServiceSpecificException e) {
+            // TODO: Add appropriate checks when other ServiceSpecificException types are supported
+            retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE);
+            retBundle.putInt(KEY_RESOURCE_ID, resourceId);
+            retBundle.putInt(KEY_SPI, spi);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return retBundle;
+    }
+
+    /** Release a previously allocated SPI that has been registered with the system server */
+    @Override
+    public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {}
+
+    /**
+     * Open a socket via the system server and bind it to the specified port (random if port=0).
+     * This will return a PFD to the user that represent a bound UDP socket. The system server will
+     * cache the socket and a record of its owner so that it can and must be freed when no longer
+     * needed.
+     */
+    @Override
+    public Bundle openUdpEncapsulationSocket(int port, IBinder binder) throws RemoteException {
+        return null;
+    }
+
+    /** close a socket that has been been allocated by and registered with the system server */
+    @Override
+    public void closeUdpEncapsulationSocket(ParcelFileDescriptor socket) {}
+
+    /**
+     * Create a transport mode transform, which represent two security associations (one in each
+     * direction) in the kernel. The transform will be cached by the system server and must be freed
+     * when no longer needed. It is possible to free one, deleting the SA from underneath sockets
+     * that are using it, which will result in all of those sockets becoming unable to send or
+     * receive data.
+     */
+    @Override
+    public Bundle createTransportModeTransform(IpSecConfig c, IBinder binder)
+            throws RemoteException {
+        // TODO: Basic input validation here since it's coming over the Binder
+        int resourceId = mNextResourceId.getAndIncrement();
+        for (int direction : DIRECTIONS) {
+            IpSecAlgorithm auth = c.getAuthentication(direction);
+            IpSecAlgorithm crypt = c.getEncryption(direction);
+            try {
+                int result =
+                        getNetdInstance()
+                                .ipSecAddSecurityAssociation(
+                                        resourceId,
+                                        c.getMode(),
+                                        direction,
+                                        (c.getLocalAddress() != null)
+                                                ? c.getLocalAddress().getHostAddress()
+                                                : "",
+                                        (c.getRemoteAddress() != null)
+                                                ? c.getRemoteAddress().getHostAddress()
+                                                : "",
+                                        (c.getNetwork() != null)
+                                                ? c.getNetwork().getNetworkHandle()
+                                                : 0,
+                                        c.getSpi(direction),
+                                        (auth != null) ? auth.getName() : "",
+                                        (auth != null) ? auth.getKey() : null,
+                                        (auth != null) ? auth.getTruncationLengthBits() : 0,
+                                        (crypt != null) ? crypt.getName() : "",
+                                        (crypt != null) ? crypt.getKey() : null,
+                                        (crypt != null) ? crypt.getTruncationLengthBits() : 0,
+                                        c.getEncapType(),
+                                        c.getEncapLocalPort(),
+                                        c.getEncapRemotePort());
+                if (result != c.getSpi(direction)) {
+                    // TODO: cleanup the first SA if creation of second SA fails
+                    Bundle retBundle = new Bundle(2);
+                    retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE);
+                    retBundle.putInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID);
+                    return retBundle;
+                }
+            } catch (ServiceSpecificException e) {
+                // FIXME: get the error code and throw is at an IOException from Errno Exception
+            }
+        }
+        synchronized (mTransformRecords) {
+            mTransformRecords.put(resourceId, new TransformRecord(c, resourceId, binder));
+        }
+
+        Bundle retBundle = new Bundle(2);
+        retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK);
+        retBundle.putInt(KEY_RESOURCE_ID, resourceId);
+        return retBundle;
+    }
+
+    /**
+     * Delete a transport mode transform that was previously allocated by + registered with the
+     * system server. If this is called on an inactive (or non-existent) transform, it will not
+     * return an error. It's safe to de-allocate transforms that may have already been deleted for
+     * other reasons.
+     */
+    @Override
+    public void deleteTransportModeTransform(int resourceId) throws RemoteException {
+        synchronized (mTransformRecords) {
+            TransformRecord record;
+            // We want to non-destructively get so that we can check credentials before removing
+            // this from the records.
+            record = mTransformRecords.get(resourceId);
+
+            if (record == null) {
+                throw new IllegalArgumentException(
+                        "Transform " + resourceId + " is not available to be deleted");
+            }
+
+            if (record.pid != Binder.getCallingPid() || record.uid != Binder.getCallingUid()) {
+                throw new SecurityException("Only the owner of an IpSec Transform may delete it!");
+            }
+
+            // TODO: if releaseResources() throws RemoteException, we can try again to clean up on
+            // binder death. Need to make sure that path is actually functional.
+            record.releaseResources();
+            mTransformRecords.remove(resourceId);
+            record.nullifyRecord();
+        }
+    }
+
+    /**
+     * Apply an active transport mode transform to a socket, which will apply the IPsec security
+     * association as a correspondent policy to the provided socket
+     */
+    @Override
+    public void applyTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
+            throws RemoteException {
+
+        synchronized (mTransformRecords) {
+            TransformRecord info;
+            // FIXME: this code should be factored out into a security check + getter
+            info = mTransformRecords.get(resourceId);
+
+            if (info == null) {
+                throw new IllegalArgumentException("Transform " + resourceId + " is not active");
+            }
+
+            // TODO: make this a function.
+            if (info.pid != getCallingPid() || info.uid != getCallingUid()) {
+                throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
+            }
+
+            IpSecConfig c = info.getConfig();
+            try {
+                for (int direction : DIRECTIONS) {
+                    getNetdInstance()
+                            .ipSecApplyTransportModeTransform(
+                                    socket.getFileDescriptor(),
+                                    resourceId,
+                                    direction,
+                                    (c.getLocalAddress() != null)
+                                            ? c.getLocalAddress().getHostAddress()
+                                            : "",
+                                    (c.getRemoteAddress() != null)
+                                            ? c.getRemoteAddress().getHostAddress()
+                                            : "",
+                                    c.getSpi(direction));
+                }
+            } catch (ServiceSpecificException e) {
+                // FIXME: get the error code and throw is at an IOException from Errno Exception
+            }
+        }
+    }
+    /**
+     * Remove a transport mode transform from a socket, applying the default (empty) policy. This
+     * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of
+     * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not
+     * used: reserved for future improved input validation.
+     */
+    @Override
+    public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
+            throws RemoteException {
+        try {
+            getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor());
+        } catch (ServiceSpecificException e) {
+            // FIXME: get the error code and throw is at an IOException from Errno Exception
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
+
+        pw.println("IpSecService Log:");
+        pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java
index 0610464..7f5befa 100644
--- a/services/core/java/com/android/server/SensorNotificationService.java
+++ b/services/core/java/com/android/server/SensorNotificationService.java
@@ -20,25 +20,46 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.hardware.GeomagneticField;
 import android.hardware.Sensor;
+import android.hardware.SensorAdditionalInfo;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
 
-public class SensorNotificationService extends SystemService implements SensorEventListener {
-    //TODO: set DBG to false or remove Slog before release
-    private static final boolean DBG = true;
+public class SensorNotificationService extends SystemService
+        implements SensorEventListener, LocationListener {
+    private static final boolean DBG = false;
     private static final String TAG = "SensorNotificationService";
-    private Context mContext;
 
+    private static final long MINUTE_IN_MS = 60 * 1000;
+    private static final long KM_IN_M = 1000;
+
+    private static final long LOCATION_MIN_TIME = 30 * MINUTE_IN_MS;
+    private static final long LOCATION_MIN_DISTANCE = 100 * KM_IN_M;
+
+    private static final String PROPERTY_USE_MOCKED_LOCATION =
+            "sensor.notification.use_mocked"; // max key length is 32
+
+    private static final long MILLIS_2010_1_1 = 1262358000000l;
+
+    private Context mContext;
     private SensorManager mSensorManager;
+    private LocationManager mLocationManager;
     private Sensor mMetaSensor;
 
+    // for rate limiting
+    private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME;
+
     public SensorNotificationService(Context context) {
         super(context);
         mContext = context;
@@ -50,7 +71,6 @@
 
     public void onBootPhase(int phase) {
         if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
-            // start
             mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
             mMetaSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DYNAMIC_SENSOR_META);
             if (mMetaSensor == null) {
@@ -60,13 +80,28 @@
                         SensorManager.SENSOR_DELAY_FASTEST);
             }
         }
+
+        if (phase == PHASE_BOOT_COMPLETED) {
+            // LocationManagerService is initialized after PHASE_THIRD_PARTY_APPS_CAN_START
+            mLocationManager =
+                    (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+            if (mLocationManager == null) {
+                if (DBG) Slog.d(TAG, "Cannot obtain location service.");
+            } else {
+                mLocationManager.requestLocationUpdates(
+                        LocationManager.PASSIVE_PROVIDER,
+                        LOCATION_MIN_TIME,
+                        LOCATION_MIN_DISTANCE,
+                        this);
+            }
+        }
     }
 
     private void broadcastDynamicSensorChanged() {
         Intent i = new Intent(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
         i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); // avoid waking up manifest receivers
         mContext.sendBroadcastAsUser(i, UserHandle.ALL);
-        if (DBG) Slog.d(TAG, "DYNS sent dynamic sensor broadcast");
+        if (DBG) Slog.d(TAG, "dynamic sensor broadcast sent");
     }
 
     @Override
@@ -77,8 +112,62 @@
     }
 
     @Override
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    public void onLocationChanged(Location location) {
+        if (DBG) Slog.d(TAG, String.format(
+                "Location is (%f, %f), h %f, acc %f, mocked %b",
+                location.getLatitude(), location.getLongitude(),
+                location.getAltitude(), location.getAccuracy(),
+                location.isFromMockProvider()));
 
+        // lat long == 0 usually means invalid location
+        if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+            return;
+        }
+
+        // update too often, ignore
+        if (SystemClock.elapsedRealtime() - mLocalGeomagneticFieldUpdateTime < 10 * MINUTE_IN_MS) {
+            return;
+        }
+
+        long time = System.currentTimeMillis();
+        // Mocked location should not be used. Except in test, only use mocked location
+        // Wrong system clock also gives bad values so ignore as well.
+        if (useMockedLocation() == location.isFromMockProvider() || time < MILLIS_2010_1_1) {
+            return;
+        }
+
+        GeomagneticField field = new GeomagneticField(
+                (float) location.getLatitude(), (float) location.getLongitude(),
+                (float) location.getAltitude(), time);
+        if (DBG) Slog.d(TAG, String.format(
+                "Nominal mag field, norm %fuT, decline %f deg, incline %f deg",
+                field.getFieldStrength() / 1000, field.getDeclination(), field.getInclination()));
+
+        try {
+            SensorAdditionalInfo info = SensorAdditionalInfo.createLocalGeomagneticField(
+                        field.getFieldStrength() / 1000, // convert from nT to uT
+                        (float)(field.getDeclination() * Math.PI / 180), // from degree to rad
+                        (float)(field.getInclination() * Math.PI / 180)); // from degree to rad
+            if (info != null) {
+                mSensorManager.setOperationParameter(info);
+                mLocalGeomagneticFieldUpdateTime = SystemClock.elapsedRealtime();
+            }
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Invalid local geomagnetic field, ignore.");
+        }
+    }
+
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+    @Override
+    public void onStatusChanged(String provider, int status, Bundle extras) {}
+    @Override
+    public void onProviderEnabled(String provider) {}
+    @Override
+    public void onProviderDisabled(String provider) {}
+
+    private boolean useMockedLocation() {
+        return "false".equals(System.getProperty(PROPERTY_USE_MOCKED_LOCATION, "false"));
     }
 }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7c1a609..dd4d906 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -32,37 +32,39 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.telephony.CellLocation;
-import android.telephony.Rlog;
-import android.telephony.TelephonyManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
-import android.telephony.VoLteServiceState;
+import android.telephony.CellLocation;
 import android.telephony.DisconnectCause;
+import android.telephony.PhoneStateListener;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.PreciseDisconnectCause;
+import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.VoLteServiceState;
 import android.text.TextUtils;
-import android.text.format.Time;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
+import android.util.LocalLog;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
-import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.IPhoneStateListener;
+import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstantConversions;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.am.BatteryStatsService;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Since phone process can be restarted, this class provides a centralized place
  * that applications can register and be called back from.
@@ -159,8 +161,6 @@
 
     private String[] mDataConnectionReason;
 
-    private String[] mDataConnectionApn;
-
     private ArrayList<String>[] mConnectedApns;
 
     private LinkProperties[] mDataConnectionLinkProperties;
@@ -191,6 +191,8 @@
 
     private boolean mCarrierNetworkChangeState = false;
 
+    private final LocalLog mLocalLog = new LocalLog(100);
+
     private PreciseDataConnectionState mPreciseDataConnectionState =
                 new PreciseDataConnectionState();
 
@@ -310,7 +312,6 @@
         mMessageWaiting = new boolean[numPhones];
         mDataConnectionPossible = new boolean[numPhones];
         mDataConnectionReason = new String[numPhones];
-        mDataConnectionApn = new String[numPhones];
         mCallForwarding = new boolean[numPhones];
         mCellLocation = new Bundle[numPhones];
         mDataConnectionLinkProperties = new LinkProperties[numPhones];
@@ -329,7 +330,6 @@
             mCallForwarding[i] =  false;
             mDataConnectionPossible[i] = false;
             mDataConnectionReason[i] =  "";
-            mDataConnectionApn[i] =  "";
             mCellLocation[i] = new Bundle();
             mCellInfo.add(i, null);
             mConnectedApns[i] = new ArrayList<String>();
@@ -536,7 +536,6 @@
                 if (DBG) {
                     log("listen:  Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
                 }
-                if (VDBG) toStringLogSSC("listen");
                 if (notifyNow && validatePhoneId(phoneId)) {
                     if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
                         try {
@@ -780,14 +779,14 @@
         }
 
         synchronized (mRecords) {
+            String str = "notifyServiceStateForSubscriber: subId=" + subId + " phoneId=" + phoneId
+                    + " state=" + state;
             if (VDBG) {
-                log("notifyServiceStateForSubscriber: subId=" + subId + " phoneId=" + phoneId
-                    + " state=" + state);
+                log(str);
             }
+            mLocalLog.log(str);
             if (validatePhoneId(phoneId)) {
                 mServiceState[phoneId] = state;
-                logServiceStateChanged("notifyServiceStateForSubscriber", subId, phoneId, state);
-                if (VDBG) toStringLogSSC("notifyServiceStateForSubscriber");
 
                 for (Record r : mRecords) {
                     if (VDBG) {
@@ -885,7 +884,6 @@
         if (VDBG) {
             log("notifySignalStrengthForPhoneId: subId=" + subId
                 +" phoneId=" + phoneId + " signalStrength=" + signalStrength);
-            toStringLogSSC("notifySignalStrengthForPhoneId");
         }
 
         synchronized (mRecords) {
@@ -1137,18 +1135,20 @@
                     modified = true;
                 }
                 if (modified) {
-                    if (DBG) {
-                        log("onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
-                            + ", " + mDataConnectionNetworkType[phoneId] + ")");
-                    }
+                    String str = "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+                            + ", " + mDataConnectionNetworkType[phoneId] + ")";
+                    log(str);
+                    mLocalLog.log(str);
                     for (Record r : mRecords) {
                         if (r.matchPhoneStateListenerEvent(
                                 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) &&
                                 idMatch(r.subId, subId, phoneId)) {
                             try {
-                                log("Notify data connection state changed on sub: " +
-                                        subId);
-                                r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                if (DBG) {
+                                    log("Notify data connection state changed on sub: " + subId);
+                                }
+                                r.callback.onDataConnectionStateChanged(
+                                        mDataConnectionState[phoneId],
                                         mDataConnectionNetworkType[phoneId]);
                             } catch (RemoteException ex) {
                                 mRemoveList.add(r.binder);
@@ -1163,7 +1163,8 @@
                     if (r.matchPhoneStateListenerEvent(
                             PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
                         try {
-                            r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+                            r.callback.onPreciseDataConnectionStateChanged(
+                                    mPreciseDataConnectionState);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -1391,36 +1392,58 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
         synchronized (mRecords) {
             final int recordCount = mRecords.size();
             pw.println("last known state:");
+            pw.increaseIndent();
             for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
-                pw.println("  Phone Id=" + i);
-                pw.println("  mCallState=" + mCallState[i]);
-                pw.println("  mCallIncomingNumber=" + mCallIncomingNumber[i]);
-                pw.println("  mServiceState=" + mServiceState[i]);
-                pw.println("  mVoiceActivationState= " + mVoiceActivationState[i]);
-                pw.println("  mDataActivationState= " + mDataActivationState[i]);
-                pw.println("  mSignalStrength=" + mSignalStrength[i]);
-                pw.println("  mMessageWaiting=" + mMessageWaiting[i]);
-                pw.println("  mCallForwarding=" + mCallForwarding[i]);
-                pw.println("  mDataActivity=" + mDataActivity[i]);
-                pw.println("  mDataConnectionState=" + mDataConnectionState[i]);
-                pw.println("  mDataConnectionPossible=" + mDataConnectionPossible[i]);
-                pw.println("  mDataConnectionReason=" + mDataConnectionReason[i]);
-                pw.println("  mDataConnectionApn=" + mDataConnectionApn[i]);
-                pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
-                pw.println("  mDataConnectionNetworkCapabilities=" +
+                pw.println("Phone Id=" + i);
+                pw.increaseIndent();
+                pw.println("mCallState=" + mCallState[i]);
+                pw.println("mCallIncomingNumber=" + mCallIncomingNumber[i]);
+                pw.println("mServiceState=" + mServiceState[i]);
+                pw.println("mVoiceActivationState= " + mVoiceActivationState[i]);
+                pw.println("mDataActivationState= " + mDataActivationState[i]);
+                pw.println("mSignalStrength=" + mSignalStrength[i]);
+                pw.println("mMessageWaiting=" + mMessageWaiting[i]);
+                pw.println("mCallForwarding=" + mCallForwarding[i]);
+                pw.println("mDataActivity=" + mDataActivity[i]);
+                pw.println("mDataConnectionState=" + mDataConnectionState[i]);
+                pw.println("mDataConnectionPossible=" + mDataConnectionPossible[i]);
+                pw.println("mDataConnectionReason=" + mDataConnectionReason[i]);
+                pw.println("mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
+                pw.println("mDataConnectionNetworkCapabilities=" +
                         mDataConnectionNetworkCapabilities[i]);
-                pw.println("  mCellLocation=" + mCellLocation[i]);
-                pw.println("  mCellInfo=" + mCellInfo.get(i));
+                pw.println("mCellLocation=" + mCellLocation[i]);
+                pw.println("mCellInfo=" + mCellInfo.get(i));
+                pw.decreaseIndent();
             }
+            pw.println("mConnectedApns=" + Arrays.toString(mConnectedApns));
+            pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
+            pw.println("mPreciseCallState=" + mPreciseCallState);
+            pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
+            pw.println("mRingingCallState=" + mRingingCallState);
+            pw.println("mForegroundCallState=" + mForegroundCallState);
+            pw.println("mBackgroundCallState=" + mBackgroundCallState);
+            pw.println("mVoLteServiceState=" + mVoLteServiceState);
+
+            pw.decreaseIndent();
+
+            pw.println("local logs:");
+            pw.increaseIndent();
+            mLocalLog.dump(fd, pw, args);
+            pw.decreaseIndent();
             pw.println("registrations: count=" + recordCount);
+            pw.increaseIndent();
             for (Record r : mRecords) {
-                pw.println("  " + r);
+                pw.println(r);
             }
+            pw.decreaseIndent();
         }
     }
 
@@ -1705,63 +1728,6 @@
         Rlog.d(TAG, s);
     }
 
-    private static class LogSSC {
-        private Time mTime;
-        private String mS;
-        private int mSubId;
-        private int mPhoneId;
-        private ServiceState mState;
-
-        public void set(Time t, String s, int subId, int phoneId, ServiceState state) {
-            mTime = t; mS = s; mSubId = subId; mPhoneId = phoneId; mState = state;
-        }
-
-        @Override
-        public String toString() {
-            return mS + " Time " + mTime.toString() + " mSubId " + mSubId + " mPhoneId "
-                    + mPhoneId + "  mState " + mState;
-        }
-    }
-
-    private LogSSC logSSC [] = new LogSSC[10];
-    private int next = 0;
-
-    private void logServiceStateChanged(String s, int subId, int phoneId, ServiceState state) {
-        if (logSSC == null || logSSC.length == 0) {
-            return;
-        }
-        if (logSSC[next] == null) {
-            logSSC[next] = new LogSSC();
-        }
-        Time t = new Time();
-        t.setToNow();
-        logSSC[next].set(t, s, subId, phoneId, state);
-        if (++next >= logSSC.length) {
-            next = 0;
-        }
-    }
-
-    private void toStringLogSSC(String prompt) {
-        if (logSSC == null || logSSC.length == 0 || (next == 0 && logSSC[next] == null)) {
-            log(prompt + ": logSSC is empty");
-        } else {
-            // There is at least one element
-            log(prompt + ": logSSC.length=" + logSSC.length + " next=" + next);
-            int i = next;
-            if (logSSC[i] == null) {
-                // logSSC is not full so back to the beginning
-                i = 0;
-            }
-            do {
-                log(logSSC[i].toString());
-                if (++i >= logSSC.length) {
-                    i = 0;
-                }
-            } while (i != next);
-            log(prompt + ": ----------------");
-        }
-    }
-
     boolean idMatch(int rSubId, int subId, int phoneId) {
 
         if(subId < 0) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index e5b2eca..983c975 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1021,32 +1021,24 @@
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                Slog.d(TAG, "begin setBatteryStateLocked");
-                try {
-                    synchronized (mStats) {
-                        final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
-                        if (mStats.isOnBattery() == onBattery) {
-                            // The battery state has not changed, so we don't need to sync external
-                            // stats immediately.
-                            mStats.setBatteryStateLocked(status, health, plugType, level, temp,
-                                    volt,
-                                    chargeUAh, chargeFullUAh);
-                            return;
-                        }
+                synchronized (mStats) {
+                    final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
+                    if (mStats.isOnBattery() == onBattery) {
+                        // The battery state has not changed, so we don't need to sync external
+                        // stats immediately.
+                        mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
+                                chargeUAh, chargeFullUAh);
+                        return;
                     }
-                } finally {
-                    Slog.d(TAG, "end setBatteryStateLocked");
                 }
 
                 // Sync external stats first as the battery has changed states. If we don't sync
                 // immediately here, we may not collect the relevant data later.
                 updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
-                Slog.d(TAG, "begin setBatteryStateLocked");
                 synchronized (mStats) {
                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
                             chargeUAh, chargeFullUAh);
                 }
-                Slog.d(TAG, "end setBatteryStateLocked");
             }
         });
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fe40efb..f62f115 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5753,20 +5753,23 @@
         synchronized (mPackages) {
             final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
             for (int n = 0; n < count; n++) {
-                ResolveInfo info = resolvedActivities.get(n);
-                String packageName = info.activityInfo.packageName;
-                PackageSetting ps = mSettings.mPackages.get(packageName);
+                final ResolveInfo info = resolvedActivities.get(n);
+                final String packageName = info.activityInfo.packageName;
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null) {
-                    // Try to get the status from User settings first
-                    long packedStatus = getDomainVerificationStatusLPr(ps, userId);
-                    int status = (int) (packedStatus >> 32);
-                    if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS
+                    // only check domain verification status if the app is not a browser
+                    if (!info.handleAllWebDataURI) {
+                        // Try to get the status from User settings first
+                        final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
+                        final int status = (int) (packedStatus >> 32);
+                        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS
                             || status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
-                        if (DEBUG_EPHEMERAL) {
-                            Slog.v(TAG, "DENY ephemeral apps;"
-                                + " pkg: " + packageName + ", status: " + status);
+                            if (DEBUG_EPHEMERAL) {
+                                Slog.v(TAG, "DENY instant app;"
+                                    + " pkg: " + packageName + ", status: " + status);
+                            }
+                            return false;
                         }
-                        return false;
                     }
                     if (ps.getInstantApp(userId)) {
                         if (DEBUG_EPHEMERAL) {
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
index ae1d50f..772fc26 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -95,20 +95,15 @@
      * Creates and Destroys the virtual display depending on the current state of VrMode.
      */
     private void updateVirtualDisplay() {
-        boolean createVirtualDisplay = "true".equals(SystemProperties.get("vr_virtualdisplay"));
         if (DEBUG) {
-            Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", createVD: " + createVirtualDisplay +
-                    ", override: " + mIsVrModeOverrideEnabled);
+            Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", override: " + mIsVrModeOverrideEnabled);
         }
 
-        if (mIsVrModeEnabled || (createVirtualDisplay && mIsVrModeOverrideEnabled)) {
+        if (mIsVrModeEnabled || mIsVrModeOverrideEnabled) {
             // TODO: Consider not creating the display until ActivityManager needs one on
             // which to display a 2D application.
-            // TODO: STOPSHIP Remove createVirtualDisplay conditional before launching.
-            if (createVirtualDisplay) {
-                startVirtualDisplay();
-                startImageReader();
-            }
+            startVirtualDisplay();
+            startImageReader();
         } else {
             // Stop virtual display to test exit condition
             stopVirtualDisplay();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 1decf4e..a8664a5 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -505,6 +505,13 @@
             getController().removeStartingWindow();
         }
 
+        // If this window was animating, then we need to ensure that the app transition notifies
+        // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so
+        // add to that list now
+        if (mAppAnimator.animating) {
+            mService.mNoAnimationNotifyOnTransitionFinished.add(token);
+        }
+
         final TaskStack stack = getTask().mStack;
         if (delayed && !isEmpty()) {
             // set the token aside because it has an active animation to be finished
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 9f0ed21..7b8057ca 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -61,17 +61,21 @@
             extends WindowManagerInternal.AppTransitionListener implements Runnable {
 
         public void onAppTransitionCancelledLocked() {
+            if (DEBUG) Slog.d(TAG, "onAppTransitionCancelledLocked:"
+                    + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition);
             animationFinished();
         }
         public void onAppTransitionFinishedLocked(IBinder token) {
+            if (DEBUG) Slog.d(TAG, "onAppTransitionFinishedLocked:"
+                    + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition);
             animationFinished();
         }
         private void animationFinished() {
             if (mFinishAnimationAfterTransition) {
                 mHandler.removeCallbacks(this);
-                // This might end up calling into activity manager which will be bad since we have the
-                // window manager lock held at this point. Post a message to take care of the processing
-                // so we don't deadlock.
+                // This might end up calling into activity manager which will be bad since we have
+                // the window manager lock held at this point. Post a message to take care of the
+                // processing so we don't deadlock.
                 mHandler.post(this);
             }
         }
@@ -195,6 +199,7 @@
             if (!mTarget.setPinnedStackSize(mTmpRect, mTmpTaskBounds)) {
                 // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
                 // any further animation.
+                if (DEBUG) Slog.d(TAG, "animateUpdate: cancelled");
                 animation.cancel();
             }
         }
@@ -203,7 +208,9 @@
         public void onAnimationEnd(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
                     + " mMoveToFullScreen=" + mMoveToFullScreen
-                    + " mSkipAnimationEnd=" + mSkipAnimationEnd);
+                    + " mSkipAnimationEnd=" + mSkipAnimationEnd
+                    + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition
+                    + " mAppTransitionIsRunning=" + mAppTransition.isRunning());
 
             // There could be another animation running. For example in the
             // move to fullscreen case, recents will also be closing while the
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 3cb96a1..ee2d5de 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -441,6 +441,8 @@
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
             appAnimator.clearThumbnail();
             appAnimator.setNullAnimation();
+            // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
+            //       animating?
             wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
             wtoken.updateReportedVisibilityLocked();
             // Force the allDrawn flag, because we want to start
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a5eac46..63af2da 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -668,6 +668,7 @@
         VibratorService vibrator = null;
         IStorageManager storageManager = null;
         NetworkManagementService networkManagement = null;
+        IpSecService ipSecService = null;
         NetworkStatsService networkStats = null;
         NetworkPolicyManagerService networkPolicy = null;
         ConnectivityService connectivity = null;
@@ -1015,6 +1016,15 @@
                     reportWtf("starting NetworkManagement Service", e);
                 }
                 traceEnd();
+
+                traceBeginAndSlog("StartIpSecService");
+                try {
+                    ipSecService = IpSecService.create(context);
+                    ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
+                } catch (Throwable e) {
+                    reportWtf("starting IpSec Service", e);
+                }
+                traceEnd();
             }
 
             if (!disableNonCoreServices && !disableTextServices) {
@@ -1628,6 +1638,7 @@
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
         final MmsServiceBroker mmsServiceF = mmsService;
+        final IpSecService ipSecServiceF = ipSecService;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -1691,6 +1702,13 @@
                         .networkScoreAndNetworkManagementServiceReady();
             }
             traceEnd();
+            traceBeginAndSlog("MakeIpSecServiceReady");
+            try {
+                if (ipSecServiceF != null) ipSecServiceF.systemReady();
+            } catch (Throwable e) {
+                reportWtf("making IpSec Service ready", e);
+            }
+            traceEnd();
             traceBeginAndSlog("MakeNetworkStatsServiceReady");
             try {
                 if (networkStatsF != null) networkStatsF.systemReady();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 590bce1..61a9294 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -23,7 +23,6 @@
 import android.net.apf.ApfCapabilities;
 import android.net.apf.ApfFilter;
 import android.net.DhcpResults;
-import android.net.INetd;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -35,12 +34,10 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpManagerEvent;
 import android.net.util.MultinetworkPolicyTracker;
-import android.net.util.NetdService;
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.LocalLog;
@@ -1030,16 +1027,14 @@
 
     private boolean startIPv6() {
         // Set privacy extensions.
-        final String PREFER_TEMPADDRS = "2";
         try {
-            NetdService.run((INetd netd) -> {
-                netd.setProcSysNet(
-                        INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr",
-                        PREFER_TEMPADDRS);
-            });
+            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
             mNwService.enableIpv6(mInterfaceName);
-        } catch (IllegalStateException|RemoteException|ServiceSpecificException e) {
-            logError("Unable to change interface settings: %s", e);
+        } catch (RemoteException re) {
+            logError("Unable to change interface settings: %s", re);
+            return false;
+        } catch (IllegalStateException ie) {
+            logError("Unable to change interface settings: %s", ie);
             return false;
         }