Merge "docs: Replacing {#link with {@link" into pi-dev
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index a3b3a9f..79d1361 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -17,7 +17,6 @@
 package android.accounts;
 
 import android.Manifest;
-import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -32,8 +31,8 @@
 
 /**
  * Abstract base class for creating AccountAuthenticators.
- * In order to be an authenticator one must extend this class, provider implementations for the
- * abstract methods and write a service that returns the result of {@link #getIBinder()}
+ * In order to be an authenticator one must extend this class, provide implementations for the
+ * abstract methods, and write a service that returns the result of {@link #getIBinder()}
  * in the service's {@link android.app.Service#onBind(android.content.Intent)} when invoked
  * with an intent with action {@link AccountManager#ACTION_AUTHENTICATOR_INTENT}. This service
  * must specify the following intent filter and metadata tags in its AndroidManifest.xml file
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/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/provider/Settings.java b/core/java/android/provider/Settings.java
index 501d7f1..de621e3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11236,6 +11236,14 @@
         public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
 
         /**
+         * Enable faster emergency phone call feature.
+         * The value is a boolean (1 or 0).
+         * @hide
+         */
+        public static final String FASTER_EMERGENCY_PHONE_CALL_ENABLED =
+                "faster_emergency_phone_call_enabled";
+
+        /**
          * See RIL_PreferredNetworkType in ril.h
          * @hide
          */
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/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/res/res/drawable/emergency_icon.xml b/core/res/res/drawable/emergency_icon.xml
index b2ffa2b..c142be3 100644
--- a/core/res/res/drawable/emergency_icon.xml
+++ b/core/res/res/drawable/emergency_icon.xml
@@ -18,7 +18,7 @@
         android:height="24.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"
-        android:tint="?attr/colorControlNormal">
+        android:tint="?attr/colorError">
     <path
         android:fillColor="#FF000000"
         android:pathData="M6.8,17.3C5.3,15.9 4.5,14.0 4.5,12.0c0.0,-2.0 0.8,-3.8 2.1,-5.2l1.4,1.4c-1.0,1.0 -1.6,2.4 -1.6,3.8c0.0,1.5 0.6,2.9 1.6,3.9L6.8,17.3z"/>
diff --git a/core/res/res/drawable/ic_faster_emergency.xml b/core/res/res/drawable/ic_faster_emergency.xml
new file mode 100644
index 0000000..680dfce
--- /dev/null
+++ b/core/res/res/drawable/ic_faster_emergency.xml
@@ -0,0 +1,31 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?attr/colorError">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M19,3H5C3.9,3,3.01,3.9,3.01,5L3,19c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19L5,19V5h14V19z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M 10.5 17 L 13.5 17 L 13.5 13.5 L 17 13.5 L 17 10.5 L 13.5 10.5 L 13.5 7 L 10.5 7 L 10.5 10.5 L 7 10.5 L 7 13.5 L 10.5 13.5 Z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+
+</vector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 38582db..6b5a914 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4166,9 +4166,9 @@
         row is full. The rowCount attribute may be used similarly in the vertical case.
         The default is horizontal. -->
         <attr name="orientation" />
-        <!-- The maxmimum number of rows to create when automatically positioning children. -->
+        <!-- The maximum number of rows to create when automatically positioning children. -->
         <attr name="rowCount" format="integer" />
-        <!-- The maxmimum number of columns to create when automatically positioning children. -->
+        <!-- The maximum number of columns to create when automatically positioning children. -->
         <attr name="columnCount" format="integer" />
         <!-- When set to true, tells GridLayout to use default margins when none are specified
         in a view's layout parameters.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a10c197..db03eee 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2613,6 +2613,7 @@
          "silent" = silent mode
          "users" = list of users
          "restart" = restart device
+         "emergency" = Launch emergency dialer
          "lockdown" = Lock down device until the user authenticates
          "logout" =  Logout the current user
          -->
@@ -2623,6 +2624,7 @@
         <item>logout</item>
         <item>bugreport</item>
         <item>screenshot</item>
