Merge "Keep FakeFeatureFlagsImpl" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8cfd9b5..b28da4f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1427,6 +1427,19 @@
android:value="true" />
</activity>
+ <activity
+ android:name=".Settings$ManageAdaptiveNotificationsActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.settings.MANAGE_ADAPTIVE_NOTIFICATIONS"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.notification.PoliteNotificationsPreferenceFragment" />
+ <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
+ android:value="@string/menu_key_notifications"/>
+ </activity>
+
<activity android:name="Settings$WallpaperSettingsActivity"
android:label="@string/wallpaper_settings_fragment_title"
android:icon="@drawable/ic_wallpaper"
diff --git a/res/xml/modes_rule_settings.xml b/res/xml/modes_rule_settings.xml
index 0df9f80..5be206e 100644
--- a/res/xml/modes_rule_settings.xml
+++ b/res/xml/modes_rule_settings.xml
@@ -67,5 +67,9 @@
<Preference
android:key="mode_display_settings"
android:title="@string/mode_display_settings_title" />
+
+ <Preference
+ android:key="mode_manual_duration"
+ android:title="@string/zen_category_duration" />
</PreferenceCategory>
</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index e3bb1a1..24d9525 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -303,6 +303,7 @@
public static class UserSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationAccessDetailsActivity extends SettingsActivity { /* empty */ }
+ public static class ManageAdaptiveNotificationsActivity extends SettingsActivity { /* empty */ }
public static class VrListenersSettingsActivity extends SettingsActivity { /* empty */ }
public static class PremiumSmsAccessActivity extends SettingsActivity { /* empty */ }
public static class PictureInPictureSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java
index 7d5d2c7..5b052f2 100644
--- a/src/com/android/settings/SettingsApplication.java
+++ b/src/com/android/settings/SettingsApplication.java
@@ -31,6 +31,7 @@
import com.android.settings.biometrics.fingerprint2.BiometricsEnvironment;
import com.android.settings.core.instrumentation.ElapsedTimeUtils;
import com.android.settings.development.DeveloperOptionsActivityLifecycle;
+import com.android.settings.flags.Flags;
import com.android.settings.fuelgauge.BatterySettingsStorage;
import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.localepicker.LocaleNotificationDataManager;
@@ -49,7 +50,7 @@
public class SettingsApplication extends Application {
private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null);
- private BiometricsEnvironment mBiometricsEnvironment;
+ @Nullable private BiometricsEnvironment mBiometricsEnvironment;
@Override
protected void attachBaseContext(Context base) {
@@ -73,7 +74,9 @@
// Set Spa environment.
setSpaEnvironment();
- mBiometricsEnvironment = new BiometricsEnvironment(this);
+ if (Flags.fingerprintV2Enrollment()) {
+ mBiometricsEnvironment = new BiometricsEnvironment(this);
+ }
if (ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
&& FeatureFlagUtils.isEnabled(this,
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragment.java
index 75b4acf..5e0ec07 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragment.java
@@ -19,6 +19,7 @@
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.os.Bundle;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -66,7 +67,13 @@
@NonNull List<AudioSharingDeviceItem> deviceItems,
@NonNull DialogEventListener listener) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
- final FragmentManager manager = host.getChildFragmentManager();
+ final FragmentManager manager;
+ try {
+ manager = host.getChildFragmentManager();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to show dialog: " + e.getMessage());
+ return;
+ }
sListener = listener;
if (manager.findFragmentByTag(TAG) == null) {
final Bundle bundle = new Bundle();
@@ -79,10 +86,18 @@
}
@Override
+ @NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle arguments = requireArguments();
List<AudioSharingDeviceItem> deviceItems =
arguments.getParcelable(BUNDLE_KEY_DEVICE_ITEMS, List.class);
+ AlertDialog.Builder builder =
+ new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.audio_sharing_call_audio_title);
+ if (deviceItems == null) {
+ Log.d(TAG, "Create dialog error: null deviceItems");
+ return builder.create();
+ }
int checkedItem = -1;
for (AudioSharingDeviceItem item : deviceItems) {
int fallbackActiveGroupId = AudioSharingUtils.getFallbackActiveGroupId(getContext());
@@ -92,17 +107,14 @@
}
String[] choices =
deviceItems.stream().map(AudioSharingDeviceItem::getName).toArray(String[]::new);
- AlertDialog.Builder builder =
- new AlertDialog.Builder(getActivity())
- .setTitle(R.string.audio_sharing_call_audio_title)
- .setSingleChoiceItems(
- choices,
- checkedItem,
- (dialog, which) -> {
- if (sListener != null) {
- sListener.onItemClick(deviceItems.get(which));
- }
- });
+ builder.setSingleChoiceItems(
+ choices,
+ checkedItem,
+ (dialog, which) -> {
+ if (sListener != null) {
+ sListener.onItemClick(deviceItems.get(which));
+ }
+ });
return builder.create();
}
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java
index e9013d7..61b1df1 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragment.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
@@ -44,7 +45,13 @@
*/
public static void show(Fragment host) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
- FragmentManager manager = host.getChildFragmentManager();
+ final FragmentManager manager;
+ try {
+ manager = host.getChildFragmentManager();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to show dialog: " + e.getMessage());
+ return;
+ }
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
if (dialog != null) {
Log.d(TAG, "Dialog is showing, return.");
@@ -56,6 +63,7 @@
}
@Override
+ @NonNull
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog dialog =
AudioSharingDialogFactory.newBuilder(getActivity())
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
index e787be3..f00cf73 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
@@ -77,7 +77,13 @@
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
- final FragmentManager manager = host.getChildFragmentManager();
+ final FragmentManager manager;
+ try {
+ manager = host.getChildFragmentManager();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to show dialog: " + e.getMessage());
+ return;
+ }
sListener = listener;
sEventData = eventData;
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
index 753daaf..81d7979 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java
@@ -414,7 +414,13 @@
private void closeOpeningDialogsOtherThan(String tag) {
if (mHostFragment == null) return;
- List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
+ List<Fragment> fragments;
+ try {
+ fragments = mHostFragment.getChildFragmentManager().getFragments();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to closeOpeningDialogsOtherThan " + tag + ": " + e.getMessage());
+ return;
+ }
for (Fragment fragment : fragments) {
if (fragment instanceof DialogFragment
&& fragment.getTag() != null
@@ -430,7 +436,13 @@
public void closeOpeningDialogsForLeaDevice(@NonNull CachedBluetoothDevice cachedDevice) {
if (mHostFragment == null) return;
int groupId = AudioSharingUtils.getGroupId(cachedDevice);
- List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
+ List<Fragment> fragments;
+ try {
+ fragments = mHostFragment.getChildFragmentManager().getFragments();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to closeOpeningDialogsForLeaDevice: " + e.getMessage());
+ return;
+ }
for (Fragment fragment : fragments) {
CachedBluetoothDevice device = getCachedBluetoothDeviceFromDialog(fragment);
if (device != null
@@ -447,7 +459,13 @@
public void closeOpeningDialogsForNonLeaDevice(@NonNull CachedBluetoothDevice cachedDevice) {
if (mHostFragment == null) return;
String address = cachedDevice.getAddress();
- List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
+ List<Fragment> fragments;
+ try {
+ fragments = mHostFragment.getChildFragmentManager().getFragments();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to closeOpeningDialogsForNonLeaDevice: " + e.getMessage());
+ return;
+ }
for (Fragment fragment : fragments) {
CachedBluetoothDevice device = getCachedBluetoothDeviceFromDialog(fragment);
if (device != null && address != null && address.equals(device.getAddress())) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHelper.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHelper.java
index 69001aa..010a3ba 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHelper.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHelper.java
@@ -51,12 +51,13 @@
public static AlertDialog getDialogIfShowing(
@NonNull FragmentManager manager, @NonNull String tag) {
Fragment dialog = manager.findFragmentByTag(tag);
- return dialog != null
- && dialog instanceof DialogFragment
- && ((DialogFragment) dialog).getDialog() != null
- && ((DialogFragment) dialog).getDialog().isShowing()
- && ((DialogFragment) dialog).getDialog() instanceof AlertDialog
+ return dialog instanceof DialogFragment
+ && ((DialogFragment) dialog).getDialog() != null
+ && ((DialogFragment) dialog).getDialog().isShowing()
+ && ((DialogFragment) dialog).getDialog() instanceof AlertDialog
? (AlertDialog) ((DialogFragment) dialog).getDialog()
: null;
}
+
+ private AudioSharingDialogHelper() {}
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
index dcd8a3b..66e327b 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
@@ -84,7 +84,13 @@
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
- FragmentManager manager = host.getChildFragmentManager();
+ final FragmentManager manager;
+ try {
+ manager = host.getChildFragmentManager();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to show dialog: " + e.getMessage());
+ return;
+ }
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
if (dialog != null) {
int newGroupId = AudioSharingUtils.getGroupId(newDevice);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
index ec669bf..9afa186 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
@@ -81,7 +81,13 @@
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
- final FragmentManager manager = host.getChildFragmentManager();
+ final FragmentManager manager;
+ try {
+ manager = host.getChildFragmentManager();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to show dialog: " + e.getMessage());
+ return;
+ }
sListener = listener;
sNewDevice = newDevice;
sEventData = eventData;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
index b8da290..d026fa7 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
@@ -81,7 +81,13 @@
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
- final FragmentManager manager = host.getChildFragmentManager();
+ final FragmentManager manager;
+ try {
+ manager = host.getChildFragmentManager();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Fail to show dialog: " + e.getMessage());
+ return;
+ }
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
if (dialog != null) {
int newGroupId = AudioSharingUtils.getGroupId(newDevice);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
index f812e06..ad358ed 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
@@ -16,6 +16,8 @@
package com.android.settings.connecteddevice.audiosharing.audiostreams;
+import static java.util.Collections.emptyList;
+
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -50,10 +52,14 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.VolumeControlProfile;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.utils.ThreadUtils;
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
public class AudioStreamMediaService extends Service {
static final String BROADCAST_ID = "audio_stream_media_service_broadcast_id";
@@ -62,118 +68,13 @@
private static final String TAG = "AudioStreamMediaService";
private static final int NOTIFICATION_ID = 1;
private static final int BROADCAST_CONTENT_TEXT = R.string.audio_streams_listening_now;
- private static final String LEAVE_BROADCAST_ACTION = "leave_broadcast_action";
+ @VisibleForTesting static final String LEAVE_BROADCAST_ACTION = "leave_broadcast_action";
private static final String LEAVE_BROADCAST_TEXT = "Leave Broadcast";
private static final String CHANNEL_ID = "bluetooth_notification_channel";
private static final String DEFAULT_DEVICE_NAME = "";
private static final int STATIC_PLAYBACK_DURATION = 100;
private static final int STATIC_PLAYBACK_POSITION = 30;
private static final int ZERO_PLAYBACK_SPEED = 0;
- private final AudioStreamsBroadcastAssistantCallback mBroadcastAssistantCallback =
- new AudioStreamsBroadcastAssistantCallback() {
- @Override
- public void onSourceLost(int broadcastId) {
- super.onSourceLost(broadcastId);
- if (broadcastId == mBroadcastId) {
- Log.d(TAG, "onSourceLost() : stopSelf");
- if (mNotificationManager != null) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
- stopSelf();
- }
- }
-
- @Override
- public void onSourceRemoved(BluetoothDevice sink, int sourceId, int reason) {
- super.onSourceRemoved(sink, sourceId, reason);
- if (mAudioStreamsHelper != null
- && mAudioStreamsHelper.getAllConnectedSources().stream()
- .map(BluetoothLeBroadcastReceiveState::getBroadcastId)
- .noneMatch(id -> id == mBroadcastId)) {
- Log.d(TAG, "onSourceRemoved() : stopSelf");
- if (mNotificationManager != null) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
- stopSelf();
- }
- }
- };
-
- private final BluetoothCallback mBluetoothCallback =
- new BluetoothCallback() {
- @Override
- public void onBluetoothStateChanged(int bluetoothState) {
- if (BluetoothAdapter.STATE_OFF == bluetoothState) {
- Log.d(TAG, "onBluetoothStateChanged() : stopSelf");
- if (mNotificationManager != null) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
- stopSelf();
- }
- }
-
- @Override
- public void onProfileConnectionStateChanged(
- @NonNull CachedBluetoothDevice cachedDevice,
- @ConnectionState int state,
- int bluetoothProfile) {
- if (state == BluetoothAdapter.STATE_DISCONNECTED
- && bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
- && mDevices != null) {
- mDevices.remove(cachedDevice.getDevice());
- cachedDevice
- .getMemberDevice()
- .forEach(
- m -> {
- // Check nullability to pass NullAway check
- if (mDevices != null) {
- mDevices.remove(m.getDevice());
- }
- });
- }
- if (mDevices == null || mDevices.isEmpty()) {
- Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
- if (mNotificationManager != null) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
- stopSelf();
- }
- }
- };
-
- private final BluetoothVolumeControl.Callback mVolumeControlCallback =
- new BluetoothVolumeControl.Callback() {
- @Override
- public void onDeviceVolumeChanged(
- @NonNull BluetoothDevice device,
- @IntRange(from = -255, to = 255) int volume) {
- if (mDevices == null || mDevices.isEmpty()) {
- Log.w(TAG, "active device or device has source is null!");
- return;
- }
- if (mDevices.contains(device)) {
- Log.d(
- TAG,
- "onDeviceVolumeChanged() bluetoothDevice : "
- + device
- + " volume: "
- + volume);
- if (volume == 0) {
- mIsMuted = true;
- } else {
- mIsMuted = false;
- mLatestPositiveVolume = volume;
- }
- if (mLocalSession != null) {
- mLocalSession.setPlaybackState(getPlaybackState());
- if (mNotificationManager != null) {
- mNotificationManager.notify(NOTIFICATION_ID, buildNotification());
- }
- }
- }
- }
- };
-
private final PlaybackState.Builder mPlayStatePlayingBuilder =
new PlaybackState.Builder()
.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_SEEK_TO)
@@ -200,20 +101,24 @@
private final MetricsFeatureProvider mMetricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+ private final AtomicBoolean mIsMuted = new AtomicBoolean(false);
+ // Set 25 as default as the volume range from `VolumeControlProfile` is from 0 to 255.
+ // If the initial volume from `onDeviceVolumeChanged` is larger than zero (not muted), we will
+ // override this value. Otherwise, we raise the volume to 25 when the play button is clicked.
+ private final AtomicInteger mLatestPositiveVolume = new AtomicInteger(25);
+ private final AtomicBoolean mHasStopped = new AtomicBoolean(false);
private int mBroadcastId;
- @Nullable private ArrayList<BluetoothDevice> mDevices;
+ @Nullable private List<BluetoothDevice> mDevices;
@Nullable private LocalBluetoothManager mLocalBtManager;
@Nullable private AudioStreamsHelper mAudioStreamsHelper;
@Nullable private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
@Nullable private VolumeControlProfile mVolumeControl;
@Nullable private NotificationManager mNotificationManager;
-
- // Set 25 as default as the volume range from `VolumeControlProfile` is from 0 to 255.
- // If the initial volume from `onDeviceVolumeChanged` is larger than zero (not muted), we will
- // override this value. Otherwise, we raise the volume to 25 when the play button is clicked.
- private int mLatestPositiveVolume = 25;
- private boolean mIsMuted = false;
- @VisibleForTesting @Nullable MediaSession mLocalSession;
+ @Nullable private MediaSession mLocalSession;
+ @VisibleForTesting @Nullable AudioStreamsBroadcastAssistantCallback mBroadcastAssistantCallback;
+ @VisibleForTesting @Nullable BluetoothCallback mBluetoothCallback;
+ @VisibleForTesting @Nullable BluetoothVolumeControl.Callback mVolumeControlCallback;
+ @VisibleForTesting @Nullable MediaSession.Callback mMediaSessionCallback;
@Override
public void onCreate() {
@@ -250,13 +155,16 @@
mNotificationManager.createNotificationChannel(notificationChannel);
}
+ mBluetoothCallback = new BtCallback();
mLocalBtManager.getEventManager().registerCallback(mBluetoothCallback);
mVolumeControl = mLocalBtManager.getProfileManager().getVolumeControlProfile();
if (mVolumeControl != null) {
+ mVolumeControlCallback = new VolumeControlCallback();
mVolumeControl.registerCallback(mExecutor, mVolumeControlCallback);
}
+ mBroadcastAssistantCallback = new AssistantCallback();
mLeBroadcastAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
}
@@ -264,25 +172,19 @@
public void onDestroy() {
Log.d(TAG, "onDestroy()");
super.onDestroy();
-
if (!AudioSharingUtils.isFeatureEnabled()) {
- Log.d(TAG, "onDestroy() : skip due to feature not enabled");
return;
}
if (mLocalBtManager != null) {
- Log.d(TAG, "onDestroy() : unregister mBluetoothCallback");
mLocalBtManager.getEventManager().unregisterCallback(mBluetoothCallback);
}
- if (mLeBroadcastAssistant != null) {
- Log.d(TAG, "onDestroy() : unregister mBroadcastAssistantCallback");
+ if (mLeBroadcastAssistant != null && mBroadcastAssistantCallback != null) {
mLeBroadcastAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
}
- if (mVolumeControl != null) {
- Log.d(TAG, "onDestroy() : unregister mVolumeControlCallback");
+ if (mVolumeControl != null && mVolumeControlCallback != null) {
mVolumeControl.unregisterCallback(mVolumeControlCallback);
}
if (mLocalSession != null) {
- Log.d(TAG, "onDestroy() : release mLocalSession");
mLocalSession.release();
mLocalSession = null;
}
@@ -291,33 +193,31 @@
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
-
- mBroadcastId = intent != null ? intent.getIntExtra(BROADCAST_ID, -1) : -1;
+ if (intent == null) {
+ Log.w(TAG, "Intent is null. Service will not start.");
+ mHasStopped.set(true);
+ stopSelf();
+ return START_NOT_STICKY;
+ }
+ mBroadcastId = intent.getIntExtra(BROADCAST_ID, -1);
if (mBroadcastId == -1) {
Log.w(TAG, "Invalid broadcast ID. Service will not start.");
- if (mNotificationManager != null) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
+ mHasStopped.set(true);
stopSelf();
return START_NOT_STICKY;
}
-
- if (intent != null) {
- mDevices = intent.getParcelableArrayListExtra(DEVICES, BluetoothDevice.class);
- }
- if (mDevices == null || mDevices.isEmpty()) {
+ var extra = intent.getParcelableArrayListExtra(DEVICES, BluetoothDevice.class);
+ if (extra == null || extra.isEmpty()) {
Log.w(TAG, "No device. Service will not start.");
- if (mNotificationManager != null) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
+ mHasStopped.set(true);
stopSelf();
return START_NOT_STICKY;
}
- if (intent != null) {
- createLocalMediaSession(intent.getStringExtra(BROADCAST_TITLE));
- startForeground(NOTIFICATION_ID, buildNotification());
- }
-
+ mDevices = Collections.synchronizedList(extra);
+ createLocalMediaSession(intent.getStringExtra(BROADCAST_TITLE));
+ startForeground(NOTIFICATION_ID, buildNotification());
+ // Reset in case the service is previously stopped but not yet destroyed.
+ mHasStopped.set(false);
return START_NOT_STICKY;
}
@@ -330,78 +230,12 @@
.build());
mLocalSession.setActive(true);
mLocalSession.setPlaybackState(getPlaybackState());
- mLocalSession.setCallback(
- new MediaSession.Callback() {
- public void onSeekTo(long pos) {
- Log.d(TAG, "onSeekTo: " + pos);
- if (mLocalSession != null) {
- mLocalSession.setPlaybackState(getPlaybackState());
- if (mNotificationManager != null) {
- mNotificationManager.notify(NOTIFICATION_ID, buildNotification());
- }
- }
- }
-
- @Override
- public void onPause() {
- if (mDevices == null || mDevices.isEmpty()) {
- Log.w(TAG, "active device or device has source is null!");
- return;
- }
- Log.d(
- TAG,
- "onPause() setting volume for device : "
- + mDevices.get(0)
- + " volume: "
- + 0);
- if (mVolumeControl != null) {
- mVolumeControl.setDeviceVolume(mDevices.get(0), 0, true);
- mMetricsFeatureProvider.action(
- getApplicationContext(),
- SettingsEnums
- .ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK,
- 1);
- }
- }
-
- @Override
- public void onPlay() {
- if (mDevices == null || mDevices.isEmpty()) {
- Log.w(TAG, "active device or device has source is null!");
- return;
- }
- Log.d(
- TAG,
- "onPlay() setting volume for device : "
- + mDevices.get(0)
- + " volume: "
- + mLatestPositiveVolume);
- if (mVolumeControl != null) {
- mVolumeControl.setDeviceVolume(
- mDevices.get(0), mLatestPositiveVolume, true);
- }
- mMetricsFeatureProvider.action(
- getApplicationContext(),
- SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK,
- 0);
- }
-
- @Override
- public void onCustomAction(@NonNull String action, Bundle extras) {
- Log.d(TAG, "onCustomAction: " + action);
- if (action.equals(LEAVE_BROADCAST_ACTION) && mAudioStreamsHelper != null) {
- mAudioStreamsHelper.removeSource(mBroadcastId);
- mMetricsFeatureProvider.action(
- getApplicationContext(),
- SettingsEnums
- .ACTION_AUDIO_STREAM_NOTIFICATION_LEAVE_BUTTON_CLICK);
- }
- }
- });
+ mMediaSessionCallback = new MediaSessionCallback();
+ mLocalSession.setCallback(mMediaSessionCallback);
}
private PlaybackState getPlaybackState() {
- return mIsMuted ? mPlayStatePausingBuilder.build() : mPlayStatePlayingBuilder.build();
+ return mIsMuted.get() ? mPlayStatePausingBuilder.build() : mPlayStatePlayingBuilder.build();
}
private String getDeviceName() {
@@ -442,4 +276,167 @@
public IBinder onBind(Intent intent) {
return null;
}
+
+ private class AssistantCallback extends AudioStreamsBroadcastAssistantCallback {
+ @Override
+ public void onSourceLost(int broadcastId) {
+ super.onSourceLost(broadcastId);
+ handleRemoveSource();
+ }
+
+ @Override
+ public void onSourceRemoved(BluetoothDevice sink, int sourceId, int reason) {
+ super.onSourceRemoved(sink, sourceId, reason);
+ handleRemoveSource();
+ }
+
+ private void handleRemoveSource() {
+ var unused =
+ ThreadUtils.postOnBackgroundThread(
+ () -> {
+ List<BluetoothLeBroadcastReceiveState> connected =
+ mAudioStreamsHelper == null
+ ? emptyList()
+ : mAudioStreamsHelper.getAllConnectedSources();
+ if (connected.stream()
+ .map(BluetoothLeBroadcastReceiveState::getBroadcastId)
+ .noneMatch(id -> id == mBroadcastId)) {
+ mHasStopped.set(true);
+ stopSelf();
+ }
+ });
+ }
+ }
+
+ private class VolumeControlCallback implements BluetoothVolumeControl.Callback {
+ @Override
+ public void onDeviceVolumeChanged(
+ @NonNull BluetoothDevice device, @IntRange(from = -255, to = 255) int volume) {
+ if (mDevices == null || mDevices.isEmpty()) {
+ Log.w(TAG, "active device or device has source is null!");
+ return;
+ }
+ Log.d(
+ TAG,
+ "onDeviceVolumeChanged() bluetoothDevice : " + device + " volume: " + volume);
+ if (mDevices.contains(device)) {
+ if (volume == 0) {
+ mIsMuted.set(true);
+ } else {
+ mIsMuted.set(false);
+ mLatestPositiveVolume.set(volume);
+ }
+ updateNotification(getPlaybackState());
+ }
+ }
+ }
+
+ private class BtCallback implements BluetoothCallback {
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
+ if (BluetoothAdapter.STATE_OFF == bluetoothState) {
+ Log.d(TAG, "onBluetoothStateChanged() : stopSelf");
+ mHasStopped.set(true);
+ stopSelf();
+ }
+ }
+
+ @Override
+ public void onProfileConnectionStateChanged(
+ @NonNull CachedBluetoothDevice cachedDevice,
+ @ConnectionState int state,
+ int bluetoothProfile) {
+ if (state == BluetoothAdapter.STATE_DISCONNECTED
+ && bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
+ && mDevices != null) {
+ mDevices.remove(cachedDevice.getDevice());
+ cachedDevice
+ .getMemberDevice()
+ .forEach(
+ m -> {
+ // Check nullability to pass NullAway check
+ if (mDevices != null) {
+ mDevices.remove(m.getDevice());
+ }
+ });
+ }
+ if (mDevices == null || mDevices.isEmpty()) {
+ Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
+ mHasStopped.set(true);
+ stopSelf();
+ }
+ }
+ }
+
+ private class MediaSessionCallback extends MediaSession.Callback {
+ public void onSeekTo(long pos) {
+ Log.d(TAG, "onSeekTo: " + pos);
+ updateNotification(getPlaybackState());
+ }
+
+ @Override
+ public void onPause() {
+ if (mDevices == null || mDevices.isEmpty()) {
+ Log.w(TAG, "active device or device has source is null!");
+ return;
+ }
+ Log.d(
+ TAG,
+ "onPause() setting volume for device : " + mDevices.get(0) + " volume: " + 0);
+ setDeviceVolume(mDevices.get(0), /* volume= */ 0);
+ }
+
+ @Override
+ public void onPlay() {
+ if (mDevices == null || mDevices.isEmpty()) {
+ Log.w(TAG, "active device or device has source is null!");
+ return;
+ }
+ Log.d(
+ TAG,
+ "onPlay() setting volume for device : "
+ + mDevices.get(0)
+ + " volume: "
+ + mLatestPositiveVolume.get());
+ setDeviceVolume(mDevices.get(0), mLatestPositiveVolume.get());
+ }
+
+ @Override
+ public void onCustomAction(@NonNull String action, Bundle extras) {
+ Log.d(TAG, "onCustomAction: " + action);
+ if (action.equals(LEAVE_BROADCAST_ACTION) && mAudioStreamsHelper != null) {
+ mAudioStreamsHelper.removeSource(mBroadcastId);
+ mMetricsFeatureProvider.action(
+ getApplicationContext(),
+ SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_LEAVE_BUTTON_CLICK);
+ }
+ }
+
+ private void setDeviceVolume(BluetoothDevice device, int volume) {
+ int event = SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK;
+ var unused =
+ ThreadUtils.postOnBackgroundThread(
+ () -> {
+ if (mVolumeControl != null) {
+ mVolumeControl.setDeviceVolume(device, volume, true);
+ mMetricsFeatureProvider.action(
+ getApplicationContext(), event, volume == 0 ? 1 : 0);
+ }
+ });
+ }
+ }
+
+ private void updateNotification(PlaybackState playbackState) {
+ var unused =
+ ThreadUtils.postOnBackgroundThread(
+ () -> {
+ if (mLocalSession != null) {
+ mLocalSession.setPlaybackState(playbackState);
+ if (mNotificationManager != null && !mHasStopped.get()) {
+ mNotificationManager.notify(
+ NOTIFICATION_ID, buildNotification());
+ }
+ }
+ });
+ }
}
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 11c05f3..734bddc 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -156,6 +156,7 @@
import com.android.settings.notification.ConfigureNotificationSettings;
import com.android.settings.notification.NotificationAccessSettings;
import com.android.settings.notification.NotificationAssistantPicker;
+import com.android.settings.notification.PoliteNotificationsPreferenceFragment;
import com.android.settings.notification.SoundSettings;
import com.android.settings.notification.app.AppBubbleNotificationSettings;
import com.android.settings.notification.app.AppNotificationSettings;
@@ -314,6 +315,7 @@
AppInfoDashboardFragment.class.getName(),
BatterySaverSettings.class.getName(),
AppNotificationSettings.class.getName(),
+ PoliteNotificationsPreferenceFragment.class.getName(),
NotificationAssistantPicker.class.getName(),
ChannelNotificationSettings.class.getName(),
SatelliteSetting.class.getName(),
diff --git a/src/com/android/settings/datausage/DataUsageList.kt b/src/com/android/settings/datausage/DataUsageList.kt
index af115d9..a293277 100644
--- a/src/com/android/settings/datausage/DataUsageList.kt
+++ b/src/com/android/settings/datausage/DataUsageList.kt
@@ -33,13 +33,10 @@
import com.android.settings.dashboard.DashboardFragment
import com.android.settings.datausage.lib.BillingCycleRepository
import com.android.settings.datausage.lib.NetworkUsageData
-import com.android.settings.network.MobileNetworkRepository
import com.android.settings.network.SubscriptionUtil
-import com.android.settings.network.telephony.requireSubscriptionManager
-import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity
+import com.android.settings.network.telephony.SubscriptionRepository
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spaprivileged.framework.common.userManager
-import com.android.settingslib.utils.ThreadUtils
import kotlin.jvm.optionals.getOrNull
/**
@@ -59,7 +56,6 @@
private lateinit var billingCycleRepository: BillingCycleRepository
private var usageAmount: Preference? = null
- private var subscriptionInfoEntity: SubscriptionInfoEntity? = null
private var dataUsageListAppsController: DataUsageListAppsController? = null
private var chartDataUsagePreferenceController: ChartDataUsagePreferenceController? = null
private var dataUsageListHeaderController: DataUsageListHeaderController? = null
@@ -90,7 +86,6 @@
finish()
return
}
- updateSubscriptionInfoEntity()
dataUsageListAppsController = use(DataUsageListAppsController::class.java).apply {
init(template)
}
@@ -132,6 +127,16 @@
viewModel.chartDataFlow.collectLatestWithLifecycle(viewLifecycleOwner) { chartData ->
chartDataUsagePreferenceController?.update(chartData)
}
+ finishIfSubscriptionDisabled()
+ }
+
+ private fun finishIfSubscriptionDisabled() {
+ if (SubscriptionManager.isUsableSubscriptionId(subId)) {
+ SubscriptionRepository(requireContext()).isSubscriptionEnabledFlow(subId)
+ .collectLatestWithLifecycle(viewLifecycleOwner) { isSubscriptionEnabled ->
+ if (!isSubscriptionEnabled) finish()
+ }
+ }
}
override fun getPreferenceScreenResId() = R.xml.data_usage_list
@@ -155,23 +160,12 @@
}
}
- private fun updateSubscriptionInfoEntity() {
- ThreadUtils.postOnBackgroundThread {
- subscriptionInfoEntity =
- MobileNetworkRepository.getInstance(context).getSubInfoById(subId.toString())
- }
- }
-
/** Update chart sweeps and cycle list to reflect [NetworkPolicy] for current [template]. */
private fun updatePolicy(isModifiable: Boolean) {
- val isBillingCycleModifiable = isModifiable && isActiveSubscription()
- dataUsageListHeaderController?.setConfigButtonVisible(isBillingCycleModifiable)
- chartDataUsagePreferenceController?.setBillingCycleModifiable(isBillingCycleModifiable)
+ dataUsageListHeaderController?.setConfigButtonVisible(isModifiable)
+ chartDataUsagePreferenceController?.setBillingCycleModifiable(isModifiable)
}
- private fun isActiveSubscription(): Boolean =
- requireContext().requireSubscriptionManager().getActiveSubscriptionInfo(subId) != null
-
/**
* Updates the chart and detail data when initial loaded or selected cycle changed.
*/
@@ -187,7 +181,7 @@
/** Updates applications data usage. */
private fun updateApps(usageData: NetworkUsageData) {
dataUsageListAppsController?.update(
- carrierId = subscriptionInfoEntity?.carrierId,
+ subId = subId,
startTime = usageData.startTime,
endTime = usageData.endTime,
)
diff --git a/src/com/android/settings/datausage/DataUsageListAppsController.kt b/src/com/android/settings/datausage/DataUsageListAppsController.kt
index 93623f4..d8bddde 100644
--- a/src/com/android/settings/datausage/DataUsageListAppsController.kt
+++ b/src/com/android/settings/datausage/DataUsageListAppsController.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.net.NetworkTemplate
import android.os.Bundle
+import android.telephony.SubscriptionManager
import androidx.annotation.OpenForTesting
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleCoroutineScope
@@ -32,6 +33,7 @@
import com.android.settings.core.SubSettingLauncher
import com.android.settings.datausage.lib.AppDataUsageRepository
import com.android.settings.datausage.lib.NetworkUsageData
+import com.android.settings.network.telephony.requireSubscriptionManager
import com.android.settingslib.AppItem
import com.android.settingslib.net.UidDetailProvider
import kotlinx.coroutines.Dispatchers
@@ -74,8 +76,11 @@
this.cycleData = cycleData
}
- fun update(carrierId: Int?, startTime: Long, endTime: Long) = lifecycleScope.launch {
+ fun update(subId: Int, startTime: Long, endTime: Long) = lifecycleScope.launch {
val apps = withContext(Dispatchers.Default) {
+ val carrierId = if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ mContext.requireSubscriptionManager().getActiveSubscriptionInfo(subId)?.carrierId
+ } else null
repository.getAppPercent(carrierId, startTime, endTime).map { (appItem, percent) ->
AppDataUsagePreference(mContext, appItem, percent, uidDetailProvider).apply {
setOnPreferenceClickListener {
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index b54801a..7cf9e44 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -53,7 +53,8 @@
public int batteryStatus;
public int pluggedStatus;
public boolean discharging = true;
- public boolean isBatteryDefender;
+ public boolean isBatteryDefender = false;
+ public boolean isLongLife = false;
public boolean isFastCharging;
public long remainingTimeUs = 0;
public long averageTimeToDischarge = EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN;
@@ -306,7 +307,7 @@
info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
info.mCharging = info.pluggedStatus != 0;
info.averageTimeToDischarge = estimate.getAverageDischargeTime();
- info.isBatteryDefender =
+ info.isLongLife =
batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_CHARGING_STATUS,
BatteryManager.CHARGING_POLICY_DEFAULT)
@@ -319,7 +320,7 @@
info.isFastCharging =
BatteryStatus.getChargingSpeed(context, batteryBroadcast)
== BatteryStatus.CHARGING_FAST;
- if (info.isBatteryDefender) {
+ if (info.isLongLife) {
info.isBatteryDefender =
FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 9e08664..7cb5733 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -600,12 +600,12 @@
context.getContentResolver(), SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0)
== 1) {
return DockDefenderMode.TEMPORARILY_BYPASSED;
- } else if (batteryInfo.isBatteryDefender
+ } else if (batteryInfo.isLongLife
&& FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
.isExtraDefend()) {
return DockDefenderMode.ACTIVE;
- } else if (!batteryInfo.isBatteryDefender) {
+ } else if (!batteryInfo.isLongLife) {
return DockDefenderMode.FUTURE_BYPASS;
}
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index dc5b226..8ba6374 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -247,7 +247,7 @@
@Override
public boolean isBatteryDefend(BatteryInfo info) {
- return info.isBatteryDefender && !isExtraDefend();
+ return info.isLongLife && !isExtraDefend();
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 639b3c7..6ff2665 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -21,7 +21,6 @@
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
-import com.android.settings.overlay.FeatureFactory;
/** Detect whether the battery is overheated */
public class BatteryDefenderDetector implements BatteryTipDetector {
@@ -35,12 +34,10 @@
@Override
public BatteryTip detect() {
- final boolean isBasicBatteryDefend =
- FeatureFactory.getFeatureFactory()
- .getPowerUsageFeatureProvider()
- .isBatteryDefend(mBatteryInfo);
final int state =
- isBasicBatteryDefend ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
+ mBatteryInfo.isBatteryDefender
+ ? BatteryTip.StateType.NEW
+ : BatteryTip.StateType.INVISIBLE;
final boolean isPluggedIn = mBatteryInfo.pluggedStatus != 0;
return new BatteryDefenderTip(state, isPluggedIn);
}
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index ebb341e..bd892c8 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -41,7 +41,6 @@
import androidx.lifecycle.LifecycleOwner;
import com.android.internal.telephony.flags.Flags;
-import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.mobile.dataservice.MobileNetworkDatabase;
@@ -435,7 +434,7 @@
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_MOBILE_NETWORK_DB_INSERT_SUB_INFO, subId);
insertUiccInfo(subId, telephonyManager);
- insertMobileNetworkInfo(context, subId, telephonyManager);
+ insertMobileNetworkInfo(subId, telephonyManager);
}
} else if (DEBUG) {
Log.d(TAG, "Can not insert subInfo, the entity is null");
@@ -517,20 +516,13 @@
}
}
- private void insertMobileNetworkInfo(Context context, int subId,
- TelephonyManager telephonyManager) {
- MobileNetworkInfoEntity mobileNetworkInfoEntity = convertToMobileNetworkInfoEntity(context,
- subId, telephonyManager);
-
+ private void insertMobileNetworkInfo(int subId, TelephonyManager telephonyManager) {
+ MobileNetworkInfoEntity mobileNetworkInfoEntity =
+ convertToMobileNetworkInfoEntity(subId, telephonyManager);
Log.d(TAG, "insertMobileNetworkInfo, mobileNetworkInfoEntity = "
+ mobileNetworkInfoEntity);
-
- if (mobileNetworkInfoEntity == null) {
- return;
- }
-
if (!sCacheMobileNetworkInfoEntityMap.containsKey(subId)
|| !sCacheMobileNetworkInfoEntityMap.get(subId).equals(mobileNetworkInfoEntity)) {
sCacheMobileNetworkInfoEntityMap.put(subId, mobileNetworkInfoEntity);
@@ -540,7 +532,7 @@
}
}
- private MobileNetworkInfoEntity convertToMobileNetworkInfoEntity(Context context, int subId,
+ private MobileNetworkInfoEntity convertToMobileNetworkInfoEntity(int subId,
TelephonyManager telephonyManager) {
boolean isDataEnabled = false;
if (telephonyManager != null) {
@@ -549,18 +541,8 @@
Log.d(TAG, "TelephonyManager is null, subId = " + subId);
}
- return new MobileNetworkInfoEntity(String.valueOf(subId),
- MobileNetworkUtils.isContactDiscoveryEnabled(context, subId),
- MobileNetworkUtils.isContactDiscoveryVisible(context, subId),
- isDataEnabled,
- MobileNetworkUtils.isCdmaOptions(context, subId),
- MobileNetworkUtils.isGsmOptions(context, subId),
- MobileNetworkUtils.isWorldMode(context, subId),
- MobileNetworkUtils.shouldDisplayNetworkSelectOptions(context, subId),
- MobileNetworkUtils.isTdscdmaSupported(context, subId),
- MobileNetworkUtils.activeNetworkIsCellular(context),
- SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager),
- /* deprecated isDataRoamingEnabled = */ false
+ return new MobileNetworkInfoEntity(String.valueOf(subId), isDataEnabled,
+ SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)
);
}
@@ -681,8 +663,7 @@
public void onUserMobileDataStateChanged(boolean enabled) {
Log.d(TAG, "onUserMobileDataStateChanged enabled " + enabled + " on SUB " + mSubId);
sExecutor.execute(() -> {
- insertMobileNetworkInfo(mContext, mSubId,
- getTelephonyManagerBySubId(mContext, mSubId));
+ insertMobileNetworkInfo(mSubId, getTelephonyManagerBySubId(mContext, mSubId));
});
}
}
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index a4193f8..0fcfcb5 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -36,6 +36,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.EventLog;
@@ -370,7 +371,7 @@
mDataUsagePreference = findPreference(PREF_KEY_DATA_USAGE);
mDataUsagePreference.setVisible(DataUsageUtils.hasWifiRadio(getContext()));
mDataUsagePreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI)
- .build(), 0 /*subId*/);
+ .build(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
mResetInternetPreference = findPreference(PREF_KEY_RESET_INTERNET);
if (mResetInternetPreference != null) {
mResetInternetPreference.setVisible(false);
diff --git a/src/com/android/settings/notification/modes/ManualDurationHelper.java b/src/com/android/settings/notification/modes/ManualDurationHelper.java
new file mode 100644
index 0000000..da9f420
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ManualDurationHelper.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.icu.text.MessageFormat;
+import android.net.Uri;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Class to contain shared utilities for reading and observing the Settings ZEN_DURATION value.
+ */
+class ManualDurationHelper {
+ private Context mContext;
+
+ ManualDurationHelper(@NonNull Context context) {
+ mContext = context;
+ }
+
+ int getZenDuration() {
+ return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ZEN_DURATION,
+ 0);
+ }
+
+ /**
+ * Generates a summary of the duration that manual DND will be on when turned on from
+ * quick settings, for example "Until you turn off" or "[number] hours", based on the given
+ * setting value.
+ */
+ public String getSummary() {
+ int zenDuration = getZenDuration();
+ String summary;
+ if (zenDuration < 0) {
+ summary = mContext.getString(R.string.zen_mode_duration_summary_always_prompt);
+ } else if (zenDuration == 0) {
+ summary = mContext.getString(R.string.zen_mode_duration_summary_forever);
+ } else {
+ if (zenDuration >= 60) {
+ MessageFormat msgFormat = new MessageFormat(
+ mContext.getString(R.string.zen_mode_duration_summary_time_hours),
+ Locale.getDefault());
+ Map<String, Object> msgArgs = new HashMap<>();
+ msgArgs.put("count", zenDuration / 60);
+ summary = msgFormat.format(msgArgs);
+ } else {
+ MessageFormat msgFormat = new MessageFormat(
+ mContext.getString(R.string.zen_mode_duration_summary_time_minutes),
+ Locale.getDefault());
+ Map<String, Object> msgArgs = new HashMap<>();
+ msgArgs.put("count", zenDuration);
+ summary = msgFormat.format(msgArgs);
+ }
+ }
+ return summary;
+ }
+
+ SettingsObserver makeSettingsObserver(@NonNull AbstractZenModePreferenceController controller) {
+ return new SettingsObserver(controller);
+ }
+
+ final class SettingsObserver extends ContentObserver {
+ private static final Uri ZEN_MODE_DURATION_URI = Settings.Secure.getUriFor(
+ Settings.Secure.ZEN_DURATION);
+
+ private final AbstractZenModePreferenceController mPrefController;
+ private Preference mPreference;
+
+ /**
+ * Create a settings observer attached to the provided PreferenceController, whose
+ * updateState method should be called onChange.
+ */
+ SettingsObserver(@NonNull AbstractZenModePreferenceController prefController) {
+ super(mContext.getMainExecutor(), 0);
+ mPrefController = prefController;
+ }
+
+ void setPreference(Preference preference) {
+ mPreference = preference;
+ }
+
+ public void register() {
+ mContext.getContentResolver().registerContentObserver(ZEN_MODE_DURATION_URI, false,
+ this);
+ }
+
+ public void unregister() {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, @Nullable Uri uri) {
+ super.onChange(selfChange, uri);
+ if (ZEN_MODE_DURATION_URI.equals(uri) && mPreference != null) {
+ mPrefController.updateState(mPreference);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ManualDurationPreferenceController.java b/src/com/android/settings/notification/modes/ManualDurationPreferenceController.java
new file mode 100644
index 0000000..073f8ab
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ManualDurationPreferenceController.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import android.content.Context;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.notification.zen.SettingsZenDurationDialog;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
+public class ManualDurationPreferenceController extends AbstractZenModePreferenceController {
+ private static final String TAG = "QsDurationPrefController";
+
+ private final Fragment mParent;
+ private final ManualDurationHelper mDurationHelper;
+ private final ManualDurationHelper.SettingsObserver mSettingsObserver;
+
+ ManualDurationPreferenceController(Context context, String key, Fragment parent,
+ ZenModesBackend backend) {
+ super(context, key, backend);
+ mParent = parent;
+ mDurationHelper = new ManualDurationHelper(context);
+ mSettingsObserver = mDurationHelper.makeSettingsObserver(this);
+ }
+
+ @Override
+ public boolean isAvailable(ZenMode zenMode) {
+ if (!super.isAvailable(zenMode)) {
+ return false;
+ }
+ return zenMode.isManualDnd();
+ }
+
+ // Called by parent fragment onAttach().
+ void registerSettingsObserver() {
+ mSettingsObserver.register();
+ }
+
+ // Called by parent fragment onDetach().
+ void unregisterSettingsObserver() {
+ mSettingsObserver.unregister();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Preference pref = screen.findPreference(getPreferenceKey());
+ if (pref != null) {
+ mSettingsObserver.setPreference(pref);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference, ZenMode unusedZenMode) {
+ // This controller is a link between a Settings value (ZEN_DURATION) and the manual DND
+ // mode. The status of the zen mode object itself doesn't affect the preference
+ // value, as that comes from settings; that value from settings will determine the
+ // condition that is attached to the mode on manual activation. Thus we ignore the actual
+ // zen mode value provided here.
+ preference.setSummary(mDurationHelper.getSummary());
+ preference.setOnPreferenceClickListener(pref -> {
+ // The new setting value is set by the dialog, so we don't need to do it here.
+ final SettingsZenDurationDialog durationDialog = new SettingsZenDurationDialog();
+ durationDialog.show(mParent.getParentFragmentManager(), TAG);
+ return true;
+ });
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
index 4a99b33..6b84414 100644
--- a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
@@ -18,21 +18,32 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.provider.Settings;
import android.widget.Button;
+import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import com.android.settings.R;
+import com.android.settings.notification.SettingsEnableZenModeDialog;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
+import java.time.Duration;
+
class ZenModeButtonPreferenceController extends AbstractZenModePreferenceController {
+ private static final String TAG = "ZenModeButtonPrefController";
private Button mZenButton;
+ private Fragment mParent;
+ private ManualDurationHelper mDurationHelper;
- public ZenModeButtonPreferenceController(Context context, String key, ZenModesBackend backend) {
+ ZenModeButtonPreferenceController(Context context, String key, Fragment parent,
+ ZenModesBackend backend) {
super(context, key, backend);
+ mParent = parent;
+ mDurationHelper = new ManualDurationHelper(context);
}
@Override
@@ -49,7 +60,23 @@
if (zenMode.isActive()) {
mBackend.deactivateMode(zenMode);
} else {
- mBackend.activateMode(zenMode, null);
+ if (zenMode.isManualDnd()) {
+ // if manual DND, potentially ask for or use desired duration
+ int zenDuration = mDurationHelper.getZenDuration();
+ switch (zenDuration) {
+ case Settings.Secure.ZEN_DURATION_PROMPT:
+ new SettingsEnableZenModeDialog().show(
+ mParent.getParentFragmentManager(), TAG);
+ break;
+ case Settings.Secure.ZEN_DURATION_FOREVER:
+ mBackend.activateMode(zenMode, null);
+ break;
+ default:
+ mBackend.activateMode(zenMode, Duration.ofMinutes(zenDuration));
+ }
+ } else {
+ mBackend.activateMode(zenMode, null);
+ }
}
});
if (zenMode.isActive()) {
diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java
index 63ed839..67815b1 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragment.java
@@ -35,7 +35,6 @@
import java.util.List;
public class ZenModeFragment extends ZenModeFragmentBase {
-
// for mode deletion menu
private static final int DELETE_MODE = 1;
@@ -48,7 +47,8 @@
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
List<AbstractPreferenceController> prefControllers = new ArrayList<>();
prefControllers.add(new ZenModeHeaderController(context, "header", this, mBackend));
- prefControllers.add(new ZenModeButtonPreferenceController(context, "activate", mBackend));
+ prefControllers.add(
+ new ZenModeButtonPreferenceController(context, "activate", this, mBackend));
prefControllers.add(new ZenModeActionsPreferenceController(context, "actions", mBackend));
prefControllers.add(new ZenModePeopleLinkPreferenceController(
context, "zen_mode_people", mBackend, mHelperBackend));
@@ -64,10 +64,20 @@
"zen_automatic_trigger_category", this, mBackend));
prefControllers.add(new InterruptionFilterPreferenceController(
context, "allow_filtering", mBackend));
+ prefControllers.add(new ManualDurationPreferenceController(
+ context, "mode_manual_duration", this, mBackend));
return prefControllers;
}
@Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+
+ // allow duration preference controller to listen for settings changes
+ use(ManualDurationPreferenceController.class).registerSettingsObserver();
+ }
+
+ @Override
public void onStart() {
super.onStart();
@@ -79,6 +89,12 @@
}
@Override
+ public void onDetach() {
+ use(ManualDurationPreferenceController.class).unregisterSettingsObserver();
+ super.onDetach();
+ }
+
+ @Override
public int getMetricsCategory() {
// TODO: b/332937635 - make this the correct metrics category
return SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION;
diff --git a/src/com/android/settings/search/SearchFeatureProviderImpl.java b/src/com/android/settings/search/SearchFeatureProviderImpl.java
deleted file mode 100644
index 3a62ddf..0000000
--- a/src/com/android/settings/search/SearchFeatureProviderImpl.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 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.search;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.provider.Settings;
-import android.text.TextUtils;
-
-import androidx.annotation.NonNull;
-
-import com.android.settingslib.search.SearchIndexableResources;
-import com.android.settingslib.search.SearchIndexableResourcesMobile;
-
-/**
- * FeatureProvider for the refactored search code.
- */
-public class SearchFeatureProviderImpl implements SearchFeatureProvider {
-
- private SearchIndexableResources mSearchIndexableResources;
-
- @Override
- public void verifyLaunchSearchResultPageCaller(@NonNull Context context,
- @NonNull String callerPackage) {
- if (TextUtils.isEmpty(callerPackage)) {
- throw new IllegalArgumentException("ExternalSettingsTrampoline intents "
- + "must be called with startActivityForResult");
- }
- final boolean isSettingsPackage = TextUtils.equals(callerPackage, context.getPackageName())
- || TextUtils.equals(getSettingsIntelligencePkgName(context), callerPackage);
- final boolean isAllowlistedPackage = isSignatureAllowlisted(context, callerPackage);
- if (isSettingsPackage || isAllowlistedPackage) {
- return;
- }
- throw new SecurityException("Search result intents must be called with from an "
- + "allowlisted package.");
- }
-
- @Override
- public SearchIndexableResources getSearchIndexableResources() {
- if (mSearchIndexableResources == null) {
- mSearchIndexableResources = new SearchIndexableResourcesMobile();
- }
- return mSearchIndexableResources;
- }
-
- @Override
- public Intent buildSearchIntent(Context context, int pageId) {
- return new Intent(Settings.ACTION_APP_SEARCH_SETTINGS)
- .setPackage(getSettingsIntelligencePkgName(context))
- .putExtra(Intent.EXTRA_REFERRER, buildReferrer(context, pageId));
- }
-
- protected boolean isSignatureAllowlisted(Context context, String callerPackage) {
- return false;
- }
-
- private static Uri buildReferrer(Context context, int pageId) {
- return new Uri.Builder()
- .scheme("android-app")
- .authority(context.getPackageName())
- .path(String.valueOf(pageId))
- .build();
- }
-}
diff --git a/src/com/android/settings/search/SearchFeatureProviderImpl.kt b/src/com/android/settings/search/SearchFeatureProviderImpl.kt
new file mode 100644
index 0000000..2ea9910
--- /dev/null
+++ b/src/com/android/settings/search/SearchFeatureProviderImpl.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.search
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.provider.Settings
+import com.android.settings.search.SearchIndexableResourcesFactory.createSearchIndexableResources
+import com.android.settingslib.search.SearchIndexableResources
+
+/** FeatureProvider for the refactored search code. */
+open class SearchFeatureProviderImpl : SearchFeatureProvider {
+ private val lazySearchIndexableResources by lazy { createSearchIndexableResources() }
+
+ override fun verifyLaunchSearchResultPageCaller(context: Context, callerPackage: String) {
+ require(callerPackage.isNotEmpty()) {
+ "ExternalSettingsTrampoline intents must be called with startActivityForResult"
+ }
+ val isSettingsPackage = callerPackage == context.packageName
+ if (isSettingsPackage ||
+ callerPackage == getSettingsIntelligencePkgName(context) ||
+ isSignatureAllowlisted(context, callerPackage)) {
+ return
+ }
+ throw SecurityException(
+ "Search result intents must be called with from an allowlisted package.")
+ }
+
+ override fun getSearchIndexableResources(): SearchIndexableResources =
+ lazySearchIndexableResources
+
+ override fun buildSearchIntent(context: Context, pageId: Int): Intent =
+ Intent(Settings.ACTION_APP_SEARCH_SETTINGS)
+ .setPackage(getSettingsIntelligencePkgName(context))
+ .putExtra(Intent.EXTRA_REFERRER, buildReferrer(context, pageId))
+
+ protected open fun isSignatureAllowlisted(context: Context, callerPackage: String): Boolean =
+ false
+
+ companion object {
+ private fun buildReferrer(context: Context, pageId: Int): Uri =
+ Uri.Builder()
+ .scheme("android-app")
+ .authority(context.packageName)
+ .path(pageId.toString())
+ .build()
+ }
+}
diff --git a/src/com/android/settings/search/SearchIndexableResourcesFactory.java b/src/com/android/settings/search/SearchIndexableResourcesFactory.java
new file mode 100644
index 0000000..25f34ed
--- /dev/null
+++ b/src/com/android/settings/search/SearchIndexableResourcesFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.search;
+
+import androidx.annotation.NonNull;
+
+import com.android.settingslib.search.SearchIndexableResources;
+import com.android.settingslib.search.SearchIndexableResourcesMobile;
+
+/**
+ * Creates the {@link SearchIndexableResourcesMobile}.
+ * <p>
+ * Since this class is generated by annotation processor, so it can only be created in Java now.
+ */
+class SearchIndexableResourcesFactory {
+ @NonNull
+ static SearchIndexableResources createSearchIndexableResources() {
+ return new SearchIndexableResourcesMobile();
+ }
+}
diff --git a/src/com/android/settings/spa/SpaBridgeActivity.kt b/src/com/android/settings/spa/SpaBridgeActivity.kt
index 61d8f51..d579fdf 100644
--- a/src/com/android/settings/spa/SpaBridgeActivity.kt
+++ b/src/com/android/settings/spa/SpaBridgeActivity.kt
@@ -17,20 +17,18 @@
package com.android.settings.spa
import android.app.Activity
-import android.content.Intent
+import android.content.pm.PackageManager.ComponentInfoFlags
+import android.content.pm.PackageManager.GET_META_DATA
import android.os.Bundle
-import com.android.settings.activityembedding.ActivityEmbeddingUtils
-import com.android.settings.activityembedding.EmbeddedDeepLinkUtils.tryStartMultiPaneDeepLink
-import com.android.settings.spa.SpaDestination.Companion.getDestination
-import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
-import com.android.settingslib.spa.framework.util.appendSpaParams
+import androidx.annotation.VisibleForTesting
+import com.android.settings.SettingsActivity.META_DATA_KEY_HIGHLIGHT_MENU_KEY
/**
* Activity used as a bridge to [SpaActivity].
*
* Since [SpaActivity] is not exported, [SpaActivity] could not be the target activity of
- * <activity-alias>, otherwise all its pages will be exported.
- * So need this bridge activity to sit in the middle of <activity-alias> and [SpaActivity].
+ * <activity-alias>, otherwise all its pages will be exported. So need this bridge activity to sit
+ * in the middle of <activity-alias> and [SpaActivity].
*/
class SpaBridgeActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -41,17 +39,28 @@
companion object {
fun Activity.startSpaActivityFromBridge(destinationFactory: (String) -> String? = { it }) {
- val (destination, highlightMenuKey) = getDestination(destinationFactory) ?: return
- val intent = Intent(this, SpaActivity::class.java)
- .appendSpaParams(
- destination = destination,
- sessionName = SESSION_EXTERNAL,
- )
- if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this) ||
- !tryStartMultiPaneDeepLink(intent, highlightMenuKey)
- ) {
- startActivity(intent)
- }
+ getDestination(destinationFactory)?.startFromExportedActivity(this)
}
+
+ @VisibleForTesting
+ fun Activity.getDestination(
+ destinationFactory: (String) -> String? = { it },
+ ): SpaDestination? {
+ val metaData =
+ packageManager
+ .getActivityInfo(componentName, ComponentInfoFlags.of(GET_META_DATA.toLong()))
+ .metaData
+ val destination = metaData.getString(META_DATA_KEY_DESTINATION)
+ if (destination.isNullOrBlank()) return null
+ val finalDestination = destinationFactory(destination)
+ if (finalDestination.isNullOrBlank()) return null
+ return SpaDestination(
+ destination = finalDestination,
+ highlightMenuKey = metaData.getString(META_DATA_KEY_HIGHLIGHT_MENU_KEY),
+ )
+ }
+
+ @VisibleForTesting
+ const val META_DATA_KEY_DESTINATION = "com.android.settings.spa.DESTINATION"
}
}
diff --git a/src/com/android/settings/spa/SpaDestination.kt b/src/com/android/settings/spa/SpaDestination.kt
index bdec1d8..cb20c37 100644
--- a/src/com/android/settings/spa/SpaDestination.kt
+++ b/src/com/android/settings/spa/SpaDestination.kt
@@ -17,33 +17,26 @@
package com.android.settings.spa
import android.app.Activity
-import android.content.pm.PackageManager
-import androidx.annotation.VisibleForTesting
-import com.android.settings.SettingsActivity.META_DATA_KEY_HIGHLIGHT_MENU_KEY
+import android.content.Intent
+import com.android.settings.activityembedding.ActivityEmbeddingUtils
+import com.android.settings.activityembedding.EmbeddedDeepLinkUtils.tryStartMultiPaneDeepLink
+import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
+import com.android.settingslib.spa.framework.util.appendSpaParams
data class SpaDestination(
val destination: String,
val highlightMenuKey: String?,
) {
- companion object {
- fun Activity.getDestination(
- destinationFactory: (String) -> String? = { it },
- ): SpaDestination? {
- val metaData = packageManager.getActivityInfo(
- componentName,
- PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA.toLong())
- ).metaData
- val destination = metaData.getString(META_DATA_KEY_DESTINATION)
- if (destination.isNullOrBlank()) return null
- val finalDestination = destinationFactory(destination)
- if (finalDestination.isNullOrBlank()) return null
- return SpaDestination(
- destination = finalDestination,
- highlightMenuKey = metaData.getString(META_DATA_KEY_HIGHLIGHT_MENU_KEY),
+ fun startFromExportedActivity(activity: Activity) {
+ val intent = Intent(activity, SpaActivity::class.java)
+ .appendSpaParams(
+ destination = destination,
+ sessionName = SESSION_EXTERNAL,
)
+ if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(activity) ||
+ !activity.tryStartMultiPaneDeepLink(intent, highlightMenuKey)
+ ) {
+ activity.startActivity(intent)
}
-
- @VisibleForTesting
- const val META_DATA_KEY_DESTINATION = "com.android.settings.spa.DESTINATION"
}
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragmentTest.java
index 7f0c1c9..51ed899 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioDialogFragmentTest.java
@@ -23,6 +23,7 @@
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
+import android.os.Bundle;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.appcompat.app.AlertDialog;
@@ -78,10 +79,6 @@
BluetoothStatusCodes.FEATURE_SUPPORTED);
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
- mFragment = new AudioSharingCallAudioDialogFragment();
- mParent = new Fragment();
- FragmentController.setupFragment(
- mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
}
@After
@@ -91,6 +88,7 @@
@Test
public void getMetricsCategory_correctValue() {
+ mFragment = new AudioSharingCallAudioDialogFragment();
assertThat(mFragment.getMetricsCategory())
.isEqualTo(SettingsEnums.DIALOG_AUDIO_SHARING_CALL_AUDIO);
}
@@ -98,21 +96,52 @@
@Test
public void onCreateDialog_flagOff_dialogNotExist() {
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
- mFragment.show(mParent, new ArrayList<>(), (item) -> {});
+ mParent = new Fragment();
+ FragmentController.setupFragment(
+ mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
+ AudioSharingCallAudioDialogFragment.show(mParent, new ArrayList<>(), (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
+ public void onCreateDialog_unattachedFragment_dialogNotExist() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mParent = new Fragment();
+ AudioSharingCallAudioDialogFragment.show(mParent, new ArrayList<>(), (item) -> {});
+ shadowMainLooper().idle();
+ AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNull();
+ }
+
+ @Test
+ public void onCreateDialog_nullDeviceItems_showEmptyDialog() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mFragment = new AudioSharingCallAudioDialogFragment();
+ mFragment.setArguments(Bundle.EMPTY);
+ FragmentController.setupFragment(
+ mFragment, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
+ AlertDialog dialog = (AlertDialog) mFragment.onCreateDialog(Bundle.EMPTY);
+ dialog.show();
+ shadowMainLooper().idle();
+ assertThat(dialog.isShowing()).isTrue();
+ assertThat(dialog.getListView()).isNull();
+ }
+
+ @Test
public void onCreateDialog_showCorrectItems() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mParent = new Fragment();
+ FragmentController.setupFragment(
+ mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
ArrayList<AudioSharingDeviceItem> deviceItemList = new ArrayList<>();
deviceItemList.add(TEST_DEVICE_ITEM1);
deviceItemList.add(TEST_DEVICE_ITEM2);
- mFragment.show(mParent, deviceItemList, (item) -> {});
+ AudioSharingCallAudioDialogFragment.show(mParent, deviceItemList, (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNotNull();
assertThat(dialog.getListView().getCount()).isEqualTo(2);
}
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragmentTest.java
index 32f666f..9aa00fb 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingConfirmDialogFragmentTest.java
@@ -96,6 +96,15 @@
}
@Test
+ public void onCreateDialog_unattachedFragment_dialogNotExist() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ AudioSharingConfirmDialogFragment.show(new Fragment());
+ shadowMainLooper().idle();
+ AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNull();
+ }
+
+ @Test
public void onCreateDialog_flagOn_showDialog() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingConfirmDialogFragment.show(mParent);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java
index 39709c1..20c225c 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java
@@ -130,7 +130,16 @@
AudioSharingDialogFragment.show(
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
+ AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNull();
+ }
+ @Test
+ public void onCreateDialog_unattachedFragment_dialogNotExist() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ AudioSharingDialogFragment.show(
+ new Fragment(), new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
+ shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java
index 53c214b..e71e876 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java
@@ -648,6 +648,15 @@
}
@Test
+ public void closeOpeningDialogsForLeaDevice_unattachedFragment_doNothing() {
+ mParentFragment = new Fragment();
+ mHandler = new AudioSharingDialogHandler(mContext, mParentFragment);
+ mHandler.closeOpeningDialogsForLeaDevice(mCachedDevice1);
+ shadowOf(Looper.getMainLooper()).idle();
+ verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider);
+ }
+
+ @Test
public void closeOpeningDialogsForLeaDevice_closeDisconnectDialog() {
// Show disconnect dialog
setUpBroadcast(true);
@@ -675,6 +684,15 @@
}
@Test
+ public void closeOpeningDialogsForNonLeaDevice_unattachedFragment_doNothing() {
+ mParentFragment = new Fragment();
+ mHandler = new AudioSharingDialogHandler(mContext, mParentFragment);
+ mHandler.closeOpeningDialogsForNonLeaDevice(mCachedDevice2);
+ shadowOf(Looper.getMainLooper()).idle();
+ verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider);
+ }
+
+ @Test
public void closeOpeningDialogsForNonLeaDevice_closeStopDialog() {
// Show stop dialog
setUpBroadcast(true);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragmentTest.java
index 6b984af..86b0d65 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragmentTest.java
@@ -154,6 +154,23 @@
}
@Test
+ public void onCreateDialog_unattachedFragment_dialogNotExist() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mDeviceItems = new ArrayList<>();
+ mDeviceItems.add(TEST_DEVICE_ITEM1);
+ mDeviceItems.add(TEST_DEVICE_ITEM2);
+ AudioSharingDisconnectDialogFragment.show(
+ new Fragment(),
+ mDeviceItems,
+ mCachedDevice3,
+ EMPTY_EVENT_LISTENER,
+ TEST_EVENT_DATA_LIST);
+ shadowMainLooper().idle();
+ AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNull();
+ }
+
+ @Test
public void onCreateDialog_flagOn_dialogShowBtnForTwoDevices() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mDeviceItems = new ArrayList<>();
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java
index 13ea965..2310d75 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java
@@ -164,6 +164,20 @@
}
@Test
+ public void onCreateDialog_unattachedFragment_dialogNotExist() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ AudioSharingJoinDialogFragment.show(
+ new Fragment(),
+ new ArrayList<>(),
+ mCachedDevice2,
+ EMPTY_EVENT_LISTENER,
+ TEST_EVENT_DATA_LIST);
+ shadowMainLooper().idle();
+ AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNull();
+ }
+
+ @Test
public void onCreateDialog_flagOn_dialogShowTextForSingleDevice() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingJoinDialogFragment.show(
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragmentTest.java
index b6babfb..c0af09f 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragmentTest.java
@@ -149,6 +149,20 @@
}
@Test
+ public void onCreateDialog_unattachedFragment_dialogNotExist() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ AudioSharingStopDialogFragment.show(
+ new Fragment(),
+ ImmutableList.of(TEST_DEVICE_ITEM2),
+ mCachedDevice1,
+ EMPTY_EVENT_LISTENER,
+ TEST_EVENT_DATA_LIST);
+ shadowMainLooper().idle();
+ AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNull();
+ }
+
+ @Test
public void onCreateDialog_oneDeviceInSharing_showDialogWithCorrectMessage() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingStopDialogFragment.show(
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
index b184d88..abdd743 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
@@ -18,22 +18,29 @@
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_ID;
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES;
+import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.LEAVE_BROADCAST_ACTION;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
+import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.content.Intent;
@@ -43,14 +50,20 @@
import android.media.session.ISession;
import android.media.session.ISessionController;
import android.media.session.MediaSessionManager;
+import android.os.Bundle;
+import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.DisplayMetrics;
import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
+import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settings.testutils.shadow.ShadowThreadUtils;
import com.android.settingslib.bluetooth.BluetoothEventManager;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -72,10 +85,12 @@
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
+import java.util.Set;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
+ ShadowThreadUtils.class,
ShadowBluetoothAdapter.class,
ShadowBluetoothUtils.class,
ShadowAudioStreamsHelper.class,
@@ -83,6 +98,8 @@
public class AudioStreamMediaServiceTest {
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ private static final String CHANNEL_ID = "bluetooth_notification_channel";
+ private static final String DEVICE_NAME = "name";
@Mock private Resources mResources;
@Mock private LocalBluetoothManager mLocalBtManager;
@Mock private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
@@ -91,17 +108,21 @@
@Mock private MediaSessionManager mMediaSessionManager;
@Mock private BluetoothEventManager mBluetoothEventManager;
@Mock private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+ @Mock private CachedBluetoothDeviceManager mCachedDeviceManager;
@Mock private VolumeControlProfile mVolumeControlProfile;
+ @Mock private CachedBluetoothDevice mCachedBluetoothDevice;
@Mock private BluetoothDevice mDevice;
@Mock private ISession mISession;
@Mock private ISessionController mISessionController;
@Mock private PackageManager mPackageManager;
@Mock private DisplayMetrics mDisplayMetrics;
@Mock private Context mContext;
+ private FakeFeatureFactory mFeatureFactory;
private AudioStreamMediaService mAudioStreamMediaService;
@Before
public void setUp() {
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
ShadowAudioStreamsHelper.setUseMock(mAudioStreamsHelper);
when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(mLeBroadcastAssistant);
ShadowBluetoothAdapter shadowBluetoothAdapter =
@@ -114,6 +135,9 @@
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
when(mLocalBtManager.getEventManager()).thenReturn(mBluetoothEventManager);
when(mLocalBtManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+ when(mLocalBtManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+ when(mCachedDeviceManager.findDevice(any())).thenReturn(mCachedBluetoothDevice);
+ when(mCachedBluetoothDevice.getName()).thenReturn(DEVICE_NAME);
when(mLocalBluetoothProfileManager.getVolumeControlProfile())
.thenReturn(mVolumeControlProfile);
@@ -169,6 +193,25 @@
}
@Test
+ public void onCreate_flagOn_createNewChannel() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ when(mNotificationManager.getNotificationChannel(anyString())).thenReturn(null);
+
+ mAudioStreamMediaService.onCreate();
+
+ ArgumentCaptor<NotificationChannel> notificationChannelCapture =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mNotificationManager)
+ .createNotificationChannel(notificationChannelCapture.capture());
+ NotificationChannel newChannel = notificationChannelCapture.getValue();
+ assertThat(newChannel).isNotNull();
+ assertThat(newChannel.getId()).isEqualTo(CHANNEL_ID);
+ assertThat(newChannel.getName())
+ .isEqualTo(mContext.getString(com.android.settings.R.string.bluetooth));
+ assertThat(newChannel.getImportance()).isEqualTo(NotificationManager.IMPORTANCE_HIGH);
+ }
+
+ @Test
public void onDestroy_flagOff_doNothing() {
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
@@ -183,8 +226,15 @@
@Test
public void onDestroy_flagOn_cleanup() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ var devices = new ArrayList<BluetoothDevice>();
+ devices.add(mDevice);
+
+ Intent intent = new Intent();
+ intent.putExtra(BROADCAST_ID, 1);
+ intent.putParcelableArrayListExtra(DEVICES, devices);
mAudioStreamMediaService.onCreate();
+ mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
mAudioStreamMediaService.onDestroy();
verify(mBluetoothEventManager).unregisterCallback(any());
@@ -196,7 +246,6 @@
public void onStartCommand_noBroadcastId_stopSelf() {
mAudioStreamMediaService.onStartCommand(new Intent(), /* flags= */ 0, /* startId= */ 0);
- assertThat(mAudioStreamMediaService.mLocalSession).isNull();
verify(mAudioStreamMediaService).stopSelf();
}
@@ -207,7 +256,6 @@
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
- assertThat(mAudioStreamMediaService.mLocalSession).isNull();
verify(mAudioStreamMediaService).stopSelf();
}
@@ -222,12 +270,179 @@
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
- assertThat(mAudioStreamMediaService.mLocalSession).isNotNull();
- verify(mAudioStreamMediaService, never()).stopSelf();
+ ArgumentCaptor<Notification> notificationCapture =
+ ArgumentCaptor.forClass(Notification.class);
+ verify(mAudioStreamMediaService).startForeground(anyInt(), notificationCapture.capture());
+ var notification = notificationCapture.getValue();
+ assertThat(notification.getSmallIcon()).isNotNull();
+ assertThat(notification.isStyle(Notification.MediaStyle.class)).isTrue();
- ArgumentCaptor<Notification> notification = ArgumentCaptor.forClass(Notification.class);
- verify(mAudioStreamMediaService).startForeground(anyInt(), notification.capture());
- assertThat(notification.getValue().getSmallIcon()).isNotNull();
- assertThat(notification.getValue().isStyle(Notification.MediaStyle.class)).isTrue();
+ verify(mAudioStreamMediaService, never()).stopSelf();
+ }
+
+ @Test
+ public void assistantCallback_onSourceLost_stopSelf() {
+ mAudioStreamMediaService.onCreate();
+
+ assertThat(mAudioStreamMediaService.mBroadcastAssistantCallback).isNotNull();
+ mAudioStreamMediaService.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 0);
+
+ verify(mAudioStreamMediaService).stopSelf();
+ }
+
+ @Test
+ public void assistantCallback_onSourceRemoved_stopSelf() {
+ mAudioStreamMediaService.onCreate();
+
+ assertThat(mAudioStreamMediaService.mBroadcastAssistantCallback).isNotNull();
+ mAudioStreamMediaService.mBroadcastAssistantCallback.onSourceRemoved(
+ mDevice, /* sourceId= */ 0, /* reason= */ 0);
+
+ verify(mAudioStreamMediaService).stopSelf();
+ }
+
+ @Test
+ public void bluetoothCallback_onBluetoothOff_stopSelf() {
+ mAudioStreamMediaService.onCreate();
+
+ assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
+ mAudioStreamMediaService.mBluetoothCallback.onBluetoothStateChanged(
+ BluetoothAdapter.STATE_OFF);
+
+ verify(mAudioStreamMediaService).stopSelf();
+ }
+
+ @Test
+ public void bluetoothCallback_onDeviceDisconnect_stopSelf() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ mAudioStreamMediaService.onCreate();
+ assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
+ mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+
+ mAudioStreamMediaService.mBluetoothCallback.onProfileConnectionStateChanged(
+ mCachedBluetoothDevice,
+ BluetoothAdapter.STATE_DISCONNECTED,
+ BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+
+ verify(mAudioStreamMediaService).stopSelf();
+ }
+
+ @Test
+ public void bluetoothCallback_onMemberDeviceDisconnect_stopSelf() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mock(BluetoothDevice.class));
+ CachedBluetoothDevice member = mock(CachedBluetoothDevice.class);
+ when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(Set.of(member));
+ when(member.getDevice()).thenReturn(mDevice);
+ var devices = new ArrayList<BluetoothDevice>();
+ devices.add(mDevice);
+
+ Intent intent = new Intent();
+ intent.putExtra(BROADCAST_ID, 1);
+ intent.putParcelableArrayListExtra(DEVICES, devices);
+
+ mAudioStreamMediaService.onCreate();
+ assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
+ mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
+ mAudioStreamMediaService.mBluetoothCallback.onProfileConnectionStateChanged(
+ mCachedBluetoothDevice,
+ BluetoothAdapter.STATE_DISCONNECTED,
+ BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+
+ verify(mAudioStreamMediaService).stopSelf();
+ }
+
+ @Test
+ public void mediaSessionCallback_onSeekTo_updateNotification() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+ mAudioStreamMediaService.onCreate();
+ mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+ assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
+ mAudioStreamMediaService.mMediaSessionCallback.onSeekTo(100);
+
+ verify(mNotificationManager).notify(anyInt(), any());
+ }
+
+ @Test
+ public void mediaSessionCallback_onPause_setVolume() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+ mAudioStreamMediaService.onCreate();
+ mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+ assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
+ mAudioStreamMediaService.mMediaSessionCallback.onPause();
+
+ verify(mVolumeControlProfile).setDeviceVolume(any(), anyInt(), anyBoolean());
+ verify(mFeatureFactory.metricsFeatureProvider)
+ .action(
+ any(),
+ eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK),
+ eq(1));
+ }
+
+ @Test
+ public void mediaSessionCallback_onPlay_setVolume() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+ mAudioStreamMediaService.onCreate();
+ mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+ assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
+ mAudioStreamMediaService.mMediaSessionCallback.onPlay();
+
+ verify(mVolumeControlProfile).setDeviceVolume(any(), anyInt(), anyBoolean());
+ verify(mFeatureFactory.metricsFeatureProvider)
+ .action(
+ any(),
+ eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK),
+ eq(0));
+ }
+
+ @Test
+ public void mediaSessionCallback_onCustomAction_leaveBroadcast() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+ mAudioStreamMediaService.onCreate();
+ mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+ assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
+ mAudioStreamMediaService.mMediaSessionCallback.onCustomAction(
+ LEAVE_BROADCAST_ACTION, Bundle.EMPTY);
+
+ verify(mAudioStreamsHelper).removeSource(anyInt());
+ verify(mFeatureFactory.metricsFeatureProvider)
+ .action(
+ any(),
+ eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_LEAVE_BUTTON_CLICK));
+ }
+
+ @Test
+ public void volumeControlCallback_onDeviceVolumeChanged_updateNotification() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+ mAudioStreamMediaService.onCreate();
+ assertThat(mAudioStreamMediaService.mVolumeControlCallback).isNotNull();
+ mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+ mAudioStreamMediaService.mVolumeControlCallback.onDeviceVolumeChanged(
+ mDevice, /* volume= */ 0);
+
+ verify(mNotificationManager).notify(anyInt(), any());
+ }
+
+ @Test
+ public void onBind_returnNull() {
+ IBinder binder = mAudioStreamMediaService.onBind(new Intent());
+
+ assertThat(binder).isNull();
+ }
+
+ private Intent setupIntent() {
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mDevice);
+ var devices = new ArrayList<BluetoothDevice>();
+ devices.add(mDevice);
+
+ Intent intent = new Intent();
+ intent.putExtra(BROADCAST_ID, 1);
+ intent.putParcelableArrayListExtra(DEVICES, devices);
+ return intent;
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index 7bafc6d..b7e6590 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -789,6 +789,40 @@
expectedChargeLabel);
}
+ @Test
+ public void getBatteryInfo_longlife_shouldSetLonglife() {
+ var batteryIntent = createIntentForLongLifeTest(/* hasLongLife= */ true);
+
+ var batteryInfo =
+ BatteryInfo.getBatteryInfo(
+ mContext,
+ batteryIntent,
+ mBatteryUsageStats,
+ /* estimate= */ MOCK_ESTIMATE,
+ /* elapsedRealtimeUs= */ 0L,
+ /* shortString= */ false,
+ /* currentTimeMs= */ 0L);
+
+ assertThat(batteryInfo.isLongLife).isTrue();
+ }
+
+ @Test
+ public void getBatteryInfo_noLonglife_shouldNotLonglife() {
+ var batteryIntent = createIntentForLongLifeTest(/* hasLongLife= */ false);
+
+ var batteryInfo =
+ BatteryInfo.getBatteryInfo(
+ mContext,
+ batteryIntent,
+ mBatteryUsageStats,
+ /* estimate= */ MOCK_ESTIMATE,
+ /* elapsedRealtimeUs= */ 0L,
+ /* shortString= */ false,
+ /* currentTimeMs= */ 0L);
+
+ assertThat(batteryInfo.isLongLife).isFalse();
+ }
+
private enum ChargingSpeed {
FAST,
REGULAR,
@@ -801,6 +835,15 @@
DOCKED
}
+ private Intent createIntentForLongLifeTest(Boolean hasLongLife) {
+ return new Intent(Intent.ACTION_BATTERY_CHANGED)
+ .putExtra(
+ BatteryManager.EXTRA_CHARGING_STATUS,
+ hasLongLife
+ ? BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE
+ : BatteryManager.CHARGING_POLICY_DEFAULT);
+ }
+
private Intent createIntentForGetBatteryInfoTest(
ChargingType chargingType, ChargingSpeed chargingSpeed, int batteryLevel) {
return createBatteryIntent(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 6b32ff5..cecf8f0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -165,7 +165,7 @@
@Test
public void isBatteryDefend_defenderModeAndExtraDefendAreFalse_returnFalse() {
- mBatteryInfo.isBatteryDefender = false;
+ mBatteryInfo.isLongLife = false;
doReturn(false).when(mPowerFeatureProvider).isExtraDefend();
assertThat(mPowerFeatureProvider.isBatteryDefend(mBatteryInfo)).isFalse();
@@ -173,7 +173,7 @@
@Test
public void isBatteryDefend_defenderModeIsFalse_returnFalse() {
- mBatteryInfo.isBatteryDefender = false;
+ mBatteryInfo.isLongLife = false;
doReturn(true).when(mPowerFeatureProvider).isExtraDefend();
assertThat(mPowerFeatureProvider.isBatteryDefend(mBatteryInfo)).isFalse();
@@ -181,7 +181,7 @@
@Test
public void isBatteryDefend_defenderModeAndExtraDefendAreTrue_returnFalse() {
- mBatteryInfo.isBatteryDefender = true;
+ mBatteryInfo.isLongLife = true;
doReturn(true).when(mPowerFeatureProvider).isExtraDefend();
assertThat(mPowerFeatureProvider.isBatteryDefend(mBatteryInfo)).isFalse();
@@ -189,7 +189,7 @@
@Test
public void isBatteryDefend_extraDefendIsFalse_returnTrue() {
- mBatteryInfo.isBatteryDefender = true;
+ mBatteryInfo.isLongLife = true;
doReturn(false).when(mPowerFeatureProvider).isExtraDefend();
assertThat(mPowerFeatureProvider.isBatteryDefend(mBatteryInfo)).isTrue();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index ab1ceb5..7643c41 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -18,15 +18,12 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.when;
-
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
-import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Test;
@@ -41,28 +38,23 @@
@Mock private BatteryInfo mBatteryInfo;
private BatteryDefenderDetector mBatteryDefenderDetector;
- private FakeFeatureFactory mFakeFeatureFactory;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
final Context context = ApplicationProvider.getApplicationContext();
mBatteryDefenderDetector = new BatteryDefenderDetector(mBatteryInfo, context);
- mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
}
@Test
public void detect_notBatteryDefend_tipInvisible() {
- when(mFakeFeatureFactory.powerUsageFeatureProvider.isBatteryDefend(mBatteryInfo))
- .thenReturn(false);
+ mBatteryInfo.isBatteryDefender = false;
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
}
@Test
public void detect_isBatteryDefend_tipNew() {
- when(mFakeFeatureFactory.powerUsageFeatureProvider.isBatteryDefend(mBatteryInfo))
- .thenReturn(true);
+ mBatteryInfo.isBatteryDefender = true;
assertThat(mBatteryDefenderDetector.detect().getState())
.isEqualTo(BatteryTip.StateType.NEW);
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index fb29e05..0161178 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -51,6 +51,7 @@
import android.os.PowerManager;
import android.os.UserManager;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
@@ -319,7 +320,8 @@
mNetworkProviderSettings.onCreate(Bundle.EMPTY);
verify(mDataUsagePreference).setVisible(true);
- verify(mDataUsagePreference).setTemplate(any(), eq(0) /*subId*/);
+ verify(mDataUsagePreference)
+ .setTemplate(any(), eq(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ManualDurationHelperTest.java b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationHelperTest.java
new file mode 100644
index 0000000..18ee2cf
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationHelperTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class ManualDurationHelperTest {
+ private Context mContext;
+ private ContentResolver mContentResolver;
+
+ private ManualDurationHelper mHelper;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mContentResolver = RuntimeEnvironment.application.getContentResolver();
+
+ mHelper = new ManualDurationHelper(mContext);
+ }
+
+ @Test
+ public void getDurationSummary_durationForever() {
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION,
+ Settings.Secure.ZEN_DURATION_FOREVER);
+ assertThat(mHelper.getSummary()).isEqualTo(
+ mContext.getString(R.string.zen_mode_duration_summary_forever));
+ }
+
+ @Test
+ public void getDurationSummary_durationPrompt() {
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION,
+ Settings.Secure.ZEN_DURATION_PROMPT);
+ assertThat(mHelper.getSummary()).isEqualTo(
+ mContext.getString(R.string.zen_mode_duration_summary_always_prompt));
+ }
+
+ @Test
+ public void getDurationSummary_durationCustom() {
+ // minutes
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION, 45);
+ assertThat(mHelper.getSummary()).isEqualTo("45 minutes");
+
+ // hours
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION, 300);
+ assertThat(mHelper.getSummary()).isEqualTo("5 hours");
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
new file mode 100644
index 0000000..0a600c0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.AutomaticZenRule;
+import android.app.Flags;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+@EnableFlags(Flags.FLAG_MODES_UI)
+public class ManualDurationPreferenceControllerTest {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ private Context mContext;
+ private ContentResolver mContentResolver;
+
+ @Mock
+ private ZenModesBackend mBackend;
+
+ @Mock
+ private Fragment mParent;
+
+ private ManualDurationPreferenceController mPrefController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mContentResolver = RuntimeEnvironment.application.getContentResolver();
+ mPrefController = new ManualDurationPreferenceController(mContext, "key", mParent,
+ mBackend);
+ }
+
+ @Test
+ public void testIsAvailable_onlyForManualDnd() {
+ assertThat(mPrefController.isAvailable(TestModeBuilder.EXAMPLE)).isFalse();
+
+ ZenMode manualDnd = ZenMode.manualDndMode(
+ new AutomaticZenRule.Builder("id", Uri.EMPTY).build(), false);
+ assertThat(mPrefController.isAvailable(manualDnd)).isTrue();
+ }
+
+ @Test
+ public void testUpdateState_durationSummary() {
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION,
+ 45 /* minutes */);
+
+ Preference pref = new Preference(mContext);
+ mPrefController.updateState(pref, TestModeBuilder.EXAMPLE);
+
+ assertThat(pref.getSummary().toString()).contains("45");
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
index 625f231..5869c6b 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
@@ -23,12 +23,18 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AutomaticZenRule;
import android.app.Flags;
+import android.content.ContentResolver;
import android.content.Context;
+import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
import android.widget.Button;
+import androidx.fragment.app.Fragment;
+
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
@@ -42,6 +48,8 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.time.Duration;
+
@EnableFlags(Flags.FLAG_MODES_UI)
@RunWith(RobolectricTestRunner.class)
public final class ZenModeButtonPreferenceControllerTest {
@@ -51,19 +59,24 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
private Context mContext;
+ private ContentResolver mContentResolver;
+
@Mock
private ZenModesBackend mBackend;
+ @Mock
+ private Fragment mParent;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
+ mContentResolver = RuntimeEnvironment.application.getContentResolver();
mController = new ZenModeButtonPreferenceController(
- mContext, "something", mBackend);
+ mContext, "something", mParent, mBackend);
}
@Test
@@ -162,4 +175,34 @@
button.callOnClick();
verify(mBackend).activateMode(zenMode, null);
}
+
+ @Test
+ public void updateStateThenClick_withDuration() {
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION,
+ 45 /* minutes */);
+ Button button = new Button(mContext);
+ LayoutPreference pref = mock(LayoutPreference.class);
+ when(pref.findViewById(anyInt())).thenReturn(button);
+ ZenMode zenMode = ZenMode.manualDndMode(
+ new AutomaticZenRule.Builder("manual", Uri.EMPTY).build(), false);
+
+ mController.updateZenMode(pref, zenMode);
+ button.callOnClick();
+ verify(mBackend).activateMode(zenMode, Duration.ofMinutes(45));
+ }
+
+ @Test
+ public void updateStateThenClick_durationForever() {
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION,
+ Settings.Secure.ZEN_DURATION_FOREVER);
+ Button button = new Button(mContext);
+ LayoutPreference pref = mock(LayoutPreference.class);
+ when(pref.findViewById(anyInt())).thenReturn(button);
+ ZenMode zenMode = ZenMode.manualDndMode(
+ new AutomaticZenRule.Builder("manual", Uri.EMPTY).build(), false);
+
+ mController.updateZenMode(pref, zenMode);
+ button.callOnClick();
+ verify(mBackend).activateMode(zenMode, null);
+ }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
index 8a7419b..599649b 100644
--- a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
@@ -124,8 +124,8 @@
}
@Test(expected = IllegalArgumentException.class)
- public void verifyLaunchSearchResultPageCaller_nullCaller_shouldCrash() {
- mProvider.verifyLaunchSearchResultPageCaller(mActivity, null /* caller */);
+ public void verifyLaunchSearchResultPageCaller_emptyCaller_shouldCrash() {
+ mProvider.verifyLaunchSearchResultPageCaller(mActivity, "");
}
@Test(expected = SecurityException.class)
diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java
index 8339798..766855c 100644
--- a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java
@@ -21,14 +21,10 @@
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.service.trust.TrustAgentService;
-import android.text.TextUtils;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -38,34 +34,30 @@
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedSwitchPreference;
-import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowApplicationPackageManager;
-import java.util.ArrayList;
-import java.util.List;
-
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowLockPatternUtils.class,
ShadowRestrictedLockUtilsInternal.class,
- ShadowDevicePolicyManager.class,
- ShadowApplicationPackageManager.class,
- TrustAgentsPreferenceControllerTest.ShadowTrustAgentManager.class
+ ShadowDevicePolicyManager.class, ShadowApplicationPackageManager.class
})
public class TrustAgentsPreferenceControllerTest {
-
- private static final Intent TEST_INTENT =
- new Intent(TrustAgentService.SERVICE_INTERFACE);
+ private static final ComponentName TRUST_AGENT_A = new ComponentName(
+ "test.data.packageA", "clzAAA");
+ private static final ComponentName TRUST_AGENT_B = new ComponentName(
+ "test.data.packageB", "clzBBB");
+ private static final ComponentName TRUST_AGENT_C = new ComponentName(
+ "test.data.packageC", "clzCCC");
+ private static final ComponentName TRUST_AGENT_D = new ComponentName(
+ "test.data.packageD", "clzDDD");
private Context mContext;
private ShadowApplicationPackageManager mPackageManager;
@@ -84,11 +76,6 @@
mPreferenceScreen.setKey("pref_key");
}
- @After
- public void tearDown() {
- ShadowTrustAgentManager.clearPermissionGrantedList();
- }
-
@Test
public void getAvailabilityStatus_byDefault_shouldBeShown() {
assertThat(mController.getAvailabilityStatus())
@@ -97,8 +84,7 @@
@Test
public void onStart_noTrustAgent_shouldNotAddPreference() {
- final List<ResolveInfo> availableAgents = createFakeAvailableAgents();
- mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
+ installFakeAvailableAgents(/* grantPermission= */ false);
mController.displayPreference(mPreferenceScreen);
mController.onStart();
@@ -106,57 +92,34 @@
assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(0);
}
- @Ignore("b/313612480")
@Test
- public void
- onStart_hasAUninstalledTrustAgent_shouldRemoveOnePreferenceAndLeaveTwoPreferences() {
- final List<ResolveInfo> availableAgents = createFakeAvailableAgents();
- final ResolveInfo uninstalledTrustAgent = availableAgents.get(0);
-
- for (ResolveInfo rInfo : availableAgents) {
- ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
- }
- mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
+ public void onStart_uninstalledTrustAgent_shouldRemoveOnePreferenceAndLeaveTwoPreferences() {
+ installFakeAvailableAgents(/* grantPermission= */ true);
mController.displayPreference(mPreferenceScreen);
mController.onStart();
- availableAgents.remove(uninstalledTrustAgent);
+ uninstallAgent(TRUST_AGENT_A);
- mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
mController.onStart();
assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(2);
}
- @Ignore("b/313612480")
@Test
public void onStart_hasANewTrustAgent_shouldAddOnePreferenceAndHaveFourPreferences() {
- final List<ResolveInfo> availableAgents = createFakeAvailableAgents();
- final ComponentName newComponentName = new ComponentName("test.data.packageD", "clzDDD");
- final ResolveInfo newTrustAgent = createFakeResolveInfo(newComponentName);
- for (ResolveInfo rInfo : availableAgents) {
- ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
- }
- mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
+ installFakeAvailableAgents(/* grantPermission= */ true);
mController.displayPreference(mPreferenceScreen);
mController.onStart();
- availableAgents.add(newTrustAgent);
- ShadowTrustAgentManager.grantPermissionToResolveInfo(newTrustAgent);
+ installFakeAvailableAgent(TRUST_AGENT_D, /* grantPermission= */ true);
- mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
mController.onStart();
assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(4);
}
- @Ignore("b/313612480")
@Test
public void onStart_hasUnrestrictedTrustAgent_shouldAddThreeChangeablePreferences() {
ShadowRestrictedLockUtilsInternal.setKeyguardDisabledFeatures(0);
- final List<ResolveInfo> availableAgents = createFakeAvailableAgents();
- for (ResolveInfo rInfo : availableAgents) {
- ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
- }
- mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
+ installFakeAvailableAgents(/* grantPermission= */ true);
mController.displayPreference(mPreferenceScreen);
mController.onStart();
@@ -169,14 +132,9 @@
}
}
- @Ignore("b/313612480")
@Test
- public void onStart_hasRestrictedTructAgent_shouldAddThreeUnchangeablePreferences() {
- final List<ResolveInfo> availableAgents = createFakeAvailableAgents();
- for (ResolveInfo rInfo : availableAgents) {
- ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
- }
- mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
+ public void onStart_hasRestrictedTrustAgent_shouldAddThreeUnchangeablePreferences() {
+ installFakeAvailableAgents(/* grantPermission= */ true);
ShadowRestrictedLockUtilsInternal.setKeyguardDisabledFeatures(
DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS);
@@ -191,51 +149,30 @@
}
}
- private List<ResolveInfo> createFakeAvailableAgents() {
- final List<ComponentName> componentNames = new ArrayList<>();
- componentNames.add(new ComponentName("test.data.packageA", "clzAAA"));
- componentNames.add(new ComponentName("test.data.packageB", "clzBBB"));
- componentNames.add(new ComponentName("test.data.packageC", "clzCCC"));
- final List<ResolveInfo> result = new ArrayList<>();
- for (ComponentName cn : componentNames) {
- final ResolveInfo ri = createFakeResolveInfo(cn);
- result.add(ri);
- }
- return result;
+ private void installFakeAvailableAgents(boolean grantPermission) {
+ installFakeAvailableAgent(TRUST_AGENT_A, grantPermission);
+ installFakeAvailableAgent(TRUST_AGENT_B, grantPermission);
+ installFakeAvailableAgent(TRUST_AGENT_C, grantPermission);
}
- private ResolveInfo createFakeResolveInfo(ComponentName cn) {
- final ResolveInfo ri = new ResolveInfo();
- ri.serviceInfo = new ServiceInfo();
- ri.serviceInfo.packageName = cn.getPackageName();
- ri.serviceInfo.name = cn.getClassName();
- ri.serviceInfo.applicationInfo = new ApplicationInfo();
- ri.serviceInfo.applicationInfo.packageName = cn.getPackageName();
- ri.serviceInfo.applicationInfo.name = cn.getClassName();
- return ri;
+ private void installFakeAvailableAgent(ComponentName name,
+ boolean grantPermission) {
+ mPackageManager.addServiceIfNotPresent(name);
+ mPackageManager.addIntentFilterForService(name,
+ new IntentFilter(TrustAgentService.SERVICE_INTERFACE));
+ if (!grantPermission) {
+ return;
+ }
+ PackageInfo pkgInfo = mPackageManager.getInternalMutablePackageInfo(
+ name.getPackageName());
+ pkgInfo.requestedPermissions =
+ new String[]{android.Manifest.permission.PROVIDE_TRUST_AGENT};
+ pkgInfo.requestedPermissionsFlags =
+ new int[]{PackageInfo.REQUESTED_PERMISSION_GRANTED};
}
- @Implements(TrustAgentManager.class)
- public static class ShadowTrustAgentManager {
- private final static List<ResolveInfo> sPermissionGrantedList = new ArrayList<>();
-
- @Implementation
- protected boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm) {
- for (ResolveInfo info : sPermissionGrantedList) {
- if (info.serviceInfo.equals(resolveInfo.serviceInfo)) {
- return true;
- }
- }
-
- return false;
- }
-
- private static void grantPermissionToResolveInfo(ResolveInfo rInfo) {
- sPermissionGrantedList.add(rInfo);
- }
-
- private static void clearPermissionGrantedList() {
- sPermissionGrantedList.clear();
- }
+ private void uninstallAgent(ComponentName name) {
+ mPackageManager.removeService(name);
+ mPackageManager.removePackage(name.getPackageName());
}
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/SpaBridgeActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/SpaBridgeActivityTest.kt
new file mode 100644
index 0000000..e29bd96
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/SpaBridgeActivityTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.spa
+
+import android.app.Activity
+import android.content.ComponentName
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.os.Bundle
+import androidx.core.os.bundleOf
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.SettingsActivity.META_DATA_KEY_HIGHLIGHT_MENU_KEY
+import com.android.settings.spa.SpaBridgeActivity.Companion.META_DATA_KEY_DESTINATION
+import com.android.settings.spa.SpaBridgeActivity.Companion.getDestination
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+class SpaBridgeActivityTest {
+ private var activityMetadata: Bundle = bundleOf()
+
+ private val mockPackageManager =
+ mock<PackageManager> {
+ on {
+ getActivityInfo(eq(COMPONENT_NAME), any<PackageManager.ComponentInfoFlags>())
+ } doAnswer { ActivityInfo().apply { metaData = activityMetadata } }
+ }
+
+ private val activity =
+ mock<Activity> {
+ on { componentName } doReturn COMPONENT_NAME
+ on { packageManager } doReturn mockPackageManager
+ }
+
+ @Test
+ fun getDestination_noDestination_returnNull() {
+ activityMetadata = bundleOf()
+
+ val destination = activity.getDestination()
+
+ assertThat(destination).isNull()
+ }
+
+ @Test
+ fun getDestination_withoutHighlightMenuKey() {
+ activityMetadata = bundleOf(META_DATA_KEY_DESTINATION to DESTINATION)
+
+ val (destination, highlightMenuKey) = activity.getDestination()!!
+
+ assertThat(destination).isEqualTo(DESTINATION)
+ assertThat(highlightMenuKey).isNull()
+ }
+
+ @Test
+ fun getDestination_withHighlightMenuKey() {
+ activityMetadata =
+ bundleOf(
+ META_DATA_KEY_DESTINATION to DESTINATION,
+ META_DATA_KEY_HIGHLIGHT_MENU_KEY to HIGHLIGHT_MENU_KEY,
+ )
+
+ val (destination, highlightMenuKey) = activity.getDestination()!!
+
+ assertThat(destination).isEqualTo(DESTINATION)
+ assertThat(highlightMenuKey).isEqualTo(HIGHLIGHT_MENU_KEY)
+ }
+
+ private companion object {
+ const val PACKAGE_NAME = "package.name"
+ const val ACTIVITY_NAME = "ActivityName"
+ val COMPONENT_NAME = ComponentName(PACKAGE_NAME, ACTIVITY_NAME)
+ const val DESTINATION = "Destination"
+ const val HIGHLIGHT_MENU_KEY = "apps"
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/spa/SpaDestinationTest.kt b/tests/spa_unit/src/com/android/settings/spa/SpaDestinationTest.kt
index 0b9eb22..ee658c1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/SpaDestinationTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/SpaDestinationTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,81 +17,32 @@
package com.android.settings.spa
import android.app.Activity
-import android.content.ComponentName
-import android.content.pm.ActivityInfo
-import android.content.pm.PackageManager
-import android.os.Bundle
-import androidx.core.os.bundleOf
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settings.SettingsActivity.META_DATA_KEY_HIGHLIGHT_MENU_KEY
-import com.android.settings.spa.SpaDestination.Companion.META_DATA_KEY_DESTINATION
-import com.android.settings.spa.SpaDestination.Companion.getDestination
-import com.google.common.truth.Truth.assertThat
+import com.android.settingslib.spa.framework.util.KEY_DESTINATION
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.kotlin.any
-import org.mockito.kotlin.doAnswer
-import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.eq
+import org.mockito.kotlin.argThat
import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
class SpaDestinationTest {
- private var activityMetadata: Bundle = bundleOf()
- private val mockPackageManager = mock<PackageManager> {
- on {
- getActivityInfo(
- eq(COMPONENT_NAME),
- any<PackageManager.ComponentInfoFlags>()
- )
- } doAnswer {
- ActivityInfo().apply { metaData = activityMetadata }
- }
- }
-
- private val activity = mock<Activity> {
- on { componentName } doReturn COMPONENT_NAME
- on { packageManager } doReturn mockPackageManager
- }
+ private val activity = mock<Activity>()
@Test
- fun getDestination_noDestination_returnNull() {
- activityMetadata = bundleOf()
+ fun startFromExportedActivity() {
+ val spaDestination = SpaDestination(destination = DESTINATION, highlightMenuKey = null)
- val destination = activity.getDestination()
+ spaDestination.startFromExportedActivity(activity)
- assertThat(destination).isNull()
- }
-
- @Test
- fun getDestination_withoutHighlightMenuKey() {
- activityMetadata = bundleOf(META_DATA_KEY_DESTINATION to DESTINATION)
-
- val (destination, highlightMenuKey) = activity.getDestination()!!
-
- assertThat(destination).isEqualTo(DESTINATION)
- assertThat(highlightMenuKey).isNull()
- }
-
- @Test
- fun getDestination_withHighlightMenuKey() {
- activityMetadata = bundleOf(
- META_DATA_KEY_DESTINATION to DESTINATION,
- META_DATA_KEY_HIGHLIGHT_MENU_KEY to HIGHLIGHT_MENU_KEY,
- )
-
- val (destination, highlightMenuKey) = activity.getDestination()!!
-
- assertThat(destination).isEqualTo(DESTINATION)
- assertThat(highlightMenuKey).isEqualTo(HIGHLIGHT_MENU_KEY)
+ verify(activity).startActivity(argThat {
+ component!!.className == SpaActivity::class.qualifiedName
+ getStringExtra(KEY_DESTINATION) == DESTINATION
+ })
}
private companion object {
- const val PACKAGE_NAME = "package.name"
- const val ACTIVITY_NAME = "ActivityName"
- val COMPONENT_NAME = ComponentName(PACKAGE_NAME, ACTIVITY_NAME)
const val DESTINATION = "Destination"
- const val HIGHLIGHT_MENU_KEY = "apps"
}
}
diff --git a/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
index 152091a..f31e274 100644
--- a/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
@@ -131,8 +131,7 @@
private MobileNetworkInfoEntity setupMobileNetworkInfoEntity(String subId,
boolean isDatEnabled) {
- return new MobileNetworkInfoEntity(subId, false, false, isDatEnabled, false, false, false,
- false, false, false, false, false);
+ return new MobileNetworkInfoEntity(subId, isDatEnabled, false);
}
@Test