Merge "Accommodate service disconnect / package update race" into oc-dev
diff --git a/api/removed.txt b/api/removed.txt
index e7b573b..f52b39a 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -73,7 +73,6 @@
     method public deprecated java.lang.String getDeviceInitializerApp();
     method public deprecated android.content.ComponentName getDeviceInitializerComponent();
     method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
-    field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
   }
 
 }
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 15de5c4..9f3970d 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -71,7 +71,6 @@
     method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
     method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
     method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
-    field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
   }
 
 }
diff --git a/api/test-removed.txt b/api/test-removed.txt
index e7b573b..f52b39a 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -73,7 +73,6 @@
     method public deprecated java.lang.String getDeviceInitializerApp();
     method public deprecated android.content.ComponentName getDeviceInitializerComponent();
     method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
-    field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
   }
 
 }
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 000420f..5fedc9e 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -84,6 +84,11 @@
 
 int main(int argc, char** argv)
 {
+    // setThreadPoolMaxThreadCount(0) actually tells the kernel it's
+    // not allowed to spawn any additional threads, but we still spawn
+    // a binder thread from userspace when we call startThreadPool().
+    // See b/36066697 for rationale
+    ProcessState::self()->setThreadPoolMaxThreadCount(0);
     ProcessState::self()->startThreadPool();
 
     const char* pname = argv[0];
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6fa0a6d..a8183f2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -976,7 +976,7 @@
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
 
-        if (getApplicationInfo().targetSdkVersion >= O && mActivityInfo.isFixedOrientation()) {
+        if (getApplicationInfo().targetSdkVersion > O && mActivityInfo.isFixedOrientation()) {
             final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
             final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
             ta.recycle();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 424e783..2de205b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -65,6 +65,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -376,7 +377,9 @@
         checkMode(mode);
         if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
             if (isCredentialProtectedStorage()
-                    && !getSystemService(UserManager.class).isUserUnlocked() && !isBuggy()) {
+                    && !getSystemService(StorageManager.class).isUserKeyUnlocked(
+                            UserHandle.myUserId())
+                    && !isBuggy()) {
                 throw new IllegalStateException("SharedPreferences in credential encrypted "
                         + "storage are not available until after user is unlocked");
             }
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 704e912..bc7fcf5 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -101,21 +101,11 @@
     /**
      * @hide
      */
-    public static final int USER_LOCKED_ALLOWED = 0x00000040;
-
-    /**
-     * @hide
-     */
     public static final int USER_LOCKED_SHOW_BADGE = 0x00000080;
 
     /**
      * @hide
      */
-    public static final int USER_LOCKED_AUDIO_ATTRIBUTES = 0x00000100;
-
-    /**
-     * @hide
-     */
     public static final int[] LOCKABLE_FIELDS = new int[] {
             USER_LOCKED_PRIORITY,
             USER_LOCKED_VISIBILITY,
@@ -123,9 +113,7 @@
             USER_LOCKED_LIGHTS,
             USER_LOCKED_VIBRATION,
             USER_LOCKED_SOUND,
-            USER_LOCKED_ALLOWED,
             USER_LOCKED_SHOW_BADGE,
-            USER_LOCKED_AUDIO_ATTRIBUTES
     };
 
     private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -273,6 +261,13 @@
     /**
      * @hide
      */
+    public void unlockFields(int field) {
+        mUserLockedFields &= ~field;
+    }
+
+    /**
+     * @hide
+     */
     public void setDeleted(boolean deleted) {
         mDeleted = deleted;
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 109b5bb..de80c36 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3038,13 +3038,6 @@
      */
     public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1;
 
-    /**
-     * Instead use {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}.
-     * @removed
-     */
-    @Deprecated
-    public static final int FLAG_EVICT_CE_KEY = 1;
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag=true, value={FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY})
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 0b0f048..f33c751 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -103,7 +103,8 @@
     }
 
     /**
-     * Return the number of indices in the array that actually have data.
+     * Returns the number of indices in the array that actually have data. Attributes with a value
+     * of @empty are included, as this is an explicit indicator.
      *
      * @throws RuntimeException if the TypedArray has already been recycled.
      */
@@ -116,7 +117,8 @@
     }
 
     /**
-     * Returns an index in the array that has data.
+     * Returns an index in the array that has data. Attributes with a value of @empty are included,
+     * as this is an explicit indicator.
      *
      * @param at The index you would like to returned, ranging from 0 to
      *           {@link #getIndexCount()}.
@@ -1017,7 +1019,7 @@
      * @param outValue TypedValue object in which to place the attribute's
      *                 data.
      *
-     * @return {@code true} if the value was retrieved, false otherwise.
+     * @return {@code true} if the value was retrieved and not @empty, {@code false} otherwise.
      * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public boolean getValue(@StyleableRes int index, TypedValue outValue) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d8eb950..07258fc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2858,6 +2858,14 @@
      */
     static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
 
+    /**
+     * Flag indicating that when layout is completed we should notify
+     * that the view was entered for autofill purposes. To minimize
+     * showing autofill for views not visible to the user we evaluate
+     * user visibility which cannot be done until the view is laid out.
+     */
+    static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x4000;
+
     static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
 
     static final int SCROLL_INDICATORS_NONE = 0x0000;
@@ -6496,7 +6504,7 @@
 
             if (mParent != null) {
                 mParent.requestChildFocus(this, this);
-                setFocusedInCluster();
+                updateFocusedInCluster(oldFocus, direction);
             }
 
             if (mAttachInfo != null) {
@@ -6845,8 +6853,15 @@
         if (isAutofillable() && isAttachedToWindow()) {
             AutofillManager afm = getAutofillManager();
             if (afm != null) {
-                if (enter && hasWindowFocus() && isFocused() && isVisibleToUser()) {
-                    afm.notifyViewEntered(this);
+                if (enter && hasWindowFocus() && isFocused()) {
+                    // We have not been laid out yet, hence cannot evaluate
+                    // whether this view is visible to the user, we will do
+                    // the evaluation once layout is complete.
+                    if (!isLaidOut()) {
+                        mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
+                    } else if (isVisibleToUser()) {
+                        afm.notifyViewEntered(this);
+                    }
                 } else if (!hasWindowFocus() || !isFocused()) {
                     afm.notifyViewExited(this);
                 }
@@ -9912,22 +9927,47 @@
      * @hide
      */
     public final void setFocusedInCluster() {
-        View top = findKeyboardNavigationCluster();
-        if (top == this) {
+        setFocusedInCluster(findKeyboardNavigationCluster());
+    }
+
+    private void setFocusedInCluster(View cluster) {
+        if (this instanceof ViewGroup) {
+            ((ViewGroup) this).mFocusedInCluster = null;
+        }
+        if (cluster == this) {
             return;
         }
         ViewParent parent = mParent;
         View child = this;
         while (parent instanceof ViewGroup) {
-            ((ViewGroup) parent).setFocusedInCluster(child);
-            if (parent == top) {
-                return;
+            ((ViewGroup) parent).mFocusedInCluster = child;
+            if (parent == cluster) {
+                break;
             }
             child = (View) parent;
             parent = parent.getParent();
         }
     }
 
+    private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) {
+        if (oldFocus != null) {
+            View oldCluster = oldFocus.findKeyboardNavigationCluster();
+            View cluster = findKeyboardNavigationCluster();
+            if (oldCluster != cluster) {
+                // Going from one cluster to another, so save last-focused.
+                // This covers cluster jumps because they are always FOCUS_DOWN
+                oldFocus.setFocusedInCluster(oldCluster);
+                if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) {
+                    // This is a result of ordered navigation so consider navigation through
+                    // the previous cluster "complete" and clear its last-focused memory.
+                    if (oldFocus.mParent instanceof ViewGroup) {
+                        ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Returns whether this View should receive focus when the focus is restored for the view
      * hierarchy containing this view.
@@ -19305,6 +19345,11 @@
 
         mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
         mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
+
+        if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
+            mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
+            notifyEnterOrExitForAutoFillIfNeeded(true);
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 18c1b8c..50593f2 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -142,7 +142,7 @@
     // that is or contains a default-focus view.
     private View mDefaultFocus;
     // The last child of this ViewGroup which held focus within the current cluster
-    private View mFocusedInCluster;
+    View mFocusedInCluster;
 
     /**
      * A Transformation used when drawing children, to
@@ -806,10 +806,6 @@
         return mDefaultFocus != null || super.hasDefaultFocus();
     }
 
-    void setFocusedInCluster(View child) {
-        mFocusedInCluster = child;
-    }
-
     /**
      * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
      * it.
@@ -825,8 +821,11 @@
         ViewParent parent = this;
         do {
             ((ViewGroup) parent).mFocusedInCluster = null;
+            if (parent == top) {
+                break;
+            }
             parent = parent.getParent();
-        } while (parent != top && parent instanceof ViewGroup);
+        } while (parent instanceof ViewGroup);
     }
 
     @Override
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 748272600..6b18591 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -9812,10 +9812,9 @@
                     }
                 });
 
-        // TODO: STOPSHIP, remove the "true" below after b/34961340 is fixed
-        if (DEBUG_ENERGY_CPU || true) {
-            Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
-                    " ms");
+        final long elapse = (mClocks.elapsedRealtime() - startTimeMs);
+        if (DEBUG_ENERGY_CPU || (elapse >= 100)) {
+            Slog.d(TAG, "Reading cpu stats took " + elapse + " ms");
         }
 
         if (mOnBatteryInternal && numWakelocks > 0) {
diff --git a/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java b/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java
index b5915aa..aa56e93 100644
--- a/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java
+++ b/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java
@@ -8,6 +8,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.BufferedReader;
+import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 
@@ -24,14 +25,25 @@
 public class KernelMemoryBandwidthStats {
     private static final String TAG = "KernelMemoryBandwidthStats";
 
-    final protected LongSparseLongArray mBandwidthEntries = new LongSparseLongArray();
     private static final String mSysfsFile = "/sys/kernel/memory_state_time/show_stat";
     private static final boolean DEBUG = false;
 
+    protected final LongSparseLongArray mBandwidthEntries = new LongSparseLongArray();
+    private boolean mStatsDoNotExist = false;
+
     public void updateStats() {
+        if (mStatsDoNotExist) {
+            // Skip reading.
+            return;
+        }
+
         StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
         try (BufferedReader reader = new BufferedReader(new FileReader(mSysfsFile))) {
             parseStats(reader);
+        } catch (FileNotFoundException e) {
+            Slog.w(TAG, "No kernel memory bandwidth stats available");
+            mBandwidthEntries.clear();
+            mStatsDoNotExist = true;
         } catch (IOException e) {
             Slog.e(TAG, "Failed to read memory bandwidth: " + e.getMessage());
             mBandwidthEntries.clear();
diff --git a/core/tests/coretests/src/android/content/pm/AppCacheTest.java b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
index 1567046..15dbddf 100644
--- a/core/tests/coretests/src/android/content/pm/AppCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
@@ -25,11 +25,11 @@
 import android.os.ServiceManager;
 import android.os.StatFs;
 import android.os.UserHandle;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.filters.Suppress;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
 import java.io.File;
@@ -48,14 +48,14 @@
     public final long WAIT_TIME_INCR=10*1000;
     private static final long THRESHOLD=5;
     private static final long ACTUAL_THRESHOLD=10;
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         if(localLOGV) Log.i(TAG, "Cleaning up cache directory first");
         cleanUpCacheDirectory();
     }
-    
+
     void cleanUpDirectory(File pDir, String dirName) {
        File testDir = new File(pDir,  dirName);
        if(!testDir.exists()) {
@@ -72,13 +72,13 @@
         }
         testDir.delete();
     }
-    
+
     void cleanUpCacheDirectory() {
         File testDir = mContext.getCacheDir();
         if(!testDir.exists()) {
             return;
         }
-        
+
          String fList[] = testDir.list();
          if(fList == null) {
              testDir.delete();
@@ -93,7 +93,7 @@
              }
          }
      }
-    
+
     @SmallTest
     public void testDeleteAllCacheFiles() {
         String testName="testDeleteAllCacheFiles";
@@ -160,9 +160,9 @@
                     +(blks1-blks3));
         }
     }
-    
+
     /**
-     * This method opens an output file writes to it, opens the same file as an input 
+     * This method opens an output file writes to it, opens the same file as an input
      * stream, reads the contents and verifies the data that was written earlier can be read
      */
     public void openOutFileInAppFilesDir(File pFile, String pFileOut) {
@@ -180,7 +180,7 @@
             failStr(e.getMessage());
         } catch (IOException e) {
             failStr(e.getMessage());
-        } 
+        }
         int count = pFileOut.getBytes().length;
         byte[] buffer = new byte[count];
         try {
@@ -194,8 +194,8 @@
         }
         String str = new String(buffer);
         assertEquals(str, pFileOut);
-    } 
-    
+    }
+
     /*
      * This test case verifies that output written to a file
      * using Context.openFileOutput has executed successfully.
@@ -215,7 +215,7 @@
             failStr(e);
         }
     }
-    
+
     @SmallTest
     public void testAppCacheCreateFile() {
         String fileName = "testFile1.txt";
@@ -225,7 +225,7 @@
         openOutFileInAppFilesDir(file, fileOut);
         cleanUpCacheDirectory();
     }
-    
+
     @MediumTest
     public void testAppCreateCacheFiles() {
         File cacheDir = mContext.getCacheDir();
@@ -261,7 +261,7 @@
             }
         }
     }
-    
+
     byte[] getBuffer() {
         String sbuffer = "a";
         for(int i = 0; i < 10; i++) {
@@ -360,7 +360,7 @@
         }
         assertTrue("Files should have been removed", removedFlag);
     }
-    
+
     //createTestFiles(new File(super.getContext().getCacheDir(), "testtmp", "dir", 3)
     void createTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
         byte buffer[] = getBuffer();
@@ -439,7 +439,7 @@
             }
         }
     }
-    
+
     class PackageDataObserver extends IPackageDataObserver.Stub {
         public boolean retValue = false;
         private boolean doneFlag = false;
@@ -455,11 +455,11 @@
             return doneFlag;
         }
     }
-    
+
     IPackageManager getPm() {
         return  IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
     }
-    
+
     boolean invokePMDeleteAppCacheFiles() throws Exception {
         try {
             String packageName = mContext.getPackageName();
@@ -485,7 +485,7 @@
             return false;
         }
     }
-    
+
     boolean invokePMFreeApplicationCache(long idealStorageSize) throws Exception {
         try {
             String packageName = mContext.getPackageName();
@@ -512,7 +512,7 @@
         }
     }
 
-    boolean invokePMFreeStorage(long idealStorageSize, FreeStorageReceiver r, 
+    boolean invokePMFreeStorage(long idealStorageSize, FreeStorageReceiver r,
             PendingIntent pi) throws Exception {
         try {
             // Spin lock waiting for call back
@@ -536,7 +536,7 @@
             return false;
         }
     }
-    
+
     @LargeTest
     public void testDeleteAppCacheFiles() throws Exception {
         String testName="testDeleteAppCacheFiles";
@@ -551,7 +551,7 @@
         public boolean retValue = false;
         public PackageStats stats;
         private boolean doneFlag = false;
-        
+
         public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
                 throws RemoteException {
             synchronized(this) {
@@ -565,7 +565,7 @@
             return doneFlag;
         }
     }
-    
+
     public PackageStats invokePMGetPackageSizeInfo() throws Exception {
         try {
             String packageName = mContext.getPackageName();
@@ -593,7 +593,7 @@
             return null;
         }
     }
-    
+
     @SmallTest
     public void testGetPackageSizeInfo() throws Exception {
         String testName="testGetPackageSizeInfo";
@@ -603,7 +603,7 @@
         if(localLOGV) Log.i(TAG, "code="+stats.codeSize+", data="+stats.dataSize+
                 ", cache="+stats.cacheSize);
     }
-    
+
     @SmallTest
     public void testGetSystemSharedLibraryNames() throws Exception {
         try {
@@ -615,17 +615,17 @@
             }
         } catch (RemoteException e) {
             fail("Failed invoking getSystemSharedLibraryNames with exception:" + e);
-        }   
+        }
     }
-    
+
     class FreeStorageReceiver extends BroadcastReceiver {
         public static final String ACTION_FREE = "com.android.unit_tests.testcallback";
         private boolean doneFlag = false;
-        
+
         public boolean isDone() {
             return doneFlag;
         }
-        
+
         @Override
         public void onReceive(Context context, Intent intent) {
             if(intent.getAction().equalsIgnoreCase(ACTION_FREE)) {
@@ -637,7 +637,7 @@
             }
         }
     }
-    
+
     // TODO: flaky test, omit from LargeTest for now
     //@LargeTest
     public void testFreeStorage() throws Exception {
@@ -664,10 +664,10 @@
         if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after freeing cache"+blks3);
         assertEquals(receiver.getResultCode(), 1);
         mContext.unregisterReceiver(receiver);
-        // Verify result  
+        // Verify result
         verifyTestFiles1(cacheDir, "testtmpdir", 5);
     }
-    
+
     /* utility method used to create observer and check async call back from PackageManager.
      * ClearApplicationUserData
      */
@@ -696,7 +696,7 @@
             return false;
         }
     }
-    
+
     void verifyUserDataCleared(File pDir) {
         if(localLOGV) Log.i(TAG, "Verifying "+pDir);
         if(pDir == null) {
@@ -717,7 +717,7 @@
             fail(pDir+" should be empty or contain only lib subdirectory. Found "+fileList[i]);
         }
     }
-    
+
     File getDataDir() {
         try {
             ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0,
@@ -727,7 +727,8 @@
             throw new RuntimeException("Pacakge manager dead", e);
         }
     }
-    
+
+    @Suppress
     @LargeTest
     public void testClearApplicationUserDataWithTestData() throws Exception {
         File cacheDir = mContext.getCacheDir();
@@ -740,14 +741,16 @@
         //confirm files dont exist
         verifyUserDataCleared(getDataDir());
     }
-    
+
+    @Suppress
     @SmallTest
     public void testClearApplicationUserDataWithNoTestData() throws Exception {
         assertTrue(invokePMClearApplicationUserData());
         //confirm files dont exist
         verifyUserDataCleared(getDataDir());
     }
-    
+
+    @Suppress
     @LargeTest
     public void testClearApplicationUserDataNoObserver() throws Exception {
         getPm().clearApplicationUserData(mContext.getPackageName(), null, UserHandle.myUserId());
@@ -756,5 +759,5 @@
         //confirm files dont exist
         verifyUserDataCleared(getDataDir());
     }
-    
+
 }
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 86ab3dc..344f3c8 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -181,9 +181,6 @@
     <allow-in-power-save package="com.android.cellbroadcastreceiver" />
     <allow-in-power-save package="com.android.shell" />
 
-    <!-- STOPSHIP(b/36856786): Revert this once it is fixed properly -->
-    <allow-in-power-save package="com.google.android.apps.enterprise.dmagent" />
-
     <!-- These are the packages that are white-listed to be able to run as system user -->
     <system-user-whitelisted-app package="com.android.settings" />
 
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 2771ade..60e3845 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -44,8 +44,7 @@
 };
 
 class BagAttributeFinder
-    : public BackTrackingAttributeFinder<BagAttributeFinder,
-                                         const ResTable::bag_entry*> {
+    : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
  public:
   BagAttributeFinder(const ResTable::bag_entry* start,
                      const ResTable::bag_entry* end)
@@ -76,8 +75,7 @@
   uint32_t def_style_bag_type_set_flags = 0;
   if (def_style_attr != 0) {
     Res_value value;
-    if (theme->getAttribute(def_style_attr, &value,
-                            &def_style_bag_type_set_flags) >= 0) {
+    if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
       if (value.dataType == Res_value::TYPE_REFERENCE) {
         def_style_res = value.data;
       }
@@ -127,18 +125,14 @@
         ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
               value.data);
       }
-    }
-
-    if (value.dataType == Res_value::TYPE_NULL) {
-      const ResTable::bag_entry* const def_style_entry =
-          def_style_attr_finder.Find(cur_ident);
+    } else {
+      const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
       if (def_style_entry != def_style_end) {
         block = def_style_entry->stringBlock;
         type_set_flags = def_style_type_set_flags;
         value = def_style_entry->map.value;
         if (kDebugStyles) {
-          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType,
-                value.data);
+          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
       }
     }
@@ -146,29 +140,24 @@
     uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ssize_t new_block = theme->resolveAttributeReference(
-          &value, block, &resid, &type_set_flags, &config);
+      ssize_t new_block =
+          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
       if (new_block >= 0) block = new_block;
       if (kDebugStyles) {
-        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType,
-              value.data);
+        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
       }
-    } else {
+    } else if (value.data != Res_value::DATA_NULL_EMPTY) {
       // If we still don't have a value for this attribute, try to find
       // it in the theme!
-      ssize_t new_block =
-          theme->getAttribute(cur_ident, &value, &type_set_flags);
+      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
       if (new_block >= 0) {
         if (kDebugStyles) {
-          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType,
-                value.data);
+          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
-        new_block = res.resolveReference(&value, new_block, &resid,
-                                         &type_set_flags, &config);
+        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
         if (new_block >= 0) block = new_block;
         if (kDebugStyles) {
-          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType,
-                value.data);
+          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
       }
     }
@@ -184,8 +173,7 @@
     }
 
     if (kDebugStyles) {
-      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident,
-            value.dataType, value.data);
+      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
     }
 
     // Write the final value back to Java.