+        <item>emergency</item>
     </string-array>
 
     <!-- Number of milliseconds to hold a wake lock to ensure that drawing is fully
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 95af9a6..eaaa866 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2989,7 +2989,7 @@
   <!-- Global actions icons -->
   <java-symbol type="drawable" name="ic_restart" />
   <java-symbol type="drawable" name="ic_screenshot" />
-
+  <java-symbol type="drawable" name="ic_faster_emergency" />
   <java-symbol type="drawable" name="emergency_icon" />
 
   <java-symbol type="array" name="config_convert_to_emergency_number_map" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index c4a3b7a..418b895 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -237,6 +237,7 @@
                     Settings.Global.EUICC_SUPPORTED_COUNTRIES,
                     Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
                     Settings.Global.FANCY_IME_ANIMATIONS,
+                    Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                     Settings.Global.FORCED_APP_STANDBY_ENABLED,
                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
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/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 54800ae..2c67f32 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -467,7 +467,7 @@
      *                 .setSampleRate(32000)
      *                 .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
      *                 .build())
-     *         .setBufferSize(2*minBuffSize)
+     *         .setBufferSizeInBytes(2*minBuffSize)
      *         .build();
      * </pre>
      * <p>
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
index b715def..7f4e0d2 100644
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml
@@ -3,7 +3,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:layout_gravity="top|right"
     android:layout_marginBottom="0dp"
+    android:orientation="vertical"
     android:paddingTop="@dimen/global_actions_top_padding"
     android:clipToPadding="false"
     android:theme="@style/qs_theme"
@@ -17,7 +19,19 @@
         android:layout_gravity="top|right"
         android:gravity="center"
         android:orientation="vertical"
-        android:padding="12dp"
-        android:translationZ="9dp" />
+        android:padding="@dimen/global_actions_padding"
+        android:translationZ="@dimen/global_actions_translate" />
+
+    <!-- For separated button-->
+    <FrameLayout
+        android:id="@+id/separated_button"
+        android:layout_width="@dimen/global_actions_panel_width"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top|right"
+        android:layout_marginTop="6dp"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:padding="@dimen/global_actions_padding"
+        android:translationZ="@dimen/global_actions_translate" />
 
 </com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7d90e02..79e1fae 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -922,6 +922,10 @@
 
     <dimen name="global_actions_top_padding">120dp</dimen>
 
+    <dimen name="global_actions_padding">12dp</dimen>
+
+    <dimen name="global_actions_translate">9dp</dimen>
+
     <!-- The maximum offset in either direction that elements are moved horizontally to prevent
          burn-in on AOD. -->
     <dimen name="burn_in_prevention_offset_x">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 9435589..f4f2ebc 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -38,6 +38,7 @@
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.systemui.util.EmergencyDialerConstants;
 
 /**
  * This class implements a smart emergency button that updates itself based
@@ -47,11 +48,13 @@
  */
 public class EmergencyButton extends Button {
     private static final Intent INTENT_EMERGENCY_DIAL = new Intent()
-            .setAction("com.android.phone.EmergencyDialer.DIAL")
+            .setAction(EmergencyDialerConstants.ACTION_DIAL)
             .setPackage("com.android.phone")
             .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP)
+            .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+                    EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
 
     private static final String LOG_TAG = "EmergencyButton";
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 98dc321..198a4e6 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -27,32 +27,33 @@
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
 import android.widget.LinearLayout;
+
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.leak.RotationUtils;
 
-import java.util.ArrayList;
-
 import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
 import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
 import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
 
