Merge "Add isEnabled API in SPP."
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 1cd5d96..a976de3 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -19,6 +19,8 @@
 import android.graphics.Canvas;
 import android.graphics.RecordingCanvas;
 import android.graphics.RenderNode;
+import android.graphics.text.LineBreakConfig;
+import android.os.LocaleList;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 
@@ -43,6 +45,19 @@
 
     public StaticLayoutPerfTest() {}
 
+    public static final String JP_TEXT_SHORT = "日本語でのパフォーマンス計測のための例文です。";
+    // About 350 chars
+    public static final String JP_TEXT_LONG = "日本語でのパフォーマンス計測のための文章ですが、長いです。"
+            + "長い文章が必要なのですが、特に書くことが思いつかないので、コロッケの作り方でも書こうと思います。"
+            + "じゃがいもを茹でて潰しておきます。私は少し形が残っているほうが好きなので、ある程度のところで潰すのを"
+            + "やめます。別のフライパンで軽く塩をして玉ねぎのみじん切りを炒め、透き通ったら、一度取り出します。"
+            + "きれいにしたフライパンに、豚ひき肉を入れてあまりイジらずに豚肉を炒めます。"
+            + "しっかり火が通ったら炒めた玉ねぎを戻し入れ、塩コショウで味を決めます。"
+            + "炒めた肉玉ねぎとじゃがいもをよく混ぜて、1個あたり100gになるように整形します。"
+            + "整形したタネに小麦粉、卵、パン粉をつけて揚げます。"
+            + "180℃で揚げ、衣がきつね色になったら引き上げて、油を切る。"
+            + "盛り付けて出来上がり。";
+
     @Rule
     public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
@@ -432,4 +447,117 @@
         }
     }
 
+    @Test
+    public void testCreate_JPText_Phrase_Short() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final String text = JP_TEXT_SHORT;
+        final LineBreakConfig config = new LineBreakConfig.Builder()
+                .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
+                .build();
+        final TextPaint paint = new TextPaint(PAINT);
+        paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+            StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+                    .setLineBreakConfig(config)
+                    .build();
+        }
+    }
+
+    @Test
+    public void testCreate_JPText_Phrase_Long() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final String text = JP_TEXT_LONG;
+        final LineBreakConfig config = new LineBreakConfig.Builder()
+                .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
+                .build();
+        final TextPaint paint = new TextPaint(PAINT);
+        paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+            StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+                    .setLineBreakConfig(config)
+                    .build();
+        }
+    }
+
+    @Test
+    public void testCreate_JPText_Phrase_LongLong() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final String text = JP_TEXT_LONG.repeat(20);  // 250 * 20 = 7000 chars
+        final LineBreakConfig config = new LineBreakConfig.Builder()
+                .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
+                .build();
+        final TextPaint paint = new TextPaint(PAINT);
+        paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+            StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+                    .setLineBreakConfig(config)
+                    .build();
+        }
+    }
+
+    @Test
+    public void testCreate_JPText_NoPhrase_Short() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final String text = JP_TEXT_SHORT;
+        final LineBreakConfig config = new LineBreakConfig.Builder()
+                .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+                .build();
+        final TextPaint paint = new TextPaint(PAINT);
+        paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+            StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+                    .setLineBreakConfig(config)
+                    .build();
+        }
+    }
+
+    @Test
+    public void testCreate_JPText_NoPhrase_Long() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final String text = JP_TEXT_LONG;
+        final LineBreakConfig config = new LineBreakConfig.Builder()
+                .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+                .build();
+        final TextPaint paint = new TextPaint(PAINT);
+        paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+            StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+                    .setLineBreakConfig(config)
+                    .build();
+        }
+    }
+
+    @Test
+    public void testCreate_JPText_NoPhrase_LongLong() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final String text = JP_TEXT_LONG.repeat(20);  // 250 * 20 = 7000 chars
+        final LineBreakConfig config = new LineBreakConfig.Builder()
+                .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+                .build();
+        final TextPaint paint = new TextPaint(PAINT);
+        paint.setTextLocales(LocaleList.forLanguageTags("ja-JP"));
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+            StaticLayout.Builder.obtain(text, 0, text.length(), paint, TEXT_WIDTH)
+                    .setLineBreakConfig(config)
+                    .build();
+        }
+    }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index cbb4fbe..ce0c551 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -26,6 +26,7 @@
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.runBlocking
 
 /**
  * The config used to load the App List.
@@ -47,8 +48,21 @@
         userIdFlow: Flow<Int>,
         showSystemFlow: Flow<Boolean>,
     ): Flow<(app: ApplicationInfo) -> Boolean>
+
+    /** Gets the system app package names. */
+    fun getSystemPackageNamesBlocking(config: AppListConfig): Set<String>
 }
 
