Merge "Add dirty_image_objects file." into oc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index a083e57..f32f23dd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -121,7 +121,6 @@
     field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
-    field public static final java.lang.String SEND_EMBMS_INTENTS = "android.permission.SEND_EMBMS_INTENTS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -10746,6 +10745,8 @@
     field public static final java.lang.String FEATURE_PC = "android.hardware.type.pc";
     field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
     field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
+    field public static final java.lang.String FEATURE_RAM_LOW = "android.hardware.ram.low";
+    field public static final java.lang.String FEATURE_RAM_NORMAL = "android.hardware.ram.normal";
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
@@ -31076,7 +31077,6 @@
     ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
     method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
     method public void close();
-    method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
     method public java.io.InputStream getInputStream();
     method public java.io.OutputStream getOutputStream();
     method public deprecated boolean isPurgingAllowed();
@@ -31508,8 +31508,6 @@
     method public void close();
     method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
     method public int describeContents();
-    method public int getFd();
-    method public java.io.FileDescriptor getFileDescriptor();
     method public int getSize();
     method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
     method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
diff --git a/api/removed.txt b/api/removed.txt
index ca34142..6c37a8f 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -25,30 +25,9 @@
     method public deprecated android.app.Notification.Builder setTimeout(long);
   }
 
-  public static final class Notification.TvExtender implements android.app.Notification.Extender {
-    method public deprecated java.lang.String getChannel();
-  }
-
   public final deprecated class PictureInPictureArgs implements android.os.Parcelable {
-    ctor public deprecated PictureInPictureArgs();
-    ctor public deprecated PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
     method public static android.app.PictureInPictureArgs convert(android.app.PictureInPictureParams);
     method public static android.app.PictureInPictureParams convert(android.app.PictureInPictureArgs);
-    method public void copyOnlySet(android.app.PictureInPictureArgs);
-    method public java.util.List<android.app.RemoteAction> getActions();
-    method public float getAspectRatio();
-    method public android.util.Rational getAspectRatioRational();
-    method public android.graphics.Rect getSourceRectHint();
-    method public android.graphics.Rect getSourceRectHintInsets();
-    method public boolean hasSetActions();
-    method public boolean hasSetAspectRatio();
-    method public boolean hasSourceBoundsHint();
-    method public boolean hasSourceBoundsHintInsets();
-    method public deprecated void setActions(java.util.List<android.app.RemoteAction>);
-    method public deprecated void setAspectRatio(float);
-    method public deprecated void setSourceRectHint(android.graphics.Rect);
-    method public deprecated void setSourceRectHintInsets(android.graphics.Rect);
-    method public void truncateActions(int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
   }
 
@@ -60,10 +39,6 @@
     method public android.app.PictureInPictureArgs.Builder setSourceRectHint(android.graphics.Rect);
   }
 
-  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
-    method public deprecated void showAsNotification(android.content.Context);
-  }
-
 }
 
 package android.app.admin {
@@ -71,8 +46,6 @@
   public class DevicePolicyManager {
     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 deprecated java.lang.String getDeviceInitializerApp();
-    method public deprecated android.content.ComponentName getDeviceInitializerComponent();
   }
 
 }
@@ -267,24 +240,12 @@
 
 }
 
-package android.net.wifi {
-
-  public class WifiManager {
-    method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
-  }
-
-}
-
 package android.os {
 
   public class BatteryManager {
     ctor public BatteryManager();
   }
 
-  public class Build {
-    field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
-  }
-
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
@@ -355,11 +316,8 @@
     field public static final java.lang.String CREATED = "created";
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String FAVICON = "favicon";
-    field public static final java.lang.String THUMBNAIL = "thumbnail";
     field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String TOUCH_ICON = "touch_icon";
     field public static final java.lang.String URL = "url";
-    field public static final java.lang.String USER_ENTERED = "user_entered";
     field public static final java.lang.String VISITS = "visits";
   }
 
@@ -450,26 +408,6 @@
 
 }
 
-package android.service.notification {
-
-  public abstract class NotificationListenerService extends android.app.Service {
-    method public android.service.notification.StatusBarNotification[] getActiveNotifications(int);
-    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[], int);
-    method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
-    method public final void setOnNotificationPostedTrim(int);
-    method public final void snoozeNotification(java.lang.String, java.lang.String);
-    method public void unregisterAsSystemService() throws android.os.RemoteException;
-    field public static final int TRIM_FULL = 0; // 0x0
-    field public static final int TRIM_LIGHT = 1; // 0x1
-  }
-
-  public static class NotificationListenerService.Ranking {
-    method public java.util.List<java.lang.String> getAdditionalPeople();
-    method public java.util.List<android.service.notification.SnoozeCriterion> getSnoozeCriteria();
-  }
-
-}
-
 package android.speech.tts {
 
   public abstract class UtteranceProgressListener {
diff --git a/api/system-current.txt b/api/system-current.txt
index 73b4ab0..970c318 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -228,7 +228,6 @@
     field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
     field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
-    field public static final java.lang.String SEND_EMBMS_INTENTS = "android.permission.SEND_EMBMS_INTENTS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
     field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
@@ -5323,7 +5322,6 @@
     method public java.lang.String getGroup();
     method public int getGroupAlertBehavior();
     method public android.graphics.drawable.Icon getLargeIcon();
-    method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
     method public java.lang.CharSequence getSettingsText();
     method public java.lang.String getShortcutId();
     method public android.graphics.drawable.Icon getSmallIcon();
@@ -6539,8 +6537,6 @@
     method public int getCurrentFailedPasswordAttempts();
     method public java.util.List<java.lang.String> getDelegatePackages(android.content.ComponentName, java.lang.String);
     method public java.util.List<java.lang.String> getDelegatedScopes(android.content.ComponentName, java.lang.String);
-    method public deprecated java.lang.String getDeviceInitializerApp();
-    method public deprecated android.content.ComponentName getDeviceInitializerComponent();
     method public java.lang.String getDeviceOwner();
     method public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
     method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
@@ -11465,6 +11461,8 @@
     field public static final java.lang.String FEATURE_PC = "android.hardware.type.pc";
     field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
     field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
+    field public static final java.lang.String FEATURE_RAM_LOW = "android.hardware.ram.low";
+    field public static final java.lang.String FEATURE_RAM_NORMAL = "android.hardware.ram.normal";
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
@@ -29283,7 +29281,6 @@
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
-    method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
     method public boolean setWifiEnabled(boolean);
     method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
     method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource);
@@ -33386,7 +33383,6 @@
     field public static final java.lang.String ID;
     field public static final java.lang.String MANUFACTURER;
     field public static final java.lang.String MODEL;
-    field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
     field public static final deprecated java.lang.String SERIAL;
@@ -33924,7 +33920,6 @@
     ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
     method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
     method public void close();
-    method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
     method public java.io.InputStream getInputStream();
     method public java.io.OutputStream getOutputStream();
     method public deprecated boolean isPurgingAllowed();
@@ -34385,8 +34380,6 @@
     method public void close();
     method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
     method public int describeContents();
-    method public int getFd();
-    method public java.io.FileDescriptor getFileDescriptor();
     method public int getSize();
     method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
     method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
@@ -40625,9 +40618,7 @@
     method public final void cancelNotification(java.lang.String);
     method public final void cancelNotifications(java.lang.String[]);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
-    method public android.service.notification.StatusBarNotification[] getActiveNotifications(int);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
-    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[], int);
     method public final int getCurrentInterruptionFilter();
     method public final int getCurrentListenerHints();
     method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
@@ -40647,16 +40638,12 @@
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
-    method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
     method public static void requestRebind(android.content.ComponentName);
     method public final void requestUnbind();
     method public final void setNotificationsShown(java.lang.String[]);
-    method public final void setOnNotificationPostedTrim(int);
-    method public final void snoozeNotification(java.lang.String, java.lang.String);
     method public final void snoozeNotification(java.lang.String, long);
-    method public void unregisterAsSystemService() throws android.os.RemoteException;
     method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel);
     field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
@@ -40691,21 +40678,17 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
-    field public static final int TRIM_FULL = 0; // 0x0
-    field public static final int TRIM_LIGHT = 1; // 0x1
   }
 
   public static class NotificationListenerService.Ranking {
     ctor public NotificationListenerService.Ranking();
     method public boolean canShowBadge();
-    method public java.util.List<java.lang.String> getAdditionalPeople();
     method public android.app.NotificationChannel getChannel();
     method public int getImportance();
     method public java.lang.CharSequence getImportanceExplanation();
     method public java.lang.String getKey();
     method public java.lang.String getOverrideGroupKey();
     method public int getRank();
-    method public java.util.List<android.service.notification.SnoozeCriterion> getSnoozeCriteria();
     method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index dfadae4..a320a8c 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -15,6 +15,7 @@
 
   public class Notification implements android.os.Parcelable {
     method public deprecated java.lang.String getChannel();
+    method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
     method public deprecated long getTimeout();
     method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
   }
@@ -29,25 +30,8 @@
   }
 
   public final deprecated class PictureInPictureArgs implements android.os.Parcelable {
-    ctor public deprecated PictureInPictureArgs();
-    ctor public deprecated PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
     method public static android.app.PictureInPictureArgs convert(android.app.PictureInPictureParams);
     method public static android.app.PictureInPictureParams convert(android.app.PictureInPictureArgs);
-    method public void copyOnlySet(android.app.PictureInPictureArgs);
-    method public java.util.List<android.app.RemoteAction> getActions();
-    method public float getAspectRatio();
-    method public android.util.Rational getAspectRatioRational();
-    method public android.graphics.Rect getSourceRectHint();
-    method public android.graphics.Rect getSourceRectHintInsets();
-    method public boolean hasSetActions();
-    method public boolean hasSetAspectRatio();
-    method public boolean hasSourceBoundsHint();
-    method public boolean hasSourceBoundsHintInsets();
-    method public deprecated void setActions(java.util.List<android.app.RemoteAction>);
-    method public deprecated void setAspectRatio(float);
-    method public deprecated void setSourceRectHint(android.graphics.Rect);
-    method public deprecated void setSourceRectHintInsets(android.graphics.Rect);
-    method public void truncateActions(int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
   }
 
@@ -59,10 +43,6 @@
     method public android.app.PictureInPictureArgs.Builder setSourceRectHint(android.graphics.Rect);
   }
 
-  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
-    method public deprecated void showAsNotification(android.content.Context);
-  }
-
 }
 
 package android.app.admin {
@@ -70,6 +50,8 @@
   public class DevicePolicyManager {
     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 deprecated java.lang.String getDeviceInitializerApp();
+    method public deprecated android.content.ComponentName getDeviceInitializerComponent();
   }
 
 }
@@ -264,12 +246,24 @@
 
 }
 
+package android.net.wifi {
+
+  public class WifiManager {
+    method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
+  }
+
+}
+
 package android.os {
 
   public class BatteryManager {
     ctor public BatteryManager();
   }
 
+  public class Build {
+    field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
+  }
+
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
@@ -340,11 +334,8 @@
     field public static final java.lang.String CREATED = "created";
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String FAVICON = "favicon";
-    field public static final java.lang.String THUMBNAIL = "thumbnail";
     field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String TOUCH_ICON = "touch_icon";
     field public static final java.lang.String URL = "url";
-    field public static final java.lang.String USER_ENTERED = "user_entered";
     field public static final java.lang.String VISITS = "visits";
   }
 
@@ -435,6 +426,26 @@
 
 }
 
+package android.service.notification {
+
+  public abstract class NotificationListenerService extends android.app.Service {
+    method public android.service.notification.StatusBarNotification[] getActiveNotifications(int);
+    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[], int);
+    method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
+    method public final void setOnNotificationPostedTrim(int);
+    method public final void snoozeNotification(java.lang.String, java.lang.String);
+    method public void unregisterAsSystemService() throws android.os.RemoteException;
+    field public static final int TRIM_FULL = 0; // 0x0
+    field public static final int TRIM_LIGHT = 1; // 0x1
+  }
+
+  public static class NotificationListenerService.Ranking {
+    method public java.util.List<java.lang.String> getAdditionalPeople();
+    method public java.util.List<android.service.notification.SnoozeCriterion> getSnoozeCriteria();
+  }
+
+}
+
 package android.speech.tts {
 
   public abstract class UtteranceProgressListener {
diff --git a/api/test-current.txt b/api/test-current.txt
index b57b82d..ccdca6a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -121,7 +121,6 @@
     field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
-    field public static final java.lang.String SEND_EMBMS_INTENTS = "android.permission.SEND_EMBMS_INTENTS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -10788,6 +10787,8 @@
     field public static final java.lang.String FEATURE_PC = "android.hardware.type.pc";
     field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
     field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
+    field public static final java.lang.String FEATURE_RAM_LOW = "android.hardware.ram.low";
+    field public static final java.lang.String FEATURE_RAM_NORMAL = "android.hardware.ram.normal";
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
@@ -31233,7 +31234,6 @@
     ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
     method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
     method public void close();
-    method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
     method public java.io.InputStream getInputStream();
     method public java.io.OutputStream getOutputStream();
     method public deprecated boolean isPurgingAllowed();
@@ -31666,8 +31666,6 @@
     method public void close();
     method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
     method public int describeContents();
-    method public int getFd();
-    method public java.io.FileDescriptor getFileDescriptor();
     method public int getSize();
     method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
     method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
diff --git a/api/test-removed.txt b/api/test-removed.txt
index ca34142..6c37a8f 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -25,30 +25,9 @@
     method public deprecated android.app.Notification.Builder setTimeout(long);
   }
 
-  public static final class Notification.TvExtender implements android.app.Notification.Extender {
-    method public deprecated java.lang.String getChannel();
-  }
-
   public final deprecated class PictureInPictureArgs implements android.os.Parcelable {
-    ctor public deprecated PictureInPictureArgs();
-    ctor public deprecated PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
     method public static android.app.PictureInPictureArgs convert(android.app.PictureInPictureParams);
     method public static android.app.PictureInPictureParams convert(android.app.PictureInPictureArgs);
-    method public void copyOnlySet(android.app.PictureInPictureArgs);
-    method public java.util.List<android.app.RemoteAction> getActions();
-    method public float getAspectRatio();
-    method public android.util.Rational getAspectRatioRational();
-    method public android.graphics.Rect getSourceRectHint();
-    method public android.graphics.Rect getSourceRectHintInsets();
-    method public boolean hasSetActions();
-    method public boolean hasSetAspectRatio();
-    method public boolean hasSourceBoundsHint();
-    method public boolean hasSourceBoundsHintInsets();
-    method public deprecated void setActions(java.util.List<android.app.RemoteAction>);
-    method public deprecated void setAspectRatio(float);
-    method public deprecated void setSourceRectHint(android.graphics.Rect);
-    method public deprecated void setSourceRectHintInsets(android.graphics.Rect);
-    method public void truncateActions(int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
   }
 
@@ -60,10 +39,6 @@
     method public android.app.PictureInPictureArgs.Builder setSourceRectHint(android.graphics.Rect);
   }
 
-  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
-    method public deprecated void showAsNotification(android.content.Context);
-  }
-
 }
 
 package android.app.admin {
@@ -71,8 +46,6 @@
   public class DevicePolicyManager {
     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 deprecated java.lang.String getDeviceInitializerApp();
-    method public deprecated android.content.ComponentName getDeviceInitializerComponent();
   }
 
 }
@@ -267,24 +240,12 @@
 
 }
 
-package android.net.wifi {
-
-  public class WifiManager {
-    method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
-  }
-
-}
-
 package android.os {
 
   public class BatteryManager {
     ctor public BatteryManager();
   }
 
-  public class Build {
-    field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
-  }
-
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
@@ -355,11 +316,8 @@
     field public static final java.lang.String CREATED = "created";
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String FAVICON = "favicon";
-    field public static final java.lang.String THUMBNAIL = "thumbnail";
     field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String TOUCH_ICON = "touch_icon";
     field public static final java.lang.String URL = "url";
-    field public static final java.lang.String USER_ENTERED = "user_entered";
     field public static final java.lang.String VISITS = "visits";
   }
 
@@ -450,26 +408,6 @@
 
 }
 
-package android.service.notification {
-
-  public abstract class NotificationListenerService extends android.app.Service {
-    method public android.service.notification.StatusBarNotification[] getActiveNotifications(int);
-    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[], int);
-    method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
-    method public final void setOnNotificationPostedTrim(int);
-    method public final void snoozeNotification(java.lang.String, java.lang.String);
-    method public void unregisterAsSystemService() throws android.os.RemoteException;
-    field public static final int TRIM_FULL = 0; // 0x0
-    field public static final int TRIM_LIGHT = 1; // 0x1
-  }
-
-  public static class NotificationListenerService.Ranking {
-    method public java.util.List<java.lang.String> getAdditionalPeople();
-    method public java.util.List<android.service.notification.SnoozeCriterion> getSnoozeCriteria();
-  }
-
-}
-
 package android.speech.tts {
 
   public abstract class UtteranceProgressListener {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index f0189c2..ad989de 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -414,7 +414,7 @@
                 try {
                     ApkLite baseApk = PackageParser.parseApkLite(file, 0);
                     PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
-                            null, null, null);
+                            null, null);
                     params.sessionParams.setSize(
                             PackageHelper.calculateInstalledSize(pkgLite, false,
                             params.sessionParams.abiOverride));
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f6eaed4..adc6467 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -31,6 +31,7 @@
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.annotation.XmlRes;
+import android.app.ActivityManager;
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
 import android.app.admin.DevicePolicyManager;
@@ -1790,6 +1791,24 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device's
+     * {@link ActivityManager#isLowRamDevice() ActivityManager.isLowRamDevice()} method returns
+     * true.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_RAM_LOW = "android.hardware.ram.low";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device's
+     * {@link ActivityManager#isLowRamDevice() ActivityManager.isLowRamDevice()} method returns
+     * false.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_RAM_NORMAL = "android.hardware.ram.normal";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device can record audio via a
      * microphone.
      */
@@ -3776,7 +3795,6 @@
 
     /**
      * @removed
-     * @hide
      */
     public abstract boolean setInstantAppCookie(@Nullable byte[] cookie);
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d0964c9..7cc02b4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -428,12 +428,9 @@
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
 
-        public final String classLoaderName;
-        public final String[] splitClassLoaderNames;
-
         public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
                 boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
-                String[] splitCodePaths, int[] splitRevisionCodes, String[] splitClassLoaderNames) {
+                String[] splitCodePaths, int[] splitRevisionCodes) {
             this.packageName = baseApk.packageName;
             this.versionCode = baseApk.versionCode;
             this.installLocation = baseApk.installLocation;
@@ -453,9 +450,6 @@
             this.use32bitAbi = baseApk.use32bitAbi;
             this.extractNativeLibs = baseApk.extractNativeLibs;
             this.isolatedSplits = baseApk.isolatedSplits;
-
-            this.classLoaderName = baseApk.classLoaderName;
-            this.splitClassLoaderNames = splitClassLoaderNames;
         }
 
         public List<String> getAllCodePaths() {
@@ -490,14 +484,13 @@
         public final boolean use32bitAbi;
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
-        public final String classLoaderName;
 
         public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
                 String configForSplit, String usesSplitName, int versionCode, int revisionCode,
                 int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
                 Certificate[][] certificates, boolean coreApp, boolean debuggable,
                 boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
-                boolean isolatedSplits, String classLoaderName) {
+                boolean isolatedSplits) {
             this.codePath = codePath;
             this.packageName = packageName;
             this.splitName = splitName;
@@ -516,7 +509,6 @@
             this.use32bitAbi = use32bitAbi;
             this.extractNativeLibs = extractNativeLibs;
             this.isolatedSplits = isolatedSplits;
-            this.classLoaderName = classLoaderName;
         }
     }
 
@@ -885,7 +877,7 @@
         final ApkLite baseApk = parseApkLite(packageFile, flags);
         final String packagePath = packageFile.getAbsolutePath();
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null, null);
+        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
     }
 
     static PackageLite parseClusterPackageLite(File packageDir, int flags)