-public class HardwareUiLayout extends FrameLayout implements Tunable {
+public class HardwareUiLayout extends LinearLayout implements Tunable {
 
     private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
     private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
     private final int[] mTmp2 = new int[2];
-    private View mChild;
+    private View mList;
+    private View mSeparatedView;
     private int mOldHeight;
     private boolean mAnimating;
     private AnimatorSet mAnimation;
     private View mDivision;
     private boolean mHasOutsideTouch;
-    private HardwareBgDrawable mBackground;
+    private HardwareBgDrawable mListBackground;
+    private HardwareBgDrawable mSeparatedViewBackground;
     private Animator mAnimator;
     private boolean mCollapse;
+    private boolean mHasSeparatedButton;
     private int mEndPoint;
     private boolean mEdgeBleed;
     private boolean mRoundedDivider;
@@ -91,16 +92,19 @@
         mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(),
                 ROUNDED_DIVIDER, 0) != 0;
         updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
-        mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
-        if (mChild != null) {
-            mChild.setBackground(mBackground);
+        mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
+        mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed,
+                getContext());
+        if (mList != null) {
+            mList.setBackground(mListBackground);
+            mSeparatedView.setBackground(mSeparatedViewBackground);
             requestLayout();
         }
     }
 
     private void updateEdgeMargin(int edge) {
-        if (mChild != null) {
-            MarginLayoutParams params = (MarginLayoutParams) mChild.getLayoutParams();
+        if (mList != null) {
+            MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams();
             if (mRotation == ROTATION_LANDSCAPE) {
                 params.topMargin = edge;
             } else if (mRotation == ROTATION_SEASCAPE) {
@@ -108,7 +112,19 @@
             } else {
                 params.rightMargin = edge;
             }
-            mChild.setLayoutParams(params);
+            mList.setLayoutParams(params);
+        }
+
+        if (mSeparatedView != null) {
+            MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
+            if (mRotation == ROTATION_LANDSCAPE) {
+                params.topMargin = edge;
+            } else if (mRotation == ROTATION_SEASCAPE) {
+                params.bottomMargin = edge;
+            } else {
+                params.rightMargin = edge;
+            }
+            mSeparatedView.setLayoutParams(params);
         }
     }
 
@@ -119,13 +135,15 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        if (mChild == null) {
+        if (mList == null) {
             if (getChildCount() != 0) {
-                mChild = getChildAt(0);
-                mChild.setBackground(mBackground);
+                mList = getChildAt(0);
+                mList.setBackground(mListBackground);
+                mSeparatedView = getChildAt(1);
+                mSeparatedView.setBackground(mSeparatedViewBackground);
                 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
-                mOldHeight = mChild.getMeasuredHeight();
-                mChild.addOnLayoutChangeListener(
+                mOldHeight = mList.getMeasuredHeight();
+                mList.addOnLayoutChangeListener(
                         (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
                                 updatePosition());
                 updateRotation();
@@ -133,7 +151,7 @@
                 return;
             }
         }
-        int newHeight = mChild.getMeasuredHeight();
+        int newHeight = mList.getMeasuredHeight();
         if (newHeight != mOldHeight) {
             animateChild(mOldHeight, newHeight);
         }
@@ -170,37 +188,60 @@
         } else {
             rotateLeft();
         }
+        if (mHasSeparatedButton) {
+            if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
+                // Separated view has top margin, so seascape separated view need special rotation,
+                // not a full left or right rotation.
+                swapLeftAndTop(mSeparatedView);
+            } else if (from == ROTATION_LANDSCAPE) {
+                rotateRight(mSeparatedView);
+            } else {
+                rotateLeft(mSeparatedView);
+            }
+        }
         if (to != ROTATION_NONE) {
-            if (mChild instanceof LinearLayout) {
+            if (mList instanceof LinearLayout) {
                 mRotatedBackground = true;
-                mBackground.setRotatedBackground(true);
-                LinearLayout linearLayout = (LinearLayout) mChild;
+                mListBackground.setRotatedBackground(true);
+                mSeparatedViewBackground.setRotatedBackground(true);
+                LinearLayout linearLayout = (LinearLayout) mList;
                 if (mSwapOrientation) {
                     linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+                    setOrientation(LinearLayout.HORIZONTAL);
                 }
-                swapDimens(this.mChild);
+                swapDimens(mList);
+                swapDimens(mSeparatedView);
             }
         } else {
-            if (mChild instanceof LinearLayout) {
+            if (mList instanceof LinearLayout) {
                 mRotatedBackground = false;
-                mBackground.setRotatedBackground(false);
-                LinearLayout linearLayout = (LinearLayout) mChild;
+                mListBackground.setRotatedBackground(false);
+                mSeparatedViewBackground.setRotatedBackground(false);
+                LinearLayout linearLayout = (LinearLayout) mList;
                 if (mSwapOrientation) {
                     linearLayout.setOrientation(LinearLayout.VERTICAL);
+                    setOrientation(LinearLayout.VERTICAL);
                 }
-                swapDimens(mChild);
+                swapDimens(mList);
+                swapDimens(mSeparatedView);
             }
         }
     }
 
     private void rotateRight() {
         rotateRight(this);
-        rotateRight(mChild);
+        rotateRight(mList);
         swapDimens(this);
 
-        LayoutParams p = (LayoutParams) mChild.getLayoutParams();
+        LayoutParams p = (LayoutParams) mList.getLayoutParams();
         p.gravity = rotateGravityRight(p.gravity);
-        mChild.setLayoutParams(p);
+        mList.setLayoutParams(p);
+
+        LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
+        separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
+        mSeparatedView.setLayoutParams(separatedViewLayoutParams);
+
+        setGravity(p.gravity);
     }
 
     private void swapDimens(View v) {
@@ -247,12 +288,18 @@
 
     private void rotateLeft() {
         rotateLeft(this);
-        rotateLeft(mChild);
+        rotateLeft(mList);
         swapDimens(this);
 
-        LayoutParams p = (LayoutParams) mChild.getLayoutParams();
+        LayoutParams p = (LayoutParams) mList.getLayoutParams();
         p.gravity = rotateGravityLeft(p.gravity);
-        mChild.setLayoutParams(p);
+        mList.setLayoutParams(p);
+
+        LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
+        separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
+        mSeparatedView.setLayoutParams(separatedViewLayoutParams);
+
+        setGravity(p.gravity);
     }
 
     private int rotateGravityLeft(int gravity) {
@@ -310,6 +357,15 @@
         v.setLayoutParams(params);
     }
 
+    private void swapLeftAndTop(View v) {
+        v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
+                v.getPaddingRight());
+        MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
+        params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
+                params.rightMargin);
+        v.setLayoutParams(params);
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -329,14 +385,14 @@
                 mAnimating = false;
             }
         });
