diff --git a/Android.bp b/Android.bp index c966eca2e92..ed094cfae72 100644 --- a/Android.bp +++ b/Android.bp @@ -115,6 +115,7 @@ android_library { "device_policy_aconfig_flags_lib", "keyboard_flags_lib", "settings_connectivity_flags", + "com_android_systemui_flags_lib", ], plugins: [ diff --git a/res/drawable/keyboard_arrow_left.xml b/res/drawable/keyboard_arrow_left.xml new file mode 100644 index 00000000000..77a2bfb6046 --- /dev/null +++ b/res/drawable/keyboard_arrow_left.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/keyboard_arrow_right.xml b/res/drawable/keyboard_arrow_right.xml new file mode 100644 index 00000000000..5b0dd3d27dd --- /dev/null +++ b/res/drawable/keyboard_arrow_right.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/accessibility_text_reading_preview.xml b/res/layout/accessibility_text_reading_preview.xml index 830d9e66778..9c3ce31db22 100644 --- a/res/layout/accessibility_text_reading_preview.xml +++ b/res/layout/accessibility_text_reading_preview.xml @@ -38,20 +38,45 @@ android:text="@string/screen_zoom_preview_title" style="@style/AccessibilityTextReadingPreviewTitle" /> - - - + android:orientation="vertical"> + + + + + + + diff --git a/res/layout/display_topology_preference.xml b/res/layout/display_topology_preference.xml index 9f2805d0e83..add84b6b235 100644 --- a/res/layout/display_topology_preference.xml +++ b/res/layout/display_topology_preference.xml @@ -14,13 +14,19 @@ limitations under the License. --> + diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml index 79949ceb85b..4edb6f43688 100644 --- a/res/values-night/colors.xml +++ b/res/values-night/colors.xml @@ -82,5 +82,9 @@ @color/settingslib_color_charcoal @android:color/system_secondary_dark + + + @android:color/system_accent1_100 + @android:color/system_accent1_100 diff --git a/res/values/colors.xml b/res/values/colors.xml index 73efeb232fa..c9e01e5a612 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -222,4 +222,9 @@ @color/settingslib_color_grey100 @android:color/system_secondary_light + + + @android:color/system_accent1_800 + @android:color/system_accent1_800 + @android:color/system_neutral2_50 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 0e88e265867..ddce9e6a9df 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -552,6 +552,7 @@ 24dp + 24dp 5dp 2dp 10dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 6f328a341db..694700c3aff 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -78,6 +78,11 @@ Preview + + Previous preview + + Next preview + QR code @@ -12602,6 +12607,12 @@ satellite messaging Use of data is included with your account + + Supported apps on your phone + + see all apps + + Supported apps on your phone Access Point Names diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index 2f9a9b98585..518e2d16e73 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -745,32 +745,6 @@ android:title="@string/force_allow_on_external" android:summary="@string/force_allow_on_external_summary" /> - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + android:order="1200"> + android:order="1300"> + android:order="1400"> @@ -857,7 +865,7 @@ + android:order="1500"> + + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/accessibility/TextReadingPreviewPreference.java b/src/com/android/settings/accessibility/TextReadingPreviewPreference.java index 9161171914a..717da70e49c 100644 --- a/src/com/android/settings/accessibility/TextReadingPreviewPreference.java +++ b/src/com/android/settings/accessibility/TextReadingPreviewPreference.java @@ -22,6 +22,7 @@ import android.os.Parcelable; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; +import android.widget.ImageButton; import android.widget.LinearLayout; import androidx.preference.Preference; @@ -99,6 +100,23 @@ public class TextReadingPreviewPreference extends Preference { (DotsPageIndicator) holder.findViewById(R.id.page_indicator); updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter); updatePagerAndIndicator(viewPager, pageIndicator); + viewPager.setClipToOutline(true); + + int layoutDirection = + getContext().getResources().getConfiguration().getLayoutDirection(); + int previousId = (layoutDirection == View.LAYOUT_DIRECTION_RTL) + ? R.id.preview_right_button : R.id.preview_left_button; + int nextId = (layoutDirection == View.LAYOUT_DIRECTION_RTL) + ? R.id.preview_left_button : R.id.preview_right_button; + final ImageButton previousButton = previewLayout.findViewById(previousId); + final ImageButton nextButton = previewLayout.findViewById(nextId); + + previousButton.setOnClickListener((view) -> setCurrentItem(getCurrentItem() - 1)); + previousButton.setContentDescription(getContext().getString( + R.string.preview_pager_previous_button)); + nextButton.setOnClickListener((view) -> setCurrentItem(getCurrentItem() + 1)); + previousButton.setContentDescription(getContext().getString( + R.string.preview_pager_next_button)); } @Override @@ -158,7 +176,9 @@ public class TextReadingPreviewPreference extends Preference { Preconditions.checkNotNull(mPreviewAdapter, "Preview adapter is null, you should init the preview adapter first"); - if (currentItem != mCurrentItem) { + if (currentItem < 0 || currentItem >= mPreviewAdapter.getCount()) { + return; + } else if (currentItem != mCurrentItem) { mCurrentItem = currentItem; notifyChanged(); } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 6773fdcf1ce..31ebeb7c705 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -1067,8 +1067,11 @@ public class FingerprintSettings extends SubSettings { mRemovalSidecar.setListener(mRemovalListener); } - mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() - .getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, null); + if (!mLaunchedConfirm && !mIsEnrolling) { + mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() + .getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, + null); + } } private void updatePreferences() { @@ -1517,6 +1520,11 @@ public class FingerprintSettings extends SubSettings { intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); intent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, mChallenge); } + + if (mCalibrator != null) { + intent.putExtras(mCalibrator.getExtrasForNextIntent()); + } + startActivityForResult(intent, AUTO_ADD_FIRST_FINGERPRINT_REQUEST); } diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java index bd160e17527..dab696e5e0b 100644 --- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java @@ -79,7 +79,8 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater // If device is LE Audio, it is compatible with HFP and A2DP. // It would show in Available Devices group if the audio sharing flag is disabled or // the device is not in the audio sharing session. - if (cachedDevice.isConnectedLeAudioDevice()) { + if (cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) { if (BluetoothUtils.isAudioSharingUIAvailable(mContext) && BluetoothUtils.hasConnectedBroadcastSource( cachedDevice, mLocalBtManager)) { diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java index 7cc874caba9..a0f5ea23050 100644 --- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java @@ -77,7 +77,12 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP. // It would not show in Connected Devices group. if (cachedDevice.isConnectedAshaHearingAidDevice() - || cachedDevice.isConnectedLeAudioDevice()) { + || cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) { + if (DBG) { + Log.d(TAG, "isFilterMatched() device : " + cachedDevice.getName() + + ", isFilterMatched : false, ha or lea device"); + } return false; } // According to the current audio profile type, diff --git a/src/com/android/settings/communal/CommunalPreferenceController.java b/src/com/android/settings/communal/CommunalPreferenceController.java index f93746833ff..e44afab90a6 100644 --- a/src/com/android/settings/communal/CommunalPreferenceController.java +++ b/src/com/android/settings/communal/CommunalPreferenceController.java @@ -21,7 +21,6 @@ import android.content.Context; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; -import com.android.settings.flags.Flags; /** * Controls the top-level Communal settings preference. @@ -40,14 +39,15 @@ public class CommunalPreferenceController extends BasePreferenceController { * Returns whether communal preferences are available. */ public static boolean isAvailable(Context context) { + if (!Utils.canCurrentUserDream(context)) { + return false; + } + if (context.getResources().getBoolean(R.bool.config_show_communal_settings)) { - return Utils.canCurrentUserDream(context); + return true; } - if (context.getResources().getBoolean(R.bool.config_show_communal_settings_mobile)) { - return Flags.enableHubModeSettingsOnMobile() && Utils.canCurrentUserDream(context); - } - - return false; + return com.android.systemui.Flags.glanceableHubV2() + && context.getResources().getBoolean(R.bool.config_show_communal_settings_mobile); } } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java index e5b984d707c..884c7813434 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java @@ -56,7 +56,8 @@ public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater // If device is LE audio device and has a broadcast source, // it would show in audio sharing devices group. if (BluetoothUtils.isAudioSharingUIAvailable(mContext) - && cachedDevice.isConnectedLeAudioDevice() + && (cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) && BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, mLocalBtManager)) { isFilterMatched = true; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java index 548d17cc9ce..7f12ec84b3b 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java @@ -62,7 +62,8 @@ public class AudioSharingDeviceVolumeControlUpdater extends BluetoothDeviceUpdat if (isDeviceConnected(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice)) { // If device is LE audio device and in a sharing session on current sharing device, // it would show in volume control group. - if (cachedDevice.isConnectedLeAudioDevice() + if ((cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) && BluetoothUtils.isBroadcasting(mBtManager) && BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, mBtManager)) { isFilterMatched = true; diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java index be0ee0b8b44..7b670a80fba 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java @@ -51,10 +51,9 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.bluetooth.VolumeControlProfile; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; @@ -73,8 +72,9 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre private final Executor mExecutor; private final ContentObserver mSettingsObserver; @Nullable private PreferenceGroup mPreferenceGroup; - private List mVolumePreferences = new ArrayList<>(); - private Map mValueMap = new HashMap(); + private CopyOnWriteArraySet mVolumePreferences = + new CopyOnWriteArraySet<>(); + private ConcurrentHashMap mValueMap = new ConcurrentHashMap<>(); private AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); @VisibleForTesting @@ -104,8 +104,8 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre + finalVolume + " for " + device.getAnonymizedAddress()); - mContext.getMainExecutor() - .execute(() -> preference.setProgress(finalVolume)); + AudioSharingUtils.postOnMainThread(mContext, + () -> preference.setProgress(finalVolume)); break; } } @@ -196,7 +196,9 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre public void onChange(boolean selfChange) { Log.d(TAG, "onChange, fallback device group id has been changed"); for (AudioSharingDeviceVolumePreference preference : mVolumePreferences) { - preference.setOrder(getPreferenceOrderForDevice(preference.getCachedDevice())); + int order = getPreferenceOrderForDevice(preference.getCachedDevice()); + Log.d(TAG, "onChange: set order to " + order + " for " + preference); + AudioSharingUtils.postOnMainThread(mContext, () -> preference.setOrder(order)); } } } @@ -240,52 +242,54 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre @Override public void onDeviceAdded(Preference preference) { - if (mPreferenceGroup != null) { - if (mPreferenceGroup.getPreferenceCount() == 0) { - mPreferenceGroup.setVisible(true); + if (!(preference instanceof AudioSharingDeviceVolumePreference)) { + Log.d(TAG, "Skip onDeviceAdded, invalid preference type"); + return; + } + var volumePref = (AudioSharingDeviceVolumePreference) preference; + mVolumePreferences.add(volumePref); + AudioSharingUtils.postOnMainThread(mContext, () -> { + if (mPreferenceGroup != null) { + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(true); + } + mPreferenceGroup.addPreference(volumePref); } - mPreferenceGroup.addPreference(preference); - } - if (preference instanceof AudioSharingDeviceVolumePreference) { - var volumePref = (AudioSharingDeviceVolumePreference) preference; - CachedBluetoothDevice cachedDevice = volumePref.getCachedDevice(); - volumePref.setOrder(getPreferenceOrderForDevice(cachedDevice)); - mVolumePreferences.add(volumePref); - if (volumePref.getProgress() > 0) return; - int volume = mValueMap.getOrDefault(BluetoothUtils.getGroupId(cachedDevice), -1); - // If the volume is invalid, try to get the volume from AudioManager.STREAM_MUSIC - int finalVolume = getAudioVolumeIfNeeded(volume); - Log.d( - TAG, - "onDeviceAdded: set volume to " - + finalVolume - + " for " - + cachedDevice.getDevice().getAnonymizedAddress()); - AudioSharingUtils.postOnMainThread(mContext, () -> volumePref.setProgress(finalVolume)); - } + }); + CachedBluetoothDevice cachedDevice = volumePref.getCachedDevice(); + String address = cachedDevice.getDevice() == null ? "null" + : cachedDevice.getDevice().getAnonymizedAddress(); + int order = getPreferenceOrderForDevice(cachedDevice); + Log.d(TAG, "onDeviceAdded: set order to " + order + " for " + address); + AudioSharingUtils.postOnMainThread(mContext, () -> volumePref.setOrder(order)); + int volume = mValueMap.getOrDefault(BluetoothUtils.getGroupId(cachedDevice), -1); + // If the volume is invalid, try to get the volume from AudioManager.STREAM_MUSIC + int finalVolume = getAudioVolumeIfNeeded(volume); + Log.d(TAG, "onDeviceAdded: set volume to " + finalVolume + " for " + address); + AudioSharingUtils.postOnMainThread(mContext, () -> volumePref.setProgress(finalVolume)); } @Override public void onDeviceRemoved(Preference preference) { - if (mPreferenceGroup != null) { - mPreferenceGroup.removePreference(preference); - if (mPreferenceGroup.getPreferenceCount() == 0) { - mPreferenceGroup.setVisible(false); - } + if (!(preference instanceof AudioSharingDeviceVolumePreference)) { + Log.d(TAG, "Skip onDeviceRemoved, invalid preference type"); + return; } - if (preference instanceof AudioSharingDeviceVolumePreference) { - var volumePref = (AudioSharingDeviceVolumePreference) preference; - if (mVolumePreferences.contains(volumePref)) { - mVolumePreferences.remove(volumePref); - } - CachedBluetoothDevice device = volumePref.getCachedDevice(); - Log.d( - TAG, - "onDeviceRemoved: " - + (device == null - ? "null" - : device.getDevice().getAnonymizedAddress())); + var volumePref = (AudioSharingDeviceVolumePreference) preference; + if (mVolumePreferences.contains(volumePref)) { + mVolumePreferences.remove(volumePref); } + String address = volumePref.getCachedDevice().getDevice() == null ? "null" + : volumePref.getCachedDevice().getDevice().getAnonymizedAddress(); + Log.d(TAG, "onDeviceRemoved: " + address); + AudioSharingUtils.postOnMainThread(mContext, () -> { + if (mPreferenceGroup != null) { + mPreferenceGroup.removePreference(volumePref); + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(false); + } + } + }); } @Override diff --git a/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt b/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt index 42e633f62e7..7894a7e6c0d 100644 --- a/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt +++ b/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt @@ -16,9 +16,10 @@ package com.android.settings.connecteddevice.display -import android.app.WallpaperManager import com.android.settings.R +import com.android.settingslib.widget.GroupSectionDividerMixin +import android.app.WallpaperManager import android.content.Context import android.graphics.Bitmap import android.graphics.PointF @@ -45,7 +46,7 @@ import kotlin.math.abs * when there is one or more extended display attached. */ class DisplayTopologyPreference(context : Context) - : Preference(context), ViewTreeObserver.OnGlobalLayoutListener { + : Preference(context), ViewTreeObserver.OnGlobalLayoutListener, GroupSectionDividerMixin { @VisibleForTesting lateinit var mPaneContent : FrameLayout @VisibleForTesting lateinit var mPaneHolder : FrameLayout @VisibleForTesting lateinit var mTopologyHint : TextView @@ -82,6 +83,8 @@ class DisplayTopologyPreference(context : Context) isPersistent = false + isCopyingEnabled = false + injector = Injector(context) } diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index 3a4e4e973b3..246359aa171 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -72,10 +72,16 @@ import com.android.settings.development.bluetooth.BluetoothHDAudioPreferenceCont import com.android.settings.development.bluetooth.BluetoothQualityDialogPreferenceController; import com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreferenceController; import com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController; +import com.android.settings.development.desktopexperience.DesktopExperiencePreferenceController; +import com.android.settings.development.desktopexperience.DesktopModePreferenceController; +import com.android.settings.development.desktopexperience.DesktopModeSecondaryDisplayPreferenceController; +import com.android.settings.development.desktopexperience.FreeformWindowsPreferenceController; import com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController; import com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController; import com.android.settings.development.qstile.DevelopmentTiles; import com.android.settings.development.storage.SharedDataPreferenceController; +import com.android.settings.development.window.NonResizableMultiWindowPreferenceController; +import com.android.settings.development.window.ResizableActivityPreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.search.BaseSearchIndexProvider; diff --git a/src/com/android/settings/development/DesktopExperiencePreferenceController.java b/src/com/android/settings/development/desktopexperience/DesktopExperiencePreferenceController.java similarity index 94% rename from src/com/android/settings/development/DesktopExperiencePreferenceController.java rename to src/com/android/settings/development/desktopexperience/DesktopExperiencePreferenceController.java index 28e92fcdac5..4075eaf77f6 100644 --- a/src/com/android/settings/development/DesktopExperiencePreferenceController.java +++ b/src/com/android/settings/development/desktopexperience/DesktopExperiencePreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_EXPERIENCE_FEATURES; import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; @@ -33,6 +33,9 @@ import androidx.preference.TwoStatePreference; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; +import com.android.settings.development.RebootConfirmationDialogHost; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; diff --git a/src/com/android/settings/development/DesktopModePreferenceController.java b/src/com/android/settings/development/desktopexperience/DesktopModePreferenceController.java similarity index 93% rename from src/com/android/settings/development/DesktopModePreferenceController.java rename to src/com/android/settings/development/desktopexperience/DesktopModePreferenceController.java index 4c6da1ee1cd..50691f60a7a 100644 --- a/src/com/android/settings/development/DesktopModePreferenceController.java +++ b/src/com/android/settings/development/desktopexperience/DesktopModePreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; import static android.window.DesktopModeFlags.ToggleOverride.fromSetting; @@ -33,6 +33,9 @@ import androidx.preference.TwoStatePreference; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; +import com.android.settings.development.RebootConfirmationDialogHost; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; diff --git a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java b/src/com/android/settings/development/desktopexperience/DesktopModeSecondaryDisplayPreferenceController.java similarity index 93% rename from src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java rename to src/com/android/settings/development/desktopexperience/DesktopModeSecondaryDisplayPreferenceController.java index 899b921e47f..d61d537c533 100644 --- a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java +++ b/src/com/android/settings/development/desktopexperience/DesktopModeSecondaryDisplayPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; @@ -29,6 +29,9 @@ import androidx.preference.TwoStatePreference; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; +import com.android.settings.development.RebootConfirmationDialogHost; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; diff --git a/src/com/android/settings/development/FreeformWindowsPreferenceController.java b/src/com/android/settings/development/desktopexperience/FreeformWindowsPreferenceController.java similarity index 92% rename from src/com/android/settings/development/FreeformWindowsPreferenceController.java rename to src/com/android/settings/development/desktopexperience/FreeformWindowsPreferenceController.java index 6cf1563bce5..60712408322 100644 --- a/src/com/android/settings/development/FreeformWindowsPreferenceController.java +++ b/src/com/android/settings/development/desktopexperience/FreeformWindowsPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; @@ -28,6 +28,9 @@ import androidx.preference.TwoStatePreference; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; +import com.android.settings.development.RebootConfirmationDialogHost; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; diff --git a/src/com/android/settings/development/desktopexperience/OWNERS b/src/com/android/settings/development/desktopexperience/OWNERS new file mode 100644 index 00000000000..6be8a6421d2 --- /dev/null +++ b/src/com/android/settings/development/desktopexperience/OWNERS @@ -0,0 +1,3 @@ +include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS +include platform/frameworks/base:/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS +include platform/frameworks/base:/libs/WindowManager/Shell/OWNERS \ No newline at end of file diff --git a/src/com/android/settings/development/NonResizableMultiWindowPreferenceController.java b/src/com/android/settings/development/window/NonResizableMultiWindowPreferenceController.java similarity index 98% rename from src/com/android/settings/development/NonResizableMultiWindowPreferenceController.java rename to src/com/android/settings/development/window/NonResizableMultiWindowPreferenceController.java index 50d90bdb3e6..f2f2de5c88a 100644 --- a/src/com/android/settings/development/NonResizableMultiWindowPreferenceController.java +++ b/src/com/android/settings/development/window/NonResizableMultiWindowPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.window; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW; diff --git a/src/com/android/settings/development/window/OWNERS b/src/com/android/settings/development/window/OWNERS new file mode 100644 index 00000000000..c437f15567d --- /dev/null +++ b/src/com/android/settings/development/window/OWNERS @@ -0,0 +1,2 @@ +include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS +include platform/frameworks/base:/libs/WindowManager/Shell/OWNERS \ No newline at end of file diff --git a/src/com/android/settings/development/ResizableActivityPreferenceController.java b/src/com/android/settings/development/window/ResizableActivityPreferenceController.java similarity index 94% rename from src/com/android/settings/development/ResizableActivityPreferenceController.java rename to src/com/android/settings/development/window/ResizableActivityPreferenceController.java index 28b1478d49e..06b819eaa81 100644 --- a/src/com/android/settings/development/ResizableActivityPreferenceController.java +++ b/src/com/android/settings/development/window/ResizableActivityPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.window; import android.content.Context; import android.provider.Settings; @@ -32,9 +32,9 @@ public class ResizableActivityPreferenceController extends DeveloperOptionsPrefe private static final String FORCE_RESIZABLE_KEY = "force_resizable_activities"; @VisibleForTesting - final static int SETTING_VALUE_ON = 1; + static final int SETTING_VALUE_ON = 1; @VisibleForTesting - final static int SETTING_VALUE_OFF = 0; + static final int SETTING_VALUE_OFF = 0; public ResizableActivityPreferenceController(Context context) { super(context); diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index c0caff7a494..cb8e6fc03b0 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -475,7 +475,10 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle updatePrivateStorageCategoryPreferencesOrder(); mIsPreferenceOrderedBySize = true; } - setPrivateStorageCategoryPreferencesVisibility(true); + + if (isValidPrivateVolume()) { + setPrivateStorageCategoryPreferencesVisibility(true); + } } private StorageCacheHelper.StorageCache getSizeInfo( diff --git a/src/com/android/settings/network/SatelliteRepository.kt b/src/com/android/settings/network/SatelliteRepository.kt index c70484a7e7a..994f8ec96d4 100644 --- a/src/com/android/settings/network/SatelliteRepository.kt +++ b/src/com/android/settings/network/SatelliteRepository.kt @@ -23,6 +23,7 @@ import android.telephony.satellite.SatelliteModemStateCallback import android.util.Log import androidx.annotation.VisibleForTesting import androidx.concurrent.futures.CallbackToFutureAdapter +import com.android.internal.telephony.flags.Flags import com.google.common.util.concurrent.Futures.immediateFuture import com.google.common.util.concurrent.ListenableFuture import java.util.concurrent.Executor @@ -40,7 +41,7 @@ import kotlinx.coroutines.flow.flowOn /** * A repository class for interacting with the SatelliteManager API. */ -class SatelliteRepository( +open class SatelliteRepository( private val context: Context, ) { @@ -196,6 +197,28 @@ class SatelliteRepository( } } + /** + * @return A list with application package names which support Satellite service. + * e.g. "com.android.settings" + */ + open fun getSatelliteDataOptimizedApps(): List { + if (!Flags.satellite25q4Apis()) { + return emptyList() + } + val satelliteManager: SatelliteManager? = + context.getSystemService(SatelliteManager::class.java) + if (satelliteManager == null) { + Log.d(TAG, "SatelliteManager is null") + return emptyList() + } + try { + return satelliteManager.getSatelliteDataOptimizedApps(); + } catch (e: IllegalStateException) { + Log.w(TAG, "IllegalStateException $e") + } + return emptyList() + } + companion object { private const val TAG: String = "SatelliteRepository" diff --git a/src/com/android/settings/network/telephony/SatelliteAppListCategoryController.java b/src/com/android/settings/network/telephony/SatelliteAppListCategoryController.java new file mode 100644 index 00000000000..4afa7f245ff --- /dev/null +++ b/src/com/android/settings/network/telephony/SatelliteAppListCategoryController.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025 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.network.telephony; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; + +import com.android.internal.telephony.flags.Flags; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.network.SatelliteRepository; +import com.android.settingslib.Utils; + +import java.util.List; + +/** A controller to show some of apps info which supported on Satellite service. */ +public class SatelliteAppListCategoryController extends BasePreferenceController { + private static final String TAG = "SatelliteAppListCategoryController"; + @VisibleForTesting + static final int MAXIMUM_OF_PREFERENCE_AMOUNT = 3; + + private List mPackageNameList; + + public SatelliteAppListCategoryController( + @NonNull Context context, + @NonNull String preferenceKey) { + super(context, preferenceKey); + } + + /** Initialize the necessary applications' data*/ + public void init() { + SatelliteRepository satelliteRepository = new SatelliteRepository(mContext); + init(satelliteRepository); + } + + @VisibleForTesting + void init(@NonNull SatelliteRepository satelliteRepository) { + mPackageNameList = satelliteRepository.getSatelliteDataOptimizedApps(); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + PreferenceCategory preferenceCategory = screen.findPreference(getPreferenceKey()); + for (int i = 0; i < mPackageNameList.size() && i < MAXIMUM_OF_PREFERENCE_AMOUNT; i++) { + String packageName = mPackageNameList.get(i); + ApplicationInfo appInfo = getApplicationInfo(mContext, packageName); + if (appInfo != null) { + Drawable icon = Utils.getBadgedIcon(mContext, appInfo); + CharSequence name = appInfo.loadLabel(mContext.getPackageManager()); + Preference pref = new Preference(mContext); + pref.setIcon(icon); + pref.setTitle(name); + preferenceCategory.addPreference(pref); + } + } + } + + @Override + public int getAvailabilityStatus() { + if (!Flags.satellite25q4Apis()) { + return CONDITIONALLY_UNAVAILABLE; + } + return mPackageNameList.isEmpty() + ? CONDITIONALLY_UNAVAILABLE + : AVAILABLE; + } + + static ApplicationInfo getApplicationInfo(Context context, String packageName) { + try { + PackageManager pm = context.getPackageManager(); + return pm.getApplicationInfoAsUser(packageName, /* flags= */ 0, context.getUserId()); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } +} diff --git a/src/com/android/settings/network/telephony/SatelliteAppListFragment.java b/src/com/android/settings/network/telephony/SatelliteAppListFragment.java new file mode 100644 index 00000000000..97f70bb2652 --- /dev/null +++ b/src/com/android/settings/network/telephony/SatelliteAppListFragment.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2025 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.network.telephony; + +import static com.android.settings.network.telephony.SatelliteAppListCategoryController.getApplicationInfo; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.graphics.drawable.Drawable; +import android.os.UserManager; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.dashboard.RestrictedDashboardFragment; +import com.android.settings.network.SatelliteRepository; +import com.android.settingslib.Utils; +import com.android.settingslib.core.AbstractPreferenceController; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.List; +import java.util.stream.Collectors; + +/** Shows all applications which support satellite service. */ +public class SatelliteAppListFragment extends RestrictedDashboardFragment { + public SatelliteAppListFragment() { + super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(SatelliteAppListPreferenceController.class).init(); + } + + @Override + protected List createPreferenceControllers(Context context) { + SatelliteAppListPreferenceController satelliteAppListPreferenceController = + new SatelliteAppListPreferenceController(getContext()); + return List.of(satelliteAppListPreferenceController); + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.satellite_settings_apps_list; + } + + @Override + protected String getLogTag() { + return "SatelliteAppListFragment"; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SATELLITE_APPS_LIST; + } + + @VisibleForTesting + static class SatelliteAppListPreferenceController extends BasePreferenceController { + private static final String TAG = "SatelliteAppListPreferenceController"; + private static final String KEY = "key_satellite_app_list"; + + private List mApplicationInfoList = List.of(); + + SatelliteAppListPreferenceController(@NonNull Context context) { + super(context, KEY); + } + + public void init() { + SatelliteRepository satelliteRepository = new SatelliteRepository(mContext); + init(satelliteRepository); + } + + void init(@NonNull SatelliteRepository satelliteRepository) { + mApplicationInfoList = + satelliteRepository.getSatelliteDataOptimizedApps() + .stream() + .map(name -> getApplicationInfo(mContext, name)) + .collect(Collectors.toList()); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + if (mApplicationInfoList.isEmpty()) { + return; + } + mApplicationInfoList.forEach(appInfo -> { + if (appInfo != null) { + Log.i(TAG, "Add preference to UI : " + appInfo.packageName); + Drawable icon = Utils.getBadgedIcon(mContext, appInfo); + CharSequence name = appInfo.loadLabel(mContext.getPackageManager()); + Preference pref = new Preference(mContext); + pref.setIcon(icon); + pref.setTitle(name); + screen.addPreference(pref); + } + }); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + } +} diff --git a/src/com/android/settings/network/telephony/SatelliteSetting.java b/src/com/android/settings/network/telephony/SatelliteSetting.java index d4bd212d153..bc10abb212d 100644 --- a/src/com/android/settings/network/telephony/SatelliteSetting.java +++ b/src/com/android/settings/network/telephony/SatelliteSetting.java @@ -26,6 +26,7 @@ import static android.telephony.CarrierConfigManager.KEY_SATELLITE_INFORMATION_R import android.app.Activity; import android.app.settings.SettingsEnums; +import android.content.Context; import android.content.Intent; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -92,6 +93,12 @@ public class SatelliteSetting extends RestrictedDashboardFragment { return SettingsEnums.SATELLITE_SETTING; } + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(SatelliteAppListCategoryController.class).init(); + } + @Override public void onCreate(@NonNull Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt b/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt index 185af0c3d09..a7f6a0b5dcb 100644 --- a/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt +++ b/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt @@ -52,7 +52,7 @@ class SubscriptionActivationRepository( Log.i(TAG, "Unable to toggle subscription due to unusable subscription ID.") return } - if (!active && isEmergencyCallbackMode(subId)) { + if (isEmergencyCallbackMode(subId)) { val intent = Intent(ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS).apply { setPackage(Utils.PHONE_PACKAGE_NAME) } diff --git a/src/com/android/settings/widget/ValidatedEditTextPreference.java b/src/com/android/settings/widget/ValidatedEditTextPreference.java index cc344ac67f1..c85e81ef381 100644 --- a/src/com/android/settings/widget/ValidatedEditTextPreference.java +++ b/src/com/android/settings/widget/ValidatedEditTextPreference.java @@ -67,6 +67,9 @@ public class ValidatedEditTextPreference extends CustomEditTextPreferenceCompat protected void onBindDialogView(View view) { super.onBindDialogView(view); final EditText editText = view.findViewById(android.R.id.edit); + if (editText != null) { + editText.setHint(getDialogTitle()); + } if (editText != null && !TextUtils.isEmpty(editText.getText())) { editText.setSelection(editText.getText().length()); } diff --git a/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java b/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java index e4ebdefb1a5..8e8dba82d7d 100644 --- a/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java +++ b/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java @@ -51,7 +51,12 @@ public class Enable16KbTest extends BaseHostJUnit4Test { @Test @AppModeFull public void enable16KbToggle() throws Exception { - assertTrue(isPackageInstalled(APP_PACKAGE)); + // Wait for 2 mins device to be online + getDevice().waitForDeviceOnline(120000); + if (!isPackageInstalled(APP_PACKAGE)) { + //If test app has failed for some reason, retry installation + installTestApp(); + } // Check if developer option is enabled otherwise exit getDevice().enableAdbRoot(); diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp index 464d9708c0a..bb70a702b6d 100644 --- a/tests/robotests/Android.bp +++ b/tests/robotests/Android.bp @@ -77,6 +77,7 @@ android_robolectric_test { "platform-test-annotations", "testables", "android.app.flags-aconfig-java", + "com_android_systemui_flags_lib", ], libs: [ diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java index 2251c3bff5a..87d7aed8f19 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java @@ -282,6 +282,28 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_notInCallFlagOff_addPref() { + mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))) + .thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mBroadcastReceiveState)); + List bisSyncState = new ArrayList<>(); + bisSyncState.add(1L); + when(mBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_leaConnected_notInCallNotInSharing_addPref() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); @@ -299,6 +321,25 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_notInCallNotInSharing_addPref() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))) + .thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of()); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_leaConnected_inCallSharingFlagOff_addPref() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java index f68a8d4cf6a..b2babc310ae 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java @@ -269,6 +269,20 @@ public class ConnectedBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } + @Test + public void onProfileConnectionStateChanged_hasLeaMemberConnected_inCall_removesPreference() { + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_IN_CALL); + when(mBluetoothDeviceUpdater + .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_removesPreference() { @@ -282,6 +296,22 @@ public class ConnectedBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } + + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_notInCall_removesPreference() { + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater + .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovesPreference() { diff --git a/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java index b88b1aa661b..cc970eb6b1d 100644 --- a/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settings.communal; import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2; import static com.google.common.truth.Truth.assertThat; @@ -34,7 +35,6 @@ import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import com.android.settings.R; -import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowUserManager; @@ -87,7 +87,7 @@ public class CommunalPreferenceControllerTest { } @Test - @EnableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) public void isAvailable_communalOnMobileEnabled_shouldBeTrueForPrimaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(true); @@ -96,7 +96,7 @@ public class CommunalPreferenceControllerTest { } @Test - @EnableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) public void isAvailable_communalOnMobileEnabled_shouldBeFalseForSecondaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(true); @@ -105,7 +105,7 @@ public class CommunalPreferenceControllerTest { } @Test - @EnableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) public void isAvailable_communalOnMobileDisabled_shouldBeFalseForPrimaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(false); @@ -114,8 +114,8 @@ public class CommunalPreferenceControllerTest { } @Test - @DisableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) - public void isAvailable_hubModeSettingsOnMobileFlagDisabled_shouldBeFalseForPrimaryUser() { + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) + public void isAvailable_glanceableHubV2FlagDisabled_shouldBeFalseForPrimaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(true); mShadowUserManager.setUserForeground(true); diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java index 12e03d4cd63..84fd820323f 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java @@ -153,6 +153,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceConnected_flagOff_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -172,6 +177,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaConnected_flagOff_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -191,6 +201,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaConnected_noSource_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of()); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -210,6 +225,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaConnected_noSource_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of()); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -229,6 +249,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_deviceIsNotInList_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mCachedDevices.clear(); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); @@ -249,6 +274,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_deviceIsNotInList_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mCachedDevices.clear(); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); @@ -269,6 +299,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnected_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -288,6 +323,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnected_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -307,6 +347,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnecting_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); doReturn(false).when(mCachedBluetoothDevice).isConnectedLeAudioDevice(); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -325,6 +370,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnecting_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); doReturn(false).when(mCachedBluetoothDevice).isConnectedLeAudioDevice(); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -344,6 +394,29 @@ public class AudioSharingBluetoothDeviceUpdaterTest { public void onProfileConnectionStateChanged_leaConnected_hasSource_addsPref() { ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); + assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); + assertThat(((BluetoothDevicePreference) captor.getValue()).getBluetoothDevice()) + .isEqualTo(mCachedBluetoothDevice); + } + + @Test + public void onProfileConnectionStateChanged_hasLeaMemberConnected_hasSource_addsPref() { + ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); + setupPreferenceMapWithDevice(false); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); @@ -355,6 +428,30 @@ public class AudioSharingBluetoothDeviceUpdaterTest { public void onProfileConnectionStateChanged_leaConnected_hasSource_hysteresisMode_addsPref() { ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); + assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); + assertThat(((BluetoothDevicePreference) captor.getValue()).getBluetoothDevice()) + .isEqualTo(mCachedBluetoothDevice); + } + + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_hasSource_hysteresis_addsPref() { + ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); + setupPreferenceMapWithDevice(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); @@ -397,10 +494,5 @@ public class AudioSharingBluetoothDeviceUpdaterTest { when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of(mState)); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); doReturn(true).when(mCachedBluetoothDevice).isConnectedLeAudioDevice(); - mDeviceUpdater.onProfileConnectionStateChanged( - mCachedBluetoothDevice, - BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.LE_AUDIO); - shadowOf(Looper.getMainLooper()).idle(); } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java index 95e51e99d51..2bdd0da243f 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java @@ -127,6 +127,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceConnected_noSharing_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mBroadcast.isEnabled(null)).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -146,6 +151,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceConnected_noSource_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of()); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -165,6 +175,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_deviceIsNotInList_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mCachedDevices.clear(); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); @@ -185,6 +200,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceDisconnected_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -204,6 +224,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceDisconnecting_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -224,6 +249,29 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { public void onProfileConnectionStateChanged_leaDeviceConnected_hasSource_addsPreference() { ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); + assertThat(captor.getValue() instanceof AudioSharingDeviceVolumePreference).isTrue(); + assertThat(((AudioSharingDeviceVolumePreference) captor.getValue()).getCachedDevice()) + .isEqualTo(mCachedBluetoothDevice); + } + + @Test + public void onProfileConnectionStateChanged_hasLeaMemberConnected_hasSource_addsPreference() { + ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); + setupPreferenceMapWithDevice(); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); assertThat(captor.getValue() instanceof AudioSharingDeviceVolumePreference).isTrue(); @@ -262,6 +310,12 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void refreshPreference_doNothing() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class)); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(ImmutableList.of()); mDeviceUpdater.refreshPreference(); @@ -276,10 +330,5 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of(mState)); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true); - mDeviceUpdater.onProfileConnectionStateChanged( - mCachedBluetoothDevice, - BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.LE_AUDIO); - shadowOf(Looper.getMainLooper()).idle(); } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java index bac8b30ff16..a739bb3b4fb 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java @@ -309,6 +309,8 @@ public class AudioSharingDeviceVolumeGroupControllerTest { when(mPreference1.getProgress()).thenReturn(TEST_VOLUME_VALUE); mController.setPreferenceGroup(mPreferenceGroup); mController.onDeviceAdded(mPreference1); + shadowOf(Looper.getMainLooper()).idle(); + verify(mPreferenceGroup).setVisible(true); assertThat(mPreferenceGroup.isVisible()).isTrue(); } @@ -365,6 +367,8 @@ public class AudioSharingDeviceVolumeGroupControllerTest { mPreferenceGroup.addPreference(mPreference1); mController.setPreferenceGroup(mPreferenceGroup); mController.onDeviceRemoved(mPreference1); + shadowOf(Looper.getMainLooper()).idle(); + verify(mPreferenceGroup).setVisible(false); assertThat(mPreferenceGroup.isVisible()).isFalse(); } diff --git a/tests/robotests/src/com/android/settings/development/DesktopExperiencePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/desktopexperience/DesktopExperiencePreferenceControllerTest.java similarity index 97% rename from tests/robotests/src/com/android/settings/development/DesktopExperiencePreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/development/desktopexperience/DesktopExperiencePreferenceControllerTest.java index 388e9b21f29..d661441a073 100644 --- a/tests/robotests/src/com/android/settings/development/DesktopExperiencePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/desktopexperience/DesktopExperiencePreferenceControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_EXPERIENCE_FEATURES; import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; @@ -44,6 +44,8 @@ import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; import com.android.window.flags.Flags; import org.junit.Before; diff --git a/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/desktopexperience/DesktopModePreferenceControllerTest.java similarity index 97% rename from tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/development/desktopexperience/DesktopModePreferenceControllerTest.java index 9f718f9db62..ffbe31f0975 100644 --- a/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/desktopexperience/DesktopModePreferenceControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_ON; @@ -44,6 +44,8 @@ import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; import com.android.internal.R; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; import com.android.window.flags.Flags; import org.junit.Before; diff --git a/tests/robotests/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/desktopexperience/DesktopModeSecondaryDisplayPreferenceControllerTest.java similarity index 91% rename from tests/robotests/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/development/desktopexperience/DesktopModeSecondaryDisplayPreferenceControllerTest.java index 2284d92cd70..3203b61609a 100644 --- a/tests/robotests/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/desktopexperience/DesktopModeSecondaryDisplayPreferenceControllerTest.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; -import static com.android.settings.development.DesktopModeSecondaryDisplayPreferenceController.SETTING_VALUE_OFF; -import static com.android.settings.development.DesktopModeSecondaryDisplayPreferenceController.SETTING_VALUE_ON; +import static com.android.settings.development.desktopexperience.DesktopModeSecondaryDisplayPreferenceController.SETTING_VALUE_OFF; +import static com.android.settings.development.desktopexperience.DesktopModeSecondaryDisplayPreferenceController.SETTING_VALUE_ON; import static com.google.common.truth.Truth.assertThat; @@ -44,6 +44,8 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import com.android.internal.R; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; import com.android.window.flags.Flags; import org.junit.Before; @@ -97,9 +99,9 @@ public class DesktopModeSecondaryDisplayPreferenceControllerTest { when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mController.displayPreference(mScreen); when(mResources.getBoolean(R.bool.config_isDesktopModeSupported)).thenReturn(false); - when(mResources - .getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops)) - .thenReturn(false); + when(mResources.getBoolean( + com.android.internal.R.bool.config_canInternalDisplayHostDesktops)).thenReturn( + false); } @DisableFlags(Flags.FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION) diff --git a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/desktopexperience/FreeformWindowsPreferenceControllerTest.java similarity index 93% rename from tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/development/desktopexperience/FreeformWindowsPreferenceControllerTest.java index b4b0bccf832..aacb4b45719 100644 --- a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/desktopexperience/FreeformWindowsPreferenceControllerTest.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.desktopexperience; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; -import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_OFF; -import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_ON; +import static com.android.settings.development.desktopexperience.FreeformWindowsPreferenceController.SETTING_VALUE_OFF; +import static com.android.settings.development.desktopexperience.FreeformWindowsPreferenceController.SETTING_VALUE_ON; import static com.google.common.truth.Truth.assertThat; @@ -43,6 +43,8 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import com.android.internal.R; +import com.android.settings.development.DevelopmentSettingsDashboardFragment; +import com.android.settings.development.RebootConfirmationDialogFragment; import com.android.window.flags.Flags; import org.junit.Before; diff --git a/tests/robotests/src/com/android/settings/development/desktopexperience/OWNERS b/tests/robotests/src/com/android/settings/development/desktopexperience/OWNERS new file mode 100644 index 00000000000..c437f15567d --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/desktopexperience/OWNERS @@ -0,0 +1,2 @@ +include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS +include platform/frameworks/base:/libs/WindowManager/Shell/OWNERS \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/development/NonResizableMultiWindowPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/window/NonResizableMultiWindowPreferenceControllerTest.java similarity index 93% rename from tests/robotests/src/com/android/settings/development/NonResizableMultiWindowPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/development/window/NonResizableMultiWindowPreferenceControllerTest.java index 7e7a258dd0d..7b8b8ae2698 100644 --- a/tests/robotests/src/com/android/settings/development/NonResizableMultiWindowPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/window/NonResizableMultiWindowPreferenceControllerTest.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.android.settings.development; +package com.android.settings.development.window; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW; -import static com.android.settings.development.NonResizableMultiWindowPreferenceController.SETTING_VALUE_OFF; -import static com.android.settings.development.NonResizableMultiWindowPreferenceController.SETTING_VALUE_ON; +import static com.android.settings.development.window.NonResizableMultiWindowPreferenceController.SETTING_VALUE_OFF; +import static com.android.settings.development.window.NonResizableMultiWindowPreferenceController.SETTING_VALUE_ON; import static com.google.common.truth.Truth.assertThat; diff --git a/tests/robotests/src/com/android/settings/development/window/OWNERS b/tests/robotests/src/com/android/settings/development/window/OWNERS new file mode 100644 index 00000000000..6be8a6421d2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/window/OWNERS @@ -0,0 +1,3 @@ +include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS +include platform/frameworks/base:/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS +include platform/frameworks/base:/libs/WindowManager/Shell/OWNERS \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/development/ResizableActivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/window/ResizableActivityPreferenceControllerTest.java similarity index 98% rename from tests/robotests/src/com/android/settings/development/ResizableActivityPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/development/window/ResizableActivityPreferenceControllerTest.java index 9a69a0a62dd..5c1f4294f48 100644 --- a/tests/robotests/src/com/android/settings/development/ResizableActivityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/window/ResizableActivityPreferenceControllerTest.java @@ -1,5 +1,3 @@ -package com.android.settings.development; - /* * Copyright (C) 2017 The Android Open Source Project * @@ -16,6 +14,8 @@ package com.android.settings.development; * limitations under the License. */ +package com.android.settings.development.window; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.verify; diff --git a/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt b/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt index 619d290f0c4..0f845df90e7 100644 --- a/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt +++ b/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt @@ -18,10 +18,12 @@ package com.android.settings.network import android.content.Context import android.os.OutcomeReceiver +import android.platform.test.annotations.EnableFlags import android.telephony.satellite.SatelliteManager import android.telephony.satellite.SatelliteManager.SatelliteException import android.telephony.satellite.SatelliteModemStateCallback import androidx.test.core.app.ApplicationProvider +import com.android.internal.telephony.flags.Flags import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.ListenableFuture import kotlinx.coroutines.flow.first @@ -38,10 +40,10 @@ import org.mockito.Mockito.* import org.mockito.Spy import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule +import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner import java.util.concurrent.Executor - @RunWith(RobolectricTestRunner::class) class SatelliteRepositoryTest { @@ -267,4 +269,35 @@ class SatelliteRepositoryTest { assertThat(flow.first()).isFalse() } -} \ No newline at end of file + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + fun getSatelliteDataOptimizedApps_returnPackageNameList() = runBlocking { + whenever( + mockSatelliteManager.getSatelliteDataOptimizedApps() + ).thenReturn( + listOf( + "com.android.settings", + "com.android.apps.messaging", + "com.android.dialer", + "com.android.systemui" + ) + ) + + val result = repository.getSatelliteDataOptimizedApps() + + assertThat(result.size == 4).isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + fun getSatelliteDataOptimizedApps_noTelephony_returnEmptyList() = runBlocking { + whenever( + mockSatelliteManager.getSatelliteDataOptimizedApps() + ).thenThrow(IllegalStateException("Telephony is null")) + + val result = repository.getSatelliteDataOptimizedApps() + + assertThat(result.isEmpty()).isTrue() + } +} diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt index 427ab7b1685..01015be7730 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt @@ -17,12 +17,15 @@ package com.android.settings.network.telephony import android.content.Context +import android.content.Intent +import android.os.UserHandle import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import android.telephony.TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.network.SatelliteRepository +import com.android.settings.network.SimOnboardingActivity import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.flowOf @@ -33,6 +36,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argThat import org.mockito.kotlin.doNothing import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.spy @@ -107,6 +111,17 @@ class SubscriptionActivationRepositoryTest { verify(context, never()).startActivity(any()) } + @Test + fun setActive_turnOnAndIsEmergencyCallbackMode() = runBlocking { + mockTelephonyManager.stub { + on { emergencyCallbackMode } doReturn true + } + + repository.setActive(subId = SUB_ID, active = true) + + verify(context).startActivity(argThat { action == ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS }) + } + @Test fun setActive_turnOffAndIsEmergencyCallbackMode() = runBlocking { mockTelephonyManager.stub { @@ -131,6 +146,19 @@ class SubscriptionActivationRepositoryTest { }) } + @Test + fun setActive_turnOnAndNotEmergencyCallbackMode() = runBlocking { + mockTelephonyManager.stub { + on { emergencyCallbackMode } doReturn false + } + + repository.setActive(subId = SUB_ID, active = true) + + verify(context).startActivityAsUser(argThat { + component?.className == SimOnboardingActivity::class.qualifiedName + }, eq(UserHandle.CURRENT)) + } + private companion object { const val SUB_ID = 1 } diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListCategoryControllerTest.java new file mode 100644 index 00000000000..74797ae69d3 --- /dev/null +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListCategoryControllerTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2025 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.network.telephony; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.network.telephony.SatelliteAppListCategoryController.MAXIMUM_OF_PREFERENCE_AMOUNT; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Looper; +import android.platform.test.annotations.EnableFlags; + +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.internal.telephony.flags.Flags; +import com.android.settings.network.SatelliteRepository; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Collections; +import java.util.List; + +public class SatelliteAppListCategoryControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private static final List PACKAGE_NAMES = List.of("com.android.settings", + "com.android.apps.messaging", "com.android.dialer", "com.android.systemui"); + private static final String KEY = "SatelliteAppListCategoryControllerTest"; + + @Mock + private PackageManager mPackageManager; + @Mock + private SatelliteRepository mRepository; + + private Context mContext; + private SatelliteAppListCategoryController mController; + + + @Before + public void setUp() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + public void displayPreference_has4SatSupportedApps_showMaxPreference() throws Exception { + when(mRepository.getSatelliteDataOptimizedApps()).thenReturn(PACKAGE_NAMES); + when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn( + new ApplicationInfo()); + mController = new SatelliteAppListCategoryController(mContext, KEY); + mController.init(mRepository); + PreferenceManager preferenceManager = new PreferenceManager(mContext); + PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext); + PreferenceCategory category = new PreferenceCategory(mContext); + category.setKey(mController.getPreferenceKey()); + preferenceScreen.addPreference(category); + + mController.displayPreference(preferenceScreen); + + assertThat(category.getPreferenceCount() == MAXIMUM_OF_PREFERENCE_AMOUNT).isTrue(); + } + + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + public void getAvailabilityStatus_hasSatSupportedApps_returnAvailable() { + when(mRepository.getSatelliteDataOptimizedApps()).thenReturn(PACKAGE_NAMES); + mController = new SatelliteAppListCategoryController(mContext, KEY); + mController.init(mRepository); + + int result = mController.getAvailabilityStatus(); + + assertThat(result).isEqualTo(AVAILABLE); + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + public void getAvailabilityStatus_noSatSupportedApps_returnUnavailable() { + List packageNames = Collections.emptyList(); + when(mRepository.getSatelliteDataOptimizedApps()).thenReturn(packageNames); + mController = new SatelliteAppListCategoryController(mContext, KEY); + mController.init(mRepository); + + int result = mController.getAvailabilityStatus(); + + assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } +} diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListFragmentTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListFragmentTest.java new file mode 100644 index 00000000000..ba91d179f99 --- /dev/null +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListFragmentTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2025 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.network.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Looper; +import android.platform.test.annotations.EnableFlags; + +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.internal.telephony.flags.Flags; +import com.android.settings.network.SatelliteRepository; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.List; + +public class SatelliteAppListFragmentTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private static final List PACKAGE_NAMES = List.of( + "com.android.settings", + "com.android.apps.messaging", + "com.android.dialer", + "com.android.systemui" + ); + private static final String KEY = "SatelliteAppListPreferenceController"; + + @Mock + private PackageManager mPackageManager; + @Mock + private SatelliteRepository mRepository; + + private Context mContext; + private SatelliteAppListFragment.SatelliteAppListPreferenceController mController; + + @Before + public void setUp() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + public void displayPreference_has4SatSupportedApps_showMaxPreference() throws Exception { + when(mRepository.getSatelliteDataOptimizedApps()).thenReturn(PACKAGE_NAMES); + when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn( + new ApplicationInfo()); + mController = new SatelliteAppListFragment.SatelliteAppListPreferenceController(mContext); + mController.init(mRepository); + PreferenceManager preferenceManager = new PreferenceManager(mContext); + PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext); + + mController.displayPreference(preferenceScreen); + + assertThat(preferenceScreen.getPreferenceCount() == PACKAGE_NAMES.size()).isTrue(); + } +}