@@ -198,7 +186,8 @@
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
 
-    if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
+    if (out_indices != nullptr &&
+        (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
       indices_idx++;
       out_indices[indices_idx] = ii;
     }
@@ -247,8 +236,7 @@
     ssize_t idx = xml_parser->indexOfStyle();
     if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
       if (value.dataType == value.TYPE_ATTRIBUTE) {
-        if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) <
-            0) {
+        if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
           value.dataType = Res_value::TYPE_NULL;
         }
       }
@@ -318,41 +306,34 @@
       // We found the attribute we were looking for.
       xml_parser->getAttributeValue(xml_attr_idx, &value);
       if (kDebugStyles) {
-        ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType,
-              value.data);
+        ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
       }
     }
 
-    if (value.dataType == Res_value::TYPE_NULL) {
-      // Walk through the style class values looking for the requested
-      // attribute.
-      const ResTable::bag_entry* const style_attr_entry =
-          style_attr_finder.Find(cur_ident);
+    if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+      // Walk through the style class values looking for the requested attribute.
+      const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
       if (style_attr_entry != style_attr_end) {
         // We found the attribute we were looking for.
         block = style_attr_entry->stringBlock;
         type_set_flags = style_type_set_flags;
         value = style_attr_entry->map.value;
         if (kDebugStyles) {
-          ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType,
-                value.data);
+          ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
       }
     }
 