-        int fromTop = mChild.getTop();
-        int fromBottom = mChild.getBottom();
+        int fromTop = mList.getTop();
+        int fromBottom = mList.getBottom();
         int toTop = fromTop - ((newHeight - oldHeight) / 2);
         int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
-        ObjectAnimator top = ObjectAnimator.ofInt(mChild, "top", fromTop, toTop);
-        top.addUpdateListener(animation -> mBackground.invalidateSelf());
+        ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
+        top.addUpdateListener(animation -> mListBackground.invalidateSelf());
         mAnimation.playTogether(top,
-                ObjectAnimator.ofInt(mChild, "bottom", fromBottom, toBottom));
+                ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
     }
 
     public void setDivisionView(View v) {
@@ -350,26 +406,30 @@
     }
 
     private void updatePosition() {
-        if (mChild == null) return;
+        if (mList == null) return;
+        // If got separated button, setRotatedBackground to false,
+        // all items won't get white background.
+        mListBackground.setRotatedBackground(mHasSeparatedButton);
+        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton);
         if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
             int index = mRotatedBackground ? 0 : 1;
             mDivision.getLocationOnScreen(mTmp2);
             float trans = mRotatedBackground ? mDivision.getTranslationX()
                     : mDivision.getTranslationY();
             int viewTop = (int) (mTmp2[index] + trans);
