Merge "Explicitly allow shell to update listener/assist" into oc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index f32f23dd..80fdb30 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -49062,6 +49062,7 @@
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public android.view.textclassifier.TextClassifier getTextClassifier();
diff --git a/api/system-current.txt b/api/system-current.txt
index 970c318..e4eea84 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -263,6 +263,7 @@
     field public static final java.lang.String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
     field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
+    field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
     field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
@@ -52844,6 +52845,7 @@
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public android.view.textclassifier.TextClassifier getTextClassifier();
@@ -52908,7 +52910,6 @@
     method public void zoomBy(float);
     method public boolean zoomIn();
     method public boolean zoomOut();
-    field public static final java.lang.String DATA_REDUCTION_PROXY_SETTING_CHANGED = "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
     field public static final int RENDERER_PRIORITY_BOUND = 1; // 0x1
     field public static final int RENDERER_PRIORITY_IMPORTANT = 2; // 0x2
     field public static final int RENDERER_PRIORITY_WAIVED = 0; // 0x0
@@ -53096,6 +53097,7 @@
     method public abstract java.lang.String findAddress(java.lang.String);
     method public abstract void freeMemoryForTests();
     method public abstract java.lang.String getDefaultUserAgent(android.content.Context);
+    method public abstract android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public abstract void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
     method public abstract android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
     method public abstract void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
diff --git a/api/test-current.txt b/api/test-current.txt
index ccdca6a..cba0dfd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -49509,6 +49509,7 @@
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public android.view.textclassifier.TextClassifier getTextClassifier();
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/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/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/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java
index 2ccd2ba..0d0f1cc 100644
--- a/core/java/android/webkit/SafeBrowsingResponse.java
+++ b/core/java/android/webkit/SafeBrowsingResponse.java
@@ -21,6 +21,11 @@
  * created by the WebView and passed to {@link android.webkit.WebViewClient#onSafeBrowsingHit}. The
  * host application must call {@link #showInterstitial(boolean)}, {@link #proceed(boolean)}, or
  * {@link #backToSafety(boolean)} to set the WebView's response to the Safe Browsing hit.
+ *
+ * <p>
+ * If reporting is enabled, all reports will be sent according to the privacy policy referenced by
+ * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}.
+ * </p>
  */
 public abstract class SafeBrowsingResponse {
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index dd716eb..650c7d9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -347,16 +347,6 @@
         implements ViewTreeObserver.OnGlobalFocusChangeListener,
         ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
 
-    /**
-     * Broadcast Action: Indicates the data reduction proxy setting changed.
-     * Sent by the settings app when user changes the data reduction proxy value. This intent will
-     * always stay as a hidden API.
-     * @hide
-     */
-    @SystemApi
-    public static final String DATA_REDUCTION_PROXY_SETTING_CHANGED =
-            "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
-
     private static final String LOGTAG = "WebView";
 
     // Throwing an exception for incorrect thread usage if the
@@ -1700,6 +1690,16 @@
     }
 
     /**
+     * Returns a URL pointing to the privacy policy for Safe Browsing reporting.
+     *
+     * @return the url pointing to a privacy policy document which can be displayed to users.
+     */
+    @NonNull
+    public static Uri getSafeBrowsingPrivacyPolicyUrl() {
+        return getFactory().getStatics().getSafeBrowsingPrivacyPolicyUrl();
+    }
+
+    /**
      * Gets the WebBackForwardList for this WebView. This contains the
      * back/forward list for use in querying each item in the history stack.
      * This is a copy of the private WebBackForwardList so it contains only a
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 613eb72..4f6513f 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
@@ -95,6 +96,13 @@
         * ValueCallback<Boolean>)}
         */
         void setSafeBrowsingWhitelist(List<String> urls, ValueCallback<Boolean> callback);
+
+        /**
+         * Implement the API method
+         * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}
+         */
+        @NonNull
+        Uri getSafeBrowsingPrivacyPolicyUrl();
     }
 
     Statics getStatics();
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/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1ad8541..5afd067 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -814,6 +814,12 @@
             addOption("-Ximage-compiler-option");
             addOption("--compiled-classes=/system/etc/compiled-classes");
         }
