Merge "Calculate and account for memory power use"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 270f503..7ef43bb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6233,6 +6233,20 @@
         public static final int VR_DISPLAY_MODE_OFF = 1;
 
         /**
+         * Whether CarrierAppUtils#disableCarrierAppsUntilPrivileged has been executed at least
+         * once.
+         *
+         * <p>This is used to ensure that we only take one pass which will disable apps that are not
+         * privileged (if any). From then on, we only want to enable apps (when a matching SIM is
+         * inserted), to avoid disabling an app that the user might actively be using.
+         *
+         * <p>Will be set to 1 once executed.
+         *
+         * @hide
+         */
+        public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
+
+        /**
          * Whether parent user can access remote contact in managed profile.
          *
          * @hide
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8f480d6..88f2135 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -22965,7 +22965,7 @@
         /**
          * Last global system UI visibility reported by the window manager.
          */
-        int mGlobalSystemUiVisibility;
+        int mGlobalSystemUiVisibility = -1;
 
         /**
          * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
diff --git a/core/java/android/webkit/WebMessagePort.java b/core/java/android/webkit/WebMessagePort.java
index 5f33c7b..54dd502 100644
--- a/core/java/android/webkit/WebMessagePort.java
+++ b/core/java/android/webkit/WebMessagePort.java
@@ -20,32 +20,32 @@
 import android.os.Handler;
 
 /**
- * The Java representation of the
+ * <p>The Java representation of the
  * <a href="https://html.spec.whatwg.org/multipage/comms.html#messageport">
- * HTML5 message ports.</a>
+ * HTML5 message ports.</a> </p>
  *
- * A Message port represents one endpoint of a Message Channel. In Android
+ * <p>A Message port represents one endpoint of a Message Channel. In Android
  * webview, there is no separate Message Channel object. When a message channel
  * is created, both ports are tangled to each other and started, and then
  * returned in a MessagePort array, see {@link WebView#createWebMessageChannel}
- * for creating a message channel.
+ * for creating a message channel. </p>
  *
- * When a message port is first created or received via transfer, it does not
+ * <p>When a message port is first created or received via transfer, it does not
  * have a WebMessageCallback to receive web messages. The messages are queued until
- * a WebMessageCallback is set.
+ * a WebMessageCallback is set. </p>
  *
- * A message port should be closed when it is not used by the embedder application
+ * <p>A message port should be closed when it is not used by the embedder application
  * anymore. A closed port cannot be transferred or cannot be reopened to send
- * messages. Close can be called multiple times.
+ * messages. Close can be called multiple times. </p>
  *
- * When a port is transferred to JS, it cannot be used to send or receive messages
+ * <p>When a port is transferred to JS, it cannot be used to send or receive messages
  * at the Java side anymore. Different from HTML5 Spec, a port cannot be transferred
  * if one of these has ever happened: i. a message callback was set, ii. a message was
  * posted on it. A transferred port cannot be closed by the application, since
- * the ownership is also transferred.
+ * the ownership is also transferred. </p>
  *
- * It is possible to transfer both ports of a channel to JS, for example for
- * communication between subframes.
+ * <p>It is possible to transfer both ports of a channel to JS, for example for
+ * communication between subframes.</p>
  */
 public abstract class WebMessagePort {
 
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 886265a..429131b 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -42,6 +42,8 @@
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Loads global system configuration info.
@@ -122,6 +124,11 @@
     // These are the permitted backup transport service components
     final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>();
 
+    // These are the packages of carrier-associated apps which should be disabled until used until
+    // a SIM is inserted which grants carrier privileges to that carrier app.
+    final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
+            new ArrayMap<>();
+
     public static SystemConfig getInstance() {
         synchronized (SystemConfig.class) {
             if (sInstance == null) {
@@ -183,6 +190,10 @@
         return mBackupTransportWhitelist;
     }
 
+    public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
+        return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
+    }
+
     SystemConfig() {
         // Read configuration from system
         readPermissions(Environment.buildPath(
@@ -476,6 +487,26 @@
                         }
                     }
                     XmlUtils.skipCurrentTag(parser);
+                } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
+                        && allowAppConfigs) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
+                    if (pkgname == null || carrierPkgname == null) {
+                        Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app"
+                                + " without package or carrierAppPackage in " + permFile + " at "
+                                + parser.getPositionDescription());
+                    } else {
+                        List<String> associatedPkgs =
+                                mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
+                                        carrierPkgname);
+                        if (associatedPkgs == null) {
+                            associatedPkgs = new ArrayList<>();
+                            mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
+                                    carrierPkgname, associatedPkgs);
+                        }
+                        associatedPkgs.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
                 } else {
                     XmlUtils.skipCurrentTag(parser);
                     continue;
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 6dbcd3f..9a242fb 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -268,7 +268,7 @@
 
 // Geometry
 void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPaint& paint) {
-    if (floatCount < 2) return;
+    if (CC_UNLIKELY(floatCount < 2 || PaintUtils::paintWillNotDraw(paint))) return;
     floatCount &= ~0x1; // round down to nearest two
 
     addOp(alloc().create_trivial<PointsOp>(
@@ -279,7 +279,7 @@
 }
 
 void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPaint& paint) {
-    if (floatCount < 4) return;
+    if (CC_UNLIKELY(floatCount < 4 || PaintUtils::paintWillNotDraw(paint))) return;
     floatCount &= ~0x3; // round down to nearest four
 
     addOp(alloc().create_trivial<LinesOp>(
@@ -290,6 +290,8 @@
 }
 
 void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
+    if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return;
+
     addOp(alloc().create_trivial<RectOp>(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
@@ -331,6 +333,8 @@
 }
 
 void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
+    if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return;
+
     if (paint.getStyle() == SkPaint::kFill_Style
             && (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) {
         int count = 0;
@@ -355,8 +359,11 @@
         }
     }
 }
+
 void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, const SkPaint& paint) {
+    if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return;
+
     if (CC_LIKELY(MathUtils::isPositive(rx) || MathUtils::isPositive(ry))) {
         addOp(alloc().create_trivial<RoundRectOp>(
                 Rect(left, top, right, bottom),
@@ -391,7 +398,8 @@
 
 void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
     // TODO: move to Canvas.h
-    if (radius <= 0) return;
+    if (CC_UNLIKELY(radius <= 0 || PaintUtils::paintWillNotDraw(paint))) return;
+
     drawOval(x - radius, y - radius, x + radius, y + radius, paint);
 }
 
@@ -411,6 +419,8 @@
 }
 
 void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+    if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return;
+
     addOp(alloc().create_trivial<OvalOp>(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
@@ -420,6 +430,8 @@
 
 void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+    if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return;
+
     if (fabs(sweepAngle) >= 360.0f) {
         drawOval(left, top, right, bottom, paint);
     } else {
@@ -433,6 +445,8 @@
 }
 
 void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+    if (CC_UNLIKELY(PaintUtils::paintWillNotDraw(paint))) return;
+
     addOp(alloc().create_trivial<PathOp>(
             Rect(path.getBounds()),
             *(mState.currentSnapshot()->transform),
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index e5fc556..392929f 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -1459,7 +1459,8 @@
 
 static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
     SkPaint paint;
-    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
+    // order put in blue channel, transparent so overlapped content doesn't get rejected
+    paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
     canvas->drawRect(0, 0, 100, 100, paint);
 }
 static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index d75ceb2..efc6b4c 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -81,6 +81,27 @@
     ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
 }
 
+TEST(RecordingCanvas, emptyPaintRejection) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        SkPaint emptyPaint;
+        emptyPaint.setColor(Color::Transparent);
+
+        float points[] = {0, 0, 200, 200};
+        canvas.drawPoints(points, 4, emptyPaint);
+        canvas.drawLines(points, 4, emptyPaint);
+        canvas.drawRect(0, 0, 200, 200, emptyPaint);
+        canvas.drawRegion(SkRegion(SkIRect::MakeWH(200, 200)), emptyPaint);
+        canvas.drawRoundRect(0, 0, 200, 200, 10, 10, emptyPaint);
+        canvas.drawCircle(100, 100, 100, emptyPaint);
+        canvas.drawOval(0, 0, 200, 200, emptyPaint);
+        canvas.drawArc(0, 0, 200, 200, 0, 360, true, emptyPaint);
+        SkPath path;
+        path.addRect(0, 0, 200, 200);
+        canvas.drawPath(path, emptyPaint);
+    });
+    EXPECT_EQ(0u, dl->getOps().size()) << "Op should be rejected";
+}
+
 TEST(RecordingCanvas, drawArc) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 716e297..325a937 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1966,10 +1966,6 @@
         PackageManagerService m = new PackageManagerService(context, installer,
                 factoryTest, onlyCore);
         m.enableSystemUserPackages();
-        // Disable any carrier apps. We do this very early in boot to prevent the apps from being
-        // disabled after already being started.
-        CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
-                UserHandle.USER_SYSTEM);
         ServiceManager.addService("package", m);
         return m;
     }
@@ -17941,6 +17937,11 @@
     public void systemReady() {
         mSystemReady = true;
 
+        // Disable any carrier apps. We do this very early in boot to prevent the apps from being
+        // disabled after already being started.
+        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
+                mContext.getContentResolver(), UserHandle.USER_SYSTEM);
+
         // Read the compatibilty setting when the system is ready.
         boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                 mContext.getContentResolver(),
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1d19637..df9242d 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -49,7 +49,6 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.SomeArgs;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.FgThread;
 
@@ -321,7 +320,6 @@
         private boolean mConnected;
         private boolean mHostConnected;
         private boolean mSourcePower;
-        private boolean mSinkPower;
         private boolean mConfigured;
         private boolean mUsbDataUnlocked;
         private String mCurrentFunctions;
@@ -403,19 +401,7 @@
         public void updateHostState(UsbPort port, UsbPortStatus status) {
             boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
             boolean sourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE;
-            boolean sinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK;
-
-            if (DEBUG) {
-                Slog.i(TAG, "updateHostState " + port + ": dataRole=" + status.getCurrentDataRole() +
-                        ", powerRole=" + status.getCurrentPowerRole());
-            }
-
-            SomeArgs args = SomeArgs.obtain();
-            args.argi1 = hostConnected ? 1 :0;
-            args.argi2 = sourcePower ? 1 :0;
-            args.argi3 = sinkPower ? 1 :0;
-
-            obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget();
+            obtainMessage(MSG_UPDATE_HOST_STATE, hostConnected ? 1 :0, sourcePower ? 1 :0).sendToTarget();
         }
 
         private boolean waitForState(String state) {
@@ -732,11 +718,8 @@
                     }
                     break;
                 case MSG_UPDATE_HOST_STATE:
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    mHostConnected = (args.argi1 == 1);
-                    mSourcePower = (args.argi2 == 1);
-                    mSinkPower = (args.argi3 == 1);
-                    args.recycle();
+                    mHostConnected = (msg.arg1 == 1);
+                    mSourcePower = (msg.arg2 == 1);
                     updateUsbNotification();
                     if (mBootCompleted) {
                         updateUsbStateBroadcastIfNeeded();
@@ -826,8 +809,6 @@
                 }
             } else if (mSourcePower) {
                 id = com.android.internal.R.string.usb_supplying_notification_title;
-            } else if (mSinkPower) {
-                id = com.android.internal.R.string.usb_charging_notification_title;
             }
             if (id != mUsbNotificationId) {
                 // clear notification if title needs changing
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index ee055f4..4da5ff2 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -514,67 +514,87 @@
      * @return A human readable string representation.
      */
     public static String capabilitiesToString(int capabilities) {
+        return capabilitiesToStringInternal(capabilities, true /* isLong */);
+    }
+
+    /**
+     * Renders a set of capability bits ({@code CAPABILITY_*}) as a *short* human readable
+     * string.
+     *
+     * @param capabilities A capability bit field.
+     * @return A human readable string representation.
+     * @hide
+     */
+    public static String capabilitiesToStringShort(int capabilities) {
+        return capabilitiesToStringInternal(capabilities, false /* isLong */);
+    }
+
+    private static String capabilitiesToStringInternal(int capabilities, boolean isLong) {
         StringBuilder builder = new StringBuilder();
-        builder.append("[Capabilities:");
+        builder.append("[");
+        if (isLong) {
+            builder.append("Capabilities:");
+        }
+
         if (can(capabilities, CAPABILITY_HOLD)) {
-            builder.append(" CAPABILITY_HOLD");
+            builder.append(isLong ? " CAPABILITY_HOLD" : " hld");
         }
         if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
-            builder.append(" CAPABILITY_SUPPORT_HOLD");
+            builder.append(isLong ? " CAPABILITY_SUPPORT_HOLD" : " sup_hld");
         }
         if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
-            builder.append(" CAPABILITY_MERGE_CONFERENCE");
+            builder.append(isLong ? " CAPABILITY_MERGE_CONFERENCE" : " mrg_cnf");
         }
         if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