-            mChild.getLocationOnScreen(mTmp2);
+            mList.getLocationOnScreen(mTmp2);
             viewTop -= mTmp2[index];
             setCutPoint(viewTop);
         } else {
-            setCutPoint(mChild.getMeasuredHeight());
+            setCutPoint(mList.getMeasuredHeight());
         }
     }
 
     private void setCutPoint(int point) {
-        int curPoint = mBackground.getCutPoint();
+        int curPoint = mListBackground.getCutPoint();
         if (curPoint == point) return;
         if (getAlpha() == 0 || curPoint == 0) {
-            mBackground.setCutPoint(point);
+            mListBackground.setCutPoint(point);
             return;
         }
         if (mAnimator != null) {
@@ -379,7 +439,7 @@
             mAnimator.cancel();
         }
         mEndPoint = point;
-        mAnimator = ObjectAnimator.ofInt(mBackground, "cutPoint", curPoint, point);
+        mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
         if (mCollapse) {
             mAnimator.setStartDelay(300);
             mCollapse = false;
@@ -404,6 +464,10 @@
         mCollapse = true;
     }
 
+    public void setHasSeparatedButton(boolean hasSeparatedButton) {
+        mHasSeparatedButton = hasSeparatedButton;
+    }
+
     public static HardwareUiLayout get(View v) {
         if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
         if (v.getParent() instanceof View) {
@@ -413,14 +477,14 @@
     }
 
     private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
-        if (mHasOutsideTouch || (mChild == null)) {
+        if (mHasOutsideTouch || (mList == null)) {
             inoutInfo.setTouchableInsets(
                     ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
             return;
         }
         inoutInfo.setTouchableInsets(
                 ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
-        inoutInfo.contentInsets.set(mChild.getLeft(), mChild.getTop(),
-                0, getBottom() - mChild.getBottom());
+        inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
+                0, getBottom() - mList.getBottom());
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index d232108..00758e8 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -28,12 +28,10 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ServiceConnection;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Point;
@@ -42,9 +40,7 @@
 import android.net.ConnectivityManager;
 import android.os.Build;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Message;
-import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
@@ -68,9 +64,9 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 import android.widget.LinearLayout;
@@ -93,6 +89,7 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.util.EmergencyDialerConstants;
 import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
 
 import java.util.ArrayList;
@@ -127,6 +124,7 @@
     private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
     private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
     private static final String GLOBAL_ACTION_KEY_LOGOUT = "logout";
+    private static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
     private static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
 
     private final Context mContext;
@@ -153,6 +151,7 @@
     private boolean mHasVibrator;
     private boolean mHasLogoutButton;
     private boolean mHasLockdownButton;
+    private boolean mSeparatedEmergencyButtonEnabled;
     private final boolean mShowSilentToggle;
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
     private final ScreenshotHelper mScreenshotHelper;
@@ -319,6 +318,8 @@
         ArraySet<String> addedKeys = new ArraySet<String>();
         mHasLogoutButton = false;
         mHasLockdownButton = false;
+        mSeparatedEmergencyButtonEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0;
         for (int i = 0; i < defaultActions.length; i++) {
             String actionKey = defaultActions[i];
             if (addedKeys.contains(actionKey)) {
@@ -365,6 +366,11 @@
                     mItems.add(new LogoutAction());
                     mHasLogoutButton = true;
                 }
+            } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
+                if (mSeparatedEmergencyButtonEnabled
+                        && !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+                    mItems.add(new EmergencyDialerAction());
+                }
             } else {
                 Log.e(TAG, "Invalid global action key " + actionKey);
             }
@@ -386,7 +392,8 @@
             }
             return false;
         };
-        ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener);
+        ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener,
+                mSeparatedEmergencyButtonEnabled);
         dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
         dialog.setKeyguardShowing(mKeyguardShowing);
 
@@ -441,6 +448,32 @@
         }
     }
 