@@ -956,7 +948,6 @@
             configForSplits = new String[size];
             splitCodePaths = new String[size];
             splitRevisionCodes = new int[size];
-            splitClassLoaderNames = new String[size];
 
             splitNames = apks.keySet().toArray(splitNames);
             Arrays.sort(splitNames, sSplitNameComparator);
@@ -968,13 +959,12 @@
                 configForSplits[i] = apk.configForSplit;
                 splitCodePaths[i] = apk.codePath;
                 splitRevisionCodes[i] = apk.revisionCode;
-                splitClassLoaderNames[i] = apk.classLoaderName;
             }
         }
 
         final String codePath = packageDir.getAbsolutePath();
         return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
-                configForSplits, splitCodePaths, splitRevisionCodes, splitClassLoaderNames);
+                configForSplits, splitCodePaths, splitRevisionCodes);
     }
 
     /**
@@ -1239,8 +1229,7 @@
                 pkg.splitPrivateFlags = new int[num];
                 pkg.applicationInfo.splitNames = pkg.splitNames;
                 pkg.applicationInfo.splitDependencies = splitDependencies;
-                pkg.applicationInfo.classLoaderName = lite.classLoaderName;
-                pkg.applicationInfo.splitClassLoaderNames = lite.splitClassLoaderNames;
+                pkg.applicationInfo.splitClassLoaderNames = new String[num];
 
                 for (int i = 0; i < num; i++) {
                     final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
@@ -1854,7 +1843,6 @@
         boolean isFeatureSplit = false;
         String configForSplit = null;
         String usesSplitName = null;
-        String classLoaderName = null;
 
         for (int i = 0; i < attrs.getAttributeCount(); i++) {
             final String attr = attrs.getAttributeName(i);
@@ -1911,14 +1899,6 @@
                     if ("extractNativeLibs".equals(attr)) {
                         extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
                     }
-                    if ("classLoader".equals(attr)) {
-                        classLoaderName = attrs.getAttributeValue(i);
-                        if (!ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
-                            throw new PackageParserException(
-                                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                                    "Invalid class loader name: " + classLoaderName);
-                        }
-                    }
                 }
             } else if (TAG_USES_SPLIT.equals(parser.getName())) {
                 if (usesSplitName != null) {
@@ -1938,7 +1918,7 @@
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                 configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
                 verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
-                extractNativeLibs, isolatedSplits, classLoaderName);
+                extractNativeLibs, isolatedSplits);
     }
 
     /**
@@ -3690,6 +3670,13 @@
         ai.uiOptions = sa.getInt(
                 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
 
+        ai.classLoaderName = sa.getString(
+            com.android.internal.R.styleable.AndroidManifestApplication_classLoader);
+        if (ai.classLoaderName != null
+                && !ClassLoaderFactory.isValidClassLoaderName(ai.classLoaderName)) {
+            outError[0] = "Invalid class loader name: " + ai.classLoaderName;
+        }
+
         sa.recycle();
 
         if (outError[0] != null) {
@@ -3939,6 +3926,16 @@
             owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
         }
 
+        final String classLoaderName = sa.getString(
+                com.android.internal.R.styleable.AndroidManifestApplication_classLoader);
+        if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+            owner.applicationInfo.splitClassLoaderNames[splitIndex] = classLoaderName;
+        } else {
+            outError[0] = "Invalid class loader name: " + classLoaderName;
+            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+            return false;
+        }
+
         final int innerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 5032e6a..7d301a3 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -136,7 +136,6 @@
     }
 
     /**
-     * @hide
      * @removed
      */
     public boolean isBuiltin() {
@@ -144,7 +143,6 @@
     }
 
     /**
-     * @hide
      * @removed
      */
     public boolean isDynamic() {
@@ -152,7 +150,6 @@
     }
 
     /**
-     * @hide
      * @removed
      */
     public boolean isStatic() {
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 181e4a2..f75789f 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -72,4 +72,6 @@
     void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
 
     void factoryReset(String subscriber);
+
+    boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 6d44330..cea5715 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3667,25 +3667,29 @@
                         0 /* old cpu power, keep for compatibility */);
             }
 
-            final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which);
-            // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes.
-            if (cpuFreqTimeMs != null) {
-                sb.setLength(0);
-                for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
-                    sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]);
-                }
-                final long[] screenOffCpuFreqTimeMs = u.getScreenOffCpuFreqTimes(which);
-                if (screenOffCpuFreqTimeMs != null) {
-                    for (int i = 0; i < screenOffCpuFreqTimeMs.length; ++i) {
-                        sb.append("," + screenOffCpuFreqTimeMs[i]);
-                    }
-                } else {
+            // If the cpuFreqs is null, then don't bother checking for cpu freq times.
+            if (cpuFreqs != null) {
+                final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which);
+                // If total cpuFreqTimes is null, then we don't need to check for
+                // screenOffCpuFreqTimes.
+                if (cpuFreqTimeMs != null && cpuFreqTimeMs.length == cpuFreqs.length) {
+                    sb.setLength(0);
                     for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
-                        sb.append(",0");
+                        sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]);
                     }
+                    final long[] screenOffCpuFreqTimeMs = u.getScreenOffCpuFreqTimes(which);
+                    if (screenOffCpuFreqTimeMs != null) {
+                        for (int i = 0; i < screenOffCpuFreqTimeMs.length; ++i) {
+                            sb.append("," + screenOffCpuFreqTimeMs[i]);
+                        }
+                    } else {
+                        for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
+                            sb.append(",0");
+                        }
+                    }
+                    dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL,
+                            cpuFreqTimeMs.length, sb.toString());
                 }
-                dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL,
-                        cpuFreqTimeMs.length, sb.toString());
             }
 
             final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 0541a53..7852125 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -757,6 +757,16 @@
 
         /**
          * O.
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li>{@link android.R.attr#focusable} defaults to a new state ({@code auto}) where it will
+         * inherit the value of {@link android.R.attr#clickable} unless explicitly overridden.</li>
+         * <li>A default theme-appropriate focus-state highlight will be supplied to all Views
+         * which don't provide a focus-state drawable themselves. This can be disabled by setting
+         * {@link android.R.attr#defaultFocusHighlightEnabled} to false.</li>
+         * </ul>
          */
         public static final int O = 26;
 
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 3de2174..b916b43 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -435,4 +435,6 @@
     int removeRoutesFromLocalNetwork(in List<RouteInfo> routes);
 
     void setAllowOnlyVpnForUids(boolean enable, in UidRange[] uidRanges);
+
+    boolean isNetworkRestricted(int uid);
 }
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index 9294c44..ff3258f 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -219,6 +219,8 @@
      * The returned file descriptor is not duplicated.
      *
      * @throws IOException If the memory file has been closed.
+     *
+     * @hide
      */
     public FileDescriptor getFileDescriptor() throws IOException {
         return mSharedMemory.getFileDescriptor();
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 459aeb0..e6c7a17 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -60,7 +60,8 @@
         }
 
         mMemoryRegistration = new MemoryRegistration(mSize);
-        mCleaner = Cleaner.create(this, new Closer(mFileDescriptor, mMemoryRegistration));
+        mCleaner = Cleaner.create(mFileDescriptor,
+                new Closer(mFileDescriptor, mMemoryRegistration));
     }
 
     /**
@@ -138,6 +139,8 @@
      * This FileDescriptor is interoperable with the ASharedMemory NDK APIs.
      *
      * @return Returns the FileDescriptor associated with this object.
+     *
+     * @hide Exists only for MemoryFile interop
      */
     public @NonNull FileDescriptor getFileDescriptor() {
         return mFileDescriptor;
@@ -150,6 +153,8 @@
      * This fd is interoperable with the ASharedMemory NDK APIs.
      *
      * @return Returns the native fd associated with this object, or -1 if it is already closed.
+     *
+     * @hide Exposed for native ASharedMemory_dupFromJava()
      */
     public int getFd() {
         return mFileDescriptor.getInt$();
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 70ef035..cc1c067 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1878,7 +1878,6 @@
          * @deprecated - Do not use. This will not be supported in the future. In the future,
          * cursors returned from related queries will be empty.
          *
-         * @hide
          * @removed
          */
         @Deprecated
@@ -2975,7 +2974,6 @@
          * @deprecated - Do not use. This will not be supported in the future. In the future,
          * cursors returned from related queries will be empty.
          *
-         * @hide
          * @removed
          */
         @Deprecated
@@ -3414,7 +3412,6 @@
      * @deprecated - Do not use. This will not be supported in the future. In the future,
      * cursors returned from related queries will be empty.
      *
-     * @hide
      * @removed
      */
     @Deprecated
@@ -3515,7 +3512,6 @@
          * @deprecated - Do not use. This will not be supported in the future. In the future,
          * cursors returned from related queries will be empty.
          *
-         * @hide
          * @removed
          */
         @Deprecated
@@ -3568,7 +3564,6 @@
      * @deprecated - Do not use. This will not be supported in the future. In the future,
      * cursors returned from related queries will be empty.
      *
-     * @hide
      * @removed
      */
     @Deprecated
@@ -3961,7 +3956,6 @@
      * @deprecated - Do not use. This will not be supported in the future. In the future,
      * cursors returned from related queries will be empty.
      *
-     * @hide
      * @removed
      */
     @Deprecated
@@ -4002,7 +3996,6 @@
      * @deprecated - Do not use. This will not be supported in the future. In the future,
      * cursors returned from related queries will be empty.
      *
-     * @hide
      * @removed
      */
     @Deprecated
diff --git a/core/java/android/service/autofill/CharSequenceTransformation.java b/core/java/android/service/autofill/CharSequenceTransformation.java
index dfb30b9..8ab856e 100644
--- a/core/java/android/service/autofill/CharSequenceTransformation.java
+++ b/core/java/android/service/autofill/CharSequenceTransformation.java
@@ -31,6 +31,7 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
@@ -53,7 +54,8 @@
  * fields (month and year) would be:
  *
  * <pre class="prettyprint">
- * new CharSequenceTransformation.Builder(ccExpMonthId, Pattern.compile("^(\\d\\d)$"), "Exp: $1")
+ * new CharSequenceTransformation
+ *   .Builder(ccExpMonthId, Pattern.compile("^(\\d\\d)$"), "Exp: $1")
  *   .addField(ccExpYearId, Pattern.compile("^(\\d\\d\\d\\d)$"), " / $1");
  * </pre>
  */
@@ -83,8 +85,13 @@
                 return;
             }
             try {
+                final Matcher matcher = field.first.matcher(value);
+                if (!matcher.matches()) {
+                    if (sDebug) Log.d(TAG, "match for " + field.first + " failed on id " + id);
+                    return;
+                }
                 // replaceAll throws an exception if the subst is invalid
-                final String convertedValue = field.first.matcher(value).replaceAll(field.second);
+                final String convertedValue = matcher.replaceAll(field.second);
                 converted.append(convertedValue);
             } catch (Exception e) {
                 // Do not log full exception to avoid PII leaking
diff --git a/core/java/android/service/autofill/ImageTransformation.java b/core/java/android/service/autofill/ImageTransformation.java
index 3627189..2151f74 100644
--- a/core/java/android/service/autofill/ImageTransformation.java
+++ b/core/java/android/service/autofill/ImageTransformation.java
@@ -78,8 +78,7 @@
         }
         final int size = mOptions.size();
         if (sDebug) {
-            Log.d(TAG, size + " multiple options on id " + childViewId + " to compare against "
-                    + value);
+            Log.d(TAG, size + " multiple options on id " + childViewId + " to compare against");
         }
 
         for (int i = 0; i < size; i++) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eea692a..2b4015f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13284,7 +13284,7 @@
                 // about in case nothing has focus.  even if this specific view
                 // isn't focusable, it may contain something that is, so let
                 // the root view try to give this focus if nothing else does.
-                if ((mParent != null)) {
+                if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) {
                     mParent.focusableViewAvailable(this);
                 }
             }
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 401cac8..02b6185 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -323,6 +323,20 @@
     }
 
     /**
+     * Sets if the source is important for accessibility.
+     *
+     * @param importantForAccessibility True if the source is important for accessibility,
+     *                                  false otherwise.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     * @hide
+     */
+    public void setImportantForAccessibility(boolean importantForAccessibility) {
+        enforceNotSealed();
+        setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, importantForAccessibility);
+    }
+
+    /**
      * Gets the number of items that can be visited.
      *
      * @return The number of items.
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 611c4b8..41fc0650 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1063,6 +1063,10 @@
             }
         }
 
+        public int getSize() {
+            return mCounts == null ? 0 : mCounts.length;
+        }
+
         /**
          * Clear state of this counter.
          */
@@ -10526,11 +10530,13 @@
                             return;
                         }
                         final Uid u = getUidStatsLocked(uid);
-                        if (u.mCpuFreqTimeMs == null) {
+                        if (u.mCpuFreqTimeMs == null
+                                || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
                             u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
                         }
                         u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
-                        if (u.mScreenOffCpuFreqTimeMs == null) {
+                        if (u.mScreenOffCpuFreqTimeMs == null
+                                || u.mScreenOffCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
                             u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
                                     mOnBatteryScreenOffTimeBase);
                         }
diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java
index 0df420b..b2b769e 100644
--- a/core/java/com/android/internal/os/ClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/ClassLoaderFactory.java
@@ -71,7 +71,7 @@
             String librarySearchPath, ClassLoader parent, String classloaderName) {
         if (isPathClassLoaderName(classloaderName)) {
             return new PathClassLoader(dexPath, librarySearchPath, parent);
-        } else if (isPathClassLoaderName(classloaderName)) {
+        } else if (isDelegateLastClassLoaderName(classloaderName)) {
             return new DelegateLastClassLoader(dexPath, librarySearchPath, parent);
         }
 
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index d109a5a..59e5a64 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -28,4 +28,12 @@
     public static <T> T firstNotNull(@Nullable T a, @NonNull T b) {
         return a != null ? a : Preconditions.checkNotNull(b);
     }
+
+    public static <T extends Comparable> int compare(@Nullable T a, @Nullable T b) {
+        if (a != null) {
+            return (b != null) ? a.compareTo(b) : 1;
+        } else {
+            return (b != null) ? -1 : 0;
+        }
+    }
 }
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 67f9f8f..81018fe 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -584,6 +584,12 @@
             addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
         }
 
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            addFeature(PackageManager.FEATURE_RAM_LOW, 0);
+        } else {
+            addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
+        }
+
         for (String featureName : mUnavailableFeatures) {
             removeFeature(featureName);
         }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 208c776..b55ad21 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1700,7 +1700,8 @@
     <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to send EMBMS download intents to apps-->
+      <!-- Allows an application to send EMBMS download intents to apps
+           @hide -->
     <permission android:name="android.permission.SEND_EMBMS_INTENTS"
         android:protectionLevel="signature|privileged" />
 
@@ -1824,10 +1825,6 @@
     <permission android:name="android.permission.MANAGE_USERS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @hide Allows an application to configure the assist gesture -->
-    <permission android:name="android.permission.CONFIGURE_ASSIST_GESTURE"
-        android:protectionLevel="signature" />
-
     <!-- @hide Allows an application to create, remove users and get the list of
          users on the device. Applications holding this permission can only create restricted,
          guest, managed, demo, and ephemeral users. For creating other kind of users,
diff --git a/core/res/res/values-mcc262-mnc02/strings.xml b/core/res/res/values-mcc262-mnc02/strings.xml
new file mode 100644
index 0000000..2b89401
--- /dev/null
+++ b/core/res/res/values-mcc262-mnc02/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2017, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+     <!-- Do not translate. Template for showing mobile network operator name while WFC is active -->
+     <string-array name="wfcSpnFormats">
+         <item>%s</item>
+         <item>%s Wi-Fi Calling</item>
+     </string-array>
+</resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 7b26cf2..733878b 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -47,10 +47,6 @@
         <item>@drawable/ic_clear_material</item>
         <item>@drawable/ic_dialog_alert_material</item>
         <item>@drawable/ic_go_search_api_material</item>
-        <item>@drawable/ic_media_route_connecting_dark_material</item>
-        <item>@drawable/ic_media_route_connecting_light_material</item>
-        <item>@drawable/ic_media_route_dark_material</item>
-        <item>@drawable/ic_media_route_light_material</item>
         <item>@drawable/ic_menu_copy_material</item>
         <item>@drawable/ic_menu_cut_material</item>
         <item>@drawable/ic_menu_moreoverflow_material</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 961d639..066c051 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2810,9 +2810,6 @@
     <!-- True if camera app should be pinned via Pinner Service -->
     <bool name="config_pinnerCameraApp">false</bool>
 
