Merge "Set a minimum height for invocation lights" into qt-qpr1-dev
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 469c964..9f4f314 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -4,4 +4,5 @@
     group graphics audio
     disabled
     oneshot
+    ioprio rt 0
     writepid /dev/stune/top-app/tasks
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 41733b3..9720e9f 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -50,6 +50,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.SurfaceControl;
 import android.view.ViewConfiguration;
 import android.view.Window;
 import android.view.WindowManagerGlobal;
@@ -528,6 +529,12 @@
             } while (mWaitingActivities.contains(aw));
 
             waitForEnterAnimationComplete(aw.activity);
+
+            // Apply an empty transaction to ensure SF has a chance to update before
+            // the Activity is ready (b/138263890).
+            try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
+                t.apply(true);
+            }
             return aw.activity;
         }
     }
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 0ccd49f..5e530ee 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -355,7 +355,8 @@
     @Override
     public Bundle call(String method, String arg, Bundle extras) {
         if (method.equals(METHOD_SLICE)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
+                    extras.getParcelable(EXTRA_BIND_URI)));
             List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
 
             String callingPackage = getCallingPackage();
@@ -369,7 +370,7 @@
         } else if (method.equals(METHOD_MAP_INTENT)) {
             Intent intent = extras.getParcelable(EXTRA_INTENT);
             if (intent == null) return null;
-            Uri uri = onMapIntentToUri(intent);
+            Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent));
             List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
             Bundle b = new Bundle();
             if (uri != null) {
@@ -383,24 +384,27 @@
         } else if (method.equals(METHOD_MAP_ONLY_INTENT)) {
             Intent intent = extras.getParcelable(EXTRA_INTENT);
             if (intent == null) return null;
-            Uri uri = onMapIntentToUri(intent);
+            Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent));
             Bundle b = new Bundle();
             b.putParcelable(EXTRA_SLICE, uri);
             return b;
         } else if (method.equals(METHOD_PIN)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
+                    extras.getParcelable(EXTRA_BIND_URI)));
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system can pin/unpin slices");
             }
             handlePinSlice(uri);
         } else if (method.equals(METHOD_UNPIN)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
+                    extras.getParcelable(EXTRA_BIND_URI)));
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system can pin/unpin slices");
             }
             handleUnpinSlice(uri);
         } else if (method.equals(METHOD_GET_DESCENDANTS)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(
+                    validateIncomingUriOrNull(extras.getParcelable(EXTRA_BIND_URI)));
             Bundle b = new Bundle();
             b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
                     new ArrayList<>(handleGetDescendants(uri)));
@@ -416,6 +420,10 @@
         return super.call(method, arg, extras);
     }
 
