Merge changes from topics "remove_feature_flag_emergency", "faster_emergency_feature_flag" into pi-dev

* changes:
  RESTRICT AUTOMERGE: Removes feature flag for faster emergency call.
  Add new metrics in power menu
  Add feature flag in Settings.
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index c7618fe..d438554 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1749,7 +1749,7 @@
     /**
      * Like {@link #execStartActivity(android.content.Context, android.os.IBinder,
      * android.os.IBinder, String, android.content.Intent, int, android.os.Bundle)},
-     * but for calls from a {#link Fragment}.
+     * but for calls from a {@link Fragment}.
      * 
      * @param who The Context from which the activity is being started.
      * @param contextThread The main thread of the Context from which the activity
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index ea0fd75..6cee2da5 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -20,13 +20,13 @@
 import android.annotation.Nullable;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ContextWrapper;
 import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Build;
-import android.os.RemoteException;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.util.Log;
 
 import java.io.FileDescriptor;
@@ -390,7 +390,7 @@
      * don't recreate until a future explicit call to
      * {@link Context#startService Context.startService(Intent)}.  The
      * service will not receive a {@link #onStartCommand(Intent, int, int)}
-     * call with a null Intent because it will not be re-started if there
+     * call with a null Intent because it will not be restarted if there
      * are no pending Intents to deliver.
      * 
      * <p>This mode makes sense for things that want to do some work as a
@@ -415,7 +415,7 @@
      * redelivery until the service calls {@link #stopSelf(int)} with the
      * start ID provided to {@link #onStartCommand}.  The
      * service will not receive a {@link #onStartCommand(Intent, int, int)}
-     * call with a null Intent because it will will only be re-started if
+     * call with a null Intent because it will only be restarted if
      * it is not finished processing all Intents sent to it (and any such
      * pending events will be delivered at the point of restart).
      */
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1b6b5a0..4405108 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2797,7 +2797,7 @@
      * socket will be encrypted.
      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
      * {@link BluetoothServerSocket}.