+
+        // If there is a dirty-image-objects file, push it.
+        if (hasFile("/system/etc/dirty-image-objects")) {
+            addOption("-Ximage-compiler-option");
+            addOption("--dirty-image-objects=/system/etc/dirty-image-objects");
+        }
     }
 
     property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6209aff..5b0f8d5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1825,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,
@@ -2265,7 +2261,7 @@
          <p>An application requesting this permission is responsible for
          verifying the source and integrity of the update before passing
          it off to the installer components.
-         @hide -->
+         @SystemApi @hide -->
     <permission android:name="android.permission.UPDATE_TIME_ZONE_RULES"
         android:protectionLevel="signature|privileged" />
 
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 066c051..95aa264 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2994,9 +2994,11 @@
     <!-- Handle volume keys directly in Window Manager without passing them to the foreground app -->
     <bool name="config_handleVolumeKeysInWindowManager">false</bool>
 
-    <!-- Volume level of in-call notification tone playback,
-         relative to the overall voice call stream volume [0..100] -->
-    <integer name="config_inCallNotificationVolumeRelative">67</integer>
+    <!-- Volume level of in-call notification tone playback [0..1] -->
+    <item name="config_inCallNotificationVolume" format="float" type="dimen">.25</item>
+
+    <!-- URI for in call notification sound -->
+    <string translatable="false" name="config_inCallNotificationSound">/system/media/audio/ui/InCallNotification.ogg</string>
 
     <!-- The OEM specified sensor type for the lift trigger to launch the camera app. -->
     <integer name="config_cameraLiftTriggerSensorType">-1</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e67884d..061413c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3039,7 +3039,8 @@
   <java-symbol type="array" name="config_allowedSecureInstantAppSettings" />
 
   <java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" />
-  <java-symbol type="integer" name="config_inCallNotificationVolumeRelative" />
+  <java-symbol type="dimen" name="config_inCallNotificationVolume" />
+  <java-symbol type="string" name="config_inCallNotificationSound" />
   <java-symbol type="bool" name="config_dozeAlwaysOnDisplayAvailable" />
   <java-symbol type="bool" name="config_displayBlanksAfterDoze" />
   <java-symbol type="bool" name="config_displayBrightnessBucketsInDoze" />