+/**
+ * Util for app list repository.
+ */
+object AppListRepositoryUtil {
+    /** Gets the system app package names. */
+    @JvmStatic
+    fun getSystemPackageNames(context: Context, config: AppListConfig): Set<String> {
+        return AppListRepositoryImpl(context).getSystemPackageNamesBlocking(config)
+    }
+}
 
 internal class AppListRepositoryImpl(private val context: Context) : AppListRepository {
     private val packageManager = context.packageManager
@@ -83,15 +97,26 @@
     ): Flow<(app: ApplicationInfo) -> Boolean> =
         userIdFlow.combine(showSystemFlow, ::showSystemPredicate)
 
+    override fun getSystemPackageNamesBlocking(config: AppListConfig) = runBlocking {
+        getSystemPackageNames(config)
+    }
+
+    private suspend fun getSystemPackageNames(config: AppListConfig): Set<String> =
+            coroutineScope {
+                val loadAppsDeferred = async { loadApps(config) }
+                val homeOrLauncherPackages = loadHomeOrLauncherPackages(config.userId)
+                val showSystemPredicate =
+                        { app: ApplicationInfo -> isSystemApp(app, homeOrLauncherPackages) }
+                loadAppsDeferred.await().filter(showSystemPredicate).map { it.packageName }.toSet()
+            }
+
     private suspend fun showSystemPredicate(
         userId: Int,
         showSystem: Boolean,
     ): (app: ApplicationInfo) -> Boolean {
         if (showSystem) return { true }
         val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId)
-        return { app ->
-            app.isUpdatedSystemApp || !app.isSystemApp || app.packageName in homeOrLauncherPackages
-        }
+        return { app -> !isSystemApp(app, homeOrLauncherPackages) }
     }
 
     private suspend fun loadHomeOrLauncherPackages(userId: Int): Set<String> {
@@ -117,6 +142,11 @@
         }
     }
 