-    if (value.dataType == Res_value::TYPE_NULL) {
-      // Walk through the default style values looking for the requested
-      // attribute.
-      const ResTable::bag_entry* const def_style_attr_entry =
-          def_style_attr_finder.Find(cur_ident);
+    if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+      // Walk through the default style values looking for the requested attribute.
+      const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
       if (def_style_attr_entry != def_style_attr_end) {
         // We found the attribute we were looking for.
         block = def_style_attr_entry->stringBlock;
         type_set_flags = style_type_set_flags;
         value = def_style_attr_entry->map.value;
         if (kDebugStyles) {
-          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType,
-                value.data);
+          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
       }
     }
@@ -360,35 +341,29 @@
     uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ssize_t new_block = theme->resolveAttributeReference(
-          &value, block, &resid, &type_set_flags, &config);
+      ssize_t new_block =
+          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
       if (new_block >= 0) {
         block = new_block;
       }
 
       if (kDebugStyles) {
-        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType,
-              value.data);
+        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
       }
-    } else {
-      // If we still don't have a value for this attribute, try to find
-      // it in the theme!
-      ssize_t new_block =
-          theme->getAttribute(cur_ident, &value, &type_set_flags);
+    } else if (value.data != Res_value::DATA_NULL_EMPTY) {
+      // If we still don't have a value for this attribute, try to find it in the theme!
+      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
       if (new_block >= 0) {
         if (kDebugStyles) {
-          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType,
-                value.data);
+          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
-        new_block = res.resolveReference(&value, new_block, &resid,
-                                         &type_set_flags, &config);
+        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
         if (new_block >= 0) {
           block = new_block;
         }
 
         if (kDebugStyles) {
-          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType,
-                value.data);
+          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
       }
     }