-            builder.append(" CAPABILITY_SWAP_CONFERENCE");
+            builder.append(isLong ? " CAPABILITY_SWAP_CONFERENCE" : " swp_cnf");
         }
         if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
-            builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
+            builder.append(isLong ? " CAPABILITY_RESPOND_VIA_TEXT" : " txt");
         }
         if (can(capabilities, CAPABILITY_MUTE)) {
-            builder.append(" CAPABILITY_MUTE");
+            builder.append(isLong ? " CAPABILITY_MUTE" : " mut");
         }
         if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
-            builder.append(" CAPABILITY_MANAGE_CONFERENCE");
+            builder.append(isLong ? " CAPABILITY_MANAGE_CONFERENCE" : " mng_cnf");
         }
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
+            builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_RX" : " VTlrx");
         }
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
+            builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_TX" : " VTltx");
         }
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
+            builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL" : " VTlbi");
         }
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
+            builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_RX" : " VTrrx");
         }
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
+            builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_TX" : " VTrtx");
         }
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
+            builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL" : " VTrbi");
         }
         if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
-            builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
+            builder.append(isLong ? " CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO" : " !v2a");
         }
         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
-            builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
+            builder.append(isLong ? " CAPABILITY_SPEED_UP_MT_AUDIO" : " spd_aud");
         }
         if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