+    private fun isSystemApp(app: ApplicationInfo, homeOrLauncherPackages: Set<String>): Boolean {
+        return !app.isUpdatedSystemApp && app.isSystemApp &&
+            !(app.packageName in homeOrLauncherPackages)
+    }
+
     companion object {
         private fun ApplicationInfo.isInAppList(
             showInstantApps: Boolean,
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index 2d8f009..b0ea40a 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -180,9 +180,7 @@
 
     @Test
     fun showSystemPredicate_showSystem() = runTest {
-        val app = ApplicationInfo().apply {
-            flags = ApplicationInfo.FLAG_SYSTEM
-        }
+        val app = SYSTEM_APP
 
         val showSystemPredicate = getShowSystemPredicate(showSystem = true)
 
@@ -191,9 +189,7 @@
 
     @Test
     fun showSystemPredicate_notShowSystemAndIsSystemApp() = runTest {
-        val app = ApplicationInfo().apply {
-            flags = ApplicationInfo.FLAG_SYSTEM
-        }
+        val app = SYSTEM_APP
 
         val showSystemPredicate = getShowSystemPredicate(showSystem = false)
 
@@ -202,9 +198,7 @@
 
     @Test
     fun showSystemPredicate_isUpdatedSystemApp() = runTest {
-        val app = ApplicationInfo().apply {
-            flags = ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
-        }
+        val app = UPDATED_SYSTEM_APP
 
         val showSystemPredicate = getShowSystemPredicate(showSystem = false)
 
@@ -213,10 +207,8 @@
 
     @Test
     fun showSystemPredicate_isHome() = runTest {
-        val app = ApplicationInfo().apply {
-            flags = ApplicationInfo.FLAG_SYSTEM
-            packageName = "home.app"
-        }
+        val app = HOME_APP
+
         whenever(packageManager.getHomeActivities(any())).thenAnswer {
             @Suppress("UNCHECKED_CAST")
             val resolveInfos = it.arguments[0] as MutableList<ResolveInfo>
@@ -231,10 +223,8 @@
 
     @Test
     fun showSystemPredicate_appInLauncher() = runTest {
-        val app = ApplicationInfo().apply {
-            flags = ApplicationInfo.FLAG_SYSTEM
-            packageName = "app.in.launcher"
-        }
+        val app = IN_LAUMCHER_APP
+
         whenever(
             packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), eq(USER_ID))
         ).thenReturn(listOf(resolveInfoOf(packageName = app.packageName)))
@@ -244,6 +234,17 @@
         assertThat(showSystemPredicate(app)).isTrue()
     }
 
+    @Test
+    fun getSystemPackageNames_returnExpectedValues() = runTest {
+        mockInstalledApplications(listOf(
+                NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUMCHER_APP))
+        val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false)
+
+        val systemPackageNames = AppListRepositoryUtil.getSystemPackageNames(context, appListConfig)
+
+        assertThat(systemPackageNames).containsExactly("system.app", "home.app", "app.in.launcher")
+    }
+
     private suspend fun getShowSystemPredicate(showSystem: Boolean) =
         repository.showSystemPredicate(
             userIdFlow = flowOf(USER_ID),
@@ -264,6 +265,26 @@
             privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT
         }
 
+        val SYSTEM_APP = ApplicationInfo().apply {
+            packageName = "system.app"
+            flags = ApplicationInfo.FLAG_SYSTEM
+        }
+
+        val UPDATED_SYSTEM_APP = ApplicationInfo().apply {
+            packageName = "updated.system.app"
+            flags = ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
+        }
+
+        val HOME_APP = ApplicationInfo().apply {
+            packageName = "home.app"
+            flags = ApplicationInfo.FLAG_SYSTEM
+        }
+
+        val IN_LAUMCHER_APP = ApplicationInfo().apply {
+            packageName = "app.in.launcher"
+            flags = ApplicationInfo.FLAG_SYSTEM
+        }
+
         fun resolveInfoOf(packageName: String) = ResolveInfo().apply {
             activityInfo = ActivityInfo().apply {
                 this.packageName = packageName
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
index f514487..7151439 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
@@ -90,6 +90,8 @@
             userIdFlow: Flow<Int>,
             showSystemFlow: Flow<Boolean>,
         ): Flow<(app: ApplicationInfo) -> Boolean> = flowOf { true }
+
+        override fun getSystemPackageNamesBlocking(config: AppListConfig): Set<String> = setOf()
     }
 
     private object FakeAppRepository : AppRepository {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index dbd58eb..81655cf 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2620,7 +2620,7 @@
         }
 
         state.setCurRawAdj(adj);
-
+        adj = psr.modifyRawOomAdj(adj);
         if (adj > state.getMaxAdj()) {
             adj = state.getMaxAdj();
             if (adj <= PERCEPTIBLE_LOW_APP_ADJ) {
@@ -2650,7 +2650,7 @@
         // it when computing the final cached adj later.  Note that we don't need to
         // worry about this for max adj above, since max adj will always be used to
         // keep it out of the cached vaues.
-        state.setCurAdj(psr.modifyRawOomAdj(adj));
+        state.setCurAdj(adj);
         state.setCurCapability(capability);
         state.setCurrentSchedulingGroup(schedGroup);
         state.setCurProcState(procState);