From 5ea28f5f0a10eb90b11fa53ec98e547487099ad3 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Mon, 23 Sep 2024 12:03:06 +0800 Subject: [PATCH 01/11] [Audiosharing] Apply new string resid Test: atest Flag: com.android.settingslib.flags.enable_le_audio_sharing Bug: 362858921 Bug: 362858894 Change-Id: I4c80d834515e43bade5f2207dc013dc30c6ab7be --- .../BluetoothDevicePairingDetailBase.java | 8 ++++---- .../AudioSharingConfirmDialogFragment.java | 2 +- .../AudioSharingErrorDialogFragment.java | 11 +++++----- ...udioSharingIncompatibleDialogFragment.java | 12 +++++------ .../AudioSharingSwitchBarController.java | 8 ++++---- .../BluetoothDevicePairingDetailBaseTest.java | 4 ++-- .../AudioSharingErrorDialogFragmentTest.java | 6 ++++++ ...SharingIncompatibleDialogFragmentTest.java | 4 ++-- .../AudioSharingSwitchBarControllerTest.java | 20 +++++++++---------- 9 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java index f1e12a4a6fe..2c65934dd72 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java @@ -359,7 +359,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere String aliasName = device.getAlias(); String deviceName = TextUtils.isEmpty(aliasName) ? device.getAddress() : aliasName; - showConnectingDialog("Connecting to " + deviceName + "..."); + showConnectingDialog(deviceName); // Wait for AUTO_DISMISS_TIME_THRESHOLD_MS and check if the paired device supports audio // sharing. if (!mHandler.hasMessages(AUTO_DISMISS_MESSAGE_ID)) { @@ -385,14 +385,15 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere } // TODO: use DialogFragment - private void showConnectingDialog(@NonNull String message) { + private void showConnectingDialog(@NonNull String deviceName) { postOnMainThread(() -> { + String message = getContext().getString(R.string.progress_dialog_connect_device_content, + deviceName); if (mProgressDialog != null) { Log.d(getLogTag(), "showConnectingDialog, is already showing"); TextView textView = mProgressDialog.findViewById(R.id.message); if (textView != null && !message.equals(textView.getText().toString())) { Log.d(getLogTag(), "showConnectingDialog, update message"); - // TODO: use string res once finalized textView.setText(message); } return; @@ -405,7 +406,6 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere null); TextView textView = customView.findViewById(R.id.message); if (textView != null) { - // TODO: use string res once finalized textView.setText(message); } AlertDialog dialog = builder.setView(customView).setCancelable(false).create(); diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java index 3750cf1ebbe..9b60df43029 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java @@ -72,7 +72,7 @@ public class AudioSharingConfirmDialogFragment extends InstrumentedDialogFragmen .setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing) .setIsCustomBodyEnabled(true) .setCustomMessage(R.string.audio_sharing_comfirm_dialog_content) - .setPositiveButton(com.android.settings.R.string.okay, (d, w) -> {}) + .setPositiveButton(R.string.okay, (d, w) -> {}) .build(); dialog.setCanceledOnTouchOutside(true); return dialog; diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java index 95b9bc36b92..e842b37eef7 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java @@ -26,6 +26,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.bluetooth.BluetoothUtils; @@ -65,15 +66,13 @@ public class AudioSharingErrorDialogFragment extends InstrumentedDialogFragment @Override @NonNull public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { - // TODO: put strings to res till they are finalized AlertDialog dialog = AudioSharingDialogFactory.newBuilder(getActivity()) - .setTitle("Couldn't share audio") - .setTitleIcon(com.android.settings.R.drawable.ic_warning_24dp) + .setTitle(R.string.audio_sharing_retry_dialog_title) + .setTitleIcon(R.drawable.ic_warning_24dp) .setIsCustomBodyEnabled(true) - .setCustomMessage("Something went wrong. Please try again.") - .setPositiveButton(com.android.settings.R.string.okay, (d, w) -> { - }) + .setCustomMessage(R.string.audio_sharing_retry_dialog_content) + .setPositiveButton(R.string.okay, (d, w) -> {}) .build(); dialog.setCanceledOnTouchOutside(true); return dialog; diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java index aceeb94420e..a8ad70b3695 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java @@ -27,6 +27,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.bluetooth.BluetoothUtils; @@ -88,15 +89,14 @@ public class AudioSharingIncompatibleDialogFragment extends InstrumentedDialogFr public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { Bundle arguments = requireArguments(); String deviceName = arguments.getString(BUNDLE_KEY_DEVICE_NAME); - // TODO: move strings to res once they are finalized AlertDialog dialog = AudioSharingDialogFactory.newBuilder(getActivity()) - .setTitle("Can't share audio with " + deviceName) - .setTitleIcon(com.android.settings.R.drawable.ic_warning_24dp) + .setTitle(getString(R.string.audio_sharing_incompatible_dialog_title, + deviceName)) + .setTitleIcon(R.drawable.ic_warning_24dp) .setIsCustomBodyEnabled(true) - .setCustomMessage( - "Audio sharing only works with headphones that support LE Audio.") - .setPositiveButton(com.android.settings.R.string.okay, (d, w) -> {}) + .setCustomMessage(R.string.audio_sharing_incompatible_dialog_content) + .setPositiveButton(R.string.okay, (d, w) -> {}) .build(); dialog.setCanceledOnTouchOutside(true); return dialog; diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java index ebc8cecadbf..b91a1f1df04 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java @@ -571,10 +571,10 @@ public class AudioSharingSwitchBarController extends BasePreferenceController if (mBroadcast != null) { mBroadcast.startPrivateBroadcast(); mSinksInAdding.clear(); - // TODO: use string res once finalized. AudioSharingUtils.postOnMainThread(mContext, () -> AudioSharingProgressDialogFragment.show(mFragment, - "Starting audio stream...")); + mContext.getString( + R.string.audio_sharing_progress_dialog_start_stream_content))); mMetricsFeatureProvider.action( mContext, SettingsEnums.ACTION_AUDIO_SHARING_MAIN_SWITCH_ON, @@ -830,8 +830,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController private void addSourceToTargetSinks(List targetActiveSinks, @NonNull String sinkName) { mSinksInAdding.addAll(targetActiveSinks); - // TODO: move to res once finalized - String progressMessage = "Sharing with " + sinkName + "..."; + String progressMessage = mContext.getString( + R.string.audio_sharing_progress_dialog_add_source_content, sinkName); showProgressDialog(progressMessage); AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager); } diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java index e326c1e2630..9f0cb6e35d9 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java @@ -211,9 +211,9 @@ public class BluetoothDevicePairingDetailBaseTest { assertThat(dialog).isNotNull(); TextView message = dialog.findViewById(R.id.message); assertThat(message).isNotNull(); - // TODO: use stringr res once finalized assertThat(message.getText().toString()).isEqualTo( - "Connecting to " + TEST_DEVICE_ADDRESS + "..."); + mContext.getString(R.string.progress_dialog_connect_device_content, + TEST_DEVICE_ADDRESS)); verify(mFragment, never()).finish(); } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragmentTest.java index fc38cd2817d..a8451b1e24e 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragmentTest.java @@ -24,11 +24,13 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothStatusCodes; import android.platform.test.flag.junit.SetFlagsRule; import android.view.View; +import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; +import com.android.settings.R; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settingslib.flags.Flags; @@ -114,6 +116,10 @@ public class AudioSharingErrorDialogFragmentTest { AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); assertThat(dialog.isShowing()).isTrue(); + TextView title = dialog.findViewById(R.id.title_text); + assertThat(title).isNotNull(); + assertThat(title.getText().toString()).isEqualTo( + mParent.getString(R.string.audio_sharing_retry_dialog_title)); } @Test diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragmentTest.java index 67cb2aa915b..8d89646d3fb 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragmentTest.java @@ -120,9 +120,9 @@ public class AudioSharingIncompatibleDialogFragmentTest { assertThat(dialog.isShowing()).isTrue(); TextView title = dialog.findViewById(R.id.title_text); assertThat(title).isNotNull(); - // TODO: use string res assertThat(title.getText().toString()).isEqualTo( - "Can't share audio with " + TEST_DEVICE_NAME); + mParent.getString(R.string.audio_sharing_incompatible_dialog_title, + TEST_DEVICE_NAME)); } @Test diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java index 58696dccbea..fb5aa1c957e 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java @@ -629,8 +629,8 @@ public class AudioSharingSwitchBarControllerTest { AudioSharingProgressDialogFragment.class.getName()); AudioSharingProgressDialogFragment progressFragment = (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments); - // TODO: use string res once finalized - String expectedMessage = "Starting audio stream..."; + String expectedMessage = mContext.getString( + R.string.audio_sharing_progress_dialog_start_stream_content); checkProgressDialogMessage(progressFragment, expectedMessage); when(mBroadcast.isEnabled(null)).thenReturn(true); @@ -640,8 +640,8 @@ public class AudioSharingSwitchBarControllerTest { verify(mFeatureFactory.metricsFeatureProvider) .action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING)); - // TODO: use string res once finalized - expectedMessage = "Sharing with " + TEST_DEVICE_NAME2 + "..."; + expectedMessage = mContext.getString( + R.string.audio_sharing_progress_dialog_add_source_content, TEST_DEVICE_NAME2); checkProgressDialogMessage(progressFragment, expectedMessage); childFragments = mParentFragment.getChildFragmentManager().getFragments(); @@ -714,8 +714,8 @@ public class AudioSharingSwitchBarControllerTest { AudioSharingProgressDialogFragment.class.getName()); AudioSharingProgressDialogFragment progressFragment = (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments); - // TODO: use string res once finalized - String expectedMessage = "Sharing with " + TEST_DEVICE_NAME1 + "..."; + String expectedMessage = mContext.getString( + R.string.audio_sharing_progress_dialog_add_source_content, TEST_DEVICE_NAME1); checkProgressDialogMessage(progressFragment, expectedMessage); childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss()); @@ -755,8 +755,8 @@ public class AudioSharingSwitchBarControllerTest { AudioSharingProgressDialogFragment.class.getName()); AudioSharingProgressDialogFragment progressFragment = (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments); - // TODO: use string res once finalized - String expectedMessage = "Sharing with " + TEST_DEVICE_NAME2 + "..."; + String expectedMessage = mContext.getString( + R.string.audio_sharing_progress_dialog_add_source_content, TEST_DEVICE_NAME2); checkProgressDialogMessage(progressFragment, expectedMessage); childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss()); @@ -1027,8 +1027,8 @@ public class AudioSharingSwitchBarControllerTest { // Progress dialog shows sharing progress for the auto add second sink. AudioSharingProgressDialogFragment progressFragment = (AudioSharingProgressDialogFragment) Iterables.getOnlyElement(childFragments); - // TODO: use string res once finalized - String expectedMessage = "Sharing with " + TEST_DEVICE_NAME1 + "..."; + String expectedMessage = mContext.getString( + R.string.audio_sharing_progress_dialog_add_source_content, TEST_DEVICE_NAME1); checkProgressDialogMessage(progressFragment, expectedMessage); childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss()); From e0f734526d27a8391570f5d113ff22d332504233 Mon Sep 17 00:00:00 2001 From: Menghan Li Date: Mon, 23 Sep 2024 09:24:38 +0000 Subject: [PATCH 02/11] refactor(brightness suw): decouple auto brightness initialization logic for setup flow The AccessibilitySettingsForSetupWizard class should not be responsible for managing the initial logic of controllers, such as determining which controllers need to be dynamically added or updated using setInSetupWizard APIs. This logic should be handled directly by the controllers themselves. Bug: 311093618 Flag: EXEMPT bugfix Test: atest AccessibilitySettingsForSetupWizardTest AutoBrightnessPreferenceControllerForSetupWizardTest AutoBrightnessPreferenceControllerTest BrightnessLevelPreferenceControllerForSetupWizardTest BrightnessLevelPreferenceControllerTest Change-Id: I6065a10e72d002981c0f514543e6933d79c2aa1b --- ...ccessibility_settings_for_setup_wizard.xml | 3 +- .../AccessibilitySettingsForSetupWizard.java | 15 +-- .../AutoBrightnessPreferenceController.java | 25 ++--- ...essPreferenceControllerForSetupWizard.java | 44 +++++++++ .../BrightnessLevelPreferenceController.java | 24 ++--- ...velPreferenceControllerForSetupWizard.java | 47 ++++++++++ ...cessibilitySettingsForSetupWizardTest.java | 10 +- ...referenceControllerForSetupWizardTest.java | 92 +++++++++++++++++++ ...utoBrightnessPreferenceControllerTest.java | 35 +------ ...referenceControllerForSetupWizardTest.java | 69 ++++++++++++++ ...ightnessLevelPreferenceControllerTest.java | 30 +----- 11 files changed, 289 insertions(+), 105 deletions(-) create mode 100644 src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizard.java create mode 100644 src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizard.java create mode 100644 tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizardTest.java create mode 100644 tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizardTest.java diff --git a/res/xml/accessibility_settings_for_setup_wizard.xml b/res/xml/accessibility_settings_for_setup_wizard.xml index a69dc26ce3f..25b8a5acf69 100644 --- a/res/xml/accessibility_settings_for_setup_wizard.xml +++ b/res/xml/accessibility_settings_for_setup_wizard.xml @@ -43,7 +43,8 @@ android:title="@string/auto_brightness_title" android:fragment="com.android.settings.accessibility.AutoBrightnessPreferenceFragmentForSetupWizard" settings:useAdminDisabledSummary="true" - settings:userRestriction="no_config_brightness"/> + settings:userRestriction="no_config_brightness" + settings:controller="com.android.settings.display.AutoBrightnessPreferenceControllerForSetupWizard"/> createPreferenceControllers(Context context) { + // Requires lifecycle, so added programmatically (normally via resId). final List controllers = new ArrayList<>(); - BrightnessLevelPreferenceController brightnessLevelPreferenceController = - new BrightnessLevelPreferenceController(context, getSettingsLifecycle()); - brightnessLevelPreferenceController.setInSetupWizard(true); - controllers.add(brightnessLevelPreferenceController); - String autoBrightnessKey = context.getString(R.string.preference_key_auto_brightness); - AutoBrightnessPreferenceController autoBrightnessPreferenceController = - new AutoBrightnessPreferenceController(context, autoBrightnessKey); - autoBrightnessPreferenceController.setInSetupWizard(true); - controllers.add(autoBrightnessPreferenceController); + controllers.add(new BrightnessLevelPreferenceControllerForSetupWizard( + context, getSettingsLifecycle())); return controllers; } diff --git a/src/com/android/settings/display/AutoBrightnessPreferenceController.java b/src/com/android/settings/display/AutoBrightnessPreferenceController.java index 3014f62b0a6..0a80d695b5f 100644 --- a/src/com/android/settings/display/AutoBrightnessPreferenceController.java +++ b/src/com/android/settings/display/AutoBrightnessPreferenceController.java @@ -22,28 +22,25 @@ import android.os.Process; import android.os.UserManager; import android.provider.Settings; +import androidx.annotation.NonNull; import androidx.preference.Preference; import com.android.settings.R; -import com.android.settings.accessibility.Flags; import com.android.settings.core.TogglePreferenceController; import com.android.settingslib.PrimarySwitchPreference; +/** + * The top-level preference controller that updates the adaptive brightness. + */ public class AutoBrightnessPreferenceController extends TogglePreferenceController { private final String SYSTEM_KEY = SCREEN_BRIGHTNESS_MODE; private final int DEFAULT_VALUE = SCREEN_BRIGHTNESS_MODE_MANUAL; - private boolean mInSetupWizard; - - public AutoBrightnessPreferenceController(Context context, String key) { + public AutoBrightnessPreferenceController(@NonNull Context context, @NonNull String key) { super(context, key); } - public void setInSetupWizard(boolean inSetupWizard) { - mInSetupWizard = inSetupWizard; - } - @Override public boolean isChecked() { return Settings.System.getInt(mContext.getContentResolver(), @@ -60,14 +57,10 @@ public class AutoBrightnessPreferenceController extends TogglePreferenceControll @Override @AvailabilityStatus public int getAvailabilityStatus() { - if (!mContext.getResources().getBoolean( - com.android.internal.R.bool.config_automatic_brightness_available)) { - return UNSUPPORTED_ON_DEVICE; - } - if (mInSetupWizard && !Flags.addBrightnessSettingsInSuw()) { - return CONDITIONALLY_UNAVAILABLE; - } - return AVAILABLE_UNSEARCHABLE; + return mContext.getResources().getBoolean( + com.android.internal.R.bool.config_automatic_brightness_available) + ? AVAILABLE_UNSEARCHABLE + : UNSUPPORTED_ON_DEVICE; } @Override diff --git a/src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizard.java b/src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizard.java new file mode 100644 index 00000000000..7cdf3e0ea35 --- /dev/null +++ b/src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizard.java @@ -0,0 +1,44 @@ +/* + * 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.settings.display; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import com.android.settings.accessibility.Flags; + +/** + * The top-level preference controller that updates the adaptive brightness in the SetupWizard. + */ +public class AutoBrightnessPreferenceControllerForSetupWizard + extends AutoBrightnessPreferenceController { + + public AutoBrightnessPreferenceControllerForSetupWizard(@NonNull Context context, + @NonNull String key) { + super(context, key); + } + + @Override + @AvailabilityStatus + public int getAvailabilityStatus() { + if (!Flags.addBrightnessSettingsInSuw()) { + return CONDITIONALLY_UNAVAILABLE; + } + return super.getAvailabilityStatus(); + } +} diff --git a/src/com/android/settings/display/BrightnessLevelPreferenceController.java b/src/com/android/settings/display/BrightnessLevelPreferenceController.java index a32c965cb29..96043db4c41 100644 --- a/src/com/android/settings/display/BrightnessLevelPreferenceController.java +++ b/src/com/android/settings/display/BrightnessLevelPreferenceController.java @@ -20,7 +20,6 @@ import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX; import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MIN; import static com.android.settingslib.display.BrightnessUtils.convertLinearToGammaFloat; -import android.annotation.Nullable; import android.app.ActivityOptions; import android.content.ContentResolver; import android.content.Context; @@ -37,12 +36,13 @@ import android.os.UserManager; import android.provider.Settings.System; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.accessibility.Flags; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.SettingsBaseActivity; @@ -54,18 +54,17 @@ import com.android.settingslib.transition.SettingsTransitionHelper; import java.text.NumberFormat; +/** + * The top-level preference controller that updates the adaptive brightness level. + */ public class BrightnessLevelPreferenceController extends BasePreferenceController implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop { - - private static final String TAG = "BrightnessPrefCtrl"; - private static final Uri BRIGHTNESS_ADJ_URI; private final ContentResolver mContentResolver; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final DisplayManager mDisplayManager; @Nullable private Preference mPreference; - private boolean mInSetupWizard; static { BRIGHTNESS_ADJ_URI = System.getUriFor(System.SCREEN_AUTO_BRIGHTNESS_ADJ); @@ -94,11 +93,13 @@ public class BrightnessLevelPreferenceController extends BasePreferenceControlle } }; - public BrightnessLevelPreferenceController(Context context, Lifecycle lifecycle) { + public BrightnessLevelPreferenceController(@NonNull Context context, + @Nullable Lifecycle lifecycle) { this(context, context.getString(R.string.preference_key_brightness_level), lifecycle); } - private BrightnessLevelPreferenceController(Context context, String key, Lifecycle lifecycle) { + private BrightnessLevelPreferenceController(@NonNull Context context, @NonNull String key, + @Nullable Lifecycle lifecycle) { super(context, key); mDisplayManager = context.getSystemService(DisplayManager.class); @@ -108,15 +109,8 @@ public class BrightnessLevelPreferenceController extends BasePreferenceControlle mContentResolver = mContext.getContentResolver(); } - public void setInSetupWizard(boolean inSetupWizard) { - mInSetupWizard = inSetupWizard; - } - @Override public int getAvailabilityStatus() { - if (mInSetupWizard && !Flags.addBrightnessSettingsInSuw()) { - return CONDITIONALLY_UNAVAILABLE; - } return AVAILABLE; } diff --git a/src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizard.java b/src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizard.java new file mode 100644 index 00000000000..6e002aed5fa --- /dev/null +++ b/src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizard.java @@ -0,0 +1,47 @@ +/* + * 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.settings.display; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settings.accessibility.Flags; +import com.android.settingslib.core.lifecycle.Lifecycle; + +/** + * The top-level preference controller that updates the adaptive brightness level in the + * SetupWizard. + */ +public class BrightnessLevelPreferenceControllerForSetupWizard extends + BrightnessLevelPreferenceController { + + public BrightnessLevelPreferenceControllerForSetupWizard(@NonNull Context context, + @Nullable Lifecycle lifecycle) { + super(context, lifecycle); + } + + @Override + @AvailabilityStatus + public int getAvailabilityStatus() { + if (!Flags.addBrightnessSettingsInSuw()) { + return CONDITIONALLY_UNAVAILABLE; + } + return super.getAvailabilityStatus(); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java index 2ae598418ce..58578e76f50 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java @@ -46,8 +46,7 @@ import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; -import com.android.settings.display.AutoBrightnessPreferenceController; -import com.android.settings.display.BrightnessLevelPreferenceController; +import com.android.settings.display.BrightnessLevelPreferenceControllerForSetupWizard; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.core.AbstractPreferenceController; @@ -146,16 +145,15 @@ public class AccessibilitySettingsForSetupWizardTest { } @Test - public void createPreferenceControllers_brightnessPreferencesControllersAreCreated() { + public void createPreferenceControllers_lifeCycleDependencyControllerIsCreated() { mFragment.onAttach(mContext); List controllers = mFragment.createPreferenceControllers(mContext); assertTrue(controllers.stream().anyMatch( - controller -> controller instanceof BrightnessLevelPreferenceController)); - assertTrue(controllers.stream().anyMatch( - controller -> controller instanceof AutoBrightnessPreferenceController)); + controller -> + controller instanceof BrightnessLevelPreferenceControllerForSetupWizard)); } private void addEnabledServiceInfo(ComponentName componentName, boolean isAccessibilityTool) { diff --git a/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizardTest.java b/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizardTest.java new file mode 100644 index 00000000000..1113d688f2b --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerForSetupWizardTest.java @@ -0,0 +1,92 @@ +/* + * 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.settings.display; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import com.android.settings.accessibility.Flags; +import com.android.settings.testutils.shadow.SettingsShadowResources; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +/** + * Tests for {@link AutoBrightnessPreferenceControllerForSetupWizard}. + */ +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {SettingsShadowResources.class}) +public class AutoBrightnessPreferenceControllerForSetupWizardTest { + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private static final String PREFERENCE_KEY = "auto_brightness"; + + private Context mContext; + private AutoBrightnessPreferenceControllerForSetupWizard mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = + new AutoBrightnessPreferenceControllerForSetupWizard(mContext, PREFERENCE_KEY); + } + + @Test + @EnableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) + public void getAvailabilityStatus_configTrueAndFlagOn_shouldReturnAvailableUnsearchable() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_automatic_brightness_available, true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); + } + + @Test + @EnableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) + public void getAvailabilityStatus_configFalseSetAndFlagOn_shouldReturnUnsupportedOnDevice() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_automatic_brightness_available, false); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + @DisableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) + public void getAvailabilityStatus_flagOff_shouldReturnConditionallyUnavailable() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_automatic_brightness_available, true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } +} + diff --git a/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java index 13cd86d5a2a..0122044f13c 100644 --- a/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AutoBrightnessPreferenceControllerTest.java @@ -21,24 +21,18 @@ import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL; import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; -import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; import android.content.ContentResolver; import android.content.Context; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import com.android.settings.R; -import com.android.settings.accessibility.Flags; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; @@ -46,13 +40,13 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +/** + * Tests for {@link AutoBrightnessPreferenceController}. + */ @RunWith(RobolectricTestRunner.class) @Config(shadows = {SettingsShadowResources.class}) public class AutoBrightnessPreferenceControllerTest { - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - private static final String PREFERENCE_KEY = "auto_brightness"; private Context mContext; @@ -130,34 +124,13 @@ public class AutoBrightnessPreferenceControllerTest { } @Test - public void getAvailabilityStatusNotInSUW_configTrueSet_shouldReturnAvailableUnsearchable() { + public void getAvailabilityStatus_configTrueSet_shouldReturnAvailableUnsearchable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_automatic_brightness_available, true); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); } - @Test - @EnableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) - public void getAvailabilityStatusInSUW_configTrueAndFlagOn_shouldReturnAvailableUnsearchable() { - SettingsShadowResources.overrideResource( - com.android.internal.R.bool.config_automatic_brightness_available, true); - mController.setInSetupWizard(true); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); - } - - @Test - @DisableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) - public void - getAvailabilityStatusInSUW_configTrueAndFlagOff_shouldReturnConditionallyUnavailable() { - SettingsShadowResources.overrideResource( - com.android.internal.R.bool.config_automatic_brightness_available, true); - mController.setInSetupWizard(true); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); - } - @Test public void getAvailabilityStatus_configFalseSet_shouldReturnUnsupportedOnDevice() { SettingsShadowResources.overrideResource( diff --git a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizardTest.java b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizardTest.java new file mode 100644 index 00000000000..25ddd1e6003 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerForSetupWizardTest.java @@ -0,0 +1,69 @@ +/* + * 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.settings.display; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import com.android.settings.accessibility.Flags; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +/** + * Tests for {@link BrightnessLevelPreferenceControllerForSetupWizard}. + */ +@RunWith(RobolectricTestRunner.class) +public class BrightnessLevelPreferenceControllerForSetupWizardTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private Context mContext; + private BrightnessLevelPreferenceControllerForSetupWizard mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new BrightnessLevelPreferenceControllerForSetupWizard(mContext, + /* lifecycle= */ null); + } + + @Test + @EnableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) + public void getAvailabilityStatus_flagOn_shouldReturnAvailable() { + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + @DisableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) + public void getAvailabilityStatus_flagOff_shouldReturnConditionallyUnavailable() { + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } +} diff --git a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java index 009ca95e4d3..eb830404307 100644 --- a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java @@ -33,9 +33,6 @@ import android.content.Context; import android.content.Intent; import android.hardware.display.BrightnessInfo; import android.os.PowerManager; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings.System; import android.view.Display; @@ -43,12 +40,10 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settings.accessibility.Flags; import com.android.settings.core.SettingsBaseActivity; import com.android.settingslib.transition.SettingsTransitionHelper; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -61,12 +56,11 @@ import org.robolectric.shadows.ShadowActivity; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowContentResolver; +/** + * Tests for {@link BrightnessLevelPreferenceController}. + */ @RunWith(RobolectricTestRunner.class) public class BrightnessLevelPreferenceControllerTest { - - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - @Mock private PowerManager mPowerManager; @Mock @@ -95,28 +89,14 @@ public class BrightnessLevelPreferenceControllerTest { mPowerManager); when(mScreen.findPreference(anyString())).thenReturn(mPreference); doReturn(mDisplay).when(mContext).getDisplay(); - mController = spy(new BrightnessLevelPreferenceController(mContext, null)); + mController = spy(new BrightnessLevelPreferenceController(mContext, /* lifecycle= */ null)); } @Test - public void isAvailable_shouldAlwaysReturnTrueWhenNotInSetupWizard() { + public void isAvailable_shouldAlwaysReturnTrue() { assertThat(mController.isAvailable()).isTrue(); } - @Test - @EnableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) - public void isAvailable_inSetupWizardAndFlagOn_shouldReturnTrue() { - mController.setInSetupWizard(true); - assertThat(mController.isAvailable()).isTrue(); - } - - @Test - @DisableFlags(Flags.FLAG_ADD_BRIGHTNESS_SETTINGS_IN_SUW) - public void isAvailable_inSetupWizardAndFlagOff_shouldReturnFalse() { - mController.setInSetupWizard(true); - assertThat(mController.isAvailable()).isFalse(); - } - @Test public void onStart_shouldRegisterObserver() { BrightnessLevelPreferenceController controller = From e060aeb1e12eb3a6750767d0f52f267565122e2c Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Wed, 18 Sep 2024 09:25:38 +0800 Subject: [PATCH 03/11] Migrate the Legal Info page to Catalyst Test: atest LegalPreferenceTest Test: atest LegalSettingsScreenTest Test: atest WallpaperAttributionsPreferenceTest Bug: 360061554 Flag: com.android.settings.flags.catalyst_legal_information Change-Id: Ic15384e853584b72a847e1a10713a0c3c29273a7 --- src/com/android/settings/LegalSettings.java | 11 +++ .../legal/CopyrightPreferenceController.java | 2 + .../deviceinfo/legal/LegalPreference.kt | 58 ++++++++++++ .../legal/LegalPreferenceController.java | 2 + .../deviceinfo/legal/LegalSettingsScreen.kt | 55 +++++++++++ .../legal/LicensePreferenceController.java | 2 + ...oduleLicensesListPreferenceController.java | 2 + .../deviceinfo/legal/ModuleLicensesScreen.kt | 61 ++++++++++++ .../legal/TermsPreferenceController.java | 2 + .../legal/WallpaperAttributionsPreference.kt | 49 ++++++++++ ...paperAttributionsPreferenceController.java | 2 + .../WebViewLicensePreferenceController.java | 2 + .../CopyrightPreferenceControllerTest.java | 2 + .../deviceinfo/legal/LegalPreferenceTest.kt | 92 +++++++++++++++++++ .../legal/LegalSettingsScreenTest.kt | 53 +++++++++++ .../LicensePreferenceControllerTest.java | 2 + .../legal/TermsPreferenceControllerTest.java | 2 + ...rAttributionsPreferenceControllerTest.java | 4 +- .../WallpaperAttributionsPreferenceTest.kt | 57 ++++++++++++ ...ebViewLicensePreferenceControllerTest.java | 2 + 20 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/deviceinfo/legal/LegalPreference.kt create mode 100644 src/com/android/settings/deviceinfo/legal/LegalSettingsScreen.kt create mode 100644 src/com/android/settings/deviceinfo/legal/ModuleLicensesScreen.kt create mode 100644 src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreference.kt create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/legal/LegalPreferenceTest.kt create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/legal/LegalSettingsScreenTest.kt create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceTest.kt diff --git a/src/com/android/settings/LegalSettings.java b/src/com/android/settings/LegalSettings.java index 9cb3bf4ef84..e48da2663b9 100644 --- a/src/com/android/settings/LegalSettings.java +++ b/src/com/android/settings/LegalSettings.java @@ -17,8 +17,13 @@ package com.android.settings; import android.app.settings.SettingsEnums; +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.deviceinfo.legal.LegalSettingsScreen; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; @@ -44,4 +49,10 @@ public class LegalSettings extends DashboardFragment { public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.about_legal); + + @Nullable + @Override + public String getPreferenceScreenBindingKey(@NonNull Context context) { + return LegalSettingsScreen.KEY; + } } diff --git a/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceController.java b/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceController.java index 68e51f40df7..4c2413a8c23 100644 --- a/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceController.java +++ b/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.deviceinfo.legal; import android.content.Context; import android.content.Intent; +// LINT.IfChange public class CopyrightPreferenceController extends LegalPreferenceController { private static final Intent INTENT = new Intent("android.settings.COPYRIGHT"); @@ -30,3 +31,4 @@ public class CopyrightPreferenceController extends LegalPreferenceController { return INTENT; } } +// LINT.ThenChange(LegalPreference.kt) diff --git a/src/com/android/settings/deviceinfo/legal/LegalPreference.kt b/src/com/android/settings/deviceinfo/legal/LegalPreference.kt new file mode 100644 index 00000000000..af3537bebb0 --- /dev/null +++ b/src/com/android/settings/deviceinfo/legal/LegalPreference.kt @@ -0,0 +1,58 @@ +/* + * 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.settings.deviceinfo.legal + +import android.content.Context +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.ResolveInfo +import androidx.annotation.StringRes +import com.android.settingslib.metadata.PreferenceAvailabilityProvider +import com.android.settingslib.metadata.PreferenceMetadata +import com.android.settingslib.metadata.PreferenceTitleProvider + +// LINT.IfChange +class LegalPreference( + override val key: String, + @StringRes val defaultTitle: Int = 0, + val intentAction: String, +) : PreferenceMetadata, PreferenceTitleProvider, PreferenceAvailabilityProvider { + + override fun getTitle(context: Context): CharSequence? { + val resolveInfo = + findMatchingSpecificActivity(context) ?: return context.getText(defaultTitle) + return resolveInfo.loadLabel(context.packageManager) + } + + override fun isAvailable(context: Context) = (findMatchingSpecificActivity(context) != null) + + override fun intent(context: Context) = + findMatchingSpecificActivity(context)?.let { + Intent() + .setClassName(it.activityInfo.packageName, it.activityInfo.name) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + + private fun findMatchingSpecificActivity(context: Context): ResolveInfo? { + val intent = Intent(intentAction) + // Find the activity that is in the system image + val list: List = context.packageManager.queryIntentActivities(intent, 0) + return list.firstOrNull { + (it.activityInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0 + } + } +} +// LINT.ThenChange(LegalPreferenceController.java) diff --git a/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java b/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java index fe45923d60b..adbc2d75a3c 100644 --- a/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java +++ b/src/com/android/settings/deviceinfo/legal/LegalPreferenceController.java @@ -27,6 +27,7 @@ import com.android.settings.core.BasePreferenceController; import java.util.List; +// LINT.IfChange public abstract class LegalPreferenceController extends BasePreferenceController { private final PackageManager mPackageManager; private Preference mPreference; @@ -94,3 +95,4 @@ public abstract class LegalPreferenceController extends BasePreferenceController mPreference.setTitle(resolveInfo.loadLabel(mPackageManager)); } } +// LINT.ThenChange(LegalPreference.kt) diff --git a/src/com/android/settings/deviceinfo/legal/LegalSettingsScreen.kt b/src/com/android/settings/deviceinfo/legal/LegalSettingsScreen.kt new file mode 100644 index 00000000000..f990b5dbeb0 --- /dev/null +++ b/src/com/android/settings/deviceinfo/legal/LegalSettingsScreen.kt @@ -0,0 +1,55 @@ +/* + * 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.settings.deviceinfo.legal + +import android.content.Context +import com.android.settings.LegalSettings +import com.android.settings.R +import com.android.settings.flags.Flags +import com.android.settingslib.metadata.ProvidePreferenceScreen +import com.android.settingslib.metadata.preferenceHierarchy +import com.android.settingslib.preference.PreferenceScreenCreator + +@ProvidePreferenceScreen +open class LegalSettingsScreen : PreferenceScreenCreator { + override val key: String + get() = KEY + + override val title: Int + get() = R.string.legal_information + + override fun isFlagEnabled(context: Context) = Flags.catalystLegalInformation() + + override fun fragmentClass() = LegalSettings::class.java + + override fun getPreferenceHierarchy(context: Context) = + preferenceHierarchy(this) { + +LegalPreference("copyright", R.string.copyright_title, "android.settings.COPYRIGHT") + +LegalPreference("license", R.string.license_title, "android.settings.LICENSE") + +LegalPreference("terms", R.string.terms_title, "android.settings.TERMS") + +ModuleLicensesScreen.KEY // Use screen key in case it is overlaid. + +LegalPreference( + "webview_license", + R.string.webview_license_title, + "android.settings.WEBVIEW_LICENSE", + ) + +WallpaperAttributionsPreference() + } + + companion object { + const val KEY = "legal_information" + } +} diff --git a/src/com/android/settings/deviceinfo/legal/LicensePreferenceController.java b/src/com/android/settings/deviceinfo/legal/LicensePreferenceController.java index 67af15b4fc6..9bd74fd3a8d 100644 --- a/src/com/android/settings/deviceinfo/legal/LicensePreferenceController.java +++ b/src/com/android/settings/deviceinfo/legal/LicensePreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.deviceinfo.legal; import android.content.Context; import android.content.Intent; +// LINT.IfChange public class LicensePreferenceController extends LegalPreferenceController { private static final Intent INTENT = new Intent("android.settings.LICENSE"); @@ -30,3 +31,4 @@ public class LicensePreferenceController extends LegalPreferenceController { return INTENT; } } +// LINT.ThenChange(LegalPreference.kt) diff --git a/src/com/android/settings/deviceinfo/legal/ModuleLicensesListPreferenceController.java b/src/com/android/settings/deviceinfo/legal/ModuleLicensesListPreferenceController.java index 9faff856074..7b6ca460cbe 100644 --- a/src/com/android/settings/deviceinfo/legal/ModuleLicensesListPreferenceController.java +++ b/src/com/android/settings/deviceinfo/legal/ModuleLicensesListPreferenceController.java @@ -24,6 +24,7 @@ import com.android.settings.core.BasePreferenceController; import java.util.List; +// LINT.IfChange public class ModuleLicensesListPreferenceController extends BasePreferenceController { public ModuleLicensesListPreferenceController(Context context, String preferenceKey) { @@ -39,3 +40,4 @@ public class ModuleLicensesListPreferenceController extends BasePreferenceContro : CONDITIONALLY_UNAVAILABLE; } } +// LINT.ThenChange(ModuleLicensesScreen.kt) diff --git a/src/com/android/settings/deviceinfo/legal/ModuleLicensesScreen.kt b/src/com/android/settings/deviceinfo/legal/ModuleLicensesScreen.kt new file mode 100644 index 00000000000..c7f5e9c05d6 --- /dev/null +++ b/src/com/android/settings/deviceinfo/legal/ModuleLicensesScreen.kt @@ -0,0 +1,61 @@ +/* + * 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.settings.deviceinfo.legal + +import android.content.Context +import com.android.settings.R +import com.android.settingslib.metadata.PreferenceAvailabilityProvider +import com.android.settingslib.metadata.ProvidePreferenceScreen +import com.android.settingslib.metadata.preferenceHierarchy +import com.android.settingslib.preference.PreferenceScreenCreator + +// LINT.IfChange +@ProvidePreferenceScreen +class ModuleLicensesScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider { + override val key: String + get() = KEY + + override val title: Int + get() = R.string.module_license_title + + // We need to avoid directly assign fragment attribute in the bind() API. So we need to create + // a screen and provide it to its parent screen LegalSettingsScreen. + // By the way, we also need to set the isFlagEnabled() as false. Let system render the legacy + // UI. The hierarchy will be added while migrating this page. + override fun isFlagEnabled(context: Context) = false + + override fun fragmentClass() = ModuleLicensesDashboard::class.java + + override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} + + override fun isAvailable(context: Context): Boolean { + val modules = context.packageManager.getInstalledModules(/* flags= */ 0) + return modules.any { + try { + ModuleLicenseProvider.getPackageAssetManager(context.packageManager, it.packageName) + .list("") + ?.contains(ModuleLicenseProvider.GZIPPED_LICENSE_FILE_NAME) == true + } catch (e: Exception) { + false + } + } + } + + companion object { + const val KEY = "module_license" + } +} +// LINT.ThenChange(ModuleLicensesListPreferenceController.java) diff --git a/src/com/android/settings/deviceinfo/legal/TermsPreferenceController.java b/src/com/android/settings/deviceinfo/legal/TermsPreferenceController.java index bccc44579b9..764bde44a04 100644 --- a/src/com/android/settings/deviceinfo/legal/TermsPreferenceController.java +++ b/src/com/android/settings/deviceinfo/legal/TermsPreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.deviceinfo.legal; import android.content.Context; import android.content.Intent; +// LINT.IfChange public class TermsPreferenceController extends LegalPreferenceController { private static final Intent INTENT = new Intent("android.settings.TERMS"); @@ -30,3 +31,4 @@ public class TermsPreferenceController extends LegalPreferenceController { return INTENT; } } +// LINT.ThenChange(LegalPreference.kt) diff --git a/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreference.kt b/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreference.kt new file mode 100644 index 00000000000..7a934c29058 --- /dev/null +++ b/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreference.kt @@ -0,0 +1,49 @@ +/* + * 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.settings.deviceinfo.legal + +import android.content.Context +import androidx.preference.Preference +import com.android.settings.R +import com.android.settingslib.metadata.PreferenceAvailabilityProvider +import com.android.settingslib.metadata.PreferenceMetadata +import com.android.settingslib.preference.PreferenceBinding + +// LINT.IfChange +class WallpaperAttributionsPreference : + PreferenceMetadata, PreferenceBinding, PreferenceAvailabilityProvider { + override val key: String + get() = KEY + + override val title: Int + get() = R.string.wallpaper_attributions + + override val summary: Int + get() = R.string.wallpaper_attributions_values + + override fun bind(preference: Preference, metadata: PreferenceMetadata) { + super.bind(preference, metadata) + preference.isSelectable = false + } + + override fun isAvailable(context: Context) = + context.resources.getBoolean(R.bool.config_show_wallpaper_attribution) + + companion object { + const val KEY = "wallpaper_attributions" + } +} +// LINT.ThenChange(WallpaperAttributionsPreferenceController.java) diff --git a/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceController.java b/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceController.java index caa5afcdc58..cc9c0928df9 100644 --- a/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceController.java +++ b/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceController.java @@ -20,6 +20,7 @@ import android.content.Context; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +// LINT.IfChange public class WallpaperAttributionsPreferenceController extends BasePreferenceController { public WallpaperAttributionsPreferenceController(Context context, String key) { @@ -33,3 +34,4 @@ public class WallpaperAttributionsPreferenceController extends BasePreferenceCon : UNSUPPORTED_ON_DEVICE; } } +// LINT.ThenChange(WallpaperAttributionsPreference.kt) diff --git a/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceController.java b/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceController.java index 9d8b3f95027..ebb9152d80a 100644 --- a/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceController.java +++ b/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.deviceinfo.legal; import android.content.Context; import android.content.Intent; +// LINT.IfChange public class WebViewLicensePreferenceController extends LegalPreferenceController { private static final Intent INTENT = new Intent("android.settings.WEBVIEW_LICENSE"); @@ -30,3 +31,4 @@ public class WebViewLicensePreferenceController extends LegalPreferenceControlle return INTENT; } } +// LINT.ThenChange(LegalPreference.kt) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceControllerTest.java index 3a6e494ff04..28772984fd0 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/CopyrightPreferenceControllerTest.java @@ -45,6 +45,7 @@ import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; +// LINT.IfChange @RunWith(RobolectricTestRunner.class) public class CopyrightPreferenceControllerTest { @@ -119,3 +120,4 @@ public class CopyrightPreferenceControllerTest { return testResolveInfo; } } +// LINT.ThenChange(LegalPreferenceTest.kt) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/LegalPreferenceTest.kt b/tests/robotests/src/com/android/settings/deviceinfo/legal/LegalPreferenceTest.kt new file mode 100644 index 00000000000..5b65b164f82 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/LegalPreferenceTest.kt @@ -0,0 +1,92 @@ +/* + * 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.settings.deviceinfo.legal + +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import androidx.test.core.app.ApplicationProvider +import com.android.settings.R +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub +import org.robolectric.RobolectricTestRunner + +// LINT.IfChange +@RunWith(RobolectricTestRunner::class) +class LegalPreferenceTest { + private val pkgManager = mock() + + private val context: Context = + object : ContextWrapper(ApplicationProvider.getApplicationContext()) { + override fun getPackageManager(): PackageManager = pkgManager + } + + private val copyrightPreference = + LegalPreference("copyright", R.string.copyright_title, "android.settings.COPYRIGHT") + + @Test + fun isAvailable_systemApp_shouldReturnTrue() { + val testResolveInfos: MutableList = ArrayList() + testResolveInfos.add(getTestResolveInfo(/* isSystemApp= */ true)) + + pkgManager.stub { + on { queryIntentActivities(any(Intent::class.java), anyInt()) } doReturn + testResolveInfos + } + + assertThat(copyrightPreference.isAvailable(context)).isTrue() + } + + @Test + fun isAvailable_nonSystemApp_shouldReturnFalse() { + val testResolveInfos: MutableList = ArrayList() + testResolveInfos.add(getTestResolveInfo(/* isSystemApp= */ false)) + + pkgManager.stub { + on { queryIntentActivities(any(Intent::class.java), anyInt()) } doReturn + testResolveInfos + } + + assertThat(copyrightPreference.isAvailable(context)).isFalse() + } + + private fun getTestResolveInfo(isSystemApp: Boolean): ResolveInfo { + val testResolveInfo = ResolveInfo() + val testAppInfo = ApplicationInfo() + if (isSystemApp) { + testAppInfo.flags = testAppInfo.flags or ApplicationInfo.FLAG_SYSTEM + } + + testResolveInfo.activityInfo = + ActivityInfo().apply { + name = "TestActivityName" + packageName = "TestPackageName" + applicationInfo = testAppInfo + } + return testResolveInfo + } +} +// LINT.ThenChange(CopyrightPreferenceControllerTest.java) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/LegalSettingsScreenTest.kt b/tests/robotests/src/com/android/settings/deviceinfo/legal/LegalSettingsScreenTest.kt new file mode 100644 index 00000000000..48e21b47dcc --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/LegalSettingsScreenTest.kt @@ -0,0 +1,53 @@ +/* + * 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.settings.deviceinfo.legal + +import android.content.Context +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import android.text.TextUtils +import androidx.test.core.app.ApplicationProvider +import com.android.settings.flags.Flags +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class LegalSettingsScreenTest { + @get:Rule val setFlagsRule = SetFlagsRule() + private val context: Context = ApplicationProvider.getApplicationContext() + private val legalSettingsScreen = LegalSettingsScreen() + + @Test + fun screenKey_exist() { + assertThat(TextUtils.equals(legalSettingsScreen.key, LegalSettingsScreen.KEY)).isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_CATALYST_LEGAL_INFORMATION) + fun isFlagEnabled_returnTrue() { + assertThat(legalSettingsScreen.isFlagEnabled(context)).isTrue() + } + + @Test + @DisableFlags(Flags.FLAG_CATALYST_LEGAL_INFORMATION) + fun isFlagDisabled_returnTrue() { + assertThat(legalSettingsScreen.isFlagEnabled(context)).isFalse() + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/LicensePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/legal/LicensePreferenceControllerTest.java index f51c7ad0e43..d6fdf73b3a2 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/legal/LicensePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/LicensePreferenceControllerTest.java @@ -45,6 +45,7 @@ import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; +// LINT.IfChange @RunWith(RobolectricTestRunner.class) public class LicensePreferenceControllerTest { @@ -119,3 +120,4 @@ public class LicensePreferenceControllerTest { return testResolveInfo; } } +// LINT.ThenChange(LegalPreferenceTest.kt) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/TermsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/legal/TermsPreferenceControllerTest.java index 2a91fe1ee65..f8ccd0e432c 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/legal/TermsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/TermsPreferenceControllerTest.java @@ -45,6 +45,7 @@ import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; +// LINT.IfChange @RunWith(RobolectricTestRunner.class) public class TermsPreferenceControllerTest { @@ -119,3 +120,4 @@ public class TermsPreferenceControllerTest { return testResolveInfo; } } +// LINT.ThenChange(LegalPreferenceTest.kt) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceControllerTest.java index c06f069e2d5..2f8a8d44c2f 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceControllerTest.java @@ -29,6 +29,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +// LINT.IfChange @RunWith(RobolectricTestRunner.class) public class WallpaperAttributionsPreferenceControllerTest { @@ -54,4 +55,5 @@ public class WallpaperAttributionsPreferenceControllerTest { assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE); } -} \ No newline at end of file +} +// LINT.ThenChange(WallpaperAttributionsPreferenceTest.kt) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceTest.kt b/tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceTest.kt new file mode 100644 index 00000000000..00e0b0150f3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/WallpaperAttributionsPreferenceTest.kt @@ -0,0 +1,57 @@ +/* + * 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.settings.deviceinfo.legal + +import android.content.Context +import android.content.ContextWrapper +import android.content.res.Resources +import androidx.test.core.app.ApplicationProvider +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub +import org.robolectric.RobolectricTestRunner + +// LINT.IfChange +@RunWith(RobolectricTestRunner::class) +class WallpaperAttributionsPreferenceTest { + private val mockResources = mock() + + private val context: Context = + object : ContextWrapper(ApplicationProvider.getApplicationContext()) { + override fun getResources(): Resources = mockResources + } + + private val wallpaperAttributionsPreference = WallpaperAttributionsPreference() + + @Test + fun isAvailable_configTrue_shouldReturnTrue() { + mockResources.stub { on { getBoolean(anyInt()) } doReturn true } + + assertThat(wallpaperAttributionsPreference.isAvailable(context)).isTrue() + } + + @Test + fun isAvailable_configFalse_shouldReturnFalse() { + mockResources.stub { on { getBoolean(anyInt()) } doReturn false } + + assertThat(wallpaperAttributionsPreference.isAvailable(context)).isFalse() + } +} +// LINT.ThenChange(WallpaperAttributionsPreferenceControllerTest.java) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceControllerTest.java index 55604c33373..0836839516c 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/WebViewLicensePreferenceControllerTest.java @@ -45,6 +45,7 @@ import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; +// LINT.IfChange @RunWith(RobolectricTestRunner.class) public class WebViewLicensePreferenceControllerTest { @@ -119,3 +120,4 @@ public class WebViewLicensePreferenceControllerTest { return testResolveInfo; } } +// LINT.ThenChange(LegalPreferenceTest.kt) From 6231453e914da015c719aff2c3e3acba8653bfdd Mon Sep 17 00:00:00 2001 From: Dongzhuo Zhang Date: Tue, 24 Sep 2024 22:28:22 +0000 Subject: [PATCH 04/11] Add contacts storage setting entry in app settings page. Test: atest SettingsRoboTests:com.android.settings.applications.contacts.ContactsStoragePreferenceControllerTest Bug: 368641291 Flag: com.android.settings.flags.enable_contacts_default_account_in_settings Change-Id: I8da16f24b17e44dc0ea417cffabd85c36d7edc5f --- res/values/strings.xml | 7 + res/xml/apps.xml | 9 + .../ContactsStoragePreferenceController.java | 68 ++++++++ ...ntactsStoragePreferenceControllerTest.java | 162 ++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index fb95aa3bd39..85d3fadecdc 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13668,4 +13668,11 @@ Search Settings + + + contacts, storage, account + + Contacts storage + + No default set diff --git a/res/xml/apps.xml b/res/xml/apps.xml index 2ffd0b1eaba..a66cea3d698 100644 --- a/res/xml/apps.xml +++ b/res/xml/apps.xml @@ -79,6 +79,15 @@ android:key="dashboard_tile_placeholder" android:order="10"/> + + + Date: Wed, 25 Sep 2024 07:20:40 +0800 Subject: [PATCH 05/11] Migrate Android version preference Bug: 365886251 Flag: com.android.settings.flags.catalyst_firmware_version Test: Unit Change-Id: I0a15cd460543a7dd84edc5c3a5a2ff900aeba13f --- .../FirmwareVersionDetailPreference.kt | 104 ++++++++++++++++++ ...wareVersionDetailPreferenceController.java | 2 + .../firmwareversion/FirmwareVersionScreen.kt | 6 +- ...VersionDetailPreferenceControllerTest.java | 2 + .../FirmwareVersionDetailPreferenceTest.kt | 76 +++++++++++++ 5 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreference.kt create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceTest.kt diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreference.kt b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreference.kt new file mode 100644 index 00000000000..a039a3a4e82 --- /dev/null +++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreference.kt @@ -0,0 +1,104 @@ +/* + * 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.settings.deviceinfo.firmwareversion + +import android.content.Context +import android.content.Intent +import android.os.Build +import android.os.SystemClock +import android.os.UserHandle +import android.os.UserManager +import androidx.preference.Preference +import com.android.internal.app.PlatLogoActivity +import com.android.settings.R +import com.android.settings.Utils +import com.android.settingslib.RestrictedLockUtils +import com.android.settingslib.RestrictedLockUtilsInternal +import com.android.settingslib.metadata.PreferenceMetadata +import com.android.settingslib.metadata.PreferenceSummaryProvider +import com.android.settingslib.preference.PreferenceBinding + +// LINT.IfChange +class FirmwareVersionDetailPreference : + PreferenceMetadata, + PreferenceSummaryProvider, + PreferenceBinding, + Preference.OnPreferenceClickListener { + + private val hits = LongArray(ACTIVITY_TRIGGER_COUNT) + + override val key: String + get() = "os_firmware_version" + + override val title: Int + get() = R.string.firmware_version + + override fun isIndexable(context: Context) = false + + override fun intent(context: Context): Intent? = + Intent(Intent.ACTION_MAIN) + .setClassName("android", PlatLogoActivity::class.java.name) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + + override fun getSummary(context: Context): CharSequence? = + Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY + + override fun bind(preference: Preference, metadata: PreferenceMetadata) { + super.bind(preference, metadata) + preference.isCopyingEnabled = true + preference.onPreferenceClickListener = this + } + + // return true swallows the click event, while return false will start the intent + override fun onPreferenceClick(preference: Preference): Boolean { + if (Utils.isMonkeyRunning()) return true + + // remove oldest hit and check whether there are 3 clicks within 500ms + for (index in 1.. DELAY_TIMER_MILLIS) return true + + val context = preference.context + val userManager = context.getSystemService(Context.USER_SERVICE) as? UserManager + if (userManager?.hasUserRestriction(UserManager.DISALLOW_FUN) != true) return false + + // Sorry, no fun for you! + val myUserId = UserHandle.myUserId() + val enforcedAdmin = + RestrictedLockUtilsInternal.checkIfRestrictionEnforced( + context, + UserManager.DISALLOW_FUN, + myUserId, + ) ?: return true + val disallowedBySystem = + RestrictedLockUtilsInternal.hasBaseUserRestriction( + context, + UserManager.DISALLOW_FUN, + myUserId, + ) + if (!disallowedBySystem) { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, enforcedAdmin) + } + return true + } + + companion object { + const val DELAY_TIMER_MILLIS = 500L + const val ACTIVITY_TRIGGER_COUNT = 3 + } +} +// LINT.ThenChange(FirmwareVersionDetailPreferenceController.java) diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java index e6ac6069d9a..7b0b2a67c63 100644 --- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java +++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java @@ -33,6 +33,7 @@ import com.android.settings.core.BasePreferenceController; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; +// LINT.IfChange public class FirmwareVersionDetailPreferenceController extends BasePreferenceController { private static final String TAG = "firmwareDialogCtrl"; @@ -125,3 +126,4 @@ public class FirmwareVersionDetailPreferenceController extends BasePreferenceCon mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId()); } } +// LINT.ThenChange(FirmwareVersionDetailPreference.kt) diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionScreen.kt b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionScreen.kt index 0075068f4dc..fbc749bb1ec 100644 --- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionScreen.kt +++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionScreen.kt @@ -20,7 +20,6 @@ import android.content.Context import android.os.Build import com.android.settings.R import com.android.settings.flags.Flags -import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceSummaryProvider import com.android.settingslib.metadata.ProvidePreferenceScreen import com.android.settingslib.metadata.preferenceHierarchy @@ -47,7 +46,7 @@ class FirmwareVersionScreen : PreferenceScreenCreator, PreferenceSummaryProvider override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) { - +PreferenceWidget("os_firmware_version", R.string.firmware_version) + +FirmwareVersionDetailPreference() +SecurityPatchLevelPreference() +MainlineModuleVersionPreference() +BasebandVersionPreference() @@ -55,9 +54,6 @@ class FirmwareVersionScreen : PreferenceScreenCreator, PreferenceSummaryProvider +SimpleBuildNumberPreference() } - private class PreferenceWidget(override val key: String, override val title: Int) : - PreferenceMetadata - companion object { const val KEY = "firmware_version" } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceControllerTest.java index 420b9a337b4..51763bc2a71 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceControllerTest.java @@ -41,6 +41,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; +// LINT.IfChange @RunWith(RobolectricTestRunner.class) public class FirmwareVersionDetailPreferenceControllerTest { @@ -112,3 +113,4 @@ public class FirmwareVersionDetailPreferenceControllerTest { } } } +// LINT.ThenChange(FirmwareVersionDetailPreferenceTest.kt) diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceTest.kt b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceTest.kt new file mode 100644 index 00000000000..69ea549bc43 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceTest.kt @@ -0,0 +1,76 @@ +/* + * 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.settings.deviceinfo.firmwareversion + +import android.content.Context +import android.content.ContextWrapper +import android.os.Build +import android.os.SystemClock +import android.os.UserManager +import androidx.preference.Preference +import androidx.test.core.app.ApplicationProvider +import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionDetailPreference.Companion.DELAY_TIMER_MILLIS +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.robolectric.RobolectricTestRunner + +// LINT.IfChange +@RunWith(RobolectricTestRunner::class) +class FirmwareVersionDetailPreferenceTest { + private var userManager: UserManager? = null + + private val context: Context = + object : ContextWrapper(ApplicationProvider.getApplicationContext()) { + override fun getSystemService(name: String): Any? = + if (name == Context.USER_SERVICE) userManager else super.getSystemService(name) + } + + private val preference = Preference(context) + + private val firmwareVersionDetailPreference = FirmwareVersionDetailPreference() + + @Test + fun getSummary() { + assertThat(firmwareVersionDetailPreference.getSummary(context)) + .isEqualTo(Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY) + } + + @Test + fun onPreferenceClick_hits() { + prepareClick() + assertThat(firmwareVersionDetailPreference.onPreferenceClick(preference)).isFalse() + } + + @Test + fun onPreferenceClick_restricted() { + prepareClick() + userManager = mock { on { hasUserRestriction(UserManager.DISALLOW_FUN) } doReturn true } + assertThat(firmwareVersionDetailPreference.onPreferenceClick(preference)).isTrue() + } + + private fun prepareClick() { + SystemClock.sleep(DELAY_TIMER_MILLIS + 1) + assertThat(SystemClock.uptimeMillis()).isGreaterThan(DELAY_TIMER_MILLIS) + for (i in 1.. Date: Wed, 25 Sep 2024 10:26:47 +0800 Subject: [PATCH 06/11] Use hasScrollAction in ApnEditPageProviderTest Instead of assuming a fixed tree structure in testing. Fix: 369416630 Flag: EXEMPT gradle only Test: atest ApnEditPageProviderTest Change-Id: I0a50e7665d9049e089b5a0877f17d1f736ee3332 --- .../network/apn/ApnEditPageProviderTest.kt | 87 ++++++++----------- 1 file changed, 35 insertions(+), 52 deletions(-) diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt index d310604ccf9..2f7417d212f 100644 --- a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt @@ -19,19 +19,16 @@ package com.android.settings.network.apn import android.content.Context import android.net.Uri import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasScrollAction import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createComposeRule -import androidx.compose.ui.test.onChild -import androidx.compose.ui.test.onChildAt import androidx.compose.ui.test.onNodeWithText -import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performScrollToNode import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.R -import com.google.common.truth.Truth +import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -39,8 +36,7 @@ import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) class ApnEditPageProviderTest { - @get:Rule - val composeTestRule = createComposeRule() + @get:Rule val composeTestRule = createComposeRule() private val context: Context = ApplicationProvider.getApplicationContext() private val apnName = "apn_name" @@ -51,86 +47,73 @@ class ApnEditPageProviderTest { private val apnProtocolOptions = context.resources.getStringArray(R.array.apn_protocol_entries).toList() private val passwordTitle = context.resources.getString(R.string.apn_password) - private val apnInit = ApnData( - name = apnName, - proxy = proxy, - port = port, - apnType = apnType, - apnRoaming = apnProtocolOptions.indexOf(apnRoaming), - ) - private val apnData = mutableStateOf( - apnInit - ) + private val apnInit = + ApnData( + name = apnName, + proxy = proxy, + port = port, + apnType = apnType, + apnRoaming = apnProtocolOptions.indexOf(apnRoaming), + ) + private val apnData = mutableStateOf(apnInit) private val uri = mock {} @Test fun apnEditPageProvider_name() { - Truth.assertThat(ApnEditPageProvider.name).isEqualTo("ApnEdit") + assertThat(ApnEditPageProvider.name).isEqualTo("ApnEdit") } @Test fun title_displayed() { - composeTestRule.setContent { - ApnPage(apnInit, remember { apnData }, uri) - } + composeTestRule.setContent { ApnPage(apnInit, apnData, uri) } + composeTestRule.onNodeWithText(context.getString(R.string.apn_edit)).assertIsDisplayed() } @Test fun name_displayed() { - composeTestRule.setContent { - ApnPage(apnInit, remember { apnData }, uri) - } + composeTestRule.setContent { ApnPage(apnInit, apnData, uri) } + composeTestRule.onNodeWithText(apnName, true).assertIsDisplayed() } @Test fun proxy_displayed() { - composeTestRule.setContent { - ApnPage(apnInit, remember { apnData }, uri) - } - composeTestRule.onRoot().onChild().onChildAt(0) - .performScrollToNode(hasText(proxy, true)) + composeTestRule.setContent { ApnPage(apnInit, apnData, uri) } + + composeTestRule.onNode(hasScrollAction()).performScrollToNode(hasText(proxy, true)) composeTestRule.onNodeWithText(proxy, true).assertIsDisplayed() } @Test fun port_displayed() { - composeTestRule.setContent { - ApnPage(apnInit, remember { apnData }, uri) - } - composeTestRule.onRoot().onChild().onChildAt(0) - .performScrollToNode(hasText(port, true)) + composeTestRule.setContent { ApnPage(apnInit, apnData, uri) } + + composeTestRule.onNode(hasScrollAction()).performScrollToNode(hasText(port, true)) composeTestRule.onNodeWithText(port, true).assertIsDisplayed() } @Test - fun apn_type_displayed() { - composeTestRule.setContent { - ApnPage(apnInit, remember { apnData }, uri) - } - composeTestRule.onRoot().onChild().onChildAt(0) - .performScrollToNode(hasText(apnType, true)) + fun apnType_displayed() { + composeTestRule.setContent { ApnPage(apnInit, apnData, uri) } + + composeTestRule.onNode(hasScrollAction()).performScrollToNode(hasText(apnType, true)) composeTestRule.onNodeWithText(apnType, true).assertIsDisplayed() } @Test - fun apn_roaming_displayed() { - composeTestRule.setContent { - ApnPage(apnInit, remember { apnData }, uri) - } - composeTestRule.onRoot().onChild().onChildAt(0) - .performScrollToNode(hasText(apnRoaming, true)) + fun apnRoaming_displayed() { + composeTestRule.setContent { ApnPage(apnInit, apnData, uri) } + + composeTestRule.onNode(hasScrollAction()).performScrollToNode(hasText(apnRoaming, true)) composeTestRule.onNodeWithText(apnRoaming, true).assertIsDisplayed() } @Test fun password_displayed() { - composeTestRule.setContent { - ApnPage(apnInit, remember { apnData }, uri) - } - composeTestRule.onRoot().onChild().onChildAt(0) - .performScrollToNode(hasText(passwordTitle, true)) + composeTestRule.setContent { ApnPage(apnInit, apnData, uri) } + + composeTestRule.onNode(hasScrollAction()).performScrollToNode(hasText(passwordTitle, true)) composeTestRule.onNodeWithText(passwordTitle, true).assertIsDisplayed() } -} \ No newline at end of file +} From 1c486036efcd95945b9bf53d37fbd5a463be9d6f Mon Sep 17 00:00:00 2001 From: Jacky Wang Date: Wed, 25 Sep 2024 11:58:10 +0800 Subject: [PATCH 07/11] Avoid potential ActivityNotFoundException Bug: 332202168 Flag: com.android.settings.flags.catalyst Test: Manual Change-Id: I74d7bbc9eb34e0f8d04cfb663b04393a3432e784 --- .../android/settings/dashboard/DashboardFragment.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java index 6333f22b95b..4d53772cf66 100644 --- a/src/com/android/settings/dashboard/DashboardFragment.java +++ b/src/com/android/settings/dashboard/DashboardFragment.java @@ -249,6 +249,15 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment @Override public boolean onPreferenceTreeClick(Preference preference) { + if (isCatalystEnabled()) { + Intent intent = preference.getIntent(); + if (intent != null && preference.getContext().getPackageManager().queryIntentActivities( + intent, 0).isEmpty()) { + Log.w(TAG, "No activity to start for " + intent); + return true; + } + } + final Collection> controllers = mPreferenceControllers.values(); for (List controllerList : controllers) { From 1020e7132de36e6e598326830670c73f6b548b8e Mon Sep 17 00:00:00 2001 From: Haijie Hong Date: Wed, 25 Sep 2024 13:48:33 +0800 Subject: [PATCH 08/11] Fix two-panel issue in tablet Keep the logic same as BlockingPrefWithSliceController. BUG: 343317785 Test: atest BluetoothDeviceDetailsViewModelTest Flag: com.android.settings.flags.enable_bluetooth_device_details_polish Change-Id: I77e62479def433869ae5e93987ec7069cc61173a --- .../ui/model/DeviceSettingPreferenceModel.kt | 7 ++++--- .../ui/view/DeviceDetailsFragmentFormatter.kt | 16 +++++++++++----- .../ui/view/DeviceDetailsMoreSettingsFragment.kt | 6 +++++- .../viewmodel/BluetoothDeviceDetailsViewModel.kt | 6 +++--- .../view/DeviceDetailsFragmentFormatterTest.kt | 4 +--- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt b/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt index f6e6f168144..b16bff1353b 100644 --- a/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt +++ b/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt @@ -16,6 +16,7 @@ package com.android.settings.bluetooth.ui.model +import android.content.Intent import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel @@ -31,7 +32,7 @@ sealed interface DeviceSettingPreferenceModel { val title: String, val summary: String? = null, val icon: DeviceSettingIcon? = null, - val onClick: (() -> Unit)? = null, + val intent: Intent? = null, ) : DeviceSettingPreferenceModel /** Models a switch preference. */ @@ -42,7 +43,7 @@ sealed interface DeviceSettingPreferenceModel { val icon: DeviceSettingIcon? = null, val checked: Boolean, val onCheckedChange: ((Boolean) -> Unit), - val onPrimaryClick: (() -> Unit)? = null, + val intent: Intent? = null, ) : DeviceSettingPreferenceModel /** Models a multi-toggle preference. */ @@ -71,6 +72,6 @@ sealed interface DeviceSettingPreferenceModel { data class HelpPreference( @DeviceSettingId override val id: Int, val icon: DeviceSettingIcon, - val onClick: (() -> Unit), + val intent: Intent, ) : DeviceSettingPreferenceModel } diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt index a5997e7bc83..074e520cbcc 100644 --- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt +++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt @@ -18,6 +18,7 @@ package com.android.settings.bluetooth.ui.view import android.bluetooth.BluetoothAdapter import android.content.Context +import android.content.Intent import android.media.AudioManager import android.os.Bundle import androidx.compose.animation.AnimatedVisibility @@ -101,13 +102,13 @@ class DeviceDetailsFragmentFormatterImpl( ) : DeviceDetailsFragmentFormatter { private val repository = featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository( - context, + fragment.requireActivity().application, bluetoothAdapter, fragment.lifecycleScope, ) private val spatialAudioInteractor = featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor( - context, + fragment.requireActivity().application, context.getSystemService(AudioManager::class.java), fragment.lifecycleScope, ) @@ -312,10 +313,10 @@ class DeviceDetailsFragmentFormatterImpl( return { deviceSettingIcon(model.icon) } } } - if (model.onPrimaryClick != null) { + if (model.intent != null) { TwoTargetSwitchPreference( switchPrefModel, - primaryOnClick = model.onPrimaryClick::invoke, + primaryOnClick = { startActivity(model.intent) }, ) } else { SwitchPreference(switchPrefModel) @@ -329,7 +330,7 @@ class DeviceDetailsFragmentFormatterImpl( override val title = model.title override val summary = { model.summary ?: "" } override val onClick = { - model.onClick?.invoke() + model.intent?.let { startActivity(it) } Unit } override val icon: (@Composable () -> Unit)? @@ -376,6 +377,11 @@ class DeviceDetailsFragmentFormatterImpl( icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) } } + private fun startActivity(intent: Intent) { + intent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) + } + private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}" companion object { diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt index c0fbd4f2c4a..98de96dfa0c 100644 --- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt +++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt @@ -19,6 +19,7 @@ package com.android.settings.bluetooth.ui.view import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager import android.content.Context +import android.content.Intent import android.graphics.PorterDuff import android.os.Bundle import android.view.Menu @@ -73,7 +74,10 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() { override fun onOptionsItemSelected(menuItem: MenuItem): Boolean { if (menuItem.itemId == MENU_HELP_ITEM_ID) { - helpItem.value?.let { it.onClick() } + helpItem.value?.intent?.let { + it.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + requireContext().startActivity(it) + } return true } return super.onOptionsItemSelected(menuItem) diff --git a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt index 67a0ebc8398..fe66cb5dd51 100644 --- a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt +++ b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt @@ -101,7 +101,7 @@ class BluetoothDeviceDetailsViewModel( DeviceSettingStateModel.ActionSwitchPreferenceState(newState) ) }, - onPrimaryClick = { intent?.let { application.startActivity(it) } }, + intent = intent, ) } else { DeviceSettingPreferenceModel.PlainPreference( @@ -109,7 +109,7 @@ class BluetoothDeviceDetailsViewModel( title = title, summary = summary, icon = icon, - onClick = { intent?.let { application.startActivity(it) } }, + intent = intent, ) } } @@ -119,7 +119,7 @@ class BluetoothDeviceDetailsViewModel( DeviceSettingPreferenceModel.HelpPreference( id = id, icon = DeviceSettingIcon.ResourceIcon(R.drawable.ic_help), - onClick = { application.startActivity(intent) }, + intent = intent, ) is DeviceSettingModel.MultiTogglePreference -> DeviceSettingPreferenceModel.MultiTogglePreference( diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt index 51c0c3076ee..1ea804449c8 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt +++ b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt @@ -178,11 +178,9 @@ class DeviceDetailsFragmentFormatterTest { }.launchIn(testScope.backgroundScope) delay(100) runCurrent() - helpPreference!!.onClick() ShadowLooper.idleMainLooper() - val shadowActivity = Shadows.shadowOf(fragmentActivity) - assertThat(shadowActivity.nextStartedActivity).isSameInstanceAs(intent) + assertThat(helpPreference?.intent).isSameInstanceAs(intent) } } From fc27dcccde7a7c0ec83d5e83bbb6da8a2c45e456 Mon Sep 17 00:00:00 2001 From: Haijie Hong Date: Wed, 25 Sep 2024 14:14:43 +0800 Subject: [PATCH 09/11] Add metrics category for more settings fragment BUG: 343317785 Test: local tested Flag: com.android.settings.flags.enable_bluetooth_device_details_polish Change-Id: I21a3ca0deea516765f1af2f5d7117b6c3c1763a7 --- .../bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt index c0fbd4f2c4a..4384eff8535 100644 --- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt +++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt @@ -16,6 +16,7 @@ package com.android.settings.bluetooth.ui.view +import android.app.settings.SettingsEnums import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager import android.content.Context @@ -48,8 +49,7 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() { private lateinit var cachedDevice: CachedBluetoothDevice private lateinit var helpItem: StateFlow - // TODO(b/343317785): add metrics category - override fun getMetricsCategory(): Int = 0 + override fun getMetricsCategory(): Int = SettingsEnums.BLUETOOTH_DEVICE_DETAILS_MORE_SETTINGS override fun onPrepareOptionsMenu(menu: Menu) { super.onPrepareOptionsMenu(menu) From 63ecd2781f215a6f7d58784f46cbdb8574ea6ef8 Mon Sep 17 00:00:00 2001 From: Haijie Hong Date: Wed, 25 Sep 2024 16:55:31 +0800 Subject: [PATCH 10/11] Add icon for more settings preference BUG: 343317785 Test: atest DeviceSettingRepositoryTest Flag: com.android.settings.flags.enable_bluetooth_device_details_polish Change-Id: Id7c272edce5ff8166f03b7162ac9ba5ff1f15097 --- .../bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt index 074e520cbcc..ecd700beee5 100644 --- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt +++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt @@ -362,7 +362,12 @@ class DeviceDetailsFragmentFormatterImpl( ) .launch() } - override val icon = @Composable { deviceSettingIcon(null) } + override val icon = + @Composable { + deviceSettingIcon( + DeviceSettingIcon.ResourceIcon(R.drawable.ic_chevron_right_24dp) + ) + } } ) } From 8b7399a8d98e6c626a8af57411b037c13fe7d61a Mon Sep 17 00:00:00 2001 From: Geoffrey Boullanger Date: Mon, 23 Sep 2024 21:32:28 +0000 Subject: [PATCH 11/11] Update titles and summaries of the Date and time settings page Design doc: go/dd-android-settings-time-2024 This change covers Part 1, which consists of adding user-friendly summary under each toggle and rewording titles. Bug: 296835792 Test: on-device and atest Flag: EXEMPT resource only update Change-Id: I0b685743599880fc1c4ad680eca9c36e4e64d0ff --- res/values/strings.xml | 16 ++++++++++------ res/xml/date_time_prefs.xml | 4 +++- .../datetime/AutoTimePreferenceController.java | 13 +++++++++++++ .../AutoTimeZonePreferenceController.java | 8 ++++---- .../AutoTimePreferenceControllerTest.java | 8 ++++++++ .../AutoTimeZonePreferenceControllerTest.java | 5 +++-- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index fb95aa3bd39..4229eb18fbb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -571,11 +571,15 @@ Roaming charges may apply. - Set time automatically + Automatic date and time + + Set automatically using your network and wireless signals - Set automatically + Automatic time zone + + Set automatically based on mobile networks near you - Location will be used for setting the time zone when this toggle is on + Set automatically using your device location, if available. An active Wifi connection may also be required. Use locale default @@ -3772,7 +3776,7 @@ Location services - Use location + Use location for time zone Cannot set the time zone automatically @@ -3800,7 +3804,7 @@ - Automatic time zone is off + Not available when automatic time zone is off @@ -3811,7 +3815,7 @@ allowed for the user, e.g. because of device policy --> Location time zone detection changes are not allowed - Location may be used to set time zone + If your device location is available, it may be used to set your time zone View legal info, status, software version diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml index 3fb4a065d7c..d8643be35f9 100644 --- a/res/xml/date_time_prefs.xml +++ b/res/xml/date_time_prefs.xml @@ -23,7 +23,7 @@ @@ -48,6 +48,7 @@ @@ -60,6 +61,7 @@