-    <!-- Component that runs demo mode when it is enabled. -->
-    <string name="config_demoModePackage" translatable="false"></string>
-
     <!-- Number of days preloaded file cache should be preserved on a device before it can be
          deleted -->
     <integer name="config_keepPreloadsMinDays">7</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6042234..e67884d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1157,7 +1157,6 @@
   <java-symbol type="string" name="lockscreen_transport_pause_description" />
   <java-symbol type="string" name="config_ethernet_tcp_buffers" />
   <java-symbol type="string" name="config_wifi_tcp_buffers" />
-  <java-symbol type="string" name="config_demoModePackage" />
   <java-symbol type="string" name="demo_starting_message" />
   <java-symbol type="string" name="demo_restarting_message" />
   <java-symbol type="string" name="conference_call" />
diff --git a/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java
new file mode 100644
index 0000000..443183e
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.internal.util;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class ObjectUtilsTest extends AndroidTestCase {
+    public void testCompare() {
+        assertEquals(0, ObjectUtils.compare(null, null));
+        assertEquals(1, ObjectUtils.compare("a", null));
+        assertEquals(-1, ObjectUtils.compare(null, "a"));
+
+        assertEquals(0, ObjectUtils.compare("a", "a"));
+
+        assertEquals(-1, ObjectUtils.compare("a", "b"));
+        assertEquals(1, ObjectUtils.compare("b", "a"));
+    }
+}
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 2fdfcd4..0700d1f 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -50,9 +50,9 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Caches::Caches(RenderState& renderState)
-        : gradientCache(mExtensions)
+        : gradientCache(extensions())
         , patchCache(renderState)
-        , programCache(mExtensions)
+        , programCache(extensions())
         , mRenderState(&renderState)
         , mInitialized(false) {
     INIT_LOGD("Creating OpenGL renderer caches");
@@ -80,7 +80,7 @@
 }
 
 void Caches::initExtensions() {
-    if (mExtensions.hasDebugMarker()) {
+    if (extensions().hasDebugMarker()) {
         eventMark = glInsertEventMarkerEXT;
 
         startMark = glPushGroupMarkerEXT;
@@ -93,12 +93,12 @@
 }
 
 void Caches::initConstraints() {
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+    maxTextureSize = DeviceInfo::get()->maxTextureSize();
 }
 
 void Caches::initStaticProperties() {
     // OpenGL ES 3.0+ specific features
-    gpuPixelBuffersEnabled = mExtensions.hasPixelBufferObjects()
+    gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects()
             && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
 }
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 19063e3..29eddde 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "DeviceInfo.h"
 #include "Extensions.h"
 #include "FboCache.h"
 #include "GammaFontRenderer.h"
@@ -145,10 +146,6 @@
     // Misc
     GLint maxTextureSize;
 
-private:
-    // Declared before gradientCache and programCache which need this to initialize.
-    // TODO: cleanup / move elsewhere
-    Extensions mExtensions;
 public:
     TextureCache textureCache;
     RenderBufferCache renderBufferCache;
@@ -174,7 +171,7 @@
     void setProgram(const ProgramDescription& description);
     void setProgram(Program* program);
 
-    const Extensions& extensions() const { return mExtensions; }
+    const Extensions& extensions() const { return DeviceInfo::get()->extensions(); }
     Program& program() { return *mProgram; }
     PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
     TextureState& textureState() { return *mTextureState; }
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index d180ba5..37965da 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -16,7 +16,8 @@
 
 #include <DeviceInfo.h>
 
-#include "Extensions.h"
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
 
 #include <thread>
 #include <mutex>
@@ -46,13 +47,22 @@
 void DeviceInfo::initialize(int maxTextureSize) {
     std::call_once(sInitializedFlag, [maxTextureSize]() {
         sDeviceInfo = new DeviceInfo();
+        sDeviceInfo->loadDisplayInfo();
         sDeviceInfo->mMaxTextureSize = maxTextureSize;
     });
 }
 
 void DeviceInfo::load() {
+    loadDisplayInfo();
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
 }
 
+void DeviceInfo::loadDisplayInfo() {
+    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain));
+    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to get display info, error %d", status);
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index aff84b0..5bd7b14 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -16,7 +16,10 @@
 #ifndef DEVICEINFO_H
 #define DEVICEINFO_H
 
+#include <ui/DisplayInfo.h>
+
 #include "utils/Macros.h"
+#include "Extensions.h"
 
 namespace android {
 namespace uirenderer {
@@ -35,14 +38,24 @@
     static void initialize(int maxTextureSize);
 
     int maxTextureSize() const { return mMaxTextureSize; }
+    const DisplayInfo& displayInfo() const { return mDisplayInfo; }
+    const Extensions& extensions() const { return mExtensions; }
+
+    static uint32_t multiplyByResolution(uint32_t in) {
+        auto di = DeviceInfo::get()->displayInfo();
+        return di.w * di.h * in;
+    }
 
 private:
     DeviceInfo() {}
     ~DeviceInfo() {}
 
     void load();
+    void loadDisplayInfo();
 
     int mMaxTextureSize;
+    DisplayInfo mDisplayInfo;
+    Extensions mExtensions;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp
index b2181b6..a39e49f 100644
--- a/libs/hwui/FboCache.cpp
+++ b/libs/hwui/FboCache.cpp
@@ -28,7 +28,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 FboCache::FboCache()
-        : mMaxSize(Properties::fboCacheSize) {}
+        : mMaxSize(0) {}
 
 FboCache::~FboCache() {
     clear();
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index ee99018..bc41810 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -32,7 +32,6 @@
 #include "utils/Timing.h"
 
 #include <algorithm>
-#include <cutils/properties.h>
 #include <RenderScript.h>
 #include <SkGlyph.h>
 #include <SkUtils.h>
@@ -99,22 +98,14 @@
         INIT_LOGD("Creating FontRenderer");
     }
 
-    mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
-            DEFAULT_TEXT_SMALL_CACHE_WIDTH);
-    mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
-            DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
+    auto deviceInfo = DeviceInfo::get();
+    int maxTextureSize = deviceInfo->maxTextureSize();
 
-    mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
-            DEFAULT_TEXT_LARGE_CACHE_WIDTH);
-    mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
-            DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
-
-    uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
-
-    mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
-    mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
-    mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
-    mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
+    // TODO: Most devices are hardcoded with this configuration, does it need to be dynamic?
+    mSmallCacheWidth = std::min(1024, maxTextureSize);
+    mSmallCacheHeight = std::min(1024, maxTextureSize);
+    mLargeCacheWidth = std::min(2048, maxTextureSize);
+    mLargeCacheHeight = std::min(1024, maxTextureSize);
 
     if (sLogFontRendererCreate) {
         INIT_LOGD("  Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index d4d0c99..2026234 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -20,6 +20,7 @@
 #include "Debug.h"
 #include "GradientCache.h"
 #include "Properties.h"
+#include "DeviceInfo.h"
 
 #include <cutils/properties.h>
 
@@ -62,14 +63,14 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-GradientCache::GradientCache(Extensions& extensions)
+GradientCache::GradientCache(const Extensions& extensions)
         : mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity)
         , mSize(0)
-        , mMaxSize(Properties::gradientCacheSize)
+        , mMaxSize(MB(1))
         , mUseFloatTexture(extensions.hasFloatTextures())
         , mHasNpot(extensions.hasNPot())
         , mHasLinearBlending(extensions.hasLinearBlending()) {
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+    mMaxTextureSize = DeviceInfo::get()->maxTextureSize();
 
     mCache.setOnEntryRemovedListener(this);
 }
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index f299a40..d95589c 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -105,7 +105,7 @@
  */
 class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
 public:
-    explicit GradientCache(Extensions& extensions);
+    explicit GradientCache(const Extensions& extensions);
     ~GradientCache();
 
     /**
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 983c17e..78c7eb9 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -32,7 +32,7 @@
 
 PatchCache::PatchCache(RenderState& renderState)
         : mRenderState(renderState)
-        , mMaxSize(Properties::patchCacheSize)
+        , mMaxSize(KB(128))
         , mSize(0)
         , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity)
         , mMeshBuffer(0)
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index cc96de7..8d4ae1b 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -38,6 +38,8 @@
 namespace android {
 namespace uirenderer {
 
+static constexpr size_t PATH_CACHE_COUNT_LIMIT = 256;
+
 template <class T>
 static bool compareWidthHeight(const T& lhs, const T& rhs) {
     return (lhs.mWidth == rhs.mWidth) && (lhs.mHeight == rhs.mHeight);
@@ -179,13 +181,9 @@
 PathCache::PathCache()
         : mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity)
         , mSize(0)
-        , mMaxSize(Properties::pathCacheSize) {
+        , mMaxSize(DeviceInfo::multiplyByResolution(4)) {
     mCache.setOnEntryRemovedListener(this);
-
-    GLint maxTextureSize;
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
-    mMaxTextureSize = maxTextureSize;
-
+    mMaxTextureSize = DeviceInfo::get()->maxTextureSize();
     mDebugEnabled = Properties::debugLevel & kDebugCaches;
 }
 
@@ -259,12 +257,7 @@
 }
 
 void PathCache::trim() {
-    // 25 is just an arbitrary lower bound to ensure we aren't in weird edge cases
-    // of things like a cap of 0 or 1 as that's going to break things.
-    // It does not represent a reasonable minimum value
-    static_assert(DEFAULT_PATH_TEXTURE_CAP > 25, "Path cache texture cap is too small");
-
-    while (mSize > mMaxSize || mCache.size() > DEFAULT_PATH_TEXTURE_CAP) {
+    while (mSize > mMaxSize || mCache.size() > PATH_CACHE_COUNT_LIMIT) {
         LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!"
                 " mSize = %u, mMaxSize = %u", mSize, mMaxSize);
         mCache.removeOldest();
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 8cc0aa7..b767046 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -505,7 +505,7 @@
 // Constructors/destructors
 ///////////////////////////////////////////////////////////////////////////////
 
-ProgramCache::ProgramCache(Extensions& extensions)
+ProgramCache::ProgramCache(const Extensions& extensions)
         : mHasES3(extensions.getMajorGlVersion() >= 3)
         , mHasLinearBlending(extensions.hasLinearBlending()) {
 }
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index cedd854b..ee76f22 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -40,7 +40,7 @@
  */
 class ProgramCache {
 public:
-    explicit ProgramCache(Extensions& extensions);
+    explicit ProgramCache(const Extensions& extensions);
     ~ProgramCache();
 
     Program* get(const ProgramDescription& description);
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index b587248..acc7539 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -16,6 +16,7 @@
 
 #include "Properties.h"
 #include "Debug.h"
+#include "DeviceInfo.h"
 
 #include <algorithm>
 #include <cstdlib>
@@ -36,20 +37,6 @@
 bool Properties::useBufferAge = true;
 bool Properties::enablePartialUpdates = true;
 
-float Properties::textGamma = DEFAULT_TEXT_GAMMA;
-
-int Properties::fboCacheSize = DEFAULT_FBO_CACHE_SIZE;
-int Properties::gradientCacheSize = MB(DEFAULT_GRADIENT_CACHE_SIZE);
-int Properties::layerPoolSize = MB(DEFAULT_LAYER_CACHE_SIZE);
-int Properties::patchCacheSize = KB(DEFAULT_PATCH_CACHE_SIZE);
-int Properties::pathCacheSize = MB(DEFAULT_PATH_CACHE_SIZE);
-int Properties::renderBufferCacheSize = MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE);
-int Properties::tessellationCacheSize = MB(DEFAULT_VERTEX_CACHE_SIZE);
-int Properties::textDropShadowCacheSize = MB(DEFAULT_DROP_SHADOW_CACHE_SIZE);
-int Properties::textureCacheSize = MB(DEFAULT_TEXTURE_CACHE_SIZE);
-
-float Properties::textureCacheFlushRate = DEFAULT_TEXTURE_CACHE_FLUSH_RATE;
-
 DebugLevel Properties::debugLevel = kDebugDisabled;
 OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
 StencilClipDebug Properties::debugStencilClip = StencilClipDebug::Hide;
@@ -80,15 +67,6 @@
     return defaultValue;
 }
 
-static float property_get_float(const char* key, float defaultValue) {
-    char buf[PROPERTY_VALUE_MAX] = {'\0',};
-
-    if (property_get(key, buf, "") > 0) {
-        return atof(buf);
-    }
-    return defaultValue;
-}
-
 bool Properties::load() {
     char property[PROPERTY_VALUE_MAX];
     bool prevDebugLayersUpdates = debugLayersUpdates;
@@ -147,20 +125,6 @@
     useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
     enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true);
 
-    textGamma = property_get_float(PROPERTY_TEXT_GAMMA, DEFAULT_TEXT_GAMMA);
-
-    fboCacheSize = property_get_int(PROPERTY_FBO_CACHE_SIZE, DEFAULT_FBO_CACHE_SIZE);
-    gradientCacheSize = MB(property_get_float(PROPERTY_GRADIENT_CACHE_SIZE, DEFAULT_GRADIENT_CACHE_SIZE));
-    layerPoolSize = MB(property_get_float(PROPERTY_LAYER_CACHE_SIZE, DEFAULT_LAYER_CACHE_SIZE));
-    patchCacheSize = KB(property_get_float(PROPERTY_PATCH_CACHE_SIZE, DEFAULT_PATCH_CACHE_SIZE));
-    pathCacheSize = MB(property_get_float(PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE));
-    renderBufferCacheSize = MB(property_get_float(PROPERTY_RENDER_BUFFER_CACHE_SIZE, DEFAULT_RENDER_BUFFER_CACHE_SIZE));
-    tessellationCacheSize = MB(property_get_float(PROPERTY_VERTEX_CACHE_SIZE, DEFAULT_VERTEX_CACHE_SIZE));
-    textDropShadowCacheSize = MB(property_get_float(PROPERTY_DROP_SHADOW_CACHE_SIZE, DEFAULT_DROP_SHADOW_CACHE_SIZE));
-    textureCacheSize = MB(property_get_float(PROPERTY_TEXTURE_CACHE_SIZE, DEFAULT_TEXTURE_CACHE_SIZE));
-    textureCacheFlushRate = std::max(0.0f, std::min(1.0f,
-            property_get_float(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, DEFAULT_TEXTURE_CACHE_FLUSH_RATE)));
-
     filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false);
 
     return (prevDebugLayersUpdates != debugLayersUpdates)
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 91b4a2d..47ae9e9 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -153,81 +153,18 @@
 #define PROPERTY_FILTER_TEST_OVERHEAD "debug.hwui.filter_test_overhead"
 
 /**
+ * Indicates whether PBOs can be used to back pixel buffers.
+ * Accepted values are "true" and "false". Default is true.
+ */
+#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "debug.hwui.use_gpu_pixel_buffers"
+
+/**
  * Allows to set rendering pipeline mode to OpenGL (default), Skia OpenGL
  * or Vulkan.
  */
 #define PROPERTY_RENDERER "debug.hwui.renderer"
 
 ///////////////////////////////////////////////////////////////////////////////
-// Runtime configuration properties
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Used to enable/disable scissor optimization. The accepted values are
- * "true" and "false". The default value is "false".
- *
- * When scissor optimization is enabled, libhwui will attempt to
- * minimize the use of scissor by selectively enabling and disabling the
- * GL scissor test.
- * When the optimization is disabled, OpenGLRenderer will keep the GL
- * scissor test enabled and change the scissor rect as needed.
- * Some GPUs (for instance the SGX 540) perform better when changing
- * the scissor rect often than when enabling/disabling the scissor test
- * often.
- */
-#define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt"
-
-/**
- * Indicates whether PBOs can be used to back pixel buffers.
- * Accepted values are "true" and "false". Default is true.
- */
-#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "ro.hwui.use_gpu_pixel_buffers"
-
-// These properties are defined in mega-bytes
-#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
-#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
-#define PROPERTY_RENDER_BUFFER_CACHE_SIZE "ro.hwui.r_buffer_cache_size"
-#define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
-#define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size"
-#define PROPERTY_VERTEX_CACHE_SIZE "ro.hwui.vertex_cache_size"
-#define PROPERTY_PATCH_CACHE_SIZE "ro.hwui.patch_cache_size"
-#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size"
-#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size"
-
-// These properties are defined in percentage (range 0..1)
-#define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flushrate"
-
-// These properties are defined in pixels
-#define PROPERTY_TEXT_SMALL_CACHE_WIDTH "ro.hwui.text_small_cache_width"
-#define PROPERTY_TEXT_SMALL_CACHE_HEIGHT "ro.hwui.text_small_cache_height"
-#define PROPERTY_TEXT_LARGE_CACHE_WIDTH "ro.hwui.text_large_cache_width"
-#define PROPERTY_TEXT_LARGE_CACHE_HEIGHT "ro.hwui.text_large_cache_height"
-
-// Gamma (>= 1.0, <= 3.0)
-#define PROPERTY_TEXT_GAMMA "hwui.text_gamma"
-
-///////////////////////////////////////////////////////////////////////////////
-// Default property values
-///////////////////////////////////////////////////////////////////////////////
-
-#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
-#define DEFAULT_LAYER_CACHE_SIZE 16.0f
-#define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f
-#define DEFAULT_PATH_CACHE_SIZE 4.0f
-#define DEFAULT_VERTEX_CACHE_SIZE 1.0f
-#define DEFAULT_PATCH_CACHE_SIZE 128.0f // in kB
-#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
-#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
-#define DEFAULT_FBO_CACHE_SIZE 0
-
-#define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f
-
-#define DEFAULT_TEXT_GAMMA 1.45f // Match design tools
-
-// cap to 256 to limite paths in the path cache
-#define DEFAULT_PATH_TEXTURE_CAP 256
-
-///////////////////////////////////////////////////////////////////////////////
 // Misc
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -279,18 +216,8 @@
     static bool useBufferAge;
     static bool enablePartialUpdates;
 
-    static float textGamma;
-
-    static int fboCacheSize;
-    static int gradientCacheSize;
-    static int layerPoolSize;
-    static int patchCacheSize;
-    static int pathCacheSize;
-    static int renderBufferCacheSize;
-    static int tessellationCacheSize;
-    static int textDropShadowCacheSize;
-    static int textureCacheSize;
-    static float textureCacheFlushRate;
+    // TODO: Move somewhere else?
+    static constexpr float textGamma = 1.45f;
 
     static DebugLevel debugLevel;
     static OverdrawColorSet overdrawColorSet;
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 1ac57cd..2f8ddfe 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -17,6 +17,7 @@
 #include "Debug.h"
 #include "Properties.h"
 #include "RenderBufferCache.h"