diff --git a/data/sounds/effects/InCallNotification.ogg b/data/sounds/effects/InCallNotification.ogg
new file mode 100644
index 0000000..4481ccb2
--- /dev/null
+++ b/data/sounds/effects/InCallNotification.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/InCallNotification.ogg b/data/sounds/effects/ogg/InCallNotification.ogg
new file mode 100644
index 0000000..4481ccb2
--- /dev/null
+++ b/data/sounds/effects/ogg/InCallNotification.ogg
Binary files differ
diff --git a/dirty-image-objects b/dirty-image-objects
new file mode 100644
index 0000000..9b4d199
--- /dev/null
+++ b/dirty-image-objects
@@ -0,0 +1,176 @@
+#
+# 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.
+#
+#
+#
+# Dirty-image-objects file for boot image.
+#
+# Objects in this file are known dirty at runtime. Current this includes:
+#   - classes with known dirty static fields.
+#
+# The image writer will bin these objects together in the image.
+#
+# This file can be generated using imgdiag with a command such as:
+#   adb shell imgdiag --image-diff-pid=<app pid> --zygote-diff-pid=<zygote pid> \
+#     --boot-image=/system/framework/boot.art --dump-dirty-objects
+# Then, grep for lines containing "Private dirty object" from the output.
+# This particular file was generated by dumping systemserver and systemui.
+#
+java.lang.System
+java.net.Inet4Address
+java.lang.Thread
+java.lang.Throwable
+java.util.Collections
+javax.net.ssl.SSLContext
+java.nio.charset.Charset
+java.security.Provider
+javax.net.ssl.HttpsURLConnection
+javax.net.ssl.SSLSocketFactory
+java.util.TimeZone
+java.util.Locale
+java.util.function.ToIntFunction
+sun.misc.FormattedFloatingDecimal
+java.util.stream.IntStream
+android.icu.util.TimeZone
+libcore.io.DropBox
+org.apache.harmony.luni.internal.util.TimezoneGetter
+dalvik.system.SocketTagger
+dalvik.system.CloseGuard
+java.lang.ref.FinalizerReference
+com.android.org.conscrypt.ct.CTLogStoreImpl
+com.android.org.conscrypt.SSLParametersImpl
+com.android.org.conscrypt.OpenSSLContextImpl
+com.android.org.conscrypt.SSLParametersImpl$AliasChooser
+com.android.org.conscrypt.SSLParametersImpl$PSKCallbacks
+com.android.org.conscrypt.NativeCrypto$SSLHandshakeCallbacks
+com.android.okhttp.OkHttpClient
+com.android.okhttp.okio.SegmentPool
+com.android.okhttp.okio.AsyncTimeout
+com.android.okhttp.HttpUrl
+android.os.StrictMode
+com.android.internal.os.BinderInternal
+android.os.storage.StorageManager
+android.os.Trace
+android.app.ActivityManager
+android.media.MediaRouter
+android.os.Environment
+android.view.ThreadedRenderer
+android.media.AudioManager
+android.app.AlarmManager
+android.telephony.TelephonyManager
+android.bluetooth.BluetoothAdapter
+com.android.internal.os.SomeArgs
+android.os.LocaleList
+android.view.WindowManagerGlobal
+android.media.AudioSystem
+android.ddm.DdmHandleAppName
+android.provider.Settings
+android.view.ViewRootImpl
+android.net.ConnectivityManager
+android.app.ActivityThread
+android.os.BaseBundle
+android.util.ArraySet
+android.view.View
+android.os.ServiceManager
+android.view.ViewTreeObserver
+android.hardware.input.InputManager
+android.os.UEventObserver
+android.app.NotificationManager
+android.hardware.display.DisplayManagerGlobal
+android.os.Binder
+android.app.AppOpsManager
+android.content.ContentResolver
+android.app.backup.BackupManager
+android.util.ArrayMap
+android.os.Looper
+android.graphics.Bitmap
+android.view.textservice.TextServicesManager
+com.android.internal.inputmethod.InputMethodUtils
+android.app.QueuedWork
+android.graphics.TemporaryBuffer
+android.widget.ImageView
+android.database.sqlite.SQLiteGlobal
+android.view.autofill.Helper
+android.text.method.SingleLineTransformationMethod
+com.android.internal.os.RuntimeInit
+android.view.inputmethod.InputMethodManager
+android.hardware.SystemSensorManager
+android.database.CursorWindow
+android.text.TextUtils
+android.media.PlayerBase
+android.app.ResourcesManager
+android.os.Message
+android.view.accessibility.AccessibilityManager
+android.app.Notification
+android.provider.ContactsContract$ContactNameColumns
+android.provider.CalendarContract$EventsColumns
+android.provider.CalendarContract$CalendarColumns
+android.provider.CalendarContract$SyncColumns
+android.provider.ContactsContract$ContactsColumns
+android.content.pm.PackageManager$OnPermissionsChangedListener
+android.net.IpConfiguration$ProxySettings
+android.provider.ContactsContract$ContactOptionsColumns
+android.net.wifi.SupplicantState
+android.provider.ContactsContract$ContactStatusColumns
+android.view.accessibility.AccessibilityManager$TouchExplorationStateChangeListener
+android.provider.CalendarContract$CalendarSyncColumns
+android.bluetooth.BluetoothProfile$ServiceListener
+android.provider.ContactsContract$ContactCounts
+android.net.IpConfiguration$IpAssignment
+android.text.TextWatcher
+android.graphics.Bitmap$CompressFormat
+android.location.LocationListener
+sun.security.jca.Providers
+java.lang.CharSequence
+android.icu.util.ULocale
+dalvik.system.BaseDexClassLoader
+android.icu.text.BreakIterator
+libcore.io.EventLogger
+libcore.net.NetworkSecurityPolicy
+android.icu.text.UnicodeSet
+com.android.org.conscrypt.TrustedCertificateStore$PreloadHolder
+android.app.SearchManager
+android.os.Build
+android.app.ContextImpl
+android.app.WallpaperManager
+android.security.net.config.ApplicationConfig
+android.animation.LayoutTransition
+android.widget.TextView
+com.android.internal.logging.MetricsLogger
+android.renderscript.RenderScriptCacheDir
+android.os.Process
+android.os.Handler
+android.content.Context
+android.graphics.drawable.AdaptiveIconDrawable
+android.provider.FontsContract
+android.text.style.SuggestionSpan
+android.graphics.drawable.VectorDrawable$VGroup
+android.view.ViewStub
+android.text.style.MetricAffectingSpan
+android.content.SharedPreferences$OnSharedPreferenceChangeListener
+android.app.PendingIntent
+android.text.SpanWatcher
+android.widget.FrameLayout
+android.net.NetworkRequest$Type
+android.net.NetworkInfo$State
+android.graphics.drawable.GradientDrawable
+android.text.style.AlignmentSpan
+android.widget.LinearLayout
+android.text.style.CharacterStyle
+android.view.View$OnApplyWindowInsetsListener
+android.view.MenuItem
+android.text.style.ReplacementSpan
+android.graphics.drawable.Icon
+android.widget.Button
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/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0a77e01..1ec4dcd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -163,7 +163,7 @@
     <string name="usb_debugging_secondary_user_title">USB debugging not allowed</string>
 
     <!-- Message of notification shown when trying to enable USB debugging but a secondary user is the current foreground user. -->