+    private class EmergencyDialerAction extends SinglePressAction {
+        private EmergencyDialerAction() {
+            super(R.drawable.ic_faster_emergency,
+                    R.string.global_action_emergency);
+        }
+
+        @Override
+        public void onPress() {
+            Intent intent = new Intent(EmergencyDialerConstants.ACTION_DIAL);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+                    EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+    }
+
     private final class RestartAction extends SinglePressAction implements LongPressAction {
         private RestartAction() {
             super(R.drawable.ic_restart, R.string.global_action_restart);
@@ -626,6 +659,12 @@
     }
 
     private Action getEmergencyAction() {
+        Drawable emergencyIcon = mContext.getDrawable(R.drawable.emergency_icon);
+        if(!mSeparatedEmergencyButtonEnabled) {
+            // use un-colored legacy treatment
+            emergencyIcon.setTintList(null);
+        }
+
         return new SinglePressAction(R.drawable.emergency_icon,
                 R.string.global_action_emergency) {
             @Override
@@ -1354,15 +1393,17 @@
         private final Context mContext;
         private final MyAdapter mAdapter;
         private final LinearLayout mListView;
+        private final FrameLayout mSeparatedView;
         private final HardwareUiLayout mHardwareLayout;
         private final OnClickListener mClickListener;
         private final OnItemLongClickListener mLongClickListener;
         private final GradientDrawable mGradientDrawable;
         private final ColorExtractor mColorExtractor;
         private boolean mKeyguardShowing;
+        private boolean mShouldDisplaySeparatedButton;
 
         public ActionsDialog(Context context, OnClickListener clickListener, MyAdapter adapter,
-                OnItemLongClickListener longClickListener) {
+                OnItemLongClickListener longClickListener, boolean shouldDisplaySeparatedButton) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
             mContext = context;
             mAdapter = adapter;
@@ -1370,6 +1411,7 @@
             mLongClickListener = longClickListener;
             mGradientDrawable = new GradientDrawable(mContext);
             mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+            mShouldDisplaySeparatedButton = shouldDisplaySeparatedButton;
 
             // Window initialization
             Window window = getWindow();
@@ -1393,8 +1435,13 @@
 
             setContentView(com.android.systemui.R.layout.global_actions_wrapped);
             mListView = findViewById(android.R.id.list);
+            mSeparatedView = findViewById(com.android.systemui.R.id.separated_button);
+            if (!mShouldDisplaySeparatedButton) {
+                mSeparatedView.setVisibility(View.GONE);
+            }
             mHardwareLayout = HardwareUiLayout.get(mListView);
             mHardwareLayout.setOutsideTouchListener(view -> dismiss());
+            mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton);
             setTitle(R.string.global_actions);
             mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
@@ -1409,13 +1456,16 @@
 
         private void updateList() {
             mListView.removeAllViews();
+            mSeparatedView.removeAllViews();
             for (int i = 0; i < mAdapter.getCount(); i++) {
-                View v = mAdapter.getView(i, null, mListView);
+                ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1
+                        ? mSeparatedView : mListView;
+                View v = mAdapter.getView(i, null, parentView);
                 final int pos = i;
                 v.setOnClickListener(view -> mClickListener.onClick(this, pos));
                 v.setOnLongClickListener(view ->
                         mLongClickListener.onItemLongClick(null, v, pos, 0));
-                mListView.addView(v);
+                parentView.addView(v);
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
new file mode 100644
index 0000000..d101ccb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+/**
+ * Constants defined and used in emergency dialer.
+ * Please keep these constants being consistent with those in com.android.phone.EmergencyDialer.
+ */
+public class EmergencyDialerConstants {
+    // Intent action for emergency dialer activity.
+    public static final String ACTION_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
+    /**
+     * Extra included in {@link #ACTION_DIAL} to indicate the entry type that user starts
+     * the emergency dialer.
+     */
+    public static final String EXTRA_ENTRY_TYPE =
+            "com.android.phone.EmergencyDialer.extra.ENTRY_TYPE";
+
+    // Indicating the entrance to emergency dialer
+    public static final int ENTRY_TYPE_UNKNOWN = 0;
+    public static final int ENTRY_TYPE_LOCKSCREEN_BUTTON = 1;
+    public static final int ENTRY_TYPE_POWER_MENU = 2;
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0833e34..b990175 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -6429,6 +6429,59 @@
     // OS: Q (will also ship in PQ1A)
     FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH = 1553;
 
+    // OPEN: Emergency dialer opened
+    // CLOSE: Emergency dialer closed
+    //  SUBTYPE: The entry type that user opened emergency dialer
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    EMERGENCY_DIALER = 1558;
+
+    // FIELD: The screen is currently locked
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    FIELD_EMERGENCY_DIALER_IS_SCREEN_LOCKED = 1559;
+
+    // FIELD: Bit flag indicating the actions performed by user
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    FIELD_EMERGENCY_DIALER_USER_ACTIONS = 1560;
+
+    // FIELD: The duration user stayed at emergency dialer
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    FIELD_EMERGENCY_DIALER_DURATION_MS = 1561;
+
+    // ACTION: Making call via emergency dialer
+    //  SUBTYPE: The UI that user made phone call
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    EMERGENCY_DIALER_MAKE_CALL = 1562;
+
+    // FIELD: The phone number type of a call user made
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    FIELD_EMERGENCY_DIALER_PHONE_NUMBER_TYPE = 1563;
+
+    // FIELD: There is a shortcut for the phone number
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    FIELD_EMERGENCY_DIALER_PHONE_NUMBER_HAS_SHORTCUT = 1564;
+
+    // FIELD: The phone is in pocket while using emergency dialer
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    FIELD_EMERGENCY_DIALER_IN_POCKET = 1565;
+
+    // ACTION: The second tap on emergency shortcut to make a phone call
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    EMERGENCY_DIALER_SHORTCUT_CONFIRM_TAP = 1566;
+
+    // FIELD: The time in milliseconds of second tap on shortcut since first tap
+    // CATEGORY: EMERGENCY_DIALER
+    // OS: Q
+    FIELD_EMERGENCY_DIALER_SHORTCUT_TAPS_INTERVAL = 1567;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
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 5b28442..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()));
     }
 
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/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
index 383d10b..bb066ad 100644
--- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
@@ -195,6 +195,8 @@
         public static final int BLOCK_CHECK_FINISHED_TIMING = 9;
         public static final int FILTERING_COMPLETED_TIMING = 10;
         public static final int FILTERING_TIMED_OUT_TIMING = 11;
+        /** {@hide} */
+        public static final int START_CONNECTION_TO_REQUEST_DISCONNECT_TIMING = 12;
 
         public static final int INVALID = 999999;
 
@@ -256,6 +258,27 @@
     public static final int SIP_PHONE = 0x8;
     public static final int THIRD_PARTY_PHONE = 0x10;
 
+    /**
+     * Indicating the call source is not specified.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_UNSPECIFIED = 0;
+
+    /**
+     * Indicating the call is initiated via emergency dialer's dialpad.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1;
+
+    /**
+     * Indicating the call is initiated via emergency dialer's shortcut button.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2;
+
     public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5;
     public static final long MILLIS_IN_1_SECOND = 1000;
 
@@ -319,6 +342,9 @@
     // A list of video events that have occurred.
     private List<VideoEvent> videoEvents;
 
+    // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants.
+    private int callSource = CALL_SOURCE_UNSPECIFIED;
+
     public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
             boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
             int callTerminationCode, boolean isEmergencyCall, String connectionService,
@@ -356,6 +382,7 @@
         isVideoCall = readByteAsBoolean(in);
         videoEvents = new LinkedList<>();
         in.readTypedList(videoEvents, VideoEvent.CREATOR);
+        callSource = in.readInt();
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -373,6 +400,7 @@
         out.writeTypedList(eventTimings);
         writeBooleanAsByte(out, isVideoCall);
         out.writeTypedList(videoEvents);
+        out.writeInt(callSource);
     }
 
     /** {@hide} */
@@ -385,6 +413,11 @@
         this.videoEvents = videoEvents;
     }
 
+    /** {@hide} */
+    public void setCallSource(int callSource) {
+        this.callSource = callSource;
+    }
+
     public long getStartTimeMillis() {
         return startTimeMillis;
     }
@@ -443,6 +476,11 @@
         return videoEvents;
     }
 
+    /** {@hide} */
+    public int getCallSource() {
+        return callSource;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 29898ff..573f7db 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -619,6 +619,18 @@
             "android.telecom.extra.USE_ASSISTED_DIALING";
 
     /**
+     * Optional extra for {@link #placeCall(Uri, Bundle)} containing an integer that specifies
+     * the source where user initiated this call. This data is used in metrics.
+     * Valid source are:
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_UNSPECIFIED},
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_DIALPAD},
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_SHORTCUT}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
+
+    /**
      * The following 4 constants define how properties such as phone numbers and names are
      * displayed to the user.
      */