-            builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
+            builder.append(isLong ? " CAPABILITY_CAN_UPGRADE_TO_VIDEO" : " a2v");
         }
         if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
-            builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
+            builder.append(isLong ? " CAPABILITY_CAN_PAUSE_VIDEO" : " paus_VT");
         }
         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
-            builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
+            builder.append(isLong ? " CAPABILITY_SINGLE_PARTY_CONFERENCE" : " 1p_cnf");
         }
         if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
-            builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
+            builder.append(isLong ? " CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION" : " rsp_by_con");
         }
         if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
-            builder.append(" CAPABILITY_CAN_PULL_CALL");
+            builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull");
         }
 
         builder.append("]");
@@ -588,31 +608,49 @@
      * @return A human readable string representation.
      */
     public static String propertiesToString(int properties) {
+        return propertiesToStringInternal(properties, true /* isLong */);
+    }
+
+    /**
+     * Renders a set of property bits ({@code PROPERTY_*}) as a *short* human readable string.
+     *
+     * @param properties A property bit field.
+     * @return A human readable string representation.
+     * @hide
+     */
+    public static String propertiesToStringShort(int properties) {
+        return propertiesToStringInternal(properties, false /* isLong */);
+    }
+
+    private static String propertiesToStringInternal(int properties, boolean isLong) {
         StringBuilder builder = new StringBuilder();
-        builder.append("[Properties:");
+        builder.append("[");
+        if (isLong) {
+            builder.append("Properties:");
+        }
 
         if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) {
-            builder.append(" PROPERTY_SHOW_CALLBACK_NUMBER");
+            builder.append(isLong ? " PROPERTY_SHOW_CALLBACK_NUMBER" : " clbk");
         }
 
         if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