@@ -404,8 +379,7 @@
     }
 
     if (kDebugStyles) {
-      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident,
-            value.dataType, value.data);
+      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
     }
 
     // Write the final value back to Java.
@@ -418,7 +392,7 @@
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
 
-    if (value.dataType != Res_value::TYPE_NULL) {
+    if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
       indices_idx++;
 
       // out_indices must NOT be nullptr.
@@ -502,7 +476,8 @@
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
 
-    if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
+    if (out_indices != nullptr &&
+        (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
       indices_idx++;
       out_indices[indices_idx] = ii;
     }
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index f661f29b..bab8883 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3538,7 +3538,8 @@
                     attrRes, bag->map.value.dataType, bag->map.value.data,
                     curEntry->value.dataType);
         }
-        if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
+        if (force || (curEntry->value.dataType == Res_value::TYPE_NULL
+                && curEntry->value.data != Res_value::DATA_NULL_EMPTY)) {
             curEntry->stringBlock = bag->stringBlock;
             curEntry->typeSpecFlags |= bagTypeSpecFlags;
             curEntry->value = bag->map.value;
@@ -3674,7 +3675,8 @@
                             }
                             ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
                             return BAD_INDEX;
-                        } else if (type != Res_value::TYPE_NULL) {
+                        } else if (type != Res_value::TYPE_NULL
+                                || te.value.data == Res_value::DATA_NULL_EMPTY) {
                             *outValue = te.value;
                             return te.stringBlock;
                         }
@@ -5997,16 +5999,14 @@
     char locale[RESTABLE_MAX_LOCALE_LEN];
 
     forEachConfiguration(false, false, includeSystemLocales, [&](const ResTable_config& cfg) {
-        if (cfg.locale != 0) {
-            cfg.getBcp47Locale(locale, mergeEquivalentLangs /* canonicalize if merging */);
+        cfg.getBcp47Locale(locale, mergeEquivalentLangs /* canonicalize if merging */);
 
-            const auto beginIter = locales->begin();
-            const auto endIter = locales->end();
+        const auto beginIter = locales->begin();
+        const auto endIter = locales->end();
 
-            auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
-            if (iter == endIter || strcmp(iter->string(), locale) != 0) {
-                locales->insertAt(String8(locale), std::distance(beginIter, iter));
-            }
+        auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
+        if (iter == endIter || strcmp(iter->string(), locale) != 0) {
+            locales->insertAt(String8(locale), std::distance(beginIter, iter));
         }
     });
 }
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index d8e5abf..fcae53b 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -264,7 +264,7 @@
 
   const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
   ASSERT_NE(nullptr, bag_two);
-  ASSERT_EQ(5u, bag_two->entry_count);
+  ASSERT_EQ(6u, bag_two->entry_count);
 
   // attr_one is inherited from StyleOne.
   EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key);
@@ -295,6 +295,11 @@
   EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType);
   EXPECT_EQ(3u, bag_two->entries[4].value.data);
   EXPECT_EQ(0, bag_two->entries[4].cookie);
