Loading packages/SettingsLib/Preference/Android.bp +13 −0 Original line number Original line Diff line number Diff line Loading @@ -22,3 +22,16 @@ android_library { ], ], kotlincflags: ["-Xjvm-default=all"], kotlincflags: ["-Xjvm-default=all"], } } android_library { name: "SettingsLibPreference-testutils", srcs: ["testutils/**/*.kt"], static_libs: [ "SettingsLibPreference", "androidx.fragment_fragment-testing", "androidx.test.core", "androidx.test.ext.junit", "flag-junit", "truth", ], } packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt +5 −2 Original line number Original line Diff line number Diff line Loading @@ -68,10 +68,13 @@ interface PreferenceBinding { preference.icon = null preference.icon = null } } val context = preference.context val context = preference.context val isPreferenceScreen = preference is PreferenceScreen preference.peekExtras()?.clear() preference.peekExtras()?.clear() extras(context)?.let { preference.extras.putAll(it) } extras(context)?.let { preference.extras.putAll(it) } preference.title = getPreferenceTitle(context) preference.title = getPreferenceTitle(context) if (!isPreferenceScreen) { preference.summary = getPreferenceSummary(context) preference.summary = getPreferenceSummary(context) } preference.isEnabled = isEnabled(context) preference.isEnabled = isEnabled(context) preference.isVisible = preference.isVisible = (this as? PreferenceAvailabilityProvider)?.isAvailable(context) != false (this as? PreferenceAvailabilityProvider)?.isAvailable(context) != false Loading @@ -81,7 +84,7 @@ interface PreferenceBinding { // dependency here. This simplifies dependency management and avoid the // dependency here. This simplifies dependency management and avoid the // IllegalStateException when call Preference.setDependency // IllegalStateException when call Preference.setDependency preference.dependency = null preference.dependency = null if (preference !is PreferenceScreen) { // avoid recursive loop when build graph if (!isPreferenceScreen) { // avoid recursive loop when build graph preference.fragment = (this as? PreferenceScreenCreator)?.fragmentClass()?.name preference.fragment = (this as? PreferenceScreenCreator)?.fragmentClass()?.name preference.intent = intent(context) preference.intent = intent(context) } } Loading packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/CatalystScreenTestCase.kt 0 → 100644 +123 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 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.settingslib.preference import android.content.Context import android.platform.test.flag.junit.SetFlagsRule import android.util.Log import androidx.fragment.app.testing.FragmentScenario import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceGroup import androidx.preference.PreferenceScreen import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith /** Test case for catalyst screen. */ @RunWith(AndroidJUnit4::class) abstract class CatalystScreenTestCase { @get:Rule val setFlagsRule = SetFlagsRule() protected val context: Context = ApplicationProvider.getApplicationContext() /** Catalyst screen. */ protected abstract val preferenceScreenCreator: PreferenceScreenCreator /** Flag to control catalyst screen. */ protected abstract val flagName: String /** * Test to compare the preference screen hierarchy between legacy screen (flag is disabled) and * catalyst screen (flag is enabled). */ @Test fun migration() { enableCatalystScreen() assertThat(preferenceScreenCreator.isFlagEnabled(context)).isTrue() val catalystScreen = stringifyPreferenceScreen() Log.i("Catalyst", catalystScreen) disableCatalystScreen() assertThat(preferenceScreenCreator.isFlagEnabled(context)).isFalse() val legacyScreen = stringifyPreferenceScreen() assertThat(catalystScreen).isEqualTo(legacyScreen) } /** * Enables the catalyst screen. * * By default, enable the [flagName]. Override for more complex situation. */ @Suppress("DEPRECATION") protected open fun enableCatalystScreen() { setFlagsRule.enableFlags(flagName) } /** * Disables the catalyst screen (legacy screen is shown). * * By default, disable the [flagName]. Override for more complex situation. */ @Suppress("DEPRECATION") protected open fun disableCatalystScreen() { setFlagsRule.disableFlags(flagName) } private fun stringifyPreferenceScreen(): String { @Suppress("UNCHECKED_CAST") val clazz = preferenceScreenCreator.fragmentClass() as Class<PreferenceFragmentCompat> val builder = StringBuilder() FragmentScenario.launch(clazz).use { it.onFragment { fragment -> fragment.preferenceScreen.toString(builder) } } return builder.toString() } private fun Preference.toString(builder: StringBuilder, indent: String = "") { val clazz = javaClass builder.append(indent).append(clazz).append(" {\n") val indent2 = "$indent " if (clazz != PreferenceScreen::class.java) { key?.let { builder.append(indent2).append("key: \"$it\"\n") } } title?.let { builder.append(indent2).append("title: \"$it\"\n") } summary?.let { builder.append(indent2).append("summary: \"$it\"\n") } fragment?.let { builder.append(indent2).append("fragment: \"$it\"\n") } builder.append(indent2).append("order: $order\n") builder.append(indent2).append("isCopyingEnabled: $isCopyingEnabled\n") builder.append(indent2).append("isEnabled: $isEnabled\n") builder.append(indent2).append("isIconSpaceReserved: $isIconSpaceReserved\n") if (clazz != Preference::class.java && clazz != PreferenceScreen::class.java) { builder.append(indent2).append("isPersistent: $isPersistent\n") } builder.append(indent2).append("isSelectable: $isSelectable\n") if (this is PreferenceGroup) { val count = preferenceCount builder.append(indent2).append("preferenceCount: $count\n") val indent4 = "$indent2 " for (index in 0..<count) { getPreference(index).toString(builder, indent4) } } builder.append(indent).append("}\n") } } Loading
packages/SettingsLib/Preference/Android.bp +13 −0 Original line number Original line Diff line number Diff line Loading @@ -22,3 +22,16 @@ android_library { ], ], kotlincflags: ["-Xjvm-default=all"], kotlincflags: ["-Xjvm-default=all"], } } android_library { name: "SettingsLibPreference-testutils", srcs: ["testutils/**/*.kt"], static_libs: [ "SettingsLibPreference", "androidx.fragment_fragment-testing", "androidx.test.core", "androidx.test.ext.junit", "flag-junit", "truth", ], }
packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt +5 −2 Original line number Original line Diff line number Diff line Loading @@ -68,10 +68,13 @@ interface PreferenceBinding { preference.icon = null preference.icon = null } } val context = preference.context val context = preference.context val isPreferenceScreen = preference is PreferenceScreen preference.peekExtras()?.clear() preference.peekExtras()?.clear() extras(context)?.let { preference.extras.putAll(it) } extras(context)?.let { preference.extras.putAll(it) } preference.title = getPreferenceTitle(context) preference.title = getPreferenceTitle(context) if (!isPreferenceScreen) { preference.summary = getPreferenceSummary(context) preference.summary = getPreferenceSummary(context) } preference.isEnabled = isEnabled(context) preference.isEnabled = isEnabled(context) preference.isVisible = preference.isVisible = (this as? PreferenceAvailabilityProvider)?.isAvailable(context) != false (this as? PreferenceAvailabilityProvider)?.isAvailable(context) != false Loading @@ -81,7 +84,7 @@ interface PreferenceBinding { // dependency here. This simplifies dependency management and avoid the // dependency here. This simplifies dependency management and avoid the // IllegalStateException when call Preference.setDependency // IllegalStateException when call Preference.setDependency preference.dependency = null preference.dependency = null if (preference !is PreferenceScreen) { // avoid recursive loop when build graph if (!isPreferenceScreen) { // avoid recursive loop when build graph preference.fragment = (this as? PreferenceScreenCreator)?.fragmentClass()?.name preference.fragment = (this as? PreferenceScreenCreator)?.fragmentClass()?.name preference.intent = intent(context) preference.intent = intent(context) } } Loading
packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/CatalystScreenTestCase.kt 0 → 100644 +123 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 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.settingslib.preference import android.content.Context import android.platform.test.flag.junit.SetFlagsRule import android.util.Log import androidx.fragment.app.testing.FragmentScenario import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceGroup import androidx.preference.PreferenceScreen import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith /** Test case for catalyst screen. */ @RunWith(AndroidJUnit4::class) abstract class CatalystScreenTestCase { @get:Rule val setFlagsRule = SetFlagsRule() protected val context: Context = ApplicationProvider.getApplicationContext() /** Catalyst screen. */ protected abstract val preferenceScreenCreator: PreferenceScreenCreator /** Flag to control catalyst screen. */ protected abstract val flagName: String /** * Test to compare the preference screen hierarchy between legacy screen (flag is disabled) and * catalyst screen (flag is enabled). */ @Test fun migration() { enableCatalystScreen() assertThat(preferenceScreenCreator.isFlagEnabled(context)).isTrue() val catalystScreen = stringifyPreferenceScreen() Log.i("Catalyst", catalystScreen) disableCatalystScreen() assertThat(preferenceScreenCreator.isFlagEnabled(context)).isFalse() val legacyScreen = stringifyPreferenceScreen() assertThat(catalystScreen).isEqualTo(legacyScreen) } /** * Enables the catalyst screen. * * By default, enable the [flagName]. Override for more complex situation. */ @Suppress("DEPRECATION") protected open fun enableCatalystScreen() { setFlagsRule.enableFlags(flagName) } /** * Disables the catalyst screen (legacy screen is shown). * * By default, disable the [flagName]. Override for more complex situation. */ @Suppress("DEPRECATION") protected open fun disableCatalystScreen() { setFlagsRule.disableFlags(flagName) } private fun stringifyPreferenceScreen(): String { @Suppress("UNCHECKED_CAST") val clazz = preferenceScreenCreator.fragmentClass() as Class<PreferenceFragmentCompat> val builder = StringBuilder() FragmentScenario.launch(clazz).use { it.onFragment { fragment -> fragment.preferenceScreen.toString(builder) } } return builder.toString() } private fun Preference.toString(builder: StringBuilder, indent: String = "") { val clazz = javaClass builder.append(indent).append(clazz).append(" {\n") val indent2 = "$indent " if (clazz != PreferenceScreen::class.java) { key?.let { builder.append(indent2).append("key: \"$it\"\n") } } title?.let { builder.append(indent2).append("title: \"$it\"\n") } summary?.let { builder.append(indent2).append("summary: \"$it\"\n") } fragment?.let { builder.append(indent2).append("fragment: \"$it\"\n") } builder.append(indent2).append("order: $order\n") builder.append(indent2).append("isCopyingEnabled: $isCopyingEnabled\n") builder.append(indent2).append("isEnabled: $isEnabled\n") builder.append(indent2).append("isIconSpaceReserved: $isIconSpaceReserved\n") if (clazz != Preference::class.java && clazz != PreferenceScreen::class.java) { builder.append(indent2).append("isPersistent: $isPersistent\n") } builder.append(indent2).append("isSelectable: $isSelectable\n") if (this is PreferenceGroup) { val count = preferenceCount builder.append(indent2).append("preferenceCount: $count\n") val indent4 = "$indent2 " for (index in 0..<count) { getPreference(index).toString(builder, indent4) } } builder.append(indent).append("}\n") } }