-    <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, please switch to an Admin user.</string>
+    <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, switch to the primary user.</string>
 
     <!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
          on a phone).  [CHAR LIMIT=25] -->
@@ -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>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 32775fe..669594b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -646,13 +646,6 @@
         return mStrongAuthTracker;
     }
 
-    public void reportSuccessfulStrongAuthUnlockAttempt() {
-        if (mFpm != null) {
-            byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
-            mFpm.resetTimeout(token);
-        }
-    }
-
     private void notifyStrongAuthStateChanged(int userId) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d132e76..4733008 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -560,9 +560,6 @@
             }
 
             tryKeyguardDone();
-            if (strongAuth) {
-                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
-            }
         }
 
         @Override
@@ -591,9 +588,6 @@
             mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable);
             mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
                     KEYGUARD_DONE_PENDING_TIMEOUT_MS);
-            if (strongAuth) {
-                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
-            }
             Trace.endSection();
         }
 
@@ -1288,7 +1282,6 @@
                 // Without this, settings is not enabled until the lock screen first appears
                 setShowingLocked(false);
                 hideLocked();
-                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
                 return;
             }
         }
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/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/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 855b9d0..b1c165e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1081,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.
@@ -1113,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..c672949 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;
@@ -560,6 +561,7 @@
         mDeviceProvisionedObserver.onSystemReady();
         // TODO: maybe skip this for split system user mode.
         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
+        mStrongAuth.systemReady();
     }
 
     private void migrateOldData() {
@@ -2360,6 +2362,7 @@
                 if (isProvisioned()) {
                     Slog.i(TAG, "Reporting device setup complete to IGateKeeperService");
                     reportDeviceSetupComplete();
+                    clearFrpCredentialIfOwnerNotSecure();
                 }
             }
         }
@@ -2387,6 +2390,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/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 0966153..542b929 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -27,6 +27,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.IStrongAuthTracker;
 import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Binder;
 import android.os.DeadObjectException;
 import android.os.Handler;
@@ -64,6 +65,7 @@
     private final Context mContext;
 
     private AlarmManager mAlarmManager;
+    private FingerprintManager mFingerprintManager;
 
     public LockSettingsStrongAuth(Context context) {
         mContext = context;
@@ -71,6 +73,10 @@
         mAlarmManager = context.getSystemService(AlarmManager.class);
     }
 
+    public void systemReady() {
+        mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+    }
+
     private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
         for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
             if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
@@ -188,6 +194,11 @@
     }
 
     public void reportSuccessfulStrongAuthUnlock(int userId) {
+        if (mFingerprintManager != null) {
+            byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
+            mFingerprintManager.resetTimeout(token);
+        }
+
         final int argNotUsed = 0;
         mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
     }
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 acf0ac1..6115e34 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -93,10 +93,10 @@
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.IRingtonePlayer;
-import android.media.ToneGenerator;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -187,13 +187,13 @@
 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;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -304,12 +304,12 @@
 
     // for enabling and disabling notification pulse behavior
     private boolean mScreenOn = true;