+
+  EXPECT_EQ(app::R::attr::attr_empty, bag_two->entries[5].key);
+  EXPECT_EQ(Res_value::TYPE_NULL, bag_two->entries[5].value.dataType);
+  EXPECT_EQ(Res_value::DATA_NULL_EMPTY, bag_two->entries[5].value.data);
+  EXPECT_EQ(0, bag_two->entries[5].cookie);
 }
 
 TEST_F(AssetManager2Test, ResolveReferenceToResource) {
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 1ff2ed4..2d73ce8 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -69,8 +69,8 @@
   ResTable::Theme theme(table_);
   ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
-  std::array<uint32_t, 4> attrs{
-      {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+  std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+                                 R::attr::attr_four, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
   ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
@@ -109,11 +109,21 @@
   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+  // @empty comes from the theme, so it has the same asset cookie and changing configurations flags
+  // as the theme.
+  values_cursor += STYLE_NUM_ENTRIES;
+  EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+  EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
+  EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+  EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+  EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+  EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
 }
 
 TEST_F(AttributeResolutionXmlTest, XmlParser) {
-  std::array<uint32_t, 4> attrs{
-      {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+  std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+                                 R::attr::attr_four, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
   ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
@@ -121,7 +131,7 @@
 
   uint32_t* values_cursor = values.data();
   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
-  EXPECT_EQ(0u, values_cursor[STYLE_DATA]);
+  EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
@@ -150,16 +160,24 @@
   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+  values_cursor += STYLE_NUM_ENTRIES;
+  EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+  EXPECT_EQ(Res_value::DATA_NULL_UNDEFINED, values_cursor[STYLE_DATA]);
+  EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+  EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
+  EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+  EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
 }
 
 TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
   ResTable::Theme theme(table_);
   ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
-  std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
-                                 R::attr::attr_four, R::attr::attr_five}};
+  std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+                                 R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
-  std::array<uint32_t, attrs.size()> indices;
+  std::array<uint32_t, attrs.size() + 1> indices;
 
   ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
              attrs.size(), values.data(), indices.data());
@@ -167,12 +185,12 @@
   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
 
   uint32_t* values_cursor = values.data();
-  EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
-  EXPECT_EQ(1u, values_cursor[STYLE_DATA]);
+  EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+  EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
-  EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+  EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
-  EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+  EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
 
   values_cursor += STYLE_NUM_ENTRIES;
   EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]);
@@ -203,6 +221,20 @@
   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+  // @empty comes from the theme, so it has the same asset cookie and changing configurations flags
+  // as the theme.
+  values_cursor += STYLE_NUM_ENTRIES;
+  EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+  EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
+  EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+  EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+  EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+  EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+  // The first element of indices contains the number of indices.
+  std::array<uint32_t, 7> expected_indices = {{6u, 0u, 1u, 2u, 3u, 4u, 5u}};
+  EXPECT_EQ(expected_indices, indices);
 }
 
 } // namespace android
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index 68527c7..05073a8 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -33,6 +33,7 @@
       attr_five = 0x7f010004u,
       attr_indirect = 0x7f010005u,
       attr_six = 0x7f010006u,
+      attr_empty = 0x7f010007u,
     };
   };
 
diff --git a/libs/androidfw/tests/data/styles/build b/libs/androidfw/tests/data/styles/build
index 81f78b1..1ef8e6e 100755
--- a/libs/androidfw/tests/data/styles/build
+++ b/libs/androidfw/tests/data/styles/build
@@ -2,4 +2,5 @@
 
 set -e
 
-aapt package -F styles.apk -M AndroidManifest.xml -S res -f
+aapt2 compile -o compiled.flata --dir res
+aapt2 link -o styles.apk --manifest AndroidManifest.xml compiled.flata
diff --git a/libs/androidfw/tests/data/styles/res/layout/layout.xml b/libs/androidfw/tests/data/styles/res/layout/layout.xml
index f3aa0f8..2c5e947 100644
--- a/libs/androidfw/tests/data/styles/res/layout/layout.xml
+++ b/libs/androidfw/tests/data/styles/res/layout/layout.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <View xmlns:app="http://schemas.android.com/apk/res-auto"
     app:attr_four="?attr/attr_indirect"
-    app:attr_three="10" />
-
+    app:attr_three="10"
+    app:attr_one="@empty" />
diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml
index da592f8..3c90317 100644
--- a/libs/androidfw/tests/data/styles/res/values/styles.xml
+++ b/libs/androidfw/tests/data/styles/res/values/styles.xml
@@ -33,6 +33,12 @@
     <public type="attr" name="attr_indirect" id="0x7f010005" />
     <attr name="attr_indirect" />
 
+    <public type="attr" name="attr_six" id="0x7f010006" />
+    <attr name="attr_six" />
+
+    <public type="attr" name="attr_empty" id="0x7f010007" />
+    <attr name="attr_empty" />
+
     <public type="string" name="string_one" id="0x7f030000" />
     <string name="string_one">Hi</string>
 
@@ -48,11 +54,9 @@
         <item name="attr_two">"string"</item>
         <item name="attr_three">?attr/attr_indirect</item>
         <item name="attr_five">@string/string_one</item>
+        <item name="attr_empty">@empty</item>
     </style>
-    
-    <public type="attr" name="attr_six" id="0x7f010006" />
-    <attr name="attr_six" />
-    
+
     <public type="style" name="StyleThree" id="0x7f020002" />
     <style name="StyleThree">
         <item name="attr_six">6</item>
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
index d4ccb83..72abf8f 100644
--- a/libs/androidfw/tests/data/styles/styles.apk
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index c157a47..a19726c 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1067,7 +1067,7 @@
         private void applyLevelLimits() {
             int[] sampleRates = null;
             Range<Integer> sampleRateRange = null, bitRates = null;
-            int maxChannels = 0;
+            int maxChannels = MAX_INPUT_CHANNEL_COUNT;
             String mime = mParent.getMimeType();
 
             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
@@ -1160,6 +1160,8 @@
             if (info.containsKey("max-channel-count")) {
                 maxInputChannels = Utils.parseIntSafely(
                         info.getString("max-channel-count"), maxInputChannels);
+            } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
+                maxInputChannels = 0;
             }
             if (info.containsKey("bitrate-range")) {
                 bitRates = bitRates.intersect(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c5853ca..6a9bfae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2499,7 +2499,7 @@
         if (animate) {
             mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount);
             mDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-            mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
             mDarkAnimator.start();
         } else {
             setDarkAmount(darkAmount);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 0999580..41a78a7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -20,6 +20,7 @@
 import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
 
 import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sPartitionMaxCount;
 import static com.android.server.autofill.Helper.sVerbose;
 import static com.android.server.autofill.Helper.bundleToString;
 
@@ -397,6 +398,21 @@
         }
     }
 