+#include "DeviceInfo.h"
 
 #include <utils/Log.h>
 
@@ -36,13 +37,20 @@
     #define RENDER_BUFFER_LOGD(...)
 #endif
 
+static uint32_t calculateRboCacheSize() {
+    // TODO: Do we need to use extensions().has4BitStencil() here?
+    // The tuning guide recommends it, but all real devices are configured
+    // with a larger cache than necessary by 4x, so keep the 2x for now regardless
+    return DeviceInfo::multiplyByResolution(2);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
 RenderBufferCache::RenderBufferCache()
         : mSize(0)
-        , mMaxSize(Properties::renderBufferCacheSize) {}
+        , mMaxSize(calculateRboCacheSize()) {}
 
 RenderBufferCache::~RenderBufferCache() {
     clear();
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 91e7ac3..01582ce 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -290,7 +290,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 TessellationCache::TessellationCache()
-        : mMaxSize(Properties::tessellationCacheSize)
+        : mMaxSize(MB(1))
         , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
         , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
     mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index e1f0b2a..c521892 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -94,7 +94,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 TextDropShadowCache::TextDropShadowCache()
-        : TextDropShadowCache(Properties::textDropShadowCacheSize) {}
+        : TextDropShadowCache(DeviceInfo::multiplyByResolution(2)) {}
 
 TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize)
         : mCache(LruCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity)
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 710cdd9..6fe3606 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -24,6 +24,7 @@
 #include "Properties.h"
 #include "utils/TraceUtils.h"
 #include "hwui/Bitmap.h"
+#include "DeviceInfo.h"
 
 namespace android {
 namespace uirenderer {
@@ -35,13 +36,10 @@
 TextureCache::TextureCache()
         : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
         , mSize(0)
-        , mMaxSize(Properties::textureCacheSize)
-        , mFlushRate(Properties::textureCacheFlushRate) {
+        , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps
+        , mFlushRate(.4f) {
     mCache.setOnEntryRemovedListener(this);
-
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
-    INIT_LOGD("    Maximum texture dimension is %d pixels", mMaxTextureSize);
-
+    mMaxTextureSize = DeviceInfo::get()->maxTextureSize();
     mDebugEnabled = Properties::debugLevel & kDebugCaches;
 }
 
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index 07e8b34..d4b4ff9 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -25,11 +25,6 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-#define DEFAULT_TEXT_SMALL_CACHE_WIDTH 1024
-#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 512
-#define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048
-#define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
-
 #ifdef TEXTURE_BORDER_SIZE
   #if TEXTURE_BORDER_SIZE != 1
     #error TEXTURE_BORDER_SIZE other than 1 is not currently supported
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index 2dfa6d4..ea292d6 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -17,7 +17,6 @@
 #include "OffscreenBufferPool.h"
 
 #include "Caches.h"
-#include "Properties.h"
 #include "renderstate/RenderState.h"
 #include "utils/FatVector.h"
 #include "utils/TraceUtils.h"
@@ -118,7 +117,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 OffscreenBufferPool::OffscreenBufferPool()
-    : mMaxSize(Properties::layerPoolSize) {
+     // 4 screen-sized RGBA_8888 textures
+    : mMaxSize(DeviceInfo::multiplyByResolution(4 * 4)) {
 }
 
 OffscreenBufferPool::~OffscreenBufferPool() {
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 2c92924..ededffb 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -53,6 +53,11 @@
     mScissor = new Scissor();
     mStencil = new Stencil();
 
+    // Deferred because creation needs GL context for texture limits
+    if (!mLayerPool) {
+        mLayerPool = new OffscreenBufferPool();
+    }
+
     // This is delayed because the first access of Caches makes GL calls
     if (!mCaches) {
         mCaches = &Caches::createInstance(*this);
@@ -67,7 +72,7 @@
 }
 
 void RenderState::onGLContextDestroyed() {
-    mLayerPool.clear();
+    mLayerPool->clear();
 
     // TODO: reset all cached state in state objects
     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
@@ -100,7 +105,7 @@
 }
 
 void RenderState::onVkContextDestroyed() {
-    mLayerPool.clear();
+    mLayerPool->clear();
     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext);
     GpuMemoryTracker::onGpuContextDestroyed();
 }
@@ -116,10 +121,10 @@
         case Caches::FlushMode::Moderate:
             // fall through
         case Caches::FlushMode::Layers:
-            mLayerPool.clear();
+            if (mLayerPool) mLayerPool->clear();
             break;
     }
-    mCaches->flush(mode);
+    if (mCaches) mCaches->flush(mode);
 }
 
 void RenderState::onBitmapDestroyed(uint32_t pixelRefId) {
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 4b7a865..df81e86 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -113,7 +113,7 @@
     Scissor& scissor() { return *mScissor; }
     Stencil& stencil() { return *mStencil; }
 
-    OffscreenBufferPool& layerPool() { return mLayerPool; }
+    OffscreenBufferPool& layerPool() { return *mLayerPool; }
 
     GrContext* getGrContext() const;
 
@@ -136,7 +136,7 @@
     Scissor* mScissor = nullptr;
     Stencil* mStencil = nullptr;
 
-    OffscreenBufferPool mLayerPool;
+    OffscreenBufferPool* mLayerPool = nullptr;
 
     std::set<Layer*> mActiveLayers;
     std::set<DeferredLayerUpdater*> mActiveLayerUpdaters;
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index d25ad51..f594421 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -47,7 +47,7 @@
  */
 GLenum Stencil::getLayerStencilFormat() {
 #if !DEBUG_STENCIL
-    const Extensions& extensions = Caches::getInstance().extensions();
+    const Extensions& extensions = DeviceInfo::get()->extensions();
     if (extensions.has4BitStencil()) {
         return GL_STENCIL_INDEX4_OES;
     }
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 919852f..308fef3 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -74,8 +74,8 @@
     OffscreenBufferPool pool;
     EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty";
     EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty";
-    EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize())
-            << "pool must read size from Properties";
+    // TODO: Does this really make sense as a test?
+    EXPECT_EQ(DeviceInfo::multiplyByResolution(4 * 4), pool.getMaxSize());
 }
 
 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClear) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 9538e1d..6b329f8 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -22,6 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
@@ -680,7 +681,8 @@
         // Other app may have shown its own main TvView.
         // Set main again to regain main session.
         synchronized (sMainTvViewLock) {
-            if (hasFocus && this == sMainTvView.get() && mSession != null) {
+            if (hasFocus && this == sMainTvView.get() && mSession != null
+                    && checkChangeHdmiCecActiveSourcePermission()) {
                 mSession.setMain();
             }
         }
@@ -848,6 +850,12 @@
         return frame;
     }
 
+    private boolean checkChangeHdmiCecActiveSourcePermission() {
+        return getContext().checkSelfPermission(
+                android.Manifest.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE)
+                        == PackageManager.PERMISSION_GRANTED;
+    }
+
     /**
      * Callback used to receive time shift position changes.
      */
@@ -1080,7 +1088,8 @@
                 mPendingAppPrivateCommands.clear();
 
                 synchronized (sMainTvViewLock) {
-                    if (hasWindowFocus() && TvView.this == sMainTvView.get()) {
+                    if (hasWindowFocus() && TvView.this == sMainTvView.get()
+                            && checkChangeHdmiCecActiveSourcePermission()) {
                         mSession.setMain();
                     }
                 }
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index c82a1f6..bbd2783 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -198,6 +198,7 @@
     ASharedMemory_create; # introduced=26
     ASharedMemory_getSize; # introduced=26
     ASharedMemory_setProt; # introduced=26
+    ASharedMemory_dupFromJava; # introduced=27
     AStorageManager_delete;
     AStorageManager_getMountedObbPath;
     AStorageManager_isObbMounted;
diff --git a/native/android/sharedmem.cpp b/native/android/sharedmem.cpp
index 9d029dfa..757aaec 100644
--- a/native/android/sharedmem.cpp
+++ b/native/android/sharedmem.cpp
@@ -14,10 +14,36 @@
  * limitations under the License.
  */
 
+#include <jni.h>
+
 #include <android/sharedmem.h>
+#include <android/sharedmem_jni.h>
 #include <cutils/ashmem.h>
+#include <log/log.h>
 #include <utils/Errors.h>
 
+#include <mutex>
+#include <unistd.h>
+
+static struct {
+    jclass clazz;
+    jmethodID getFd;
+} sSharedMemory;
+
+static void jniInit(JNIEnv* env) {
+    static std::once_flag sJniInitialized;
+    std::call_once(sJniInitialized, [](JNIEnv* env) {
+        jclass clazz = env->FindClass("android/os/SharedMemory");
+        LOG_ALWAYS_FATAL_IF(clazz == nullptr, "Failed to find android.os.SharedMemory");
+        sSharedMemory.clazz = (jclass) env->NewGlobalRef(clazz);
+        LOG_ALWAYS_FATAL_IF(sSharedMemory.clazz == nullptr,
+                "Failed to create global ref of android.os.SharedMemory");
+        sSharedMemory.getFd = env->GetMethodID(sSharedMemory.clazz, "getFd", "()I");
+        LOG_ALWAYS_FATAL_IF(sSharedMemory.getFd == nullptr,
+                "Failed to find method SharedMemory#getFd()");
+    }, env);
+}
+
 int ASharedMemory_create(const char *name, size_t size) {
     if (size == 0) {
         return android::BAD_VALUE;
@@ -32,3 +58,20 @@
 int ASharedMemory_setProt(int fd, int prot) {
     return ashmem_set_prot_region(fd, prot);
 }
+
+int ASharedMemory_dupFromJava(JNIEnv* env, jobject javaSharedMemory) {
+    if (env == nullptr || javaSharedMemory == nullptr) {
+        return -1;
+    }
+    jniInit(env);
+    if (!env->IsInstanceOf(javaSharedMemory, sSharedMemory.clazz)) {
+        ALOGW("ASharedMemory_dupFromJava called with object "
+                "that's not an instanceof android.os.SharedMemory");
+        return -1;
+    }
+    int fd = env->CallIntMethod(javaSharedMemory, sSharedMemory.getFd);
+    if (fd != -1) {
+        fd = dup(fd);
+    }
+    return fd;
+}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9067865..d668a41 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1152,7 +1152,7 @@
     <string name="monitoring_description_vpn_settings_separator">" "</string>
 
     <!-- Monitoring dialog: Link to open the VPN settings page [CHAR LIMIT=60] -->
-    <string name="monitoring_description_vpn_settings">Open VPN Settings</string>
+    <string name="monitoring_description_vpn_settings">Open VPN settings</string>
 
     <!-- Monitoring dialog: Space that separates the CA certs body text and the "Open trusted credentials" link that follows it. [CHAR LIMIT=5] -->
     <string name="monitoring_description_ca_cert_settings_separator">" "</string>
@@ -1987,8 +1987,10 @@
     <!-- SysUI Tuner: App subheading for shortcut selection [CHAR LIMIT=60] -->
     <string name="tuner_app"><xliff:g id="app">%1$s</xliff:g> app</string>
 
-    <!-- Title for the notification channel containing important alerts like low battery. [CHAR LIMIT=NONE] -->
+    <!-- Title for the notification channel containing important alerts. [CHAR LIMIT=NONE] -->
     <string name="notification_channel_alerts">Alerts</string>
+    <!-- Title for the notification channel for battery warnings (i.e. < 15%). [CHAR LIMIT=NONE] -->
+    <string name="notification_channel_battery">Battery</string>
     <!-- Title for the notification channel dedicated to screenshot progress. [CHAR LIMIT=NONE] -->
     <string name="notification_channel_screenshot">Screenshots</string>
     <!-- Title for the notification channel for miscellaneous notices. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e23875f..d132e76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -659,7 +659,7 @@
     }
 
     boolean mustNotUnlockCurrentUser() {
-        return (UserManager.isSplitSystemUser() || UserManager.isDeviceInDemoMode(mContext))
+        return UserManager.isSplitSystemUser()
                 && KeyguardUpdateMonitor.getCurrentUser() == UserHandle.USER_SYSTEM;
     }
 
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 d3be19d..9b48320 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -42,6 +42,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -387,7 +388,10 @@
                 if (!mSendingHoverAccessibilityEvents) {
                     AccessibilityEvent event = AccessibilityEvent.obtain(
                             AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+                    event.setImportantForAccessibility(true);
                     event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
+                    event.setWindowId(
+                            AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
                     mAccessibilityManager.sendAccessibilityEvent(event);
                     mSendingHoverAccessibilityEvents = true;
                 }
@@ -397,7 +401,10 @@
                 if (mSendingHoverAccessibilityEvents) {
                     AccessibilityEvent event = AccessibilityEvent.obtain(
                             AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+                    event.setImportantForAccessibility(true);
                     event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
+                    event.setWindowId(
+                            AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
                     mAccessibilityManager.sendAccessibilityEvent(event);
                     mSendingHoverAccessibilityEvents = false;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 6b3daa3..e76276d 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -17,6 +17,7 @@
 package com.android.systemui.power;
 
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -40,6 +41,7 @@
 import android.util.Slog;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
@@ -173,8 +175,9 @@
     private void showWarningNotification() {
         final int textRes = R.string.battery_low_percent_format;
         final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0);
+
         final Notification.Builder nb =
-                new Notification.Builder(mContext, NotificationChannels.ALERTS)
+                new Notification.Builder(mContext, NotificationChannels.BATTERY)
                         .setSmallIcon(R.drawable.ic_power_low)
                         // Bump the notification when the bucket dropped.
                         .setWhen(mBucketDroppedNegativeTimeMs)
@@ -191,10 +194,8 @@
         nb.addAction(0,
                 mContext.getString(R.string.battery_saver_start_action),
                 pendingBroadcast(ACTION_START_SAVER));
-        if (mPlaySound) {
-            attachLowBatterySound(nb);
-            mPlaySound = false;
-        }
+        nb.setOnlyAlertOnce(!mPlaySound);
+        mPlaySound = false;
         SystemUI.overrideNotificationAppName(mContext, nb);
         final Notification n = nb.build();
         mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL);
@@ -335,43 +336,12 @@
     public void showLowBatteryWarning(boolean playSound) {
         Slog.i(TAG,
                 "show low battery warning: level=" + mBatteryLevel
-                + " [" + mBucket + "] playSound=" + playSound);
+                        + " [" + mBucket + "] playSound=" + playSound);
         mPlaySound = playSound;
         mWarning = true;
         updateNotification();
     }
 
-    private void attachLowBatterySound(Notification.Builder b) {
-        final ContentResolver cr = mContext.getContentResolver();
-
-        final int silenceAfter = Settings.Global.getInt(cr,
-                Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0);
-        final long offTime = SystemClock.elapsedRealtime() - mScreenOffTime;
-        if (silenceAfter > 0
-                && mScreenOffTime > 0
-                && offTime > silenceAfter) {
-            Slog.i(TAG, "screen off too long (" + offTime + "ms, limit " + silenceAfter
-                    + "ms): not waking up the user with low battery sound");
-            return;
-        }
-
-        if (DEBUG) {
-            Slog.d(TAG, "playing low battery sound. pick-a-doop!"); // WOMP-WOMP is deprecated
-        }
-
-        if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) {
-            final String soundPath = Settings.Global.getString(cr,
-                    Settings.Global.LOW_BATTERY_SOUND);
-            if (soundPath != null) {
-                final Uri soundUri = Uri.parse("file://" + soundPath);
-                if (soundUri != null) {
-                    b.setSound(soundUri, AUDIO_ATTRIBUTES);
-                    if (DEBUG) Slog.d(TAG, "playing sound " + soundUri);
-                }
-            }
-        }
-    }
-
     @Override
     public void dismissInvalidChargerWarning() {
         dismissInvalidChargerNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index a913999..28172b7 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -231,6 +231,7 @@
                         && (bucket < oldBucket || oldPlugged)
                         && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
                         && bucket < 0) {
+
                     // only play SFX when the dialog comes up or the bucket changes
                     final boolean playSound = bucket != oldBucket || oldPlugged;
                     mWarnings.showLowBatteryWarning(playSound);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 3ce1465c..e574c01 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -320,7 +320,7 @@
     }
 
     private String getPositiveButton() {
-        return mContext.getString(R.string.quick_settings_done);
+        return mContext.getString(R.string.ok);
     }
 
     protected CharSequence getManagementMessage(boolean isDeviceManaged,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 9b0179d..378dad7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -49,6 +49,8 @@
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
         attrs.setTitle(getClass().getSimpleName());
         getWindow().setAttributes(attrs);
+
+        registerDismissListener(this);
     }
 
     public void setShowForAllUsers(boolean show) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index ae8afe4..87bc0e6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -19,6 +19,10 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.net.Uri;
+import android.provider.Settings;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
@@ -31,11 +35,21 @@
     public static String GENERAL     = "GEN";
     public static String STORAGE     = "DSK";
     public static String TVPIP       = "TPP";
+    public static String BATTERY     = "BAT";
 
     @VisibleForTesting
     static void createAll(Context context) {
-
         final NotificationManager nm = context.getSystemService(NotificationManager.class);
+        NotificationChannel batteryChannel = new NotificationChannel(BATTERY,
+                context.getString(R.string.notification_channel_battery),
+                NotificationManager.IMPORTANCE_MAX);
+        final String soundPath = Settings.Global.getString(context.getContentResolver(),
+                Settings.Global.LOW_BATTERY_SOUND);
+        batteryChannel.setSound(Uri.parse("file://" + soundPath), new AudioAttributes.Builder()
+                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
+                .build());
+
         nm.createNotificationChannels(Arrays.asList(
                 new NotificationChannel(
                         ALERTS,
@@ -54,8 +68,10 @@
                         context.getString(R.string.notification_channel_storage),
                         isTv(context)
                                 ? NotificationManager.IMPORTANCE_DEFAULT
-                                : NotificationManager.IMPORTANCE_LOW)
-                ));
+                                : NotificationManager.IMPORTANCE_LOW),
+                batteryChannel
+        ));
+
         if (isTv(context)) {
             // TV specific notification channel for TV PIP controls.
             // Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index eb59a34..ac37d1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.NotificationChannels;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -108,23 +109,13 @@
     }
 
     @Test
-    public void testShowLowBatteryNotification_Silent() {
-        mPowerNotificationWarnings.showLowBatteryWarning(false);
-        ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
-        verify(mMockNotificationManager)
-                .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW),
-                        captor.capture(), any());
-        assertEquals(null, captor.getValue().sound);
-    }
-
-    @Test
-    public void testShowLowBatteryNotification_Sound() {
+    public void testShowLowBatteryNotification_BatteryChannel() {
         mPowerNotificationWarnings.showLowBatteryWarning(true);
         ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
         verify(mMockNotificationManager)
                 .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW),
                         captor.capture(), any());
-        assertNotEqual(null, captor.getValue().sound);
+        assertTrue(captor.getValue().getChannelId() == NotificationChannels.BATTERY);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
new file mode 100644
index 0000000..dcd531d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class SystemUIDialogTest extends SysuiTestCase {
+
+    private SystemUIDialog mDialog;
+
+    Context mContextSpy;
+
+    @Before
+    public void setup() {
+        mContextSpy = spy(mContext);
+        mDialog = new SystemUIDialog(mContextSpy);
+    }
+
+    @Test
+    public void testRegisterReceiver() {
+        final ArgumentCaptor<IntentFilter> intentFilterCaptor =
+                ArgumentCaptor.forClass(IntentFilter.class);
+
+        verify(mContextSpy).registerReceiverAsUser(any(), any(),
+                intentFilterCaptor.capture(), any(), any());
+
+        assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
index f67296d..04bdc04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java
@@ -56,7 +56,8 @@
                 NotificationChannels.ALERTS,
                 NotificationChannels.SCREENSHOTS,
                 NotificationChannels.STORAGE,
-                NotificationChannels.GENERAL
+                NotificationChannels.GENERAL,
+                NotificationChannels.BATTERY
         ));
         NotificationChannels.createAll(mContext);
         ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index bb6ed74..8d7afc2 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4262,6 +4262,9 @@
     // OS: O MR
     DATA_PLAN_USAGE_SUMMARY = 1088;
 
+    // FIELD: The numeric preference value (of type int) when it is changed in Settings
+    FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE = 1089;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index e1756d1..1bf12c4 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -29,18 +29,23 @@
 import android.os.DropBoxManager;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.StatFs;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.text.format.Time;
+import android.util.ArrayMap;
 import android.util.Slog;
 
 import libcore.io.IoUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IDropBoxManagerService;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.ObjectUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -52,7 +57,7 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Objects;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.zip.GZIPOutputStream;
@@ -87,7 +92,7 @@
     // Accounting of all currently written log files (set in init()).
 
     private FileList mAllFiles = null;
-    private HashMap<String, FileList> mFilesByTag = null;
+    private ArrayMap<String, FileList> mFilesByTag = null;
 
     // Various bits of disk information
 
@@ -153,7 +158,7 @@
      * @param context to use for receiving free space & gservices intents
      */
     public DropBoxManagerService(final Context context) {
-        this(context, new File("/data/system/dropbox"));
+        this(context, new File("/data/system/dropbox"), FgThread.get().getLooper());
     }
 
     /**
@@ -163,11 +168,12 @@
      * @param context to use for receiving free space & gservices intents
      * @param path to store drop box entries in
      */
-    public DropBoxManagerService(final Context context, File path) {
+    @VisibleForTesting
+    public DropBoxManagerService(final Context context, File path, Looper looper) {
         super(context);
         mDropBoxDir = path;
         mContentResolver = getContext().getContentResolver();
-        mHandler = new Handler() {
+        mHandler = new Handler(looper) {
             @Override
             public void handleMessage(Message msg) {
                 if (msg.what == MSG_SEND_BROADCAST) {
@@ -338,11 +344,12 @@
             if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
                 return new DropBoxManager.Entry(entry.tag, entry.timestampMillis);
             }
+            final File file = entry.getFile(mDropBoxDir);
             try {
                 return new DropBoxManager.Entry(
-                        entry.tag, entry.timestampMillis, entry.file, entry.flags);
+                        entry.tag, entry.timestampMillis, file, entry.flags);
             } catch (IOException e) {
-                Slog.e(TAG, "Can't read: " + entry.file, e);
+                Slog.wtf(TAG, "Can't read: " + file, e);
                 // Continue to next file
             }
         }
@@ -410,7 +417,9 @@
             numFound++;
             if (doPrint) out.append("========================================\n");
             out.append(date).append(" ").append(entry.tag == null ? "(no tag)" : entry.tag);
-            if (entry.file == null) {
+
+            final File file = entry.getFile(mDropBoxDir);
+            if (file == null) {
                 out.append(" (no file)\n");
                 continue;
             } else if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
@@ -420,12 +429,12 @@
                 out.append(" (");
                 if ((entry.flags & DropBoxManager.IS_GZIPPED) != 0) out.append("compressed ");
                 out.append((entry.flags & DropBoxManager.IS_TEXT) != 0 ? "text" : "data");
-                out.append(", ").append(entry.file.length()).append(" bytes)\n");
+                out.append(", ").append(file.length()).append(" bytes)\n");
             }
 
             if (doFile || (doPrint && (entry.flags & DropBoxManager.IS_TEXT) == 0)) {
                 if (!doPrint) out.append("    ");
-                out.append(entry.file.getPath()).append("\n");
+                out.append(file.getPath()).append("\n");
             }
 
             if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
@@ -433,7 +442,7 @@
                 InputStreamReader isr = null;
                 try {
                     dbe = new DropBoxManager.Entry(
-                             entry.tag, entry.timestampMillis, entry.file, entry.flags);
+                             entry.tag, entry.timestampMillis, file, entry.flags);
 
                     if (doPrint) {
                         isr = new InputStreamReader(dbe.getInputStream());
@@ -466,7 +475,7 @@
                     }
                 } catch (IOException e) {
                     out.append("*** ").append(e.toString()).append("\n");
-                    Slog.e(TAG, "Can't read: " + entry.file, e);
+                    Slog.e(TAG, "Can't read: " + file, e);
                 } finally {
                     if (dbe != null) dbe.close();
                     if (isr != null) {
@@ -509,29 +518,37 @@
         }
     }
 
-    /** Metadata describing an on-disk log file. */
-    private static final class EntryFile implements Comparable<EntryFile> {
+    /**
+     * Metadata describing an on-disk log file.
+     *
+     * Note its instances do no have knowledge on what directory they're stored, just to save
+     * 4/8 bytes per instance.  Instead, {@link #getFile} takes a directory so it can build a
+     * fullpath.
+     */
+    @VisibleForTesting
+    static final class EntryFile implements Comparable<EntryFile> {
         public final String tag;
         public final long timestampMillis;
         public final int flags;
-        public final File file;
         public final int blocks;
 
         /** Sorts earlier EntryFile instances before later ones. */
         public final int compareTo(EntryFile o) {
-            if (timestampMillis < o.timestampMillis) return -1;
-            if (timestampMillis > o.timestampMillis) return 1;
-            if (file != null && o.file != null) return file.compareTo(o.file);
-            if (o.file != null) return -1;
-            if (file != null) return 1;
-            if (this == o) return 0;
-            if (hashCode() < o.hashCode()) return -1;
-            if (hashCode() > o.hashCode()) return 1;
-            return 0;
+            int comp = Long.compare(timestampMillis, o.timestampMillis);
+            if (comp != 0) return comp;
+
+            comp = ObjectUtils.compare(tag, o.tag);
+            if (comp != 0) return comp;
+
+            comp = Integer.compare(flags, o.flags);
+            if (comp != 0) return comp;
+
+            return Integer.compare(hashCode(), o.hashCode());
         }
 
         /**
          * Moves an existing temporary file to a new log filename.
+         *
          * @param temp file to rename
          * @param dir to store file in
          * @param tag to use for new log file name
@@ -544,76 +561,94 @@
                          int flags, int blockSize) throws IOException {
             if ((flags & DropBoxManager.IS_EMPTY) != 0) throw new IllegalArgumentException();
 
-            this.tag = tag;
+            this.tag = TextUtils.safeIntern(tag);
             this.timestampMillis = timestampMillis;
             this.flags = flags;
-            this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis +
-                    ((flags & DropBoxManager.IS_TEXT) != 0 ? ".txt" : ".dat") +
-                    ((flags & DropBoxManager.IS_GZIPPED) != 0 ? ".gz" : ""));
 
-            if (!temp.renameTo(this.file)) {
-                throw new IOException("Can't rename " + temp + " to " + this.file);
+            final File file = this.getFile(dir);
+            if (!temp.renameTo(file)) {
+                throw new IOException("Can't rename " + temp + " to " + file);
             }
-            this.blocks = (int) ((this.file.length() + blockSize - 1) / blockSize);
+            this.blocks = (int) ((file.length() + blockSize - 1) / blockSize);
         }
 
         /**
          * Creates a zero-length tombstone for a file whose contents were lost.
+         *
          * @param dir to store file in
          * @param tag to use for new log file name
          * @param timestampMillis of log entry
          * @throws IOException if the file can't be created.
          */
         public EntryFile(File dir, String tag, long timestampMillis) throws IOException {
-            this.tag = tag;
+            this.tag = TextUtils.safeIntern(tag);
             this.timestampMillis = timestampMillis;
             this.flags = DropBoxManager.IS_EMPTY;
-            this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis + ".lost");
             this.blocks = 0;
-            new FileOutputStream(this.file).close();
+            new FileOutputStream(getFile(dir)).close();
         }
 
         /**
          * Extracts metadata from an existing on-disk log filename.
+         *
+         * Note when a filename is not recognizable, it will create an instance that
+         * {@link #hasFile()} would return false on, and also remove the file.
+         *
          * @param file name of existing log file
          * @param blockSize to use for space accounting
          */
         public EntryFile(File file, int blockSize) {
-            this.file = file;
-            this.blocks = (int) ((this.file.length() + blockSize - 1) / blockSize);
+
+            boolean parseFailure = false;
 
             String name = file.getName();
-            int at = name.lastIndexOf('@');
-            if (at < 0) {
-                this.tag = null;
-                this.timestampMillis = 0;
-                this.flags = DropBoxManager.IS_EMPTY;
-                return;
-            }
-
             int flags = 0;
-            this.tag = Uri.decode(name.substring(0, at));
-            if (name.endsWith(".gz")) {
-                flags |= DropBoxManager.IS_GZIPPED;
-                name = name.substring(0, name.length() - 3);
-            }
-            if (name.endsWith(".lost")) {
-                flags |= DropBoxManager.IS_EMPTY;
-                name = name.substring(at + 1, name.length() - 5);
-            } else if (name.endsWith(".txt")) {
-                flags |= DropBoxManager.IS_TEXT;
-                name = name.substring(at + 1, name.length() - 4);
-            } else if (name.endsWith(".dat")) {
-                name = name.substring(at + 1, name.length() - 4);
+            String tag = null;
+            long millis = 0;
+
+            final int at = name.lastIndexOf('@');
+            if (at < 0) {
+                parseFailure = true;
             } else {
+                tag = Uri.decode(name.substring(0, at));
+                if (name.endsWith(".gz")) {
+                    flags |= DropBoxManager.IS_GZIPPED;
+                    name = name.substring(0, name.length() - 3);
+                }
+                if (name.endsWith(".lost")) {
+                    flags |= DropBoxManager.IS_EMPTY;
+                    name = name.substring(at + 1, name.length() - 5);
+                } else if (name.endsWith(".txt")) {
+                    flags |= DropBoxManager.IS_TEXT;
+                    name = name.substring(at + 1, name.length() - 4);
+                } else if (name.endsWith(".dat")) {
+                    name = name.substring(at + 1, name.length() - 4);
+                } else {
+                    parseFailure = true;
+                }
+                if (!parseFailure) {
+                    try {
+                        millis = Long.parseLong(name);
+                    } catch (NumberFormatException e) {
+                        parseFailure = true;
+                    }
+                }
+            }
+            if (parseFailure) {
+                Slog.wtf(TAG, "Invalid filename: " + file);
+
+                // Remove the file and return an empty instance.
+                file.delete();
+                this.tag = null;
                 this.flags = DropBoxManager.IS_EMPTY;
                 this.timestampMillis = 0;
+                this.blocks = 0;
                 return;
             }
-            this.flags = flags;
 
-            long millis;
-            try { millis = Long.parseLong(name); } catch (NumberFormatException e) { millis = 0; }
+            this.blocks = (int) ((file.length() + blockSize - 1) / blockSize);
+            this.tag = TextUtils.safeIntern(tag);
+            this.flags = flags;
             this.timestampMillis = millis;
         }
 
@@ -625,9 +660,50 @@
             this.tag = null;
             this.timestampMillis = millis;
             this.flags = DropBoxManager.IS_EMPTY;
-            this.file = null;
             this.blocks = 0;
         }
+
+        /**
+         * @return whether an entry actually has a backing file, or it's an empty "tombstone"
+         * entry.
+         */
+        public boolean hasFile() {
+            return tag != null;
+        }
+
+        /** @return File extension for the flags. */
+        private String getExtension() {
+            if ((flags &  DropBoxManager.IS_EMPTY) != 0) {
+                return ".lost";
+            }
+            return ((flags & DropBoxManager.IS_TEXT) != 0 ? ".txt" : ".dat") +
+                    ((flags & DropBoxManager.IS_GZIPPED) != 0 ? ".gz" : "");
+        }
+
+        /**
+         * @return filename for this entry without the pathname.
+         */
+        public String getFilename() {
+            return hasFile() ? Uri.encode(tag) + "@" + timestampMillis + getExtension() : null;
+        }
+
+        /**
+         * Get a full-path {@link File} representing this entry.
+         * @param dir Parent directly.  The caller needs to pass it because {@link EntryFile}s don't
+         *            know in which directory they're stored.
+         */
+        public File getFile(File dir) {
+            return hasFile() ? new File(dir, getFilename()) : null;
+        }
+
+        /**
+         * If an entry has a backing file, remove it.
+         */
+        public void deleteFile(File dir) {
+            if (hasFile()) {
+                getFile(dir).delete();
+            }
+        }
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -651,7 +727,7 @@
             if (files == null) throw new IOException("Can't list files: " + mDropBoxDir);
 
             mAllFiles = new FileList();
-            mFilesByTag = new HashMap<String, FileList>();
+            mFilesByTag = new ArrayMap<>();
 
             // Scan pre-existing files.
             for (File file : files) {
@@ -662,16 +738,12 @@
                 }
 
                 EntryFile entry = new EntryFile(file, mBlockSize);
-                if (entry.tag == null) {
-                    Slog.w(TAG, "Unrecognized file: " + file);
-                    continue;
-                } else if (entry.timestampMillis == 0) {
-                    Slog.w(TAG, "Invalid filename: " + file);
-                    file.delete();
-                    continue;
-                }
 
-                enrollEntry(entry);
+                if (entry.hasFile()) {
+                    // Enroll only when the filename is valid.  Otherwise the above constructor
+                    // has removed the file already.
+                    enrollEntry(entry);
+                }
             }
         }
     }
@@ -684,11 +756,11 @@
         // mFilesByTag is used for trimming, so don't list empty files.
         // (Zero-length/lost files are trimmed by date from mAllFiles.)
 
-        if (entry.tag != null && entry.file != null && entry.blocks > 0) {
+        if (entry.hasFile() && entry.blocks > 0) {
             FileList tagFiles = mFilesByTag.get(entry.tag);
             if (tagFiles == null) {
                 tagFiles = new FileList();
-                mFilesByTag.put(entry.tag, tagFiles);
+                mFilesByTag.put(TextUtils.safeIntern(entry.tag), tagFiles);
             }
             tagFiles.contents.add(entry);
             tagFiles.blocks += entry.blocks;
@@ -722,8 +794,8 @@
                     tagFiles.blocks -= late.blocks;
                 }
                 if ((late.flags & DropBoxManager.IS_EMPTY) == 0) {
-                    enrollEntry(new EntryFile(
-                            late.file, mDropBoxDir, late.tag, t++, late.flags, mBlockSize));
+                    enrollEntry(new EntryFile(late.getFile(mDropBoxDir), mDropBoxDir,
+                            late.tag, t++, late.flags, mBlockSize));
                 } else {
                     enrollEntry(new EntryFile(mDropBoxDir, late.tag, t++));
                 }
@@ -757,7 +829,7 @@
             FileList tag = mFilesByTag.get(entry.tag);
             if (tag != null && tag.contents.remove(entry)) tag.blocks -= entry.blocks;
             if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
-            if (entry.file != null) entry.file.delete();
+            entry.deleteFile(mDropBoxDir);
         }
 
         // Compute overall quota (a fraction of available free space) in blocks.
@@ -823,7 +895,7 @@
                     if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
 
                     try {
-                        if (entry.file != null) entry.file.delete();
+                        entry.deleteFile(mDropBoxDir);
                         enrollEntry(new EntryFile(mDropBoxDir, entry.tag, entry.timestampMillis));
                     } catch (IOException e) {
                         Slog.e(TAG, "Can't write tombstone file", e);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 7959e39..ac4423d 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2647,6 +2647,42 @@
         return failures;
     }
 
+    @Override
+    public boolean isNetworkRestricted(int uid) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        return isNetworkRestrictedInternal(uid);
+    }
+
+    private boolean isNetworkRestrictedInternal(int uid) {
+        synchronized (mRulesLock) {
+            if (getFirewallChainState(FIREWALL_CHAIN_STANDBY)
+                    && mUidFirewallStandbyRules.get(uid) == FIREWALL_RULE_DENY) {
+                if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of app standby mode");
+                return true;
+            }
+            if (getFirewallChainState(FIREWALL_CHAIN_DOZABLE)
+                    && mUidFirewallDozableRules.get(uid) != FIREWALL_RULE_ALLOW) {
+                if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of device idle mode");
+                return true;
+            }
+            if (getFirewallChainState(FIREWALL_CHAIN_POWERSAVE)
+                    && mUidFirewallPowerSaveRules.get(uid) != FIREWALL_RULE_ALLOW) {
+                if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of power saver mode");
+                return true;
+            }
+            if (mUidRejectOnMetered.get(uid)) {
+                if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
+                        + " in the background");
+                return true;
+            }
+            if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
+                if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
+                return true;
+            }
+            return false;
+        }
+    }
+
     private void setFirewallChainState(int chain, boolean state) {
         synchronized (mRulesLock) {
             mFirewallChainStates.put(chain, state);
@@ -2663,33 +2699,7 @@
     class LocalService extends NetworkManagementInternal {
         @Override
         public boolean isNetworkRestrictedForUid(int uid) {
-            synchronized (mRulesLock) {
-                if (getFirewallChainState(FIREWALL_CHAIN_STANDBY)
-                        && mUidFirewallStandbyRules.get(uid) == FIREWALL_RULE_DENY) {
-                    if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of app standby mode");
-                    return true;
-                }
-                if (getFirewallChainState(FIREWALL_CHAIN_DOZABLE)
-                        && mUidFirewallDozableRules.get(uid) != FIREWALL_RULE_ALLOW) {
-                    if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of device idle mode");
-                    return true;
-                }
-                if (getFirewallChainState(FIREWALL_CHAIN_POWERSAVE)
-                        && mUidFirewallPowerSaveRules.get(uid) != FIREWALL_RULE_ALLOW) {
-                    if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of power saver mode");
-                    return true;
-                }
-                if (mUidRejectOnMetered.get(uid)) {
-                    if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
-                            + " in the background");
-                    return true;
-                }
-                if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
-                    if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
-                    return true;
-                }
-                return false;
-            }
+            return isNetworkRestrictedInternal(uid);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7a19cc3..4a9b98d 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -2012,7 +2012,7 @@
     public boolean okToShowLocked() {
         return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
                 || (mStackSupervisor.isCurrentProfileLocked(userId)
-                && !service.mUserController.isUserStoppingOrShuttingDownLocked(userId));
+                && service.mUserController.isUserRunningLocked(userId, 0 /* flags */));
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ceae82f..9c8ba5a 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1447,15 +1447,6 @@
         return mStartedUserArray;
     }
 
-    boolean isUserStoppingOrShuttingDownLocked(int userId) {
-        UserState state = getStartedUserStateLocked(userId);
-        if (state == null) {
-            return false;
-        }
-        return state.state == UserState.STATE_STOPPING
-                || state.state == UserState.STATE_SHUTDOWN;
-    }
-
     boolean isUserRunningLocked(int userId, int flags) {
         UserState state = getStartedUserStateLocked(userId);
         if (state == null) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 6cc7071..b1c165e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -921,7 +921,9 @@
 
                         @Override
                         public void sendResult(Bundle data) throws RemoteException {
-                            mWakeLock.release();
+                            if (mWakeLock.isHeld()) {
+                                mWakeLock.release();
+                            }
                         }
                     });
                 } catch (DeadObjectException e) {
@@ -1079,18 +1081,19 @@
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName) {
             final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
-            final int pid = Binder.getCallingPid();
             final boolean restricted = isRestricted();
+
+            if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+                    callingUserId)) {
+                if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
+                return;
+            }
+
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (!canUseFingerprint(opPackageName, true /* foregroundOnly */,
-                            callingUid, pid, callingUserId)) {
-                        if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
-                        return;
-                    }
-
                     MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
 
                     // Get performance stats object for this user.