+    private Uri validateIncomingUriOrNull(Uri uri) {
+        return uri == null ? null : validateIncomingUri(uri);
+    }
+
     private Collection<Uri> handleGetDescendants(Uri uri) {
         mCallback = "onGetSliceDescendants";
         return onGetSliceDescendants(uri);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 037a149..d58eb0d 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -507,6 +507,18 @@
      * {@link Intent#CATEGORY_LAUNCHER}, for a specified user. Result may include
      * synthesized activities like app details Activity injected by system.
      *
+     * <p>As of <a href="/reference/android/os/Build.VERSION_CODES.html#Q">Android Q</a>, the
+     * launchable activities for a given app are included in the returned list unless the app
+     * satisfies at least one of the following conditions:</p>
+     * <ul>
+     * <li>The app is a system app.</li>
+     * <li>The app doesn't declare any <a href="/guide/topics/permissions/overview">permissions</a>.
+     * </li>
+     * <li>The <code>&lt;application&gt;</code> tag in the app's manifest file doesn't contain any
+     * child elements that represent
+     * <a href="/guide/components/fundamentals#DeclaringComponents">app components</a>.</li>
+     * </ul>
+     *
      * @param packageName The specific package to query. If null, it checks all installed packages
      *            in the profile.
      * @param user The UserHandle of the profile.
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 099ae29..e78fb7f 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -339,6 +339,8 @@
      * for {@link #TYPE_STEP_COUNTER} instead. It is defined as a
      * {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER} sensor.
      * <p>
+     * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}.
+     * <p>
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
      */
     public static final int TYPE_STEP_DETECTOR = 18;
@@ -384,8 +386,6 @@
      * gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
      * use the gyroscope. However, it is more noisy and will work best outdoors.
      * <p>
-     * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}.
-     * <p>
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
      */
     public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
index e6a9e47..e5a54b8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
@@ -25,7 +25,7 @@
  */
 public class DozeAuthRemover implements DozeMachine.Part {
 
-    KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     public DozeAuthRemover(Context context) {
         mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index d22d2c3..347b964 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -30,6 +30,7 @@
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.classifier.FalsingManagerFactory;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.AsyncSensorManager;
@@ -47,6 +48,7 @@
         SensorManager sensorManager = Dependency.get(AsyncSensorManager.class);
         AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
         DockManager dockManager = Dependency.get(DockManager.class);
+        WakefulnessLifecycle wakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
 
         DozeHost host = getHost(dozeService);
         AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
@@ -61,7 +63,8 @@
         wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(wrappedService,
                 params);
 
-        DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock);
+        DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
+                wakefulnessLifecycle);
         machine.setParts(new DozeMachine.Part[]{
                 new DozePauser(handler, machine, alarmManager, params.getPolicy()),
                 new DozeFalsingManagerAdapter(FalsingManagerFactory.getInstance(context)),
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 8bf2256..93a51cc 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -24,6 +24,8 @@
 import android.view.Display;
 
 import com.android.internal.util.Preconditions;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.wakelock.WakeLock;
@@ -118,6 +120,7 @@
     private final Service mDozeService;
     private final WakeLock mWakeLock;
     private final AmbientDisplayConfiguration mConfig;
+    private final WakefulnessLifecycle mWakefulnessLifecycle;
     private Part[] mParts;
 
     private final ArrayList<State> mQueuedRequests = new ArrayList<>();
@@ -126,9 +129,10 @@
     private boolean mWakeLockHeldForCurrentState = false;
 
     public DozeMachine(Service service, AmbientDisplayConfiguration config,
-            WakeLock wakeLock) {
+            WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle) {
         mDozeService = service;
         mConfig = config;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
         mWakeLock = wakeLock;
     }
 
@@ -334,9 +338,18 @@
         switch (state) {
             case INITIALIZED:
             case DOZE_PULSE_DONE:
-                transitionTo(mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)
-                        ? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE,
-                        DozeLog.PULSE_REASON_NONE);
+                final State nextState;
+                @Wakefulness int wakefulness = mWakefulnessLifecycle.getWakefulness();
+                if (wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE
+                        || wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING) {
+                    nextState = State.FINISH;
+                } else if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
+                    nextState = State.DOZE_AOD;
+                } else {
+                    nextState = State.DOZE;
+                }
+
+                transitionTo(nextState, DozeLog.PULSE_REASON_NONE);
                 break;
             default:
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
index 52a0214..d17f2f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.keyguard;
 
+import android.annotation.IntDef;
 import android.os.Trace;
 
 import com.android.systemui.Dumpable;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -33,6 +36,15 @@
 public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observer> implements
         Dumpable {
 
+    @IntDef(prefix = { "WAKEFULNESS_" }, value = {
+            WAKEFULNESS_ASLEEP,
+            WAKEFULNESS_WAKING,
+            WAKEFULNESS_AWAKE,
+            WAKEFULNESS_GOING_TO_SLEEP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Wakefulness {}
+
     public static final int WAKEFULNESS_ASLEEP = 0;
     public static final int WAKEFULNESS_WAKING = 1;
     public static final int WAKEFULNESS_AWAKE = 2;
@@ -44,7 +56,7 @@
     public WakefulnessLifecycle() {
     }
 
-    public int getWakefulness() {
+    public @Wakefulness int getWakefulness() {
         return mWakefulness;
     }
 
@@ -86,7 +98,7 @@
         pw.println("  mWakefulness=" + mWakefulness);
     }
 
-    private void setWakefulness(int wakefulness) {
+    private void setWakefulness(@Wakefulness int wakefulness) {
         mWakefulness = wakefulness;
         Trace.traceCounter(Trace.TRACE_TAG_APP, "wakefulness", wakefulness);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 991d9fa..0403a05 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -248,7 +248,9 @@
         int numPages = Math.max(nTiles / mPages.get(0).maxTiles(), 1);
 
         // Add one more not full page if needed
-        numPages += (nTiles % mPages.get(0).maxTiles() == 0 ? 0 : 1);
+        if (nTiles > numPages * mPages.get(0).maxTiles()) {
+            numPages++;
+        }
 
         final int NP = mPages.size();
         for (int i = 0; i < NP; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 4562763..e75365e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -216,10 +216,14 @@
 
         MobileIconGroup hGroup = TelephonyIcons.THREE_G;
         MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G;
-        if (mConfig.hspaDataDistinguishable) {
+        if (mConfig.show4gFor3g) {
+            hGroup = TelephonyIcons.FOUR_G;
+            hPlusGroup = TelephonyIcons.FOUR_G;
+        } else if (mConfig.hspaDataDistinguishable) {
             hGroup = TelephonyIcons.H;
             hPlusGroup = TelephonyIcons.H_PLUS;
         }
+
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d545dc8..1c24bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -1114,6 +1114,7 @@
         Map<Integer, MobileIconGroup> nr5GIconMap = new HashMap<>();
 
         boolean showAtLeast3G = false;
+        boolean show4gFor3g = false;
         boolean alwaysShowCdmaRssi = false;
         boolean show4gForLte = false;
         boolean hideLtePlus = false;
@@ -1158,6 +1159,8 @@
                         CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
                 config.show4gForLte = b.getBoolean(
                         CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
+                config.show4gFor3g = b.getBoolean(
+                        CarrierConfigManager.KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL);
                 config.hideLtePlus = b.getBoolean(
                         CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
                 config.patternOfCarrierSpecificDataIcon = b.getString(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 6dfb19e..1e18e51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -45,11 +45,14 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.util.wakelock.WakeLockFake;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -58,6 +61,8 @@
 
     DozeMachine mMachine;
 
+    @Mock
+    private WakefulnessLifecycle mWakefulnessLifecycle;
     private DozeServiceFake mServiceFake;
     private WakeLockFake mWakeLockFake;
     private AmbientDisplayConfiguration mConfigMock;
@@ -65,12 +70,13 @@
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mServiceFake = new DozeServiceFake();
         mWakeLockFake = new WakeLockFake();
         mConfigMock = mock(AmbientDisplayConfiguration.class);
         mPartMock = mock(DozeMachine.Part.class);
 
-        mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake);
+        mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake, mWakefulnessLifecycle);
 
         mMachine.setParts(new DozeMachine.Part[]{mPartMock});
     }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 4d39f9a..bec08f4 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -39,6 +39,12 @@
 27391 user_activity_timeout_override (override|2|3)
 27392 battery_saver_setting (threshold|1)
 
+
+# ---------------------------
+# ThermalManagerService.java
+# ---------------------------
+2737 thermal_changed (name|3),(type|1|5),(temperature|5),(sensor_status|1|5),(previous_system_status|1|5)
+
 #
 # Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
 #
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 1552fd5..491c5ab 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -38,11 +38,13 @@
 import android.os.ShellCommand;
 import android.os.Temperature;
 import android.util.ArrayMap;
+import android.util.EventLog;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
+import com.android.server.EventLogTags;
 import com.android.server.FgThread;
 import com.android.server.SystemService;
 
@@ -250,6 +252,8 @@
         } finally {
             mThermalEventListeners.finishBroadcast();
         }
+        EventLog.writeEvent(EventLogTags.THERMAL_CHANGED, temperature.getName(),
+                temperature.getType(), temperature.getValue(), temperature.getStatus(), mStatus);
     }
 
     private void shutdownIfNeeded(Temperature temperature) {
@@ -860,10 +864,10 @@
                     mThermalHal11.linkToDeath(new DeathRecipient(),
                             THERMAL_HAL_DEATH_COOKIE);
                     mThermalHal11.registerThermalCallback(mThermalCallback11);
+                    Slog.i(TAG, "Thermal HAL 1.1 service connected, limited thermal functions "
+                            + "due to legacy API.");
                 } catch (NoSuchElementException | RemoteException e) {
-                    Slog.e(TAG,
-                            "Thermal HAL 1.1 service not connected, no thermal call back will be "
-                                    + "called.");
+                    Slog.e(TAG, "Thermal HAL 1.1 service not connected.");
                     mThermalHal11 = null;
                 }
                 return (mThermalHal11 != null);
@@ -978,8 +982,9 @@
                     mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
                     mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
                             0 /* not used */);
+                    Slog.i(TAG, "Thermal HAL 2.0 service connected.");
                 } catch (NoSuchElementException | RemoteException e) {
-                    Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
+                    Slog.e(TAG, "Thermal HAL 2.0 service not connected.");
                     mThermalHal20 = null;
                 }
                 return (mThermalHal20 != null);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 133b82f..97e003c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -23,6 +23,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.annotation.NonNull;
+import android.annotation.StringRes;
 import android.app.ActivityThread;
 import android.app.INotificationManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -1251,14 +1252,22 @@
             startSystemCaptionsManagerService(context);
 
             // App prediction manager service
-            traceBeginAndSlog("StartAppPredictionService");
-            mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
-            traceEnd();
+            if (deviceHasConfigString(context, R.string.config_defaultAppPredictionService)) {
+                traceBeginAndSlog("StartAppPredictionService");
+                mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
+                traceEnd();
+            } else {
+                Slog.d(TAG, "AppPredictionService not defined by OEM");
+            }
 
             // Content suggestions manager service
-            traceBeginAndSlog("StartContentSuggestionsService");
-            mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
-            traceEnd();
+            if (deviceHasConfigString(context, R.string.config_defaultContentSuggestionsService)) {
+                traceBeginAndSlog("StartContentSuggestionsService");
+                mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
+                traceEnd();
+            } else {
+                Slog.d(TAG, "ContentSuggestionsService not defined by OEM");
+            }
 
             traceBeginAndSlog("InitNetworkStackClient");
             try {
@@ -2249,10 +2258,13 @@
         }, BOOT_TIMINGS_TRACE_LOG);
     }
 
+    private boolean deviceHasConfigString(@NonNull Context context, @StringRes int resId) {
+        String serviceName = context.getString(resId);
+        return !TextUtils.isEmpty(serviceName);
+    }
+
     private void startSystemCaptionsManagerService(@NonNull Context context) {
-        String serviceName = context.getString(
-                com.android.internal.R.string.config_defaultSystemCaptionsManagerService);
-        if (TextUtils.isEmpty(serviceName)) {
+        if (!deviceHasConfigString(context, R.string.config_defaultSystemCaptionsManagerService)) {
             Slog.d(TAG, "SystemCaptionsManagerService disabled because resource is not overlaid");
             return;
         }
@@ -2279,9 +2291,7 @@
 
         // Then check if OEM overlaid the resource that defines the service.
         if (!explicitlyEnabled) {
-            final String serviceName = context
-                    .getString(com.android.internal.R.string.config_defaultContentCaptureService);
-            if (TextUtils.isEmpty(serviceName)) {
+            if (!deviceHasConfigString(context, R.string.config_defaultContentCaptureService)) {
                 Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
                 return;
             }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7b4f2f8..cb7014e 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1405,6 +1405,13 @@
             "show_4g_for_lte_data_icon_bool";
 
     /**
+     * Boolean indicating if default data account should show 4G icon when in 3G.
+     * @hide
+     */
+    public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL =
+            "show_4g_for_3g_data_icon_bool";
+
+    /**
      * Boolean indicating if lte+ icon should be shown if available
      * @hide
      */
@@ -3407,6 +3414,7 @@
         sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false);
+        sDefaults.putBoolean(KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL, false);
         sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, "");
         sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);