-            builder.append(" PROPERTY_HIGH_DEF_AUDIO");
+            builder.append(isLong ? " PROPERTY_HIGH_DEF_AUDIO" : " HD");
         }
 
         if (can(properties, PROPERTY_WIFI)) {
-            builder.append(" PROPERTY_WIFI");
+            builder.append(isLong ? " PROPERTY_WIFI" : " wifi");
         }
 
         if (can(properties, PROPERTY_GENERIC_CONFERENCE)) {
-            builder.append(" PROPERTY_GENERIC_CONFERENCE");
+            builder.append(isLong ? " PROPERTY_GENERIC_CONFERENCE" : " gen_conf");
         }
 
         if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) {
-            builder.append(" PROPERTY_IS_EXTERNAL_CALL");
+            builder.append(isLong ? " PROPERTY_IS_EXTERNAL_CALL" : " xtrnl");
         }
 
         if (can(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
-            builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
+            builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv");
         }
 
         builder.append("]");
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index ca7354f..8b81b0d 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -17,18 +17,23 @@
 package com.android.internal.telephony;
 
 import android.annotation.Nullable;
+import android.content.ContentResolver;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.os.RemoteException;
+import android.provider.Settings;
 import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemConfig;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Utilities for handling carrier applications.
@@ -53,6 +58,11 @@
      * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if
      * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED.
      *
+     * In addition, there is a list of carrier-associated applications in
+     * {@link SystemConfig#getDisabledUntilUsedPreinstalledCarrierAssociatedApps}. Each app in this
+     * list is associated with a carrier app. When the given carrier app is enabled/disabled per the
+     * above, the associated applications are enabled/disabled to match.
+     *
      * When enabling a carrier app we also grant it default permissions.
      *
      * This method is idempotent and is safe to be called at any time; it should be called once at
@@ -60,19 +70,24 @@
      * privileged apps may have changed.
      */
     public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
-            IPackageManager packageManager, TelephonyManager telephonyManager, int userId) {
+            IPackageManager packageManager, TelephonyManager telephonyManager,
+            ContentResolver contentResolver, int userId) {
         if (DEBUG) {
             Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
         }
+        SystemConfig config = SystemConfig.getInstance();
         String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
                 com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
-        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager, userId,
-                systemCarrierAppsDisabledUntilUsed);
+        ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
+                config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager,
+                contentResolver, userId, systemCarrierAppsDisabledUntilUsed,
+                systemCarrierAssociatedAppsDisabledUntilUsed);
     }
 
     /**
      * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager,
-     * int)}, but assumes that no carrier apps have carrier privileges.
+     * ContentResolver, int)}, but assumes that no carrier apps have carrier privileges.
      *
      * This prevents a potential race condition on first boot - since the app's default state is
      * enabled, we will initially disable it when the telephony stack is first initialized as it has
@@ -82,29 +97,43 @@
      * Manager can kill it, and this can lead to crashes as the app is in an unexpected state.
      */
     public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