@@ -1111,29 +1114,31 @@
 
         @Override // Binder call
         public void cancelAuthentication(final IBinder token, final String opPackageName) {
-            final int uid = Binder.getCallingUid();
-            final int pid = Binder.getCallingPid();
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
+
+            if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+                    callingUserId)) {
+                if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
+                return;
+            }
+
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, uid, pid,
-                            callingUserId)) {
-                        if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
-                    } else {
-                        ClientMonitor client = mCurrentClient;
-                        if (client instanceof AuthenticationClient) {
-                            if (client.getToken() == token) {
-                                if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
-                                client.stop(client.getToken() == token);
-                            } else {
-                                if (DEBUG) Slog.v(TAG, "can't stop client "
-                                        + client.getOwnerString() + " since tokens don't match");
-                            }
-                        } else if (client != null) {
-                            if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
-                                    + client.getOwnerString());
+                    ClientMonitor client = mCurrentClient;
+                    if (client instanceof AuthenticationClient) {
+                        if (client.getToken() == token) {
+                            if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
+                            client.stop(client.getToken() == token);
+                        } else {
+                            if (DEBUG) Slog.v(TAG, "can't stop client "
+                                    + client.getOwnerString() + " since tokens don't match");
                         }
+                    } else if (client != null) {
+                        if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
+                                + client.getOwnerString());
                     }
                 }
             });
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 2f166e9..c6ea72f 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -25,6 +25,7 @@
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
 import static com.android.internal.widget.LockPatternUtils.USER_FRP;
 import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