-     * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {#link
+     * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {@link
      * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is
      * closed, Bluetooth is turned off, or the application exits unexpectedly.
      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
@@ -2847,7 +2847,7 @@
      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
      * {@link BluetoothServerSocket}.
      * <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value
-     * can be read from the {#link BluetoothServerSocket#getPsm()} and this value will be released
+     * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released
      * when this server socket is closed, Bluetooth is turned off, or the application exits
      * unexpectedly.
      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 7a6b72e..f4b7d7c 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1567,7 +1567,7 @@
      * For example, for Bluetooth 2.1 devices, if any of the devices does not
      * have an input and output capability or just has the ability to
      * display a numeric key, a secure socket connection is not possible.
-     * In such a case, use {#link createInsecureRfcommSocket}.
+     * In such a case, use {@link createInsecureRfcommSocket}.
      * For more details, refer to the Security Model section 5.2 (vol 3) of
      * Bluetooth Core Specification version 2.1 + EDR.
      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
@@ -1601,7 +1601,7 @@
      * For example, for Bluetooth 2.1 devices, if any of the devices does not
      * have an input and output capability or just has the ability to
      * display a numeric key, a secure socket connection is not possible.
-     * In such a case, use {#link createInsecureRfcommSocket}.
+     * In such a case, use {@link createInsecureRfcommSocket}.
      * For more details, refer to the Security Model section 5.2 (vol 3) of
      * Bluetooth Core Specification version 2.1 + EDR.
      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
@@ -1658,7 +1658,7 @@
      * For example, for Bluetooth 2.1 devices, if any of the devices does not
      * have an input and output capability or just has the ability to
      * display a numeric key, a secure socket connection is not possible.
-     * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
+     * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}.
      * For more details, refer to the Security Model section 5.2 (vol 3) of
      * Bluetooth Core Specification version 2.1 + EDR.
      * <p>Hint: If you are connecting to a Bluetooth serial board then try
@@ -1938,7 +1938,7 @@
      * encrypted.
      * <p> Use this socket if an authenticated socket link is possible. Authentication refers
      * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a
-     * secure socket connection is not possible, use {#link createInsecureLeL2capCocSocket(int,
+     * secure socket connection is not possible, use {@link createInsecureLeL2capCocSocket(int,
      * int)}.
      *
      * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index ebb7f18..ca29ef3 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -201,7 +201,7 @@
     /**
      * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
      * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
-     * {#link BluetoothAdapter.listenUsingL2capCoc(int)} or {#link
+     * {@link BluetoothAdapter.listenUsingL2capCoc(int)} or {@link
      * BluetoothAdapter.listenUsingInsecureL2capCoc(int)}. The returned value is undefined if this
      * method is called on non-L2CAP server sockets.
      *
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index b4c8a5e..d26c5162 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2110,7 +2110,7 @@
      * Called when the application has reported a new location of its text
      * cursor.  This is only called if explicitly requested by the input method.
      * The default implementation does nothing.
-     * @deprecated Use {#link onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
+     * @deprecated Use {@link #onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
      */
     @Deprecated
     public void onUpdateCursor(Rect newCursor) {
@@ -2177,7 +2177,7 @@
     }
 
     /**
-     * @return {#link ExtractEditText} if it is considered to be visible and active. Otherwise
+     * @return {@link ExtractEditText} if it is considered to be visible and active. Otherwise
      * {@code null} is returned.
      */
     private ExtractEditText getExtractEditTextIfVisible() {
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 795117e..bf579a7 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -103,9 +103,9 @@
     /**
      * Set which boundary of the screen the DockWindow sticks to.
      * 
-     * @param gravity The boundary of the screen to stick. See {#link
-     *        android.view.Gravity.LEFT}, {#link android.view.Gravity.TOP},
-     *        {#link android.view.Gravity.BOTTOM}, {#link
+     * @param gravity The boundary of the screen to stick. See {@link
+     *        android.view.Gravity.LEFT}, {@link android.view.Gravity.TOP},
+     *        {@link android.view.Gravity.BOTTOM}, {@link
      *        android.view.Gravity.RIGHT}.
      */
     public void setGravity(int gravity) {
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 69f50a2..a2da6ea 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -46,7 +46,7 @@
 
     /**
      * Set if the user desires to use this network even if it is unvalidated. This field has meaning
-     * only if {#link explicitlySelected} is true. If it is, this field must also be set to the
+     * only if {@link explicitlySelected} is true. If it is, this field must also be set to the
      * appropriate value based on previous user choice.
      */
     public boolean acceptUnvalidated;
diff --git a/core/java/android/net/UrlQuerySanitizer.java b/core/java/android/net/UrlQuerySanitizer.java
index d2073b4..5b67406 100644
--- a/core/java/android/net/UrlQuerySanitizer.java
+++ b/core/java/android/net/UrlQuerySanitizer.java
@@ -287,7 +287,7 @@
         /**
          * Sanitize a value.
          * <ol>
-         * <li>If script URLs are not OK, the will be removed.
+         * <li>If script URLs are not OK, they will be removed.
          * <li>If neither spaces nor other white space is OK, then
          * white space will be trimmed from the beginning and end of
          * the URL. (Just the actual white space characters are trimmed, not
@@ -563,7 +563,7 @@
     }
 
     /**
-     * Constructs a UrlQuerySanitizer and parse a URL.
+     * Constructs a UrlQuerySanitizer and parses a URL.
      * This constructor is provided for convenience when the
      * default parsing behavior is acceptable.
      * <p>
@@ -644,7 +644,7 @@
     }
 
     /**
-     * An array list of all of the parameter value pairs in the sanitized
+     * An array list of all of the parameter-value pairs in the sanitized
      * query, in the order they appeared in the query. May contain duplicate
      * parameters.
      * <p class="note"><b>Note:</b> Do not modify this list. Treat it as a read-only list.</p>
@@ -656,7 +656,7 @@
     /**
      * Check if a parameter exists in the current sanitized query.
      * @param parameter the unencoded name of a parameter.
-     * @return true if the paramater exists in the current sanitized queary.
+     * @return true if the parameter exists in the current sanitized queary.
      */
     public boolean hasParameter(String parameter) {
         return mEntries.containsKey(parameter);
@@ -766,7 +766,7 @@
      * the value. If all goes well then addSanitizedValue is called with
      * the unescaped parameter and the sanitized unescaped value.
      * @param parameter an escaped parameter
-     * @param value an unsanitzied escaped value
+     * @param value an unsanitized escaped value
      */
     protected void parseEntry(String parameter, String value) {
         String unescapedParameter = unescape(parameter);
@@ -812,7 +812,7 @@
     /**
      * Get the effective value sanitizer for a parameter. Like getValueSanitizer,
      * except if there is no value sanitizer registered for a parameter, and
-     * unregistered paramaters are allowed, then the default value sanitizer is
+     * unregistered parameters are allowed, then the default value sanitizer is
      * returned.
      * @param parameter an unescaped parameter
      * @return the effective value sanitizer for a parameter.
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 7d1c6c4..50f63f8 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -16,13 +16,15 @@
 
 package android.util;
 
+import libcore.internal.StringPool;
+
 import java.io.Closeable;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.Reader;
 import java.util.ArrayList;
 import java.util.List;
-import libcore.internal.StringPool;
+
 
 /**
  * Reads a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
@@ -295,7 +297,7 @@
 
     /**
      * Consumes the next token from the JSON stream and asserts that it is the
-     * end of the current array.
+     * end of the current object.
      */
     public void endObject() throws IOException {
         expect(JsonToken.END_OBJECT);
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 02202db..503eb97 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -123,7 +123,7 @@
     /**
      * Modifier keys may be chorded with character keys.
      *
-     * @see {#link #getModifierBehavior()} for more details.
+     * @see {@link #getModifierBehavior()} for more details.
      */
     public static final int MODIFIER_BEHAVIOR_CHORDED = 0;
 
@@ -131,7 +131,7 @@
      * Modifier keys may be chorded with character keys or they may toggle
      * into latched or locked states when pressed independently.
      *
-     * @see {#link #getModifierBehavior()} for more details.
+     * @see {@link #getModifierBehavior()} for more details.
      */
     public static final int MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1;
 
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index a597405..86554fe 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -883,8 +883,8 @@
     /**
      * {@link #getAction} value: multiple duplicate key events have
      * occurred in a row, or a complex string is being delivered.  If the
-     * key code is not {#link {@link #KEYCODE_UNKNOWN} then the
-     * {#link {@link #getRepeatCount()} method returns the number of times
+     * key code is not {@link #KEYCODE_UNKNOWN} then the
+     * {@link #getRepeatCount()} method returns the number of times
      * the given key code should be executed.
      * Otherwise, if the key code is {@link #KEYCODE_UNKNOWN}, then
      * this is a sequence of characters as returned by {@link #getCharacters}.
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index da5a1cd..0e1e379 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -418,20 +418,28 @@
      *
      * @param nodes The nodes in the hosting window.
      * @param rootNodeId The id of the root to evict.
+     *
+     * @return {@code true} if the cache was cleared
      */
-    private void clearSubTreeRecursiveLocked(LongSparseArray<AccessibilityNodeInfo> nodes,
+    private boolean clearSubTreeRecursiveLocked(LongSparseArray<AccessibilityNodeInfo> nodes,
             long rootNodeId) {
         AccessibilityNodeInfo current = nodes.get(rootNodeId);
         if (current == null) {
-            return;
+            // The node isn't in the cache, but its descendents might be.
+            clear();
+            return true;
         }
         nodes.remove(rootNodeId);
         final int childCount = current.getChildCount();
         for (int i = 0; i < childCount; i++) {
             final long childNodeId = current.getChildId(i);
-            clearSubTreeRecursiveLocked(nodes, childNodeId);
+            if (clearSubTreeRecursiveLocked(nodes, childNodeId)) {
+                current.recycle();
+                return true;
+            }
         }
         current.recycle();
+        return false;
     }
 
     /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4a99623..42bbe20 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -995,7 +995,7 @@
 
     <!-- Allows a calling application which manages it own calls through the self-managed
          {@link android.telecom.ConnectionService} APIs.  See
-         {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED for more information on the
+         {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED} for more information on the
          self-managed ConnectionService APIs.
          <p>Protection level: normal
     -->
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index 4de8155..993378d 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -300,6 +300,26 @@
     }
 
     @Test
+    public void subTreeChangeEventFromUncachedNode_clearsNodeInCache() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1);
+        long id = nodeInfo.getSourceNodeId();
+        mAccessibilityCache.add(nodeInfo);
+        nodeInfo.recycle();
+
+        AccessibilityEvent event = AccessibilityEvent
+                .obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+        event.setSource(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+
+        mAccessibilityCache.onAccessibilityEvent(event);
+        AccessibilityNodeInfo shouldBeNull = mAccessibilityCache.getNode(WINDOW_ID_1, id);
+        if (shouldBeNull != null) {
+            shouldBeNull.recycle();
+        }
+        assertNull(shouldBeNull);
+    }
+
+    @Test
     public void scrollEvent_clearsNodeAndChild() {
         AccessibilityEvent event = AccessibilityEvent
                 .obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0c38c38..8686253 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4552,7 +4552,7 @@
 
     /**
      * The message sent to apps when the contents of the device list changes if they provide
-     * a {#link Handler} object to addOnAudioDeviceConnectionListener().
+     * a {@link Handler} object to addOnAudioDeviceConnectionListener().
      */
     private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
     private final static int MSG_DEVICES_DEVICES_ADDED = 1;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 97d0a6e..3151c28 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -226,7 +226,7 @@
  *         transfers the object to the <em>Prepared</em> state once the method call
  *         returns, or a call to {@link #prepareAsync()} (asynchronous) which
  *         first transfers the object to the <em>Preparing</em> state after the
- *         call returns (which occurs almost right way) while the internal
+ *         call returns (which occurs almost right away) while the internal
  *         player engine continues working on the rest of preparation work
  *         until the preparation work completes. When the preparation completes or when {@link #prepare()} call returns,
  *         the internal player engine then calls a user supplied callback method,
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 56423fd..828c673 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -4781,7 +4781,7 @@
 
         private void sendCompleteNotification(int status) {
             // In {@link #notifyWhenCommandLabelReached} case, a separate callback
-            // {#link #onCommandLabelReached} is already called in {@code process()}.
+            // {@link #onCommandLabelReached} is already called in {@code process()}.
             if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
                 return;
             }
diff --git a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java
index 6595baa..7919723 100644
--- a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java
+++ b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java
@@ -38,7 +38,7 @@
  * <p>To use, connect up the sourceListener callback, and then when executing
  * the graph, use the SurfaceTexture object passed to the callback to feed
  * frames into the filter graph. For example, pass the SurfaceTexture into
- * {#link
+ * {@link
  * android.hardware.Camera.setPreviewTexture(android.graphics.SurfaceTexture)}.
  * This filter is intended for applications that need for flexibility than the
  * CameraSource and MediaSource provide. Note that the application needs to
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index f9dccea0..aad890b 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -22,6 +22,7 @@
 
 import android.annotation.Nullable;
 import android.os.FileUtils;
+import android.os.SystemProperties;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -38,6 +39,10 @@
 final class MemoryStatUtil {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
 
+    /** True if device has per-app memcg */
+    private static final Boolean DEVICE_HAS_PER_APP_MEMCG =
+            SystemProperties.getBoolean("ro.config.per_app_memcg", false);
+
     /** Path to check if device has memcg */
     private static final String MEMCG_TEST_PATH = "/dev/memcg/apps/memory.stat";
     /** Path to memory stat file for logging app start memory state */
@@ -55,15 +60,12 @@
     private static final int PGMAJFAULT_INDEX = 11;
     private static final int RSS_IN_BYTES_INDEX = 23;
 
-    /** True if device has memcg */
-    private static volatile Boolean sDeviceHasMemCg;
-
     private MemoryStatUtil() {}
 
     /**
      * Reads memory stat for a process.
      *
-     * Reads from memcg if available on device, else fallback to procfs.
+     * Reads from per-app memcg if available on device, else fallback to procfs.
      * Returns null if no stats can be read.
      */
     @Nullable
@@ -156,15 +158,10 @@
     }
 
     /**
-     * Checks if memcg is available on device.
-     *
-     * Touches the filesystem to do the check.
+     * Returns whether per-app memcg is available on device.
      */
     static boolean hasMemcg() {
-        if (sDeviceHasMemCg == null) {
-            sDeviceHasMemCg = (new File(MEMCG_TEST_PATH)).exists();
-        }
-        return sDeviceHasMemCg;
+        return DEVICE_HAS_PER_APP_MEMCG;
     }
 
     static final class MemoryStat {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ae0f7ed..b724716 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2299,8 +2299,9 @@
         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
                 String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
+
             return mRankingHelper.getNotificationChannelGroups(
-                    pkg, Binder.getCallingUid(), false, false);
+                    pkg, Binder.getCallingUid(), false, false, true);
         }
 
         @Override
@@ -2376,7 +2377,9 @@
         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
                 String pkg, int uid, boolean includeDeleted) {
             checkCallerIsSystem();
-            return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
+
+            return mRankingHelper.getNotificationChannelGroups(
+                    pkg, uid, includeDeleted, true, false);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index af64683..605348b 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -36,7 +36,7 @@
     void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
             boolean fromTargetApp);
     ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
-            int uid, boolean includeDeleted, boolean includeNonGrouped);
+            int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty);
     void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
             boolean fromTargetApp, boolean hasDndAccess);
     void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 61b5415..da6e9c0 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -830,7 +830,7 @@
 
     @Override
     public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
-            int uid, boolean includeDeleted, boolean includeNonGrouped) {
+            int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
         Preconditions.checkNotNull(pkg);
         Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
         Record r = getRecord(pkg, uid);
@@ -861,6 +861,13 @@
         if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
             groups.put(null, nonGrouped);
         }
+        if (includeEmpty) {
+            for (NotificationChannelGroup group : r.groups.values()) {
+                if (!groups.containsKey(group.getId())) {
+                    groups.put(group.getId(), group);
+                }
+            }
+        }
         return new ParceledListSlice<>(new ArrayList<>(groups.values()));
     }
 
@@ -1244,7 +1251,7 @@
     /**
      * Dump only the ban information as structured JSON for the stats collector.
      *
-     * This is intentionally redundant with {#link dumpJson} because the old
+     * This is intentionally redundant with {@link dumpJson} because the old
      * scraper will expect this format.
      *
      * @param filter
@@ -1288,7 +1295,7 @@
     /**
      * Dump only the channel information as structured JSON for the stats collector.
      *
-     * This is intentionally redundant with {#link dumpJson} because the old
+     * This is intentionally redundant with {@link dumpJson} because the old
      * scraper will expect this format.
      *
      * @param filter
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 98c6ec4..a9e713e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -399,7 +399,7 @@
                 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
 
         List<NotificationChannelGroup> actualGroups =
-                mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList();
+                mHelper.getNotificationChannelGroups(PKG, UID, false, true, false).getList();
         boolean foundNcg = false;
         for (NotificationChannelGroup actual : actualGroups) {
             if (ncg.getId().equals(actual.getId())) {
@@ -469,7 +469,7 @@
                 mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
 
         List<NotificationChannelGroup> actualGroups =
-                mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList();
+                mHelper.getNotificationChannelGroups(PKG, UID, false, true, false).getList();
         boolean foundNcg = false;
         for (NotificationChannelGroup actual : actualGroups) {
             if (ncg.getId().equals(actual.getId())) {
@@ -784,6 +784,31 @@
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false);
     }
 
+    @Test
+    public void testGetChannelGroups_includeEmptyGroups() {
+        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
+        NotificationChannelGroup ncgEmpty = new NotificationChannelGroup("group2", "name2");
+        mHelper.createNotificationChannelGroup(PKG, UID, ncgEmpty, true);
+
+        NotificationChannel channel1 =
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+        channel1.setGroup(ncg.getId());
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+
+        List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
+                PKG, UID, false, false, true).getList();
+
+        assertEquals(2, actual.size());
+        for (NotificationChannelGroup group : actual) {
+            if (Objects.equals(group.getId(), ncg.getId())) {
+                assertEquals(1, group.getChannels().size());
+            }
+            if (Objects.equals(group.getId(), ncgEmpty.getId())) {
+                assertEquals(0, group.getChannels().size());
+            }
+        }
+    }
 
     @Test
     public void testUpdate() throws Exception {
@@ -1421,7 +1446,7 @@
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
         assertEquals(0,
-                mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList().size());
+                mHelper.getNotificationChannelGroups(PKG, UID, true, true, false).getList().size());
     }
 
     @Test
@@ -1510,7 +1535,7 @@
         mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
 
         List<NotificationChannelGroup> actual =
-                mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
+                mHelper.getNotificationChannelGroups(PKG, UID, true, true, false).getList();
         assertEquals(3, actual.size());
         for (NotificationChannelGroup group : actual) {
             if (group.getId() == null) {
@@ -1542,13 +1567,13 @@
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
         mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
-        mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
+        mHelper.getNotificationChannelGroups(PKG, UID, true, true, false).getList();
 
         channel1.setImportance(IMPORTANCE_LOW);
         mHelper.updateNotificationChannel(PKG, UID, channel1, true);
 
         List<NotificationChannelGroup> actual =
-                mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
+                mHelper.getNotificationChannelGroups(PKG, UID, true, true, false).getList();
 
         assertEquals(2, actual.size());
         for (NotificationChannelGroup group : actual) {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 4a7d703..55c7fc1 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -504,7 +504,7 @@
     /**
      * @hide
      * Universal name for app creating the configuration
-     *    see {#link {@link PackageManager#getNameForUid(int)}
+     *    see {@link PackageManager#getNameForUid(int)}
      */
     @SystemApi
     public String creatorName;
@@ -512,7 +512,7 @@
     /**
      * @hide
      * Universal name for app updating the configuration
-     *    see {#link {@link PackageManager#getNameForUid(int)}
+     *    see {@link PackageManager#getNameForUid(int)}
      */
     @SystemApi
     public String lastUpdateName;