-            IPackageManager packageManager, int userId) {
+            IPackageManager packageManager, ContentResolver contentResolver, int userId) {
         if (DEBUG) {
             Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
         }
+        SystemConfig config = SystemConfig.getInstance();
         String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
                 com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
+        ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
+                config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
         disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
-                null /* telephonyManager */, userId, systemCarrierAppsDisabledUntilUsed);
+                null /* telephonyManager */, contentResolver, userId,
+                systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed);
     }
 
     // Must be public b/c framework unit tests can't access package-private methods.
     @VisibleForTesting
     public static void disableCarrierAppsUntilPrivileged(String callingPackage,
-            IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, int userId,
-            String[] systemCarrierAppsDisabledUntilUsed) {
+            IPackageManager packageManager, @Nullable TelephonyManager telephonyManager,
+            ContentResolver contentResolver, int userId,
+            String[] systemCarrierAppsDisabledUntilUsed,
+            ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
         List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
                 userId, systemCarrierAppsDisabledUntilUsed);
         if (candidates == null || candidates.isEmpty()) {
             return;
         }
 
+        Map<String, List<ApplicationInfo>> associatedApps = getDefaultCarrierAssociatedAppsHelper(
+                packageManager,
+                userId,
+                systemCarrierAssociatedAppsDisabledUntilUsed);
+
         List<String> enabledCarrierPackages = new ArrayList<>();
 