+import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
 
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -2360,6 +2361,7 @@
                 if (isProvisioned()) {
                     Slog.i(TAG, "Reporting device setup complete to IGateKeeperService");
                     reportDeviceSetupComplete();
+                    clearFrpCredentialIfOwnerNotSecure();
                 }
             }
         }
@@ -2387,6 +2389,23 @@
             }
         }
 
+        /**
+         * Clears the FRP credential if the user that controls it does not have a secure
+         * lockscreen.
+         */
+        private void clearFrpCredentialIfOwnerNotSecure() {
+            List<UserInfo> users = mUserManager.getUsers();
+            for (UserInfo user : users) {
+                if (userOwnsFrpCredential(user)) {
+                    if (!isUserSecure(user.id)) {
+                        mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
+                                0, null);
+                    }
+                    return;
+                }
+            }
+        }
+
         private void updateRegistration() {
             boolean register = !isProvisioned();
             if (register == mRegistered) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index aabb245..0072ba4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -4315,6 +4315,47 @@
         }
     }
 
+    @Override
+    public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        return isUidNetworkingBlockedInternal(uid, isNetworkMetered);
+    }
+
+    private boolean isUidNetworkingBlockedInternal(int uid, boolean isNetworkMetered) {
+        final int uidRules;
+        final boolean isBackgroundRestricted;
+        synchronized (mUidRulesFirstLock) {
+            uidRules = mUidRules.get(uid, RULE_NONE);
+            isBackgroundRestricted = mRestrictBackground;
+        }
+        if (hasRule(uidRules, RULE_REJECT_ALL)) {
+            if (LOGV) logUidStatus(uid, "blocked by power restrictions");
+            return true;
+        }
+        if (!isNetworkMetered) {
+            if (LOGV) logUidStatus(uid, "allowed on unmetered network");
+            return false;
+        }
+        if (hasRule(uidRules, RULE_REJECT_METERED)) {
+            if (LOGV) logUidStatus(uid, "blacklisted on metered network");
+            return true;
+        }
+        if (hasRule(uidRules, RULE_ALLOW_METERED)) {
+            if (LOGV) logUidStatus(uid, "whitelisted on metered network");
+            return false;
+        }
+        if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
+            if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network");
+            return false;
+        }
+        if (isBackgroundRestricted) {
+            if (LOGV) logUidStatus(uid, "blocked when background is restricted");
+            return true;
+        }
+        if (LOGV) logUidStatus(uid, "allowed by default");
+        return false;
+    }
+
     private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
 
         @Override
@@ -4352,42 +4393,11 @@
          */
         @Override
         public boolean isUidNetworkingBlocked(int uid, String ifname) {
-            final int uidRules;
-            final boolean isBackgroundRestricted;
             final boolean isNetworkMetered;
-            synchronized (mUidRulesFirstLock) {
-                uidRules = mUidRules.get(uid, RULE_NONE);
-                isBackgroundRestricted = mRestrictBackground;
-                synchronized (mNetworkPoliciesSecondLock) {
-                    isNetworkMetered = mMeteredIfaces.contains(ifname);
-                }
+            synchronized (mNetworkPoliciesSecondLock) {
+                isNetworkMetered = mMeteredIfaces.contains(ifname);
             }
-            if (hasRule(uidRules, RULE_REJECT_ALL)) {
-                if (LOGV) logUidStatus(uid, "blocked by power restrictions");
-                return true;
-            }
-            if (!isNetworkMetered) {
-                if (LOGV) logUidStatus(uid, "allowed on unmetered network");
-                return false;
-            }
-            if (hasRule(uidRules, RULE_REJECT_METERED)) {
-                if (LOGV) logUidStatus(uid, "blacklisted on metered network");
-                return true;
-            }
-            if (hasRule(uidRules, RULE_ALLOW_METERED)) {
-                if (LOGV) logUidStatus(uid, "whitelisted on metered network");
-                return false;
-            }
-            if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
-                if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network");
-                return false;
-            }
-            if (isBackgroundRestricted) {
-                if (LOGV) logUidStatus(uid, "blocked when background is restricted");
-                return true;
-            }
-            if (LOGV) logUidStatus(uid, "allowed by default");
-            return false;
+            return isUidNetworkingBlockedInternal(uid, isNetworkMetered);
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 57c558c..ce805aad 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -38,14 +38,14 @@
     private final Callback mCallback;
 
     // Map of user : <Map of package : notification keys>. Only contains notifications that are not
-    // groupd by the app (aka no group or sort key).
+    // grouped by the app (aka no group or sort key).
     Map<Integer, Map<String, LinkedHashSet<String>>> mUngroupedNotifications = new HashMap<>();
 
     public GroupHelper(Callback callback) {;
         mCallback = callback;
     }
 
-    public void onNotificationPosted(StatusBarNotification sbn) {
+    public void onNotificationPosted(StatusBarNotification sbn, boolean autogroupSummaryExists) {
         if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey());
         try {
             List<String> notificationsToGroup = new ArrayList<>();
@@ -68,7 +68,8 @@
                     notificationsForPackage.add(sbn.getKey());
                     ungroupedNotificationsByUser.put(sbn.getPackageName(), notificationsForPackage);
 
-                    if (notificationsForPackage.size() >= AUTOGROUP_AT_COUNT) {
+                    if (notificationsForPackage.size() >= AUTOGROUP_AT_COUNT
+                            || autogroupSummaryExists) {
                         notificationsToGroup.addAll(notificationsForPackage);
                     }
                 }
@@ -120,6 +121,7 @@
             // If the status change of this notification has brought the number of loose
             // notifications to zero, remove the summary and un-autogroup.
             if (notificationsForPackage.size() == 0) {
+                ungroupedNotificationsByUser.remove(sbn.getPackageName());
                 removeSummary = true;
             }
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index abf391e..cc9f183 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -187,7 +187,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -795,6 +794,15 @@
         updateLightsLocked();
     }
 
+    protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+                mZenModeHelper.updateDefaultZenRules();
+            }
+        }
+    };
+
     private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -1056,7 +1064,7 @@
     }
 
     private SettingsObserver mSettingsObserver;
-    private ZenModeHelper mZenModeHelper;
+    protected ZenModeHelper mZenModeHelper;
 
     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
         int[] ar = r.getIntArray(resid);
@@ -1364,6 +1372,9 @@
         IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
         getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
 
+        IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
+        getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
+
         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
         publishLocalService(NotificationManagerInternal.class, mInternalService);
     }
@@ -2039,9 +2050,7 @@
 
         private StatusBarNotification sanitizeSbn(String pkg, int userId,
                 StatusBarNotification sbn) {
-            if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
-                    && (sbn.getNotification().flags
-                    & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
+            if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
                 // We could pass back a cloneLight() but clients might get confused and
                 // try to send this thing back to notify() again, which would not work
                 // very well.
@@ -3049,6 +3058,12 @@
         }
     }
 
+    @GuardedBy("mNotificationLock")
+    private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
+        ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
+        return summaries != null && summaries.containsKey(sbn.getPackageName());
+    }
+
     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
         NotificationRecord summaryRecord = null;
@@ -3824,7 +3839,8 @@
                             mHandler.post(new Runnable() {
                                 @Override
                                 public void run() {
-                                    mGroupHelper.onNotificationPosted(n);
+                                    mGroupHelper.onNotificationPosted(
+                                            n, hasAutoGroupSummaryLocked(n));
                                 }
                             });
                         }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 15e32ff..1a0b878 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -16,11 +16,6 @@
 
 package com.android.server.notification;
 
-import static android.media.AudioAttributes.USAGE_NOTIFICATION;
-import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
-import static android.media.AudioAttributes.USAGE_UNKNOWN;
-import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE;
-
 import android.app.AppOpsManager;
 import android.app.AutomaticZenRule;
 import android.app.NotificationManager;
@@ -52,7 +47,6 @@
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.ConditionProviderService;
-import android.service.notification.NotificationServiceDumpProto;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.EventInfo;
 import android.service.notification.ZenModeConfig.ScheduleInfo;
@@ -60,6 +54,7 @@
 import android.service.notification.ZenModeProto;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
@@ -93,7 +88,7 @@
     private final H mHandler;
     private final SettingsObserver mSettingsObserver;
     private final AppOpsManager mAppOps;
-    private final ZenModeConfig mDefaultConfig;
+    protected ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final ZenModeFiltering mFiltering;
     private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate();
@@ -102,11 +97,16 @@
     private final Metrics mMetrics = new Metrics();
     private final ConditionProviders.Config mServiceConfig;
 
+    protected final ArrayList<String> mDefaultRuleIds = new ArrayList<>();
+    private final String EVENTS_DEFAULT_RULE = "EVENTS_DEFAULT_RULE";
+    private final String SCHEDULED_DEFAULT_RULE_1 = "SCHEDULED_DEFAULT_RULE_1";
+    private final String SCHEDULED_DEFAULT_RULE_2 = "SCHEDULED_DEFAULT_RULE_2";
+
     private int mZenMode;
     private int mUser = UserHandle.USER_SYSTEM;
-    private ZenModeConfig mConfig;
+    protected ZenModeConfig mConfig;
     private AudioManagerInternal mAudioManager;
-    private PackageManager mPm;
+    protected PackageManager mPm;
     private long mSuppressedEffects;
 
     public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
@@ -114,21 +114,33 @@
     public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
             | SUPPRESSED_EFFECT_NOTIFICATIONS;
 
+    protected String mDefaultRuleWeeknightsName;
+    protected String mDefaultRuleEventsName;
+    protected String mDefaultRuleWeekendsName;
+
     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
         mContext = context;
         mHandler = new H(looper);
         addCallback(mMetrics);
         mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        mDefaultConfig = readDefaultConfig(context.getResources());
-        appendDefaultScheduleRules(mDefaultConfig);
-        appendDefaultEventRules(mDefaultConfig);
+
+        mDefaultConfig = new ZenModeConfig();
+        mDefaultRuleWeeknightsName = mContext.getResources()
+                .getString(R.string.zen_mode_default_weeknights_name);
+        mDefaultRuleWeekendsName = mContext.getResources()
+                .getString(R.string.zen_mode_default_weekends_name);
+        mDefaultRuleEventsName = mContext.getResources()
+                .getString(R.string.zen_mode_default_events_name);
+        setDefaultZenRules(mContext);
         mConfig = mDefaultConfig;
         mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
+
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
         mFiltering = new ZenModeFiltering(mContext);
         mConditions = new ZenModeConditions(this, conditionProviders);
         mServiceConfig = conditionProviders.getConfig();
+
     }
 
     public Looper getLooper() {
@@ -412,6 +424,54 @@
         }
     }
 
+    public void setDefaultZenRules(Context context) {
+        mDefaultConfig = readDefaultConfig(context.getResources());
+
+        mDefaultRuleIds.add(EVENTS_DEFAULT_RULE);
+        mDefaultRuleIds.add(SCHEDULED_DEFAULT_RULE_1);
+        mDefaultRuleIds.add(SCHEDULED_DEFAULT_RULE_2);
+
+        appendDefaultRules(mDefaultConfig);
+    }
+
+    private void appendDefaultRules (ZenModeConfig config) {
+        appendDefaultScheduleRules(config);
+        appendDefaultEventRules(config);
+    }
+
+    // Checks zen rule properties are the same (doesn't check creation time, name nor enabled)
+    // used to check if default rules were customized or not
+    private boolean ruleValuesEqual(AutomaticZenRule rule, ZenRule defaultRule) {
+        if (rule == null || defaultRule == null) {
+            return false;
+        }
+        return rule.getInterruptionFilter() ==
+                NotificationManager.zenModeToInterruptionFilter(defaultRule.zenMode)
+                && rule.getConditionId().equals(defaultRule.conditionId)
+                && rule.getOwner().equals(defaultRule.component);
+    }
+
+    protected void updateDefaultZenRules() {
+        ZenModeConfig configDefaultRules = new ZenModeConfig();
+        appendDefaultRules(configDefaultRules); // "new" localized default rules
+        for (String ruleId : mDefaultRuleIds) {
+            AutomaticZenRule currRule = getAutomaticZenRule(ruleId);
+            ZenRule defaultRule = configDefaultRules.automaticRules.get(ruleId);
+            // if default rule wasn't customized, use localized name instead of previous
+            if (ruleValuesEqual(currRule, defaultRule) &&
+                    !defaultRule.name.equals(currRule.getName())) {
+                if (canManageAutomaticZenRule(defaultRule)) {
+                    if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name "
+                            + "from " + currRule.getName() + " to " + defaultRule.name);
+                    // update default rule (if locale changed, name of rule will change)
+                    AutomaticZenRule defaultAutoRule = createAutomaticZenRule(defaultRule);
+                    updateAutomaticZenRule(ruleId, defaultAutoRule,
+                            "locale changed");
+                }
+            }
+        }
+    }
+
     private boolean isSystemRule(AutomaticZenRule rule) {
         return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
     }
@@ -453,7 +513,7 @@
                 automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
     }
 
-    private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
+    protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
         return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
                 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
                 rule.creationTime);
@@ -853,12 +913,11 @@
         weeknights.endHour = 7;
         final ZenRule rule1 = new ZenRule();
         rule1.enabled = false;
-        rule1.name = mContext.getResources()
-                .getString(R.string.zen_mode_default_weeknights_name);
+        rule1.name = mDefaultRuleWeeknightsName;
         rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
         rule1.zenMode = Global.ZEN_MODE_ALARMS;
         rule1.component = ScheduleConditionProvider.COMPONENT;
-        rule1.id = ZenModeConfig.newRuleId();
+        rule1.id = SCHEDULED_DEFAULT_RULE_1;
         rule1.creationTime = System.currentTimeMillis();
         config.automaticRules.put(rule1.id, rule1);
 