+    // Called by Shell command.
+    public int getMaxPartitions() {
+        synchronized (mLock) {
+            return sPartitionMaxCount;
+        }
+    }
+
+    // Called by Shell command.
+    public void setMaxPartitions(int max) {
+        Slog.i(TAG, "setMaxPartitions(): " + max);
+        synchronized (mLock) {
+            sPartitionMaxCount = max;
+        }
+    }
+
     private void setDebugLocked(boolean debug) {
         com.android.server.autofill.Helper.sDebug = debug;
         android.view.autofill.Helper.sDebug = debug;
@@ -628,6 +644,7 @@
                     pw.print("Debug mode: "); pw.println(oldDebug);
                     pw.print("Verbose mode: "); pw.println(sVerbose);
                     pw.print("Disabled users: "); pw.println(mDisabledUsers);
+                    pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
                     final int size = mServicesCache.size();
                     pw.print("Cached services: ");
                     if (size == 0) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 1b9c86e..f3de557 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -70,9 +70,15 @@
             pw.println("  get log_level ");
             pw.println("    Gets the Autofill log level (off | debug | verbose).");
             pw.println("");
+            pw.println("  get max_partitions");
+            pw.println("    Gets the maximum number of partitions per session.");
+            pw.println("");
             pw.println("  set log_level [off | debug | verbose]");
             pw.println("    Sets the Autofill log level.");
             pw.println("");
+            pw.println("  set max_partitions number");
+            pw.println("    Sets the maximum number of partitions per session.");
+            pw.println("");
             pw.println("  list sessions [--user USER_ID]");
             pw.println("    List all pending sessions.");
             pw.println("");
@@ -86,9 +92,33 @@
     }
 
     private int requestGet(PrintWriter pw) {
-        if (!isNextArgLogLevel(pw, "get")) {
-            return -1;
+        final String what = getNextArgRequired();
+        switch(what) {
+            case "log_level":
+                return getLogLevel(pw);
+            case "max_partitions":
+                return getMaxPartitions(pw);
+            default:
+                pw.println("Invalid set: " + what);
+                return -1;
         }
+    }
+
+    private int requestSet(PrintWriter pw) {
+        final String what = getNextArgRequired();
+
+        switch(what) {
+            case "log_level":
+                return setLogLevel(pw);
+            case "max_partitions":
+                return setMaxPartitions();
+            default:
+                pw.println("Invalid set: " + what);
+                return -1;
+        }
+    }
+
+    private int getLogLevel(PrintWriter pw) {
         final int logLevel = mService.getLogLevel();
         switch (logLevel) {
             case AutofillManager.FLAG_ADD_CLIENT_VERBOSE:
@@ -106,11 +136,8 @@
         }
     }
 
-    private int requestSet(PrintWriter pw) {
-        if (!isNextArgLogLevel(pw, "set")) {
-            return -1;
-        }
-        final String logLevel = getNextArg();
+    private int setLogLevel(PrintWriter pw) {
+        final String logLevel = getNextArgRequired();
         switch (logLevel.toLowerCase()) {
             case "verbose":
                 mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_VERBOSE);
@@ -127,6 +154,16 @@
         }
     }
 
+    private int getMaxPartitions(PrintWriter pw) {
+        pw.println(mService.getMaxPartitions());
+        return 0;
+    }
+
+    private int setMaxPartitions() {
+        mService.setMaxPartitions(Integer.parseInt(getNextArgRequired()));
+        return 0;
+    }
+
     private int requestDestroy(PrintWriter pw) {
         if (!isNextArgSessions(pw)) {
             return -1;
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index ffcde8d..0281f73 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -26,16 +26,23 @@
 
     /**
      * Defines a logging flag that can be dynamically changed at runtime using
-     * {@code cmd autofill debug [on|off]}.
+     * {@code cmd autofill set log_level debug}.
      */
     public static boolean sDebug = false;
 
     /**
      * Defines a logging flag that can be dynamically changed at runtime using
-     * {@code cmd autofill verbose [on|off]}.
+     * {@code cmd autofill set log_level verbose}.
      */
     public static boolean sVerbose = false;
 
+    /**
+     * Maximum number of partitions that can be allowed in a session.
+     *
+     * <p>Can be modified using {@code cmd autofill set max_partitions}.
+     */
+    static int sPartitionMaxCount = 10;
+
     private Helper() {
         throw new UnsupportedOperationException("contains static members only");
     }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index a12ebb2..35f4fae 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -27,11 +27,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.ICancellationSignal;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.autofill.AutofillService;
 import android.service.autofill.FillRequest;
@@ -43,6 +45,7 @@
 import android.text.format.DateUtils;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.HandlerCaller;
 import com.android.server.FgThread;
 
@@ -63,6 +66,9 @@
     // How long after the last interaction with the service we would unbind
     private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
 
+    // How long after we make a remote request to a fill service we timeout
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
+
     private final Context mContext;
 
     private final ComponentName mComponentName;
@@ -413,12 +419,18 @@
 
     private static final class PendingFillRequest extends PendingRequest {
         private final Object mLock = new Object();
+
         private final WeakReference<RemoteFillService> mWeakService;
         private final FillRequest mRequest;
         private final IFillCallback mCallback;
         private ICancellationSignal mCancellation;
+
+        @GuardedBy("mLock")
         private boolean mCancelled;
 
+        @GuardedBy("mLock")
+        private boolean mCompleted;
+
         public PendingFillRequest(FillRequest request, RemoteFillService service) {
             mRequest = request;
             mWeakService = new WeakReference<>(service);
@@ -443,8 +455,15 @@
 
                 @Override
                 public void onSuccess(FillResponse response) {
+                    synchronized (mLock) {
+                        if (mCompleted) {
+                            return;
+                        }
+                        mCompleted = true;
+                    }
                     RemoteFillService remoteService = mWeakService.get();
                     if (remoteService != null) {
+                        service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
                         remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
                                 getCallingUid(), request.getFlags(), response);
                     }
@@ -452,13 +471,29 @@
 
                 @Override
                 public void onFailure(CharSequence message) {
+                    synchronized (mLock) {
+                        if (mCompleted) {
+                            return;
+                        }
+                        mCompleted = true;
+                    }
                     RemoteFillService remoteService = mWeakService.get();
                     if (remoteService != null) {
+                        service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
                         remoteService.dispatchOnFillRequestFailure(
                                 PendingFillRequest.this, message);
                     }
                 }
             };
+            service.mHandler.getHandler().postAtTime(() -> {
+                cancel();
+                try {
+                    mCallback.onFailure(null);
+                } catch (RemoteException e) {
+                    /* ignore */
+                }
+            }, PendingFillRequest.this,
+                    SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
         }
 
         @Override
@@ -496,10 +531,15 @@
     }
 
     private static final class PendingSaveRequest extends PendingRequest {
+        private final Object mLock = new Object();
+
         private final WeakReference<RemoteFillService> mWeakService;
         private final SaveRequest mRequest;
         private final ISaveCallback mCallback;
 
+        @GuardedBy("mLock")
+        private boolean mCompleted;
+
         public PendingSaveRequest(@NonNull SaveRequest request,
                 @NonNull RemoteFillService service) {
             mRequest = request;
@@ -507,8 +547,16 @@
             mCallback = new ISaveCallback.Stub() {
                 @Override
                 public void onSuccess() {
+                    synchronized (mLock) {
+                        if (mCompleted) {
+                            return;
+                        }
+                        mCompleted = true;
+                    }
+                    cancel();
                     RemoteFillService service = mWeakService.get();
                     if (service != null) {
+                        service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
                         service.dispatchOnSaveRequestSuccess(
                                 PendingSaveRequest.this);
                     }
@@ -516,13 +564,29 @@
 
                 @Override
                 public void onFailure(CharSequence message) {
+                    synchronized (mLock) {
+                        if (mCompleted) {
+                            return;
+                        }
+                        mCompleted = true;
+                    }
                     RemoteFillService service = mWeakService.get();
                     if (service != null) {
+                        service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
                         service.dispatchOnSaveRequestFailure(
                                 PendingSaveRequest.this, message);
                     }
                 }
             };
+            service.mHandler.getHandler().postAtTime(() -> {
+                cancel();
+                try {
+                    mCallback.onFailure(null);
+                } catch (RemoteException e) {
+                    /* ignore */
+                }
+            }, PendingSaveRequest.this,
+                    SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
         }
 
         @Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ef5cdd1..4746ee9 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -26,6 +26,7 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 
 import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sPartitionMaxCount;
 import static com.android.server.autofill.Helper.sVerbose;
 import static com.android.server.autofill.ViewState.STATE_AUTOFILLED;
 import static com.android.server.autofill.ViewState.STATE_RESTARTED_SESSION;
@@ -162,6 +163,7 @@
     @GuardedBy("mLock")
     private boolean mIsSaving;
 
+
     /**
      * Receiver of assist data from the app's {@link Activity}.
      */
@@ -933,7 +935,6 @@
         }
     }
 
-    private static final int PARTITION_MAX_COUNT = 64;
     /**
      * Determines if a new partition should be started for an id.
      *
@@ -947,8 +948,9 @@
         }
 
         final int numResponses = mResponses.size();
-        if (numResponses >= PARTITION_MAX_COUNT) {
-            Slog.e(TAG, "Cannot create more than 64 partitions. Not creating a new partition.");
+        if (numResponses >= sPartitionMaxCount) {
+            Slog.e(TAG, "Not starting a new partition on " + id + " because session " + this.id
+                    + " reached maximum of " + sPartitionMaxCount);
             return false;
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 5c57be2..f13dad7 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -2180,7 +2180,7 @@
 
     void setRequestedOrientation(int requestedOrientation) {
         if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen
-                && appInfo.targetSdkVersion >= O) {
+                && appInfo.targetSdkVersion > O) {
             throw new IllegalStateException("Only fullscreen activities can request orientation");
         }
 
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 7758516..788f21d 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -48,11 +48,13 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 
 public class RankingHelper implements RankingConfig {
     private static final String TAG = "RankingHelper";
@@ -574,12 +576,8 @@
         updateConfig();
     }
 
-    private void clearLockedFields(NotificationChannel channel) {
-        int clearMask = 0;
-        for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
-            clearMask |= NotificationChannel.LOCKABLE_FIELDS[i];
-        }
-        channel.lockFields(~clearMask);
+    void clearLockedFields(NotificationChannel channel) {
+        channel.unlockFields(channel.getUserLockedFields());
     }
 
     @Override
@@ -597,6 +595,7 @@
         if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
             updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
         }
+        lockFieldsForUpdate(channel, updatedChannel);
         r.channels.put(updatedChannel.getId(), updatedChannel);
 
         if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(updatedChannel.getId())) {
@@ -805,6 +804,35 @@
                 enabled ? DEFAULT_IMPORTANCE : NotificationManager.IMPORTANCE_NONE);
     }
 
+    @VisibleForTesting
+    void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
+        update.unlockFields(update.getUserLockedFields());
+        update.lockFields(original.getUserLockedFields());
+        if (original.canBypassDnd() != update.canBypassDnd()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
+        }
+        if (original.getLockscreenVisibility() != update.getLockscreenVisibility()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
+        }
+        if (original.getImportance() != update.getImportance()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+        }
+        if (original.shouldShowLights() != update.shouldShowLights()
+                || original.getLightColor() != update.getLightColor()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
+        }
+        if (!Objects.equals(original.getSound(), update.getSound())) {
+            update.lockFields(NotificationChannel.USER_LOCKED_SOUND);
+        }
+        if (!Arrays.equals(original.getVibrationPattern(), update.getVibrationPattern())
+                || original.shouldVibrate() != update.shouldVibrate()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
+        }
+        if (original.canShowBadge() != update.canShowBadge()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
         if (filter == null) {
             final int N = mSignalExtractors.length;
diff --git a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
index bbd4048..575e0f9 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
@@ -21,6 +21,7 @@
 import android.os.ShellCommand;
 
 import java.io.PrintWriter;
+import java.util.Locale;
 
 class OtaDexoptShellCommand extends ShellCommand {
     final IOtaDexopt mInterface;
@@ -93,7 +94,10 @@
     private int runOtaProgress() throws RemoteException {
         final float progress = mInterface.getProgress();
         final PrintWriter pw = getOutPrintWriter();
-        pw.format("%.2f", progress);
+        // Note: The float output is parsed by update_engine. It does needs to be non-localized,
+        //       as it's always expected to be "0.xy," never "0,xy" or similar. So use the ROOT
+        //       Locale for formatting. (b/37760573)
+        pw.format(Locale.ROOT, "%.2f", progress);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 982561c..96ea5e5 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1248,11 +1248,11 @@
      */
     @Override
     int getOrientation(int candidate) {
-        // We do not allow non-fullscreen apps to influence orientation at and beyond O. While we do
+        // We do not allow non-fullscreen apps to influence orientation beyond O. While we do
         // throw an exception in {@link Activity#onCreate} and
         // {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that
         // other calculations aren't affected.
-        if (!fillsParent() && mTargetSdk >= O) {
+        if (!fillsParent() && mTargetSdk > O) {
             // Can't specify orientation if app doesn't fill parent.
             return SCREEN_ORIENTATION_UNSET;
         }
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index b927e67..9c44c14 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 
 import android.app.ActivityManager.StackId;
 import android.app.RemoteAction;
@@ -285,13 +286,16 @@
             if (StackId.tasksAreFloating(mStackId)) {
                 // Floating tasks should not be resized to the screen's bounds.
 
-                if (bounds.width() == mTmpDisplayBounds.width() &&
+                if (mStackId == PINNED_STACK_ID && bounds.width() == mTmpDisplayBounds.width() &&
                         bounds.height() == mTmpDisplayBounds.height()) {
                     // If the bounds we are animating is the same as the fullscreen stack
                     // dimensions, then apply the same inset calculations that we normally do for
                     // the fullscreen stack, without intersecting it with the display bounds
                     stableBounds.inset(mTmpStableInsets);
                     nonDecorBounds.inset(mTmpNonDecorInsets);
+                    // Move app bounds to zero to apply intersection with parent correctly. They are
+                    // used only for evaluating width and height, so it's OK to move them around.
+                    config.appBounds.offsetTo(0, 0);
                     intersectParentBounds = true;
                 }
                 width = (int) (stableBounds.width() / density);
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 7bef033..30d6812 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -55,6 +55,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
+import android.util.Slog;
 import android.util.Xml;
 
 import java.io.BufferedInputStream;
@@ -90,6 +91,7 @@
     @Mock NotificationUsageStats mUsageStats;
     @Mock RankingHandler mHandler;
     @Mock PackageManager mPm;
+    @Mock Context mContext;
 
     private Notification mNotiGroupGSortA;
     private Notification mNotiGroupGSortB;
@@ -113,60 +115,6 @@
         MockitoAnnotations.initMocks(this);
         UserHandle user = UserHandle.ALL;
 
-        mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
-                new String[] {ImportanceExtractor.class.getName()});
-
-        mNotiGroupGSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
-                .setContentTitle("A")
-                .setGroup("G")
-                .setSortKey("A")
-                .setWhen(1205)
-                .build();
-        mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
-
-        mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
-                .setContentTitle("B")
-                .setGroup("G")
-                .setSortKey("B")
-                .setWhen(1200)
-                .build();
-        mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
-
-        mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
-                .setContentTitle("C")
-                .setWhen(1201)
-                .build();
-        mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, mNotiNoGroup, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
-
-        mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
-                .setContentTitle("D")
-                .setWhen(1202)
-                .build();
-        mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
-
-        mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
-                .setContentTitle("E")
-                .setWhen(1201)
-                .setSortKey("A")
-                .build();
-        mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
-
-        mAudioAttributes = new AudioAttributes.Builder()
-                .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
-                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
-                .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
-                .build();
-
         final ApplicationInfo legacy = new ApplicationInfo();
         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         final ApplicationInfo upgrade = new ApplicationInfo();
@@ -174,6 +122,64 @@
         when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
         when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
         when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
+        when(mContext.getResources()).thenReturn(
+                InstrumentationRegistry.getContext().getResources());
+        when(mContext.getPackageManager()).thenReturn(mPm);
+        when(mContext.getApplicationInfo()).thenReturn(legacy);
+
+        mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
+                new String[] {ImportanceExtractor.class.getName()});
+
+        mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setContentTitle("A")
+                .setGroup("G")
+                .setSortKey("A")
+                .setWhen(1205)
+                .build();
+        mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user,
+                null, System.currentTimeMillis()), getDefaultChannel());
+
+        mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setContentTitle("B")
+                .setGroup("G")
+                .setSortKey("B")
+                .setWhen(1200)
+                .build();
+        mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user,
+                null, System.currentTimeMillis()), getDefaultChannel());
+
+        mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setContentTitle("C")
+                .setWhen(1201)
+                .build();
+        mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user,
+                null, System.currentTimeMillis()), getDefaultChannel());
+
+        mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setContentTitle("D")
+                .setWhen(1202)
+                .build();
+        mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user,
+                null, System.currentTimeMillis()), getDefaultChannel());
+
+        mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setContentTitle("E")
+                .setWhen(1201)
+                .setSortKey("A")
+                .build();
+        mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user,
+                null, System.currentTimeMillis()), getDefaultChannel());
+
+        mAudioAttributes = new AudioAttributes.Builder()
+                .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+                .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+                .build();
     }
 
     private NotificationChannel getDefaultChannel() {
@@ -229,6 +235,10 @@
         assertEquals(expected.getName(), actual.getName());
     }
 