+        boolean hasRunOnce = Settings.Secure.getIntForUser(
+                contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0, userId) == 1;
+
         try {
             for (ApplicationInfo ai : candidates) {
                 String packageName = ai.packageName;
@@ -112,33 +141,92 @@
                         telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
                                 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 
-                // Only update enabled state for the app on /system. Once it has been updated we
-                // shouldn't touch it.
-                if (!ai.isUpdatedSystemApp()) {
-                    if (hasPrivileges
-                            && (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                if (hasPrivileges) {
+                    // Only update enabled state for the app on /system. Once it has been
+                    // updated we shouldn't touch it.
+                    if (!ai.isUpdatedSystemApp()
+                            && (ai.enabledSetting ==
+                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                             || ai.enabledSetting ==
                             PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
                         Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
                                 + userId);
-                        packageManager.setApplicationEnabledSetting(packageName,
+                        packageManager.setApplicationEnabledSetting(
+                                packageName,
                                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
-                                PackageManager.DONT_KILL_APP, userId, callingPackage);
-                    } else if (!hasPrivileges
+                                PackageManager.DONT_KILL_APP,
+                                userId,
+                                callingPackage);
+                    }
+
+                    // Also enable any associated apps for this carrier app.
+                    List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
+                    if (associatedAppList != null) {
+                        for (ApplicationInfo associatedApp : associatedAppList) {
+                            if (associatedApp.enabledSetting ==
+                                    PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                                    || associatedApp.enabledSetting ==
+                                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                                Slog.i(TAG, "Update associated state(" + associatedApp.packageName
+                                        + "): ENABLED for user " + userId);
+                                packageManager.setApplicationEnabledSetting(
+                                        associatedApp.packageName,
+                                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                                        PackageManager.DONT_KILL_APP,
+                                        userId,
+                                        callingPackage);
+                            }
+                        }
+                    }
+
+                    // Always re-grant default permissions to carrier apps w/ privileges.
+                    enabledCarrierPackages.add(ai.packageName);
+                } else {  // No carrier privileges
+                    // Only update enabled state for the app on /system. Once it has been
+                    // updated we shouldn't touch it.
+                    if (!ai.isUpdatedSystemApp()
                             && ai.enabledSetting ==
                             PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                         Slog.i(TAG, "Update state(" + packageName
                                 + "): DISABLED_UNTIL_USED for user " + userId);
-                        packageManager.setApplicationEnabledSetting(packageName,
-                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
-                                userId, callingPackage);
+                        packageManager.setApplicationEnabledSetting(
+                                packageName,
+                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+                                0,
+                                userId,
+                                callingPackage);
+                    }
+
+                    // Also disable any associated apps for this carrier app if this is the first
+                    // run. We avoid doing this a second time because it is brittle to rely on the
+                    // distinction between "default" and "enabled".
+                    if (!hasRunOnce) {
+                        List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
+                        if (associatedAppList != null) {
+                            for (ApplicationInfo associatedApp : associatedAppList) {
+                                if (associatedApp.enabledSetting
+                                        == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+                                    Slog.i(TAG,
+                                            "Update associated state(" + associatedApp.packageName
+                                                    + "): DISABLED_UNTIL_USED for user " + userId);
+                                    packageManager.setApplicationEnabledSetting(
+                                            associatedApp.packageName,
+                                            PackageManager
+                                                    .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+                                            0,
+                                            userId,
+                                            callingPackage);
+                                }
+                            }
+                        }
                     }
                 }
+            }
 
-                // Always re-grant default permissions to carrier apps w/ privileges.
-                if (hasPrivileges) {
-                    enabledCarrierPackages.add(ai.packageName);
-                }
+            // Mark the execution so we do not disable apps again.
+            if (!hasRunOnce) {
+                Settings.Secure.putIntForUser(
+                        contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1, userId);
             }
 
             if (!enabledCarrierPackages.isEmpty()) {
@@ -190,8 +278,8 @@
      *
      * These are the apps subject to the hiding/showing logic in
      * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager,
-     * TelephonyManager, int)}, as well as the apps which should have default permissions granted,
-     * when a matching SIM is inserted.
+     * TelephonyManager, ContentResolver, int)}, as well as the apps which should have default
+     * permissions granted, when a matching SIM is inserted.
      *
      * Whether or not the app is actually considered a default app depends on whether the app has
      * carrier privileges as determined by the SIMs in the device.
@@ -205,30 +293,68 @@
     }
 
     private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