@@ -869,12 +928,11 @@
         weekends.endHour = 10;
         final ZenRule rule2 = new ZenRule();
         rule2.enabled = false;
-        rule2.name = mContext.getResources()
-                .getString(R.string.zen_mode_default_weekends_name);
+        rule2.name = mDefaultRuleWeekendsName;
         rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
         rule2.zenMode = Global.ZEN_MODE_ALARMS;
         rule2.component = ScheduleConditionProvider.COMPONENT;
-        rule2.id = ZenModeConfig.newRuleId();
+        rule2.id = SCHEDULED_DEFAULT_RULE_2;
         rule2.creationTime = System.currentTimeMillis();
         config.automaticRules.put(rule2.id, rule2);
     }
@@ -887,11 +945,11 @@
         events.reply = EventInfo.REPLY_YES_OR_MAYBE;
         final ZenRule rule = new ZenRule();
         rule.enabled = false;
-        rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name);
+        rule.name = mDefaultRuleEventsName;
         rule.conditionId = ZenModeConfig.toEventConditionId(events);
         rule.zenMode = Global.ZEN_MODE_ALARMS;
         rule.component = EventConditionProvider.COMPONENT;
-        rule.id = ZenModeConfig.newRuleId();
+        rule.id = EVENTS_DEFAULT_RULE;
         rule.creationTime = System.currentTimeMillis();
         config.automaticRules.put(rule.id, rule);
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d492590..082dd2b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1153,7 +1153,7 @@
         // This is kind of hacky; we're creating a half-parsed package that is
         // straddled between the inherited and staged APKs.
         final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
-                splitPaths.toArray(new String[splitPaths.size()]), null, null);
+                splitPaths.toArray(new String[splitPaths.size()]), null);
         final boolean isForwardLocked =
                 (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index faeb05b..46e21db 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -175,7 +175,7 @@
                 try {
                     ApkLite baseApk = PackageParser.parseApkLite(file, 0);
                     PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
-                            null, null, null);
+                            null, null);
                     params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
                             pkgLite, false, params.sessionParams.abiOverride));
                 } catch (PackageParserException | IOException e) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 72a832a..312327e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2378,6 +2378,9 @@
             BroadcastReceiver result) {
         Intent intent = new Intent(action);
         intent.setComponent(admin.info.getComponent());
+        if (UserManager.isDeviceInDemoMode(mContext)) {
+            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        }
         if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
             intent.putExtra("expiration", admin.passwordExpirationDate);
         }
@@ -8177,23 +8180,6 @@
                 return null;
             }
 
-            final UserInfo userInfo = getUserInfo(userHandle);
-            if (userInfo != null && userInfo.isDemo()) {
-                try {
-                    final ApplicationInfo ai = mIPackageManager.getApplicationInfo(adminPkg,
-                            PackageManager.MATCH_DISABLED_COMPONENTS, userHandle);
-                    final boolean isSystemApp =
-                            ai != null && (ai.flags & (ApplicationInfo.FLAG_SYSTEM
-                                    | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
-                    if (isSystemApp) {
-                        mIPackageManager.setApplicationEnabledSetting(adminPkg,
-                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
-                                PackageManager.DONT_KILL_APP, userHandle, "DevicePolicyManager");
-                    }
-                } catch (RemoteException e) {
-                }
-            }
-
             setActiveAdmin(profileOwner, true, userHandle);
             // User is not started yet, the broadcast by setActiveAdmin will not be received.
             // So we store adminExtras for broadcasting when the user starts for first time.
@@ -8487,6 +8473,8 @@
             enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
                     DELEGATION_ENABLE_SYSTEM_APP);
 
+            final boolean isDemo = isCurrentUserDemo();
+
             int userId = UserHandle.getCallingUserId();
             long id = mInjector.binderClearCallingIdentity();
 
@@ -8497,14 +8485,19 @@
                 }
 
                 int parentUserId = getProfileParentId(userId);
-                if (!isSystemApp(mIPackageManager, packageName, parentUserId)) {
+                if (!isDemo && !isSystemApp(mIPackageManager, packageName, parentUserId)) {
                     throw new IllegalArgumentException("Only system apps can be enabled this way.");
                 }
 
                 // Install the app.
                 mIPackageManager.installExistingPackageAsUser(packageName, userId,
                         0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY);
-
+                if (isDemo) {
+                    // Ensure the app is also ENABLED for demo users.
+                    mIPackageManager.setApplicationEnabledSetting(packageName,
+                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                            PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
+                }
             } catch (RemoteException re) {
                 // shouldn't happen
                 Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
@@ -8949,7 +8942,8 @@
                 return;
             }
 
-            if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) {
+            if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)
+                    && !UserManager.isDeviceInDemoMode(mContext)) {
                 throw new SecurityException(String.format(
                         "Permission denial: device owners cannot update %1$s", setting));
             }
@@ -8981,11 +8975,12 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             if (isDeviceOwner(who, callingUserId)) {
-                if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting)) {
+                if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting)
+                        && !isCurrentUserDemo()) {
                     throw new SecurityException(String.format(
                             "Permission denial: Device owners cannot update %1$s", setting));
                 }
-            } else if (!SECURE_SETTINGS_WHITELIST.contains(setting)) {
+            } else if (!SECURE_SETTINGS_WHITELIST.contains(setting) && !isCurrentUserDemo()) {
                 throw new SecurityException(String.format(
                         "Permission denial: Profile owners cannot update %1$s", setting));
             }
@@ -9436,12 +9431,6 @@
 
     @Override
     public SystemUpdatePolicy getSystemUpdatePolicy() {
-        if (UserManager.isDeviceInDemoMode(mContext)) {
-            // Pretending to have an automatic update policy when the device is in retail demo
-            // mode. This will allow the device to download and install an ota without
-            // any user interaction.
-            return SystemUpdatePolicy.createAutomaticInstallPolicy();
-        }
         synchronized (this) {
             SystemUpdatePolicy policy =  mOwners.getSystemUpdatePolicy();
             if (policy != null && !policy.isValid()) {
@@ -10448,6 +10437,19 @@
         }
     }
 
+    private boolean isCurrentUserDemo() {
+        if (UserManager.isDeviceInDemoMode(mContext)) {
+            final int userId = mInjector.userHandleGetCallingUserId();
+            final long callingIdentity = mInjector.binderClearCallingIdentity();
+            try {
+                return mUserManager.getUserInfo(userId).isDemo();
+            } finally {
+                mInjector.binderRestoreCallingIdentity(callingIdentity);
+            }
+        }
+        return false;
+    }
+
     private void removePackageIfRequired(final String packageName, final int userId) {
         if (!packageHasActiveAdmins(packageName, userId)) {
             // Will not do anything if uninstall was not requested or was already started.
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 8dd1779..f75c648 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -15,6 +15,9 @@
  */
 package com.android.server.notification;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -29,18 +32,16 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import android.app.AlarmManager;
 import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -77,7 +78,8 @@
     public void testNoGroup_postingUnderLimit() throws Exception {
         final String pkg = "package";
         for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT - 1; i++) {
-            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM),
+                    false);
         }
         verify(mCallback, never()).addAutoGroupSummary(
                 eq(UserHandle.USER_SYSTEM), eq(pkg), anyString());
@@ -91,10 +93,11 @@
         final String pkg = "package";
         final String pkg2 = "package2";
         for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT - 1; i++) {
-            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM),
+                    false);
         }
         mGroupHelper.onNotificationPosted(
-                getSbn(pkg2, GroupHelper.AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM));
+                getSbn(pkg2, GroupHelper.AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM), false);
         verify(mCallback, never()).addAutoGroupSummary(
                 eq(UserHandle.USER_SYSTEM), eq(pkg), anyString());
         verify(mCallback, never()).addAutoGroup(anyString());
@@ -106,10 +109,12 @@
     public void testNoGroup_multiUser() throws Exception {
         final String pkg = "package";
         for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT - 1; i++) {
-            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM),
+                    false);
         }
         mGroupHelper.onNotificationPosted(
-                getSbn(pkg, GroupHelper.AUTOGROUP_AT_COUNT, "four", UserHandle.ALL));
+                getSbn(pkg, GroupHelper.AUTOGROUP_AT_COUNT, "four", UserHandle.ALL),
+                false);
         verify(mCallback, never()).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
         verify(mCallback, never()).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
@@ -120,10 +125,12 @@
     public void testNoGroup_someAreGrouped() throws Exception {
         final String pkg = "package";
         for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT - 1; i++) {
-            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+            mGroupHelper.onNotificationPosted(
+                    getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false);
         }
         mGroupHelper.onNotificationPosted(
-                getSbn(pkg, GroupHelper.AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM, "a"));
+                getSbn(pkg, GroupHelper.AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM, "a"),
+                false);
         verify(mCallback, never()).addAutoGroupSummary(
                 eq(UserHandle.USER_SYSTEM), eq(pkg), anyString());
         verify(mCallback, never()).addAutoGroup(anyString());
@@ -136,7 +143,8 @@
     public void testPostingOverLimit() throws Exception {
         final String pkg = "package";
         for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT; i++) {
-            mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+            mGroupHelper.onNotificationPosted(
+                    getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false);
         }
         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
         verify(mCallback, times(GroupHelper.AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
@@ -151,7 +159,7 @@
         for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT; i++) {
             final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
             posted.add(sbn);
-            mGroupHelper.onNotificationPosted(sbn);
+            mGroupHelper.onNotificationPosted(sbn, false);
         }
         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
         verify(mCallback, times(GroupHelper.AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
@@ -178,7 +186,7 @@
         for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT; i++) {
             final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
             posted.add(sbn);
-            mGroupHelper.onNotificationPosted(sbn);
+            mGroupHelper.onNotificationPosted(sbn, false);
         }
         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
         verify(mCallback, times(GroupHelper.AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
@@ -190,7 +198,7 @@
         for (i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT - 2; i++) {
             final StatusBarNotification sbn =
                     getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group");
-            mGroupHelper.onNotificationPosted(sbn);
+            mGroupHelper.onNotificationPosted(sbn, false);
         }
         verify(mCallback, times(GroupHelper.AUTOGROUP_AT_COUNT - 2)).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -199,9 +207,48 @@
         for (; i < GroupHelper.AUTOGROUP_AT_COUNT; i++) {
             final StatusBarNotification sbn =
                     getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group");
-            mGroupHelper.onNotificationPosted(sbn);
+            mGroupHelper.onNotificationPosted(sbn, false);
         }
         verify(mCallback, times(2)).removeAutoGroup(anyString());
         verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), anyString());
     }
+
+    @Test
+    public void testNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled()
+            throws Exception {
+        final String pkg = "package";
+        List<StatusBarNotification> posted = new ArrayList<>();
+        for (int i = 0; i < GroupHelper.AUTOGROUP_AT_COUNT; i++) {
+            final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
+            posted.add(sbn);
+            mGroupHelper.onNotificationPosted(sbn, false);
+        }
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
+        verify(mCallback, times(GroupHelper.AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+        Mockito.reset(mCallback);
+
+        for (int i = posted.size() - 2; i >= 0; i--) {
+            mGroupHelper.onNotificationRemoved(posted.remove(i));
+        }
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+        Mockito.reset(mCallback);
+
+        // only one child remains
+        Map<String, LinkedHashSet<String>> ungroupedForUser =
+                mGroupHelper.mUngroupedNotifications.get(UserHandle.USER_SYSTEM);
+        assertNotNull(ungroupedForUser);
+        assertEquals(1, ungroupedForUser.get(pkg).size());
+
+        // Add new notification; it should be autogrouped even though the total count is
+        // < AUTOGROUP_AT_COUNT
+        final StatusBarNotification sbn = getSbn(pkg, 5, String.valueOf(5), UserHandle.SYSTEM);
+        posted.add(sbn);
+        mGroupHelper.onNotificationPosted(sbn, true);
+        verify(mCallback, times(posted.size())).addAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+    }
 }
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 09af1e2..04b42f1 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -48,6 +48,7 @@
 import android.companion.ICompanionDeviceManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -60,7 +61,6 @@
 import android.provider.Settings.Secure;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
-import android.service.notification.ZenModeConfig;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -1339,7 +1339,7 @@
         runnable.run();
         waitForIdle();
 
-        verify(mGroupHelper, times(1)).onNotificationPosted(any());
+        verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
     }
 
     @Test
@@ -1355,7 +1355,7 @@
         runnable.run();
         waitForIdle();
 
-        verify(mGroupHelper, times(1)).onNotificationPosted(any());
+        verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
     }
 
     @Test
@@ -1371,7 +1371,7 @@
         runnable.run();
         waitForIdle();
 
-        verify(mGroupHelper, never()).onNotificationPosted(any());
+        verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean());
     }
 
     @Test
@@ -1550,4 +1550,14 @@
         verify(mAssistants, times(2)).migrateToXml();
     }
 
+
+    @Test
+    public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception {
+        ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+        mNotificationManagerService.mZenModeHelper = mZenModeHelper;
+        mNotificationManagerService.mLocaleChangeReceiver.onReceive(mContext,
+                new Intent(Intent.ACTION_LOCALE_CHANGED));
+
+        verify(mZenModeHelper, times(1)).updateDefaultZenRules();
+    }
 }
diff --git a/services/tests/servicestests/res/raw/conntestapp b/services/tests/servicestests/res/raw/conntestapp
index 6093303..e993164 100644
--- a/services/tests/servicestests/res/raw/conntestapp
+++ b/services/tests/servicestests/res/raw/conntestapp
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
index 7f28d44..56773e8 100644
--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -18,18 +18,20 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.Intent;
 import android.os.DropBoxManager;
+import android.os.Looper;
 import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
 import android.os.Process;
-import android.os.ServiceManager;
 import android.os.StatFs;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
 
-import com.android.server.DropBoxManagerService;
+import com.android.server.DropBoxManagerService.EntryFile;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -41,8 +43,28 @@
 import java.util.Random;
 import java.util.zip.GZIPOutputStream;
 
-/** Test {@link DropBoxManager} functionality. */
+/**
+ * Test {@link DropBoxManager} functionality.
+ *
+ * Run with:
+ * bit FrameworksServicesTests:com.android.server.DropBoxTest
+ */
 public class DropBoxTest extends AndroidTestCase {
+    private Context mContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mContext = new ContextWrapper(super.getContext()) {
+            @Override
+            public void sendBroadcastAsUser(Intent intent,
+                    UserHandle user, String receiverPermission) {
+                // Don't actually send broadcasts.
+            }
+        };
+    }
+
     public void tearDown() throws Exception {
         ContentResolver cr = getContext().getContentResolver();
         Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "");