+    private NotificationChannel getChannel() {
+        return new NotificationChannel("id", "name", IMPORTANCE_LOW);
+    }
+
     @Test
     public void testFindAfterRankingWithASplitGroup() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -644,14 +654,119 @@
     }
 
     @Test
+    public void testClearLockedFields() throws Exception {
+        final NotificationChannel channel = getChannel();
+        mHelper.clearLockedFields(channel);
+        assertEquals(0, channel.getUserLockedFields());
+
+        channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
+                | NotificationChannel.USER_LOCKED_IMPORTANCE);
+        mHelper.clearLockedFields(channel);
+        assertEquals(0, channel.getUserLockedFields());
+    }
+
+    @Test
+    public void testLockFields_soundAndVibration() throws Exception {
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+
+        final NotificationChannel update1 = getChannel();
+        update1.setSound(new Uri.Builder().scheme("test").build(),
+                new AudioAttributes.Builder().build());
+        update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
+        mHelper.updateNotificationChannel(PKG, UID, update1);
+        assertEquals(NotificationChannel.USER_LOCKED_SOUND,
+                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                        .getUserLockedFields());
+
+        NotificationChannel update2 = getChannel();
+        update2.enableVibration(true);
+        mHelper.updateNotificationChannel(PKG, UID, update2);
+        assertEquals(NotificationChannel.USER_LOCKED_SOUND
+                        | NotificationChannel.USER_LOCKED_VIBRATION,
+                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                        .getUserLockedFields());
+    }
+
+    @Test
+    public void testLockFields_vibrationAndLights() throws Exception {
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+
+        final NotificationChannel update1 = getChannel();
+        update1.setVibrationPattern(new long[]{7945, 46 ,246});
+        mHelper.updateNotificationChannel(PKG, UID, update1);
+        assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
+                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                        .getUserLockedFields());
+
+        final NotificationChannel update2 = getChannel();
+        update2.enableLights(true);
+        mHelper.updateNotificationChannel(PKG, UID, update2);
+        assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
+                        | NotificationChannel.USER_LOCKED_LIGHTS,
+                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                        .getUserLockedFields());
+    }
+
+    @Test
+    public void testLockFields_lightsAndImportance() throws Exception {
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+
+        final NotificationChannel update1 = getChannel();
+        update1.setLightColor(Color.GREEN);
+        mHelper.updateNotificationChannel(PKG, UID, update1);
+        assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
+                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                        .getUserLockedFields());
+
+        final NotificationChannel update2 = getChannel();
+        update2.setImportance(IMPORTANCE_DEFAULT);
+        mHelper.updateNotificationChannel(PKG, UID, update2);
+        assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
+                        | NotificationChannel.USER_LOCKED_IMPORTANCE,
+                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                        .getUserLockedFields());
+    }
+
+    @Test
+    public void testLockFields_visibilityAndDndAndBadge() throws Exception {
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+        assertEquals(0,
+                mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false)
+                        .getUserLockedFields());
+
+        final NotificationChannel update1 = getChannel();
+        update1.setBypassDnd(true);
+        mHelper.updateNotificationChannel(PKG, UID, update1);
+        assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
+                mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+                        .getUserLockedFields());
+
+        final NotificationChannel update2 = getChannel();
+        update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+        mHelper.updateNotificationChannel(PKG, UID, update2);
+        assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
+                        | NotificationChannel.USER_LOCKED_VISIBILITY,
+                mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+                        .getUserLockedFields());
+
+        final NotificationChannel update3 = getChannel();
+        update3.setShowBadge(false);
+        mHelper.updateNotificationChannel(PKG, UID, update3);
+        assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
+                        | NotificationChannel.USER_LOCKED_VISIBILITY
+                        | NotificationChannel.USER_LOCKED_SHOW_BADGE,
+                mHelper.getNotificationChannel(PKG, UID, update3.getId(), false)
+                        .getUserLockedFields());
+    }
+
+    @Test
     public void testDeleteNonExistentChannel() throws Exception {
         mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist");
     }
 
     @Test
     public void testGetDeletedChannel() throws Exception {
-        NotificationChannel channel =
-                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+        NotificationChannel channel = getChannel();
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
         channel.enableLights(true);
         channel.setBypassDnd(true);