-            IPackageManager packageManager, int userId,
+            IPackageManager packageManager,
+            int userId,
             String[] systemCarrierAppsDisabledUntilUsed) {
         if (systemCarrierAppsDisabledUntilUsed == null
                 || systemCarrierAppsDisabledUntilUsed.length == 0) {
             return null;
         }
-        List<ApplicationInfo> apps = null;
-        try {
-            apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
-            for (String packageName : systemCarrierAppsDisabledUntilUsed) {
-                ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
-                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
-                if (ai == null) {
-                    // No app found for packageName
-                    continue;
-                }
-                if (!ai.isSystemApp()) {
-                    continue;
-                }
+        List<ApplicationInfo> apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
+        for (int i = 0; i < systemCarrierAppsDisabledUntilUsed.length; i++) {
+            String packageName = systemCarrierAppsDisabledUntilUsed[i];
+            ApplicationInfo ai =
+                    getApplicationInfoIfSystemApp(packageManager, userId, packageName);
+            if (ai != null) {
                 apps.add(ai);
             }
+        }
+        return apps;
+    }
+
+    private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper(
+            IPackageManager packageManager,
+            int userId,
+            ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
+        int size = systemCarrierAssociatedAppsDisabledUntilUsed.size();
+        Map<String, List<ApplicationInfo>> associatedApps = new ArrayMap<>(size);
+        for (int i = 0; i < size; i++) {
+            String carrierAppPackage = systemCarrierAssociatedAppsDisabledUntilUsed.keyAt(i);
+            List<String> associatedAppPackages =
+                    systemCarrierAssociatedAppsDisabledUntilUsed.valueAt(i);
+            for (int j = 0; j < associatedAppPackages.size(); j++) {
+                ApplicationInfo ai =
+                        getApplicationInfoIfSystemApp(
+                                packageManager, userId, associatedAppPackages.get(j));
+                // Only update enabled state for the app on /system. Once it has been updated we
+                // shouldn't touch it.
+                if (ai != null && !ai.isUpdatedSystemApp()) {
+                    List<ApplicationInfo> appList = associatedApps.get(carrierAppPackage);
+                    if (appList == null) {
+                        appList = new ArrayList<>();
+                        associatedApps.put(carrierAppPackage, appList);
+                    }
+                    appList.add(ai);
+                }
+            }
+        }
+        return associatedApps;
+    }
+
+    @Nullable
+    private static ApplicationInfo getApplicationInfoIfSystemApp(
+            IPackageManager packageManager,
+            int userId,
+            String packageName) {
+        try {
+            ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
+                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
+            if (ai != null && ai.isSystemApp()) {
+                return ai;
+            }
         } catch (RemoteException e) {
             Slog.w(TAG, "Could not reach PackageManager", e);
         }
-        return apps;
+        return null;
     }
 }
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 336fce9..b6f46a2 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -554,6 +554,15 @@
     return all_emoji, default_emoji, equivalent_emoji
 
 
+def check_vertical_metrics():
+    for record in _fallback_chain:
+        if record.name in ['sans-serif', 'sans-serif-condensed']:
+            font = open_font(record.font)
+            assert (font['head'].yMax == 2163 and font['head'].yMin == -555 and
+                    font['hhea'].ascent == 1900 and font['hhea'].descent == -500), (
+                   'Vertical metrics of %s do not match expected Roboto metrics.' % (record.font,))
+
+
 def main():
     global _fonts_dir
     target_out = sys.argv[1]
@@ -562,6 +571,8 @@
     fonts_xml_path = path.join(target_out, 'etc', 'fonts.xml')
     parse_fonts_xml(fonts_xml_path)
 
+    check_vertical_metrics()
+
     hyphens_dir = path.join(target_out, 'usr', 'hyphen-data')
     check_hyphens(hyphens_dir)