@@ -51,9 +73,15 @@
         Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
     public void testAddText() throws Exception {
         File dir = getEmptyDir("testAddText");
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
@@ -89,15 +117,19 @@
 
     public void testAddData() throws Exception {
         File dir = getEmptyDir("testAddData");
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
+        Thread.sleep(1);
         dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
+        Thread.sleep(1);
         long after = System.currentTimeMillis();
 
         DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", before);
-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
+        assertNotNull(e);
+        assertNull(dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
 
         assertEquals("DropBoxTest", e.getTag());
         assertTrue(e.getTimeMillis() >= before);
@@ -114,10 +146,12 @@
         File dir = getEmptyDir("testAddFile");
         long before = System.currentTimeMillis();
 
-        File f0 = new File(dir, "f0.txt");
-        File f1 = new File(dir, "f1.txt.gz");
-        File f2 = new File(dir, "f2.dat");
-        File f3 = new File(dir, "f2.dat.gz");
+        File clientDir = getEmptyDir("testAddFile_client");
+
+        File f0 = new File(clientDir, "f0.txt");
+        File f1 = new File(clientDir, "f1.txt.gz");
+        File f2 = new File(clientDir, "f2.dat");
+        File f3 = new File(clientDir, "f2.dat.gz");
 
         FileWriter w0 = new FileWriter(f0);
         GZIPOutputStream gz1 = new GZIPOutputStream(new FileOutputStream(f1));
@@ -134,7 +168,8 @@
         os2.close();
         gz3.close();
 
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
@@ -200,7 +235,8 @@
         // Tombstone in the far future
         new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
 
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         // Until a write, the timestamps are taken at face value
@@ -251,7 +287,8 @@
 
     public void testIsTagEnabled() throws Exception {
         File dir = getEmptyDir("testIsTagEnabled");
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
@@ -284,7 +321,8 @@
 
     public void testGetNextEntry() throws Exception {
         File dir = getEmptyDir("testGetNextEntry");
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         long before = System.currentTimeMillis();
@@ -346,7 +384,8 @@
 
         final int overhead = 64;
         long before = System.currentTimeMillis();
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
@@ -440,7 +479,8 @@
 
         // Write one normal entry and another so big that it is instantly tombstoned
         long before = System.currentTimeMillis();
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         dropbox.addText("DropBoxTest", "TEST");
@@ -471,7 +511,8 @@
     public void testFileCountLimits() throws Exception {
         File dir = getEmptyDir("testFileCountLimits");
 
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
         dropbox.addText("DropBoxTest", "TEST0");
         dropbox.addText("DropBoxTest", "TEST1");
@@ -524,7 +565,8 @@
 
         File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
         new FileOutputStream(dir).close();  // Create an empty file
-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir,
+                Looper.getMainLooper());
         DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
 
         dropbox.addText("DropBoxTest", "should be ignored");
@@ -735,6 +777,223 @@
         assertTrue(after < before + 20);
     }
 
+    public void testEntryFile() throws Exception {
+        File fromDir = getEmptyDir("testEntryFile_from");
+        File toDir = getEmptyDir("testEntryFile_to");
+
+        {
+            File f = new File(fromDir, "f0.txt");
+            try (FileWriter w = new FileWriter(f)) {
+                w.write("abc");
+            }
+
+            EntryFile e = new EntryFile(f, toDir, "tag:!", 12345, DropBoxManager.IS_TEXT, 1024);
+
+            assertEquals("tag:!", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_TEXT, e.flags);
+            assertEquals(1, e.blocks);
+
+            assertFalse(f.exists()); // Because it should be renamed.
+
+            assertTrue(e.hasFile());
+            assertEquals(new File(toDir, "tag%3A!@12345.txt"), e.getFile(toDir));
+            assertTrue(e.getFile(toDir).exists());
+        }
+        // Same test with gzip.
+        {
+            File f = new File(fromDir, "f0.txt.gz"); // It's a lie; it's not actually gz.
+            try (FileWriter w = new FileWriter(f)) {
+                w.write("abc");
+            }
+
+            EntryFile e = new EntryFile(f, toDir, "tag:!", 12345,
+                    DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED, 1024);
+
+            assertEquals("tag:!", e.tag);
+
+            assertFalse(f.exists()); // Because it should be renamed.
+
+            assertTrue(e.hasFile());
+            assertEquals(new File(toDir, "tag%3A!@12345.txt.gz"), e.getFile(toDir));
+            assertTrue(e.getFile(toDir).exists());
+
+        }
+        // binary, gzip.
+        {
+            File f = new File(fromDir, "f0.dat.gz"); // It's a lie; it's not actually gz.
+            try (FileWriter w = new FileWriter(f)) {
+                w.write("abc");
+            }
+
+            EntryFile e = new EntryFile(f, toDir, "tag:!", 12345,
+                    DropBoxManager.IS_GZIPPED, 1024);
+
+            assertEquals("tag:!", e.tag);
+
+            assertFalse(f.exists()); // Because it should be renamed.
+
+            assertTrue(e.hasFile());
+            assertEquals(new File(toDir, "tag%3A!@12345.dat.gz"), e.getFile(toDir));
+            assertTrue(e.getFile(toDir).exists());
+
+        }
+
+        // Tombstone.
+        {
+            EntryFile e = new EntryFile(toDir, "tag:!", 12345);
+
+            assertEquals("tag:!", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertTrue(e.hasFile());
+            assertEquals(new File(toDir, "tag%3A!@12345.lost"), e.getFile(toDir));
+            assertTrue(e.getFile(toDir).exists());
+        }
+
+        // From existing files.
+        {
+            File f = new File(fromDir, "tag%3A!@12345.dat");
+            f.createNewFile();
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals("tag:!", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(0, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertTrue(f.exists());
+        }
+        {
+            File f = new File(fromDir, "tag%3A!@12345.dat.gz");
+            f.createNewFile();
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals("tag:!", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_GZIPPED, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertTrue(f.exists());
+        }
+        {
+            File f = new File(fromDir, "tag%3A!@12345.txt");
+            try (FileWriter w = new FileWriter(f)) {
+                w.write(new char[1024]);
+            }
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals("tag:!", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_TEXT, e.flags);
+            assertEquals(1, e.blocks);
+
+            assertTrue(f.exists());
+        }
+        {
+            File f = new File(fromDir, "tag%3A!@12345.txt.gz");
+            try (FileWriter w = new FileWriter(f)) {
+                w.write(new char[1025]);
+            }
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals("tag:!", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED, e.flags);
+            assertEquals(2, e.blocks);
+
+            assertTrue(f.exists());
+        }
+        {
+            File f = new File(fromDir, "tag%3A!@12345.lost");
+            f.createNewFile();
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals("tag:!", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertTrue(f.exists());
+        }
+        {
+            File f = new File(fromDir, "@12345.dat"); // Empty tag -- this actually works.
+            f.createNewFile();
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals("", e.tag);
+            assertEquals(12345, e.timestampMillis);
+            assertEquals(0, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertTrue(f.exists());
+        }
+        // From invalid filenames.
+        {
+            File f = new File(fromDir, "tag.dat"); // No @.
+            f.createNewFile();
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals(null, e.tag);
+            assertEquals(0, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertFalse(f.exists());
+        }
+        {
+            File f = new File(fromDir, "tag@.dat"); // Invalid timestamp.
+            f.createNewFile();
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals(null, e.tag);
+            assertEquals(0, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertFalse(f.exists());
+        }
+        {
+            File f = new File(fromDir, "tag@12345.daxt"); // Invalid extension.
+            f.createNewFile();
+
+            EntryFile e = new EntryFile(f, 1024);
+
+            assertEquals(null, e.tag);
+            assertEquals(0, e.timestampMillis);
+            assertEquals(DropBoxManager.IS_EMPTY, e.flags);
+            assertEquals(0, e.blocks);
+
+            assertFalse(f.exists());
+        }
+    }
+
+    public void testCompareEntries() {
+        File dir = getEmptyDir("testCompareEntries");
+        assertEquals(-1,
+                new EntryFile(new File(dir, "aaa@100.dat"), 1).compareTo(
+                new EntryFile(new File(dir, "bbb@200.dat"), 1)));
+        assertEquals(1,
+                new EntryFile(new File(dir, "aaa@200.dat"), 1).compareTo(
+                new EntryFile(new File(dir, "bbb@100.dat"), 1)));
+        assertEquals(-1,
+                new EntryFile(new File(dir, "aaa@100.dat"), 1).compareTo(
+                new EntryFile(new File(dir, "bbb@100.dat"), 1)));
+        assertEquals(1,
+                new EntryFile(new File(dir, "bbb@100.dat"), 1).compareTo(
+                new EntryFile(new File(dir, "aaa@100.dat"), 1)));
+    }
+
     private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
         byte[] bytes = new byte[size];
         new Random(System.currentTimeMillis()).nextBytes(bytes);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index dcca724..e3faa52 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -384,74 +384,6 @@
         mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
     }
 
-    public void testCreateAndManageUser_demoUserSystemApp() throws Exception {
-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
-
-        setDeviceOwner();
-
-        final int id = UserHandle.getUserId(DpmMockContext.CALLER_UID);
-
-        final UserInfo demoUserInfo = mock(UserInfo.class);
-        demoUserInfo.id = id;
-        doReturn(UserHandle.of(id)).when(demoUserInfo).getUserHandle();
-        doReturn(true).when(demoUserInfo).isDemo();
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        doReturn(demoUserInfo).when(um).getUserInfo(id);
-        doReturn(demoUserInfo).when(mContext.getUserManagerInternal())
-                .createUserEvenWhenDisallowed(anyString(), anyInt());
-
-        final ApplicationInfo applicationInfo = getServices().ipackageManager.getApplicationInfo(
-                admin2.getPackageName(), PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, id);
-        applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
-        doReturn(applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
-                anyString(), anyInt(), anyInt());
-
-        final UserHandle userHandle = dpm.createAndManageUser(admin1, "", admin2, null, 0);
-
-        verify(getServices().ipackageManager, times(1)).setApplicationEnabledSetting(
-                eq(admin2.getPackageName()),
-                eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
-                eq(PackageManager.DONT_KILL_APP),
-                eq(id),
-                anyString());
-
-        assertNotNull(userHandle);
-    }
-
-    public void testCreateAndManageUser_demoUserSystemUpdatedApp() throws Exception {
-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
-
-        setDeviceOwner();
-
-        final int id = UserHandle.getUserId(DpmMockContext.CALLER_UID);
-
-        final UserInfo demoUserInfo = mock(UserInfo.class);
-        demoUserInfo.id = id;
-        doReturn(UserHandle.of(id)).when(demoUserInfo).getUserHandle();
-        doReturn(true).when(demoUserInfo).isDemo();
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        doReturn(demoUserInfo).when(um).getUserInfo(id);
-        doReturn(demoUserInfo).when(mContext.getUserManagerInternal())
-                .createUserEvenWhenDisallowed(anyString(), anyInt());
-
-        final ApplicationInfo applicationInfo = getServices().ipackageManager.getApplicationInfo(
-                admin2.getPackageName(), PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, id);
-        applicationInfo.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-        doReturn(applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
-                anyString(), anyInt(), anyInt());
-
-        final UserHandle userHandle = dpm.createAndManageUser(admin1, "", admin2, null, 0);
-
-        verify(getServices().ipackageManager, times(1)).setApplicationEnabledSetting(
-                eq(admin2.getPackageName()),
-                eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
-                eq(PackageManager.DONT_KILL_APP),
-                eq(id),
-                anyString());
-
-        assertNotNull(userHandle);
-    }
-
     public void testSetActiveAdmin_multiUsers() throws Exception {
 
         final int ANOTHER_USER_ID = 100;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 8121bcf..99f54ba 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -46,6 +46,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.provider.Settings;
 import android.security.KeyChain;
 import android.telephony.TelephonyManager;
 import android.test.mock.MockContentResolver;
@@ -53,6 +54,7 @@
 import android.util.Pair;
 import android.view.IWindowManager;
 
+import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
@@ -130,6 +132,7 @@
         packageManager = spy(realContext.getPackageManager());
 
         contentResolver = new MockContentResolver();
+        contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
 
         // Add the system user with a fake profile group already set up (this can happen in the real
         // world if a managed profile is added and then removed).
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index f02cf51..5b4c10f 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -20,7 +20,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -37,8 +36,6 @@
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Bundle;
@@ -101,19 +98,16 @@
 
     private static final long WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
 
-    private static final long NETWORK_CHECK_TIMEOUT_MS = 6000; // 6 sec
+    private static final long NETWORK_CHECK_TIMEOUT_MS = 4000; // 4 sec
 
     private static final long SCREEN_ON_DELAY_MS = 500; // 0.5 sec
 
-    private static final String NETWORK_STATUS_SEPARATOR = "\\|";
-
     private static final int REPEAT_TEST_COUNT = 5;
 
     private static Context mContext;
     private static UiDevice mUiDevice;
     private static int mTestPkgUid;
     private static BatteryManager mBatteryManager;
-    private static ConnectivityManager mConnectivityManager;
 
     @BeforeClass
     public static void setUpOnce() throws Exception {
@@ -126,8 +120,6 @@
         mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
 
         mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
-        mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
     }
 
     @AfterClass
@@ -144,9 +136,6 @@
 
     @Test
     public void testStartActivity_batterySaver() throws Exception {
-        if (!isNetworkAvailable()) {
-            fail("Device doesn't have network connectivity");
-        }
         setBatterySaverMode(true);
         try {
             testConnOnActivityStart("testStartActivity_batterySaver");
@@ -157,9 +146,6 @@
 
     @Test
     public void testStartActivity_dataSaver() throws Exception {
-        if (!isNetworkAvailable()) {
-            fail("Device doesn't have network connectivity");
-        }
         setDataSaverMode(true);
         try {
             testConnOnActivityStart("testStartActivity_dataSaver");
@@ -170,9 +156,6 @@
 
     @Test
     public void testStartActivity_dozeMode() throws Exception {
-        if (!isNetworkAvailable()) {
-            fail("Device doesn't have network connectivity");
-        }
         setDozeMode(true);
         try {
             testConnOnActivityStart("testStartActivity_dozeMode");
@@ -183,9 +166,6 @@
 
     @Test
     public void testStartActivity_appStandby() throws Exception {
-        if (!isNetworkAvailable()) {
-            fail("Device doesn't have network connectivity");
-        }
         try{
             turnBatteryOff();
             setAppIdle(true);
@@ -200,9 +180,6 @@
 
     @Test
     public void testStartActivity_backgroundRestrict() throws Exception {
-        if (!isNetworkAvailable()) {
-            fail("Device doesn't have network connectivity");
-        }
         updateRestrictBackgroundBlacklist(true);
         try {
             testConnOnActivityStart("testStartActivity_backgroundRestrict");
@@ -347,11 +324,6 @@
                 + maxTries + " attempts. Last result: '" + result + "'");
     }
 
-    private boolean isNetworkAvailable() throws Exception {
-        final NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
-        return networkInfo != null && networkInfo.isConnected();
-    }
-
     private void startActivityAndCheckNetworkAccess() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         final Intent launchIntent = new Intent().setComponent(
@@ -361,15 +333,15 @@
         extras.putBinder(EXTRA_NETWORK_STATE_OBSERVER, new INetworkStateObserver.Stub() {
             @Override
             public void onNetworkStateChecked(String resultData) {
-                errors[0] = checkForAvailability(resultData);
+                errors[0] = resultData;
                 latch.countDown();
             }
         });
         launchIntent.putExtras(extras);
         mContext.startActivity(launchIntent);
         if (latch.await(NETWORK_CHECK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-            if (!errors[0].isEmpty()) {
-                fail("Network not available for test app " + mTestPkgUid);
+            if (errors[0] != null) {
+                fail("Network not available for test app " + mTestPkgUid + ". " + errors[0]);
             }
         } else {
             fail("Timed out waiting for network availability status from test app " + mTestPkgUid);
@@ -381,43 +353,6 @@
                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         mContext.sendBroadcast(finishIntent);
     }
-
-    private String checkForAvailability(String resultData) {
-        if (resultData == null) {
-            assertNotNull("Network status from app2 is null, Uid: " + mTestPkgUid, resultData);
-        }
-        // Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
-        final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
-        assertEquals("Wrong network status: " + resultData + ", Uid: " + mTestPkgUid,
-                5, parts.length); // Sanity check
-        final NetworkInfo.State state = parts[0].equals("null")
-                ? null : NetworkInfo.State.valueOf(parts[0]);
-        final NetworkInfo.DetailedState detailedState = parts[1].equals("null")
-                ? null : NetworkInfo.DetailedState.valueOf(parts[1]);
-        final boolean connected = Boolean.valueOf(parts[2]);
-        final String connectionCheckDetails = parts[3];
-        final String networkInfo = parts[4];
-
-        final StringBuilder errors = new StringBuilder();
-        final NetworkInfo.State expectedState = NetworkInfo.State.CONNECTED;
-        final NetworkInfo.DetailedState expectedDetailedState = NetworkInfo.DetailedState.CONNECTED;
-
-        if (true != connected) {
-            errors.append(String.format("External site connection failed: expected %s, got %s\n",
-                    true, connected));
-        }
-        if (expectedState != state || expectedDetailedState != detailedState) {
-            errors.append(String.format("Connection state mismatch: expected %s/%s, got %s/%s\n",
-                    expectedState, expectedDetailedState, state, detailedState));
-        }
-
-        if (errors.length() > 0) {
-            errors.append("\tnetworkInfo: " + networkInfo + "\n");
-            errors.append("\tconnectionCheckDetails: " + connectionCheckDetails + "\n");
-        }
-        return errors.toString();
-    }
-
     private static void installAppAndAssertInstalled() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         final int[] result = {PackageInstaller.STATUS_SUCCESS};
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
index 02afe83..030a709 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
@@ -17,7 +17,6 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
 
 LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
index 0da3562..6671410 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
@@ -17,8 +17,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.servicestests.apps.conntestapp">
 
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
 
     <application>
         <activity android:name=".ConnTestActivity"
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
index 11ebfca..c5c7add 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
+++ b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
@@ -21,19 +21,17 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
+import android.net.INetworkPolicyManager;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.INetworkManagementService;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 
 import com.android.servicestests.aidl.INetworkStateObserver;
 
-import java.net.HttpURLConnection;
-import java.net.URL;
-
 public class ConnTestActivity extends Activity {
     private static final String TAG = ConnTestActivity.class.getSimpleName();
 
@@ -41,10 +39,6 @@
     private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
     private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
 
-    private static final int NETWORK_TIMEOUT_MS = 5 * 1000;
-
-    private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s";
-
     private BroadcastReceiver finishCommandReceiver = null;
 
     @Override
@@ -84,7 +78,7 @@
         if (observer != null) {
             AsyncTask.execute(() -> {
                 try {
-                    observer.onNetworkStateChecked(checkNetworkStatus(ConnTestActivity.this));
+                    observer.onNetworkStateChecked(checkNetworkStatus());
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error occured while notifying the observer: " + e);
                 }
@@ -93,78 +87,25 @@
     }
 
     /**
-     * Checks whether the network is available and return a string which can then be send as a
-     * result data for the ordered broadcast.
+     * Checks whether the network is restricted.
      *
-     * <p>
-     * The string has the following format:
-     *
-     * <p><pre><code>
-     * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
-     * </code></pre>
-     *
-     * <p>Where:
-     *
-     * <ul>
-     * <li>{@code NetinfoState}: enum value of {@link NetworkInfo.State}.
-     * <li>{@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}.
-     * <li>{@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt
-     *     to access an external website.
-     * <li>{@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real
-     *     connection attempt
-     * <li>{@code Netinfo}: string representation of the {@link NetworkInfo}.
-     * </ul>
-     *
-     * For example, if the connection was established fine, the result would be something like:
-     * <p><pre><code>
-     * CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
-     * </code></pre>
+     * @return null if network is not restricted, otherwise an error message.
      */
-    private String checkNetworkStatus(Context context) {
-        final ConnectivityManager cm =
-                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        final String address = "http://example.com";
-        final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
-        Log.d(TAG, "Running checkNetworkStatus() on thread "
-                + Thread.currentThread().getName() + " for UID " + getUid(context)
-                + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
-        boolean checkStatus = false;
-        String checkDetails = "N/A";
+    private String checkNetworkStatus() {
+        final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+        final INetworkPolicyManager npms = INetworkPolicyManager.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
         try {
-            final URL url = new URL(address);
-            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-            conn.setReadTimeout(NETWORK_TIMEOUT_MS);
-            conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
-            conn.setRequestMethod("GET");
-            conn.setDoInput(true);
-            conn.connect();
-            final int response = conn.getResponseCode();
-            checkStatus = true;
-            checkDetails = "HTTP response for " + address + ": " + response;
-        } catch (Exception e) {
-            checkStatus = false;
-            checkDetails = "Exception getting " + address + ": " + e;
-        }
-        Log.d(TAG, checkDetails);
-        final String state, detailedState;
-        if (networkInfo != null) {
-            state = networkInfo.getState().name();
-            detailedState = networkInfo.getDetailedState().name();
-        } else {
-            state = detailedState = "null";
-        }
-        final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState,
-                Boolean.valueOf(checkStatus), checkDetails, networkInfo);
-        Log.d(TAG, "Offering " + status);
-        return status;
-    }
-
-    private int getUid(Context context) {
-        final String packageName = context.getPackageName();
-        try {
-            return context.getPackageManager().getPackageUid(packageName, 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new IllegalStateException("Could not get UID for " + packageName, e);
+            final boolean restrictedByFwRules = nms.isNetworkRestricted(Process.myUid());
+            final boolean restrictedByUidRules = npms.isUidNetworkingBlocked(Process.myUid(), true);
+            if (restrictedByFwRules || restrictedByUidRules) {
+                return "Network is restricted by fwRules: " + restrictedByFwRules
+                        + " and uidRules: " + restrictedByUidRules;
+            }
+            return null;
+        } catch (RemoteException e) {
+            return "Error talking to system server: " + e;
         }
     }
 }
\ No newline at end of file