-    private boolean mInCall = false;
+    protected boolean mInCall = false;
     private boolean mNotificationPulseEnabled;
 
-    // for generating notification tones in-call
-    private ToneGenerator mInCallToneGenerator;
-    private final Object mInCallToneGeneratorLock = new Object();
+    private Uri mInCallNotificationUri;
+    private AudioAttributes mInCallNotificationAudioAttributes;
+    private float mInCallNotificationVolume;
 
     // used as a mutex for access to all active notifications & listeners
     final Object mNotificationLock = new Object();
@@ -947,30 +947,6 @@
                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
                 updateNotificationPulse();
-                synchronized (mInCallToneGeneratorLock) {
-                    if (mInCall) {
-                        if (mInCallToneGenerator == null) {
-                            int relativeToneVolume = getContext().getResources().getInteger(
-                                    R.integer.config_inCallNotificationVolumeRelative);
-                            if (relativeToneVolume < ToneGenerator.MIN_VOLUME
-                                    || relativeToneVolume > ToneGenerator.MAX_VOLUME) {
-                                relativeToneVolume = ToneGenerator.MAX_VOLUME;
-                            }
-                            try {
-                                mInCallToneGenerator = new ToneGenerator(
-                                        AudioManager.STREAM_VOICE_CALL, relativeToneVolume);
-                            } catch (RuntimeException e) {
-                                Log.e(TAG, "Error creating local tone generator: " + e);
-                                mInCallToneGenerator = null;
-                            }
-                        }
-                    } else {
-                        if (mInCallToneGenerator != null) {
-                            mInCallToneGenerator.release();
-                            mInCallToneGenerator = null;
-                        }
-                     }
-                }
             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (userHandle >= 0) {
@@ -1277,6 +1253,15 @@
                 VIBRATE_PATTERN_MAXLEN,
                 DEFAULT_VIBRATE_PATTERN);
 
+        mInCallNotificationUri = Uri.parse("file://" +
+                resources.getString(R.string.config_inCallNotificationSound));
+        mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
+                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+                .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+                .build();
+        mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
+
         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
 
         // Don't start allowing notifications until the setup wizard has run once.
@@ -2051,9 +2036,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.
@@ -3061,6 +3044,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;
@@ -3836,7 +3825,8 @@
                             mHandler.post(new Runnable() {
                                 @Override
                                 public void run() {
-                                    mGroupHelper.onNotificationPosted(n);
+                                    mGroupHelper.onNotificationPosted(
+                                            n, hasAutoGroupSummaryLocked(n));
                                 }
                             });
                         }
@@ -4152,21 +4142,21 @@
                 mUserProfiles.isCurrentProfile(record.getUserId()));
     }
 
-    private void playInCallNotification() {
+    protected void playInCallNotification() {
         new Thread() {
             @Override
             public void run() {
-                // If toneGenerator creation fails, just continue the call
-                // without playing the notification sound.
+                final long identity = Binder.clearCallingIdentity();
                 try {
-                    synchronized (mInCallToneGeneratorLock) {
-                        if (mInCallToneGenerator != null) {
-                            // limit this tone to 1 second; BEEP2 should in fact be much shorter
-                            mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000);
-                        }
+                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+                    if (player != null) {
+                        player.play(new Binder(), mInCallNotificationUri,
+                                mInCallNotificationAudioAttributes,
+                                mInCallNotificationVolume, false);
                     }
-                } catch (RuntimeException e) {
-                    Log.w(TAG, "Exception from ToneGenerator: " + e);
+                } catch (RemoteException e) {
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
                 }
             }
         }.start();
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 835603a..529ac3a 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -537,6 +537,21 @@
     }
 
     @Test
+    public void testInCallNotification() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        mService.mInCall = true;
+        mService.buzzBeepBlinkLocked(r);
+
+        //verify(mService, times(1)).playInCallNotification();
+        verifyNeverBeep(); // doesn't play normal beep
+    }
+
+    @Test
     public void testNoDemoteSoundToVibrateIfVibrateGiven() throws Exception {
         NotificationRecord r = getBuzzyBeepyNotification();
         assertTrue(r.getSound() != null);
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 9acf519..04b42f1 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -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
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/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