Snap for 12210778 from dbbcdd6ebe to 24Q4-release

Change-Id: I31a7d1a612f87f2f310d7c32f0c43c18e6d7038a
This commit is contained in:
Android Build Coastguard Worker
2024-08-10 01:25:48 +00:00
33 changed files with 677 additions and 390 deletions

View File

@@ -44,6 +44,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:contentDescription="@null" android:contentDescription="@null"
android:paddingBottom="24dp"
android:visibility="gone" /> android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView

View File

@@ -152,6 +152,7 @@
android:summary="@string/contact_discovery_opt_in_summary" android:summary="@string/contact_discovery_opt_in_summary"
settings:controller="com.android.settings.network.telephony.ContactDiscoveryPreferenceController"/> settings:controller="com.android.settings.network.telephony.ContactDiscoveryPreferenceController"/>
<!-- Settings search is handled by PreferredNetworkModeSearchItem. -->
<ListPreference <ListPreference
android:key="preferred_network_mode_key" android:key="preferred_network_mode_key"
android:title="@string/preferred_network_mode_title" android:title="@string/preferred_network_mode_title"
@@ -159,8 +160,10 @@
android:entries="@array/preferred_network_mode_choices" android:entries="@array/preferred_network_mode_choices"
android:entryValues="@array/preferred_network_mode_values" android:entryValues="@array/preferred_network_mode_values"
android:dialogTitle="@string/preferred_network_mode_dialogtitle" android:dialogTitle="@string/preferred_network_mode_dialogtitle"
settings:searchable="false"
settings:controller="com.android.settings.network.telephony.PreferredNetworkModePreferenceController"/> settings:controller="com.android.settings.network.telephony.PreferredNetworkModePreferenceController"/>
<!-- Settings search is handled by EnabledNetworkModeSearchItem. -->
<ListPreference <ListPreference
android:key="enabled_networks_key" android:key="enabled_networks_key"
android:title="@string/preferred_network_mode_title" android:title="@string/preferred_network_mode_title"
@@ -168,6 +171,7 @@
android:entries="@array/enabled_networks_choices" android:entries="@array/enabled_networks_choices"
android:entryValues="@array/enabled_networks_values" android:entryValues="@array/enabled_networks_values"
android:dialogTitle="@string/preferred_network_mode_dialogtitle" android:dialogTitle="@string/preferred_network_mode_dialogtitle"
settings:searchable="false"
settings:controller="com.android.settings.network.telephony.EnabledNetworkModePreferenceController"/> settings:controller="com.android.settings.network.telephony.EnabledNetworkModePreferenceController"/>
<Preference <Preference

View File

@@ -89,7 +89,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
private LocalBluetoothManager mManager; private LocalBluetoothManager mManager;
private LocalBluetoothProfileManager mProfileManager; private LocalBluetoothProfileManager mProfileManager;
private CachedBluetoothDevice mCachedDevice; private CachedBluetoothDevice mCachedDevice;
private List<CachedBluetoothDevice> mAllOfCachedDevices; private Set<CachedBluetoothDevice> mCachedDeviceGroup;
private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap = private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap =
new HashMap<String, List<CachedBluetoothDevice>>(); new HashMap<String, List<CachedBluetoothDevice>>();
private boolean mIsLeContactSharingEnabled = false; private boolean mIsLeContactSharingEnabled = false;
@@ -105,7 +105,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
mManager = manager; mManager = manager;
mProfileManager = mManager.getProfileManager(); mProfileManager = mManager.getProfileManager();
mCachedDevice = device; mCachedDevice = device;
mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice);
} }
@Override @Override
@@ -310,10 +310,10 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
private List<LocalBluetoothProfile> getProfiles() { private List<LocalBluetoothProfile> getProfiles() {
List<LocalBluetoothProfile> result = new ArrayList<>(); List<LocalBluetoothProfile> result = new ArrayList<>();
mProfileDeviceMap.clear(); mProfileDeviceMap.clear();
if (mAllOfCachedDevices == null || mAllOfCachedDevices.isEmpty()) { if (mCachedDeviceGroup == null || mCachedDeviceGroup.isEmpty()) {
return result; return result;
} }
for (CachedBluetoothDevice cachedItem : mAllOfCachedDevices) { for (CachedBluetoothDevice cachedItem : mCachedDeviceGroup) {
List<LocalBluetoothProfile> tmpResult = cachedItem.getUiAccessibleProfiles(); List<LocalBluetoothProfile> tmpResult = cachedItem.getUiAccessibleProfiles();
for (LocalBluetoothProfile profile : tmpResult) { for (LocalBluetoothProfile profile : tmpResult) {
if (mProfileDeviceMap.containsKey(profile.toString())) { if (mProfileDeviceMap.containsKey(profile.toString())) {
@@ -514,7 +514,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
@Override @Override
public void onPause() { public void onPause() {
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.unregisterCallback(this); item.unregisterCallback(this);
} }
mProfileManager.removeServiceListener(this); mProfileManager.removeServiceListener(this);
@@ -523,7 +523,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
@Override @Override
public void onResume() { public void onResume() {
updateLeAudioConfig(); updateLeAudioConfig();
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.registerCallback(this); item.registerCallback(this);
} }
mProfileManager.addServiceListener(this); mProfileManager.addServiceListener(this);
@@ -545,11 +545,11 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
@Override @Override
public void onDeviceAttributesChanged() { public void onDeviceAttributesChanged() {
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.unregisterCallback(this); item.unregisterCallback(this);
} }
mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice);
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.registerCallback(this); item.registerCallback(this);
} }

View File

@@ -46,6 +46,7 @@ import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.GearPreference; import com.android.settings.widget.GearPreference;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils;
@@ -55,6 +56,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/** /**
* BluetoothDevicePreference is the preference type used to display each remote * BluetoothDevicePreference is the preference type used to display each remote
@@ -76,7 +78,10 @@ public final class BluetoothDevicePreference extends GearPreference {
} }
private final CachedBluetoothDevice mCachedDevice; private final CachedBluetoothDevice mCachedDevice;
private Set<CachedBluetoothDevice> mCachedDeviceGroup;
private final UserManager mUserManager; private final UserManager mUserManager;
private final LocalBluetoothManager mLocalBtManager;
private Set<BluetoothDevice> mBluetoothDevices; private Set<BluetoothDevice> mBluetoothDevices;
@VisibleForTesting @VisibleForTesting
@@ -113,6 +118,21 @@ public final class BluetoothDevicePreference extends GearPreference {
@Override @Override
public void onDeviceAttributesChanged() { public void onDeviceAttributesChanged() {
onPreferenceAttributesChanged(); onPreferenceAttributesChanged();
Set<CachedBluetoothDevice> newCachedDeviceGroup = new HashSet<>(
Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice));
if (!mCachedDeviceGroup.equals(newCachedDeviceGroup)) {
for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) {
cachedBluetoothDevice.unregisterCallback(this);
}
unregisterMetadataChangedListener();
mCachedDeviceGroup = newCachedDeviceGroup;
for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) {
cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), this);
}
registerMetadataChangedListener();
}
} }
} }
@@ -121,6 +141,7 @@ public final class BluetoothDevicePreference extends GearPreference {
super(context, null); super(context, null);
mResources = getContext().getResources(); mResources = getContext().getResources();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mLocalBtManager = Utils.getLocalBluetoothManager(context);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mShowDevicesWithoutNames = showDeviceWithoutNames; mShowDevicesWithoutNames = showDeviceWithoutNames;
@@ -131,6 +152,8 @@ public final class BluetoothDevicePreference extends GearPreference {
} }
mCachedDevice = cachedDevice; mCachedDevice = cachedDevice;
mCachedDeviceGroup = new HashSet<>(
Utils.findAllCachedBluetoothDevicesByGroupId(mLocalBtManager, mCachedDevice));
mCallback = new BluetoothDevicePreferenceCallback(); mCallback = new BluetoothDevicePreferenceCallback();
mId = sNextId.getAndIncrement(); mId = sNextId.getAndIncrement();
mType = type; mType = type;
@@ -164,7 +187,9 @@ public final class BluetoothDevicePreference extends GearPreference {
protected void onPrepareForRemoval() { protected void onPrepareForRemoval() {
super.onPrepareForRemoval(); super.onPrepareForRemoval();
if (!mIsCallbackRemoved) { if (!mIsCallbackRemoved) {
mCachedDevice.unregisterCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) {
cachedBluetoothDevice.unregisterCallback(mCallback);
}
unregisterMetadataChangedListener(); unregisterMetadataChangedListener();
mIsCallbackRemoved = true; mIsCallbackRemoved = true;
} }
@@ -178,7 +203,9 @@ public final class BluetoothDevicePreference extends GearPreference {
public void onAttached() { public void onAttached() {
super.onAttached(); super.onAttached();
if (mIsCallbackRemoved) { if (mIsCallbackRemoved) {
mCachedDevice.registerCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) {
cachedBluetoothDevice.registerCallback(getContext().getMainExecutor(), mCallback);
}
registerMetadataChangedListener(); registerMetadataChangedListener();
mIsCallbackRemoved = false; mIsCallbackRemoved = false;
} }
@@ -189,7 +216,9 @@ public final class BluetoothDevicePreference extends GearPreference {
public void onDetached() { public void onDetached() {
super.onDetached(); super.onDetached();
if (!mIsCallbackRemoved) { if (!mIsCallbackRemoved) {
mCachedDevice.unregisterCallback(mCallback); for (CachedBluetoothDevice cachedBluetoothDevice : mCachedDeviceGroup) {
cachedBluetoothDevice.unregisterCallback(mCallback);
}
unregisterMetadataChangedListener(); unregisterMetadataChangedListener();
mIsCallbackRemoved = true; mIsCallbackRemoved = true;
} }
@@ -200,16 +229,11 @@ public final class BluetoothDevicePreference extends GearPreference {
Log.d(TAG, "No mBluetoothAdapter"); Log.d(TAG, "No mBluetoothAdapter");
return; return;
} }
if (mBluetoothDevices == null) {
mBluetoothDevices = new HashSet<>(); mBluetoothDevices = mCachedDeviceGroup.stream()
} .map(CachedBluetoothDevice::getDevice)
mBluetoothDevices.clear(); .collect(Collectors.toCollection(HashSet::new));
if (mCachedDevice.getDevice() != null) {
mBluetoothDevices.add(mCachedDevice.getDevice());
}
for (CachedBluetoothDevice cbd : mCachedDevice.getMemberDevice()) {
mBluetoothDevices.add(cbd.getDevice());
}
if (mBluetoothDevices.isEmpty()) { if (mBluetoothDevices.isEmpty()) {
Log.d(TAG, "No BT device to register."); Log.d(TAG, "No BT device to register.");
return; return;

View File

@@ -47,7 +47,7 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.widget.LayoutPreference; import com.android.settingslib.widget.LayoutPreference;
import java.util.List; import java.util.Set;
/** /**
* This class adds a header with device name and status (connected/disconnected, etc.). * This class adds a header with device name and status (connected/disconnected, etc.).
@@ -90,7 +90,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr
LayoutPreference mLayoutPreference; LayoutPreference mLayoutPreference;
LocalBluetoothManager mManager; LocalBluetoothManager mManager;
private CachedBluetoothDevice mCachedDevice; private CachedBluetoothDevice mCachedDevice;
private List<CachedBluetoothDevice> mAllOfCachedDevices; private Set<CachedBluetoothDevice> mCachedDeviceGroup;
@VisibleForTesting @VisibleForTesting
Handler mHandler = new Handler(Looper.getMainLooper()); Handler mHandler = new Handler(Looper.getMainLooper());
@VisibleForTesting @VisibleForTesting
@@ -128,7 +128,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr
return; return;
} }
mIsRegisterCallback = true; mIsRegisterCallback = true;
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.registerCallback(this); item.registerCallback(this);
} }
refresh(); refresh();
@@ -139,7 +139,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr
if (!mIsRegisterCallback) { if (!mIsRegisterCallback) {
return; return;
} }
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.unregisterCallback(this); item.unregisterCallback(this);
} }
@@ -155,7 +155,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr
mCachedDevice = cachedBluetoothDevice; mCachedDevice = cachedBluetoothDevice;
mManager = bluetoothManager; mManager = bluetoothManager;
mProfileManager = bluetoothManager.getProfileManager(); mProfileManager = bluetoothManager.getProfileManager();
mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice);
} }
@VisibleForTesting @VisibleForTesting
@@ -230,7 +230,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr
// Init the battery layouts. // Init the battery layouts.
hideAllOfBatteryLayouts(); hideAllOfBatteryLayouts();
LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile(); LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile();
if (mAllOfCachedDevices.isEmpty()) { if (mCachedDeviceGroup.isEmpty()) {
Log.e(TAG, "There is no LeAudioProfile."); Log.e(TAG, "There is no LeAudioProfile.");
return; return;
} }
@@ -244,7 +244,7 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr
return; return;
} }
for (CachedBluetoothDevice cachedDevice : mAllOfCachedDevices) { for (CachedBluetoothDevice cachedDevice : mCachedDeviceGroup) {
int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice()); int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice());
Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress() Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress()
+ ", deviceId:" + deviceId); + ", deviceId:" + deviceId);
@@ -300,15 +300,15 @@ public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceContr
@Override @Override
public void onDeviceAttributesChanged() { public void onDeviceAttributesChanged() {
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.unregisterCallback(this); item.unregisterCallback(this);
} }
mAllOfCachedDevices = Utils.getAllOfCachedBluetoothDevices(mManager, mCachedDevice); mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice);
for (CachedBluetoothDevice item : mAllOfCachedDevices) { for (CachedBluetoothDevice item : mCachedDeviceGroup) {
item.registerCallback(this); item.registerCallback(this);
} }
if (!mAllOfCachedDevices.isEmpty()) { if (!mCachedDeviceGroup.isEmpty()) {
refresh(); refresh();
} }
} }

View File

@@ -48,8 +48,9 @@ import com.android.settingslib.utils.ThreadUtils;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import java.util.ArrayList; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask; import java.util.concurrent.FutureTask;
@@ -239,12 +240,12 @@ public final class Utils {
* @param cachedBluetoothDevice The main cachedBluetoothDevice. * @param cachedBluetoothDevice The main cachedBluetoothDevice.
* @return all cachedBluetoothDevices with the same groupId. * @return all cachedBluetoothDevices with the same groupId.
*/ */
public static List<CachedBluetoothDevice> getAllOfCachedBluetoothDevices( public static Set<CachedBluetoothDevice> findAllCachedBluetoothDevicesByGroupId(
LocalBluetoothManager localBtMgr, LocalBluetoothManager localBtMgr,
CachedBluetoothDevice cachedBluetoothDevice) { CachedBluetoothDevice cachedBluetoothDevice) {
List<CachedBluetoothDevice> cachedBluetoothDevices = new ArrayList<>(); Set<CachedBluetoothDevice> cachedBluetoothDevices = new HashSet<>();
if (cachedBluetoothDevice == null) { if (cachedBluetoothDevice == null) {
Log.e(TAG, "getAllOfCachedBluetoothDevices: no cachedBluetoothDevice"); Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no cachedBluetoothDevice");
return cachedBluetoothDevices; return cachedBluetoothDevices;
} }
int deviceGroupId = cachedBluetoothDevice.getGroupId(); int deviceGroupId = cachedBluetoothDevice.getGroupId();
@@ -254,7 +255,7 @@ public final class Utils {
} }
if (localBtMgr == null) { if (localBtMgr == null) {
Log.e(TAG, "getAllOfCachedBluetoothDevices: no LocalBluetoothManager"); Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: no LocalBluetoothManager");
return cachedBluetoothDevices; return cachedBluetoothDevices;
} }
CachedBluetoothDevice mainDevice = CachedBluetoothDevice mainDevice =
@@ -262,16 +263,14 @@ public final class Utils {
.filter(cachedDevice -> cachedDevice.getGroupId() == deviceGroupId) .filter(cachedDevice -> cachedDevice.getGroupId() == deviceGroupId)
.findFirst().orElse(null); .findFirst().orElse(null);
if (mainDevice == null) { if (mainDevice == null) {
Log.e(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId Log.e(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId
+ ", no main device."); + ", no main device.");
return cachedBluetoothDevices; return cachedBluetoothDevices;
} }
cachedBluetoothDevice = mainDevice; cachedBluetoothDevice = mainDevice;
cachedBluetoothDevices.add(cachedBluetoothDevice); cachedBluetoothDevices.add(cachedBluetoothDevice);
for (CachedBluetoothDevice member : cachedBluetoothDevice.getMemberDevice()) { cachedBluetoothDevices.addAll(cachedBluetoothDevice.getMemberDevice());
cachedBluetoothDevices.add(member); Log.d(TAG, "findAllCachedBluetoothDevicesByGroupId: groupId = " + deviceGroupId
}
Log.d(TAG, "getAllOfCachedBluetoothDevices: groupId = " + deviceGroupId
+ " , cachedBluetoothDevice = " + cachedBluetoothDevice + " , cachedBluetoothDevice = " + cachedBluetoothDevice
+ " , deviceList = " + cachedBluetoothDevices); + " , deviceList = " + cachedBluetoothDevices);
return cachedBluetoothDevices; return cachedBluetoothDevices;

View File

@@ -30,6 +30,9 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothPairingDetail;
import com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsQrCodeFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -130,9 +133,27 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
builder.setTitle(R.string.audio_sharing_share_dialog_title) builder.setTitle(R.string.audio_sharing_share_dialog_title)
.setCustomImage(R.drawable.audio_sharing_guidance) .setCustomImage(R.drawable.audio_sharing_guidance)
.setCustomMessage(R.string.audio_sharing_dialog_connect_device_content) .setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
.setNegativeButton( .setCustomPositiveButton(
R.string.audio_sharing_close_button_label, R.string.audio_sharing_pair_button_label,
(dig, which) -> onCancelClick()); v -> {
dismiss();
new SubSettingLauncher(getContext())
.setDestination(BluetoothPairingDetail.class.getName())
.setSourceMetricsCategory(getMetricsCategory())
.launch();
logDialogPositiveBtnClick();
})
.setCustomNegativeButton(
R.string.audio_sharing_qrcode_button_label,
v -> {
dismiss();
new SubSettingLauncher(getContext())
.setTitleRes(R.string.audio_streams_qr_code_page_title)
.setDestination(AudioStreamsQrCodeFragment.class.getName())
.setSourceMetricsCategory(getMetricsCategory())
.launch();
logDialogNegativeBtnClick();
});
} else if (deviceItems.size() == 1) { } else if (deviceItems.size() == 1) {
AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems); AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems);
builder.setTitle( builder.setTitle(
@@ -145,11 +166,7 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
v -> { v -> {
if (sListener != null) { if (sListener != null) {
sListener.onItemClick(deviceItem); sListener.onItemClick(deviceItem);
mMetricsFeatureProvider.action( logDialogPositiveBtnClick();
getContext(),
SettingsEnums
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
sEventData);
} }
dismiss(); dismiss();
}) })
@@ -165,6 +182,7 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
(AudioSharingDeviceItem item) -> { (AudioSharingDeviceItem item) -> {
if (sListener != null) { if (sListener != null) {
sListener.onItemClick(item); sListener.onItemClick(item);
logDialogPositiveBtnClick();
} }
dismiss(); dismiss();
}, },
@@ -178,11 +196,22 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
private void onCancelClick() { private void onCancelClick() {
if (sListener != null) { if (sListener != null) {
sListener.onCancelClick(); sListener.onCancelClick();
mMetricsFeatureProvider.action( logDialogNegativeBtnClick();
getContext(),
SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
sEventData);
} }
dismiss(); dismiss();
} }
private void logDialogPositiveBtnClick() {
mMetricsFeatureProvider.action(
getContext(),
SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
sEventData);
}
private void logDialogNegativeBtnClick() {
mMetricsFeatureProvider.action(
getContext(),
SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
sEventData);
}
} }

View File

@@ -499,7 +499,7 @@ public class AudioSharingDialogHandler {
private void removeSourceForGroup( private void removeSourceForGroup(
int groupId, Map<Integer, List<BluetoothDevice>> groupedDevices) { int groupId, Map<Integer, List<BluetoothDevice>> groupedDevices) {
if (mAssistant == null) { if (mAssistant == null) {
Log.d(TAG, "Fail to add source due to null profiles, group = " + groupId); Log.d(TAG, "Fail to remove source due to null profiles, group = " + groupId);
return; return;
} }
if (!groupedDevices.containsKey(groupId)) { if (!groupedDevices.containsKey(groupId)) {

View File

@@ -81,9 +81,15 @@ public class AudioSharingReceiver extends BroadcastReceiver {
break; break;
case ACTION_LE_AUDIO_SHARING_STOP: case ACTION_LE_AUDIO_SHARING_STOP:
LocalBluetoothManager manager = Utils.getLocalBtManager(context); LocalBluetoothManager manager = Utils.getLocalBtManager(context);
AudioSharingUtils.stopBroadcasting(manager); if (BluetoothUtils.isBroadcasting(manager)) {
metricsFeatureProvider.action( AudioSharingUtils.stopBroadcasting(manager);
context, SettingsEnums.ACTION_STOP_AUDIO_SHARING_FROM_NOTIFICATION); metricsFeatureProvider.action(
context, SettingsEnums.ACTION_STOP_AUDIO_SHARING_FROM_NOTIFICATION);
} else {
cancelSharingNotification(context);
metricsFeatureProvider.action(
context, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION);
}
break; break;
default: default:
Log.w(TAG, "Received unexpected intent " + intent.getAction()); Log.w(TAG, "Received unexpected intent " + intent.getAction());

View File

@@ -39,6 +39,11 @@ public class AutoTimePreferenceController extends TogglePreferenceController {
public AutoTimePreferenceController(Context context, String preferenceKey) { public AutoTimePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
mTimeManager = context.getSystemService(TimeManager.class); mTimeManager = context.getSystemService(TimeManager.class);
// This is a no-op implementation of UpdateTimeAndDateCallback to avoid a NPE when
// setTimeAndDateCallback() isn't called, e.g. for slices and other cases where the
// controller is instantiated outside of the context of the real Date & Time settings
// screen.
mCallback = (c) -> {};
} }
public void setDateAndTimeCallback(UpdateTimeAndDateCallback callback) { public void setDateAndTimeCallback(UpdateTimeAndDateCallback callback) {

View File

@@ -40,6 +40,11 @@ public class AutoTimeZonePreferenceController extends TogglePreferenceController
public AutoTimeZonePreferenceController(Context context, String preferenceKey) { public AutoTimeZonePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
mTimeManager = context.getSystemService(TimeManager.class); mTimeManager = context.getSystemService(TimeManager.class);
// This is a no-op implementation of UpdateTimeAndDateCallback to avoid a NPE when
// setTimeAndDateCallback() isn't called, e.g. for slices and other cases where the
// controller is instantiated outside of the context of the real Date & Time settings
// screen.
mCallback = (c) -> {};
} }
/** /**

View File

@@ -43,6 +43,11 @@ public class TimeFormatPreferenceController extends TogglePreferenceController {
public TimeFormatPreferenceController(Context context, String key) { public TimeFormatPreferenceController(Context context, String key) {
super(context, key); super(context, key);
mDummyDate = Calendar.getInstance(); mDummyDate = Calendar.getInstance();
// This is a no-op implementation of UpdateTimeAndDateCallback to avoid a NPE when
// setTimeAndDateCallback() isn't called, e.g. for slices and other cases where the
// controller is instantiated outside of the context of the real Date & Time settings
// screen.
mUpdateTimeAndDateCallback = (c) -> {};
} }
/** /**

View File

@@ -78,6 +78,11 @@ public class DynamicDenylistManager {
return; return;
} }
if (mNetworkPolicyManager == null) {
Log.w(TAG, "syncPolicyIfNeeded: invalid mNetworkPolicyManager");
return;
}
final SharedPreferences.Editor editor = getManualDenylistPref().edit(); final SharedPreferences.Editor editor = getManualDenylistPref().edit();
final int[] existedUids = mNetworkPolicyManager final int[] existedUids = mNetworkPolicyManager
.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND); .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
@@ -91,6 +96,11 @@ public class DynamicDenylistManager {
/** Set policy flags for specific UID. */ /** Set policy flags for specific UID. */
public void setUidPolicyLocked(int uid, int policy) { public void setUidPolicyLocked(int uid, int policy) {
if (mNetworkPolicyManager == null) {
Log.w(TAG, "setUidPolicyLocked: invalid mNetworkPolicyManager");
return;
}
Log.i(TAG, "setUidPolicyLocked: uid=" + uid + " policy=" + policy); Log.i(TAG, "setUidPolicyLocked: uid=" + uid + " policy=" + policy);
synchronized (mLock) { synchronized (mLock) {
mNetworkPolicyManager.setUidPolicy(uid, policy); mNetworkPolicyManager.setUidPolicy(uid, policy);
@@ -100,7 +110,7 @@ public class DynamicDenylistManager {
/** Suggest a list of package to set as POLICY_REJECT. */ /** Suggest a list of package to set as POLICY_REJECT. */
public void setDenylist(Set<Integer> denylistTargetUids) { public void setDenylist(Set<Integer> denylistTargetUids) {
if (denylistTargetUids == null) { if (denylistTargetUids == null || mNetworkPolicyManager == null) {
return; return;
} }
final Set<Integer> manualDenylistUids = getDenylistAllUids(getManualDenylistPref()); final Set<Integer> manualDenylistUids = getDenylistAllUids(getManualDenylistPref());
@@ -164,6 +174,12 @@ public class DynamicDenylistManager {
Log.w(TAG, "resetDenylistIfNeeded: invalid conditions"); Log.w(TAG, "resetDenylistIfNeeded: invalid conditions");
return; return;
} }
if (mNetworkPolicyManager == null) {
Log.w(TAG, "setUidPolicyLocked: invalid mNetworkPolicyManager");
return;
}
synchronized (mLock) { synchronized (mLock) {
final int[] uids = mNetworkPolicyManager final int[] uids = mNetworkPolicyManager
.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND); .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);

View File

@@ -19,9 +19,11 @@ package com.android.settings.network.telephony;
import static androidx.lifecycle.Lifecycle.Event.ON_START; import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static androidx.lifecycle.Lifecycle.Event.ON_STOP; import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.getNetworkModePreferenceType;
import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.setAllowedNetworkTypes; import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.setAllowedNetworkTypes;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager; import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
@@ -44,6 +46,7 @@ import androidx.preference.PreferenceScreen;
import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.flags.Flags;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.AllowedNetworkTypesListener; import com.android.settings.network.AllowedNetworkTypesListener;
import com.android.settings.network.CarrierConfigCache; import com.android.settings.network.CarrierConfigCache;
import com.android.settings.network.SubscriptionsChangeListener; import com.android.settings.network.SubscriptionsChangeListener;
@@ -61,16 +64,17 @@ import java.util.stream.Stream;
* Preference controller for "Enabled network mode" * Preference controller for "Enabled network mode"
*/ */
public class EnabledNetworkModePreferenceController extends public class EnabledNetworkModePreferenceController extends
TelephonyBasePreferenceController implements BasePreferenceController implements
ListPreference.OnPreferenceChangeListener, LifecycleObserver, ListPreference.OnPreferenceChangeListener, LifecycleObserver,
SubscriptionsChangeListener.SubscriptionsChangeListenerClient { SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
private static final String LOG_TAG = "EnabledNetworkMode"; private static final String LOG_TAG = "EnabledNetworkMode";
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private AllowedNetworkTypesListener mAllowedNetworkTypesListener; private AllowedNetworkTypesListener mAllowedNetworkTypesListener;
private Preference mPreference; private Preference mPreference;
private PreferenceScreen mPreferenceScreen; private PreferenceScreen mPreferenceScreen;
private TelephonyManager mTelephonyManager; private TelephonyManager mTelephonyManager;
private CarrierConfigCache mCarrierConfigCache;
private PreferenceEntriesBuilder mBuilder; private PreferenceEntriesBuilder mBuilder;
private SubscriptionsChangeListener mSubscriptionsListener; private SubscriptionsChangeListener mSubscriptionsListener;
private int mCallState = TelephonyManager.CALL_STATE_IDLE; private int mCallState = TelephonyManager.CALL_STATE_IDLE;
@@ -81,36 +85,16 @@ public class EnabledNetworkModePreferenceController extends
public EnabledNetworkModePreferenceController(Context context, String key) { public EnabledNetworkModePreferenceController(Context context, String key) {
super(context, key); super(context, key);
mSubscriptionsListener = new SubscriptionsChangeListener(context, this); mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
mCarrierConfigCache = CarrierConfigCache.getInstance(context);
if (mTelephonyCallback == null) { if (mTelephonyCallback == null) {
mTelephonyCallback = new PhoneCallStateTelephonyCallback(); mTelephonyCallback = new PhoneCallStateTelephonyCallback();
} }
} }
@Override @Override
public int getAvailabilityStatus(int subId) { public int getAvailabilityStatus() {
boolean visible; return getNetworkModePreferenceType(mContext, mSubId)
== NetworkModePreferenceType.EnabledNetworkMode
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId); ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
visible = false;
} else if (carrierConfig == null
|| !CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) {
visible = false;
} else if (carrierConfig.getBoolean(
CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
|| carrierConfig.getBoolean(
CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL)) {
visible = false;
} else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {
visible = false;
} else if (!isCallStateIdle()) {
return AVAILABLE_UNSEARCHABLE;
} else {
visible = true;
}
return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} }
protected boolean isCallStateIdle() { protected boolean isCallStateIdle() {
@@ -953,9 +937,14 @@ public class EnabledNetworkModePreferenceController extends
} }
} }
/**
* Returns the resources associated with Subscription.
*
* @return Resources associated with Subscription.
*/
@VisibleForTesting @VisibleForTesting
PhoneCallStateTelephonyCallback getTelephonyCallback() { Resources getResourcesForSubId() {
return mTelephonyCallback; return SubscriptionManager.getResourcesForSubId(mContext, mSubId);
} }
@Override @Override

View File

@@ -16,9 +16,15 @@
package com.android.settings.network.telephony package com.android.settings.network.telephony
import android.content.Context
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.android.settings.R
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -33,3 +39,62 @@ fun TelephonyManager.setAllowedNetworkTypes(
) )
} }
} }
enum class NetworkModePreferenceType {
EnabledNetworkMode,
PreferredNetworkMode,
None,
}
fun getNetworkModePreferenceType(context: Context, subId: Int): NetworkModePreferenceType {
if (!SubscriptionManager.isValidSubscriptionId(subId)) return NetworkModePreferenceType.None
data class Config(
val carrierConfigApplied: Boolean,
val hideCarrierNetworkSettings: Boolean,
val hidePreferredNetworkType: Boolean,
val worldPhone: Boolean,
)
val config =
CarrierConfigRepository(context).transformConfig(subId) {
Config(
carrierConfigApplied =
getBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL),
hideCarrierNetworkSettings =
getBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL),
hidePreferredNetworkType =
getBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL),
worldPhone = getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL),
)
}
return when {
!config.carrierConfigApplied ||
config.hideCarrierNetworkSettings ||
config.hidePreferredNetworkType -> NetworkModePreferenceType.None
config.worldPhone -> NetworkModePreferenceType.PreferredNetworkMode
else -> NetworkModePreferenceType.EnabledNetworkMode
}
}
class PreferredNetworkModeSearchItem(private val context: Context) :
MobileNetworkSettingsSearchItem {
private val title: String = context.getString(R.string.preferred_network_mode_title)
override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? =
when (getNetworkModePreferenceType(context, subId)) {
NetworkModePreferenceType.PreferredNetworkMode ->
MobileNetworkSettingsSearchResult(
key = "preferred_network_mode_key",
title = title,
)
NetworkModePreferenceType.EnabledNetworkMode ->
MobileNetworkSettingsSearchResult(
key = "enabled_networks_key",
title = title,
)
else -> null
}
}

View File

@@ -20,11 +20,13 @@ import android.content.Context
import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.telephony.data.ApnSetting import android.telephony.data.ApnSetting
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.android.settings.R import com.android.settings.R
import com.android.settings.Settings.MobileNetworkActivity.EXTRA_MMS_MESSAGE import com.android.settings.Settings.MobileNetworkActivity.EXTRA_MMS_MESSAGE
import com.android.settings.core.TogglePreferenceController import com.android.settings.core.TogglePreferenceController
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@@ -109,7 +111,7 @@ constructor(
} }
class MmsMessageSearchItem( class MmsMessageSearchItem(
context: Context, private val context: Context,
private val getDefaultDataSubId: () -> Int = { private val getDefaultDataSubId: () -> Int = {
SubscriptionManager.getDefaultDataSubscriptionId() SubscriptionManager.getDefaultDataSubscriptionId()
}, },
@@ -117,12 +119,18 @@ constructor(
private var telephonyManager: TelephonyManager = private var telephonyManager: TelephonyManager =
context.getSystemService(TelephonyManager::class.java)!! context.getSystemService(TelephonyManager::class.java)!!
override val key: String = EXTRA_MMS_MESSAGE @VisibleForTesting
override val title: String = context.getString(R.string.mms_message_title) fun isAvailable(subId: Int): Boolean =
override fun isAvailable(subId: Int): Boolean =
getAvailabilityStatus( getAvailabilityStatus(
telephonyManager.createForSubscriptionId(subId), subId, getDefaultDataSubId) telephonyManager.createForSubscriptionId(subId), subId, getDefaultDataSubId)
override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
if (!isAvailable(subId)) return null
return MobileNetworkSettingsSearchResult(
key = EXTRA_MMS_MESSAGE,
title = context.getString(R.string.mms_message_title),
)
}
} }
} }
} }

View File

@@ -39,15 +39,14 @@ class MobileNetworkSettingsSearchIndex(
private val searchItemsFactory: (context: Context) -> List<MobileNetworkSettingsSearchItem> = private val searchItemsFactory: (context: Context) -> List<MobileNetworkSettingsSearchItem> =
::createSearchItems, ::createSearchItems,
) { ) {
data class MobileNetworkSettingsSearchResult(
val key: String,
val title: String,
val keywords: String? = null,
)
interface MobileNetworkSettingsSearchItem { interface MobileNetworkSettingsSearchItem {
val key: String fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult?
val title: String
val keywords: String?
get() = null
fun isAvailable(subId: Int): Boolean
} }
fun createSearchIndexableData(): SearchIndexableData { fun createSearchIndexableData(): SearchIndexableData {
@@ -71,13 +70,15 @@ class MobileNetworkSettingsSearchIndex(
searchItem: MobileNetworkSettingsSearchItem, searchItem: MobileNetworkSettingsSearchItem,
subInfos: List<SubscriptionInfo> subInfos: List<SubscriptionInfo>
): List<SearchIndexableRaw> = ): List<SearchIndexableRaw> =
subInfos subInfos.mapNotNull { subInfo ->
.filter { searchItem.isAvailable(it.subscriptionId) } searchItem.getSearchResult(subInfo.subscriptionId)?.let { searchResult ->
.map { subInfo -> searchIndexableRaw(context, searchItem, subInfo) } searchIndexableRaw(context, searchResult, subInfo)
}
}
private fun searchIndexableRaw( private fun searchIndexableRaw(
context: Context, context: Context,
searchItem: MobileNetworkSettingsSearchItem, searchResult: MobileNetworkSettingsSearchResult,
subInfo: SubscriptionInfo, subInfo: SubscriptionInfo,
): SearchIndexableRaw { ): SearchIndexableRaw {
val key = val key =
@@ -85,7 +86,7 @@ class MobileNetworkSettingsSearchIndex(
.setFragment( .setFragment(
SpaSearchLandingFragment.newBuilder() SpaSearchLandingFragment.newBuilder()
.setFragmentName(MobileNetworkSettings::class.java.name) .setFragmentName(MobileNetworkSettings::class.java.name)
.setPreferenceKey(searchItem.key) .setPreferenceKey(searchResult.key)
.putArguments( .putArguments(
Settings.EXTRA_SUB_ID, Settings.EXTRA_SUB_ID,
BundleValue.newBuilder().setIntValue(subInfo.subscriptionId).build())) BundleValue.newBuilder().setIntValue(subInfo.subscriptionId).build()))
@@ -94,8 +95,8 @@ class MobileNetworkSettingsSearchIndex(
return createSearchIndexableRaw( return createSearchIndexableRaw(
context = context, context = context,
spaSearchLandingKey = key, spaSearchLandingKey = key,
itemTitle = searchItem.title, itemTitle = searchResult.title,
keywords = searchItem.keywords, keywords = searchResult.keywords,
indexableClass = MobileNetworkSettings::class.java, indexableClass = MobileNetworkSettings::class.java,
pageTitle = "$simsTitle > ${subInfo.displayName}", pageTitle = "$simsTitle > ${subInfo.displayName}",
) )
@@ -115,6 +116,7 @@ class MobileNetworkSettingsSearchIndex(
listOf( listOf(
MmsMessageSearchItem(context), MmsMessageSearchItem(context),
NrAdvancedCallingSearchItem(context), NrAdvancedCallingSearchItem(context),
PreferredNetworkModeSearchItem(context),
RoamingSearchItem(context), RoamingSearchItem(context),
WifiCallingSearchItem(context), WifiCallingSearchItem(context),
) )

View File

@@ -25,6 +25,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
import com.android.settings.spa.preference.ComposePreferenceController import com.android.settings.spa.preference.ComposePreferenceController
import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreference
@@ -79,12 +80,17 @@ class NrAdvancedCallingPreferenceController @JvmOverloads constructor(
companion object { companion object {
class NrAdvancedCallingSearchItem(private val context: Context) : class NrAdvancedCallingSearchItem(private val context: Context) :
MobileNetworkSettingsSearchItem { MobileNetworkSettingsSearchItem {
override val key = "nr_advanced_calling"
override val title: String = context.getString(R.string.nr_advanced_calling_title)
override val keywords: String = context.getString(R.string.keywords_nr_advanced_calling)
override fun isAvailable(subId: Int): Boolean = fun isAvailable(subId: Int): Boolean = VoNrRepository(context, subId).isVoNrAvailable()
VoNrRepository(context, subId).isVoNrAvailable()
override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
if (!isAvailable(subId)) return null
return MobileNetworkSettingsSearchResult(
key = "nr_advanced_calling",
title = context.getString(R.string.nr_advanced_calling_title),
keywords = context.getString(R.string.keywords_nr_advanced_calling),
)
}
} }
} }
} }

View File

@@ -16,6 +16,8 @@
package com.android.settings.network.telephony; package com.android.settings.network.telephony;
import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.getNetworkModePreferenceType;
import android.content.Context; import android.content.Context;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager; import android.telephony.CarrierConfigManager;
@@ -27,16 +29,18 @@ import androidx.preference.ListPreference;
import androidx.preference.Preference; import androidx.preference.Preference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.CarrierConfigCache; import com.android.settings.network.CarrierConfigCache;
import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants; import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants;
/** /**
* Preference controller for "Preferred network mode" * Preference controller for "Preferred network mode"
*/ */
public class PreferredNetworkModePreferenceController extends TelephonyBasePreferenceController public class PreferredNetworkModePreferenceController extends BasePreferenceController
implements ListPreference.OnPreferenceChangeListener { implements ListPreference.OnPreferenceChangeListener {
private static final String TAG = "PrefNetworkModeCtrl"; private static final String TAG = "PrefNetworkModeCtrl";
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private CarrierConfigCache mCarrierConfigCache; private CarrierConfigCache mCarrierConfigCache;
private TelephonyManager mTelephonyManager; private TelephonyManager mTelephonyManager;
private boolean mIsGlobalCdma; private boolean mIsGlobalCdma;
@@ -47,25 +51,10 @@ public class PreferredNetworkModePreferenceController extends TelephonyBasePrefe
} }
@Override @Override
public int getAvailabilityStatus(int subId) { public int getAvailabilityStatus() {
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId); return getNetworkModePreferenceType(mContext, mSubId)
boolean visible; == NetworkModePreferenceType.PreferredNetworkMode
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
visible = false;
} else if (carrierConfig == null) {
visible = false;
} else if (carrierConfig.getBoolean(
CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
|| carrierConfig.getBoolean(
CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL)) {
visible = false;
} else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {
visible = true;
} else {
visible = false;
}
return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} }
@Override @Override

View File

@@ -29,6 +29,7 @@ import androidx.compose.ui.res.stringResource
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
import com.android.settings.spa.preference.ComposePreferenceController import com.android.settings.spa.preference.ComposePreferenceController
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
@@ -98,16 +99,21 @@ constructor(
companion object { companion object {
private const val DIALOG_TAG = "MobileDataDialog" private const val DIALOG_TAG = "MobileDataDialog"
class RoamingSearchItem(context: Context) : MobileNetworkSettingsSearchItem { class RoamingSearchItem(private val context: Context) : MobileNetworkSettingsSearchItem {
override val key = "button_roaming_key"
override val title: String = context.getString(R.string.roaming)
private val carrierConfigRepository = CarrierConfigRepository(context) private val carrierConfigRepository = CarrierConfigRepository(context)
override fun isAvailable(subId: Int): Boolean = fun isAvailable(subId: Int): Boolean =
SubscriptionManager.isValidSubscriptionId(subId) && SubscriptionManager.isValidSubscriptionId(subId) &&
!carrierConfigRepository.getBoolean( !carrierConfigRepository.getBoolean(
subId, CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL) subId, CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL)
override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
if (!isAvailable(subId)) return null
return MobileNetworkSettingsSearchResult(
key = "button_roaming_key",
title = context.getString(R.string.roaming),
)
}
} }
} }
} }

View File

@@ -17,9 +17,6 @@
package com.android.settings.network.telephony; package com.android.settings.network.telephony;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
@@ -59,29 +56,4 @@ public abstract class TelephonyBasePreferenceController extends BasePreferenceCo
public void unsetAvailabilityStatus() { public void unsetAvailabilityStatus() {
mSetSessionCount.getAndDecrement(); mSetSessionCount.getAndDecrement();
} }
/**
* Get carrier config based on specific subscription id.
*
* @param subId is the subscription id
* @return {@link PersistableBundle} of carrier config, or {@code null} when carrier config
* is not available.
*/
public PersistableBundle getCarrierConfigForSubId(int subId) {
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
return null;
}
final CarrierConfigManager carrierConfigMgr =
mContext.getSystemService(CarrierConfigManager.class);
return carrierConfigMgr.getConfigForSubId(subId);
}
/**
* Returns the resources associated with Subscription.
*
* @return Resources associated with Subscription.
*/
public Resources getResourcesForSubId() {
return SubscriptionManager.getResourcesForSubId(mContext, mSubId);
}
} }

View File

@@ -27,6 +27,7 @@ import androidx.preference.Preference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.android.settings.R import com.android.settings.R
import com.android.settings.core.BasePreferenceController import com.android.settings.core.BasePreferenceController
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
import com.android.settings.network.telephony.wificalling.WifiCallingRepository import com.android.settings.network.telephony.wificalling.WifiCallingRepository
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
@@ -132,12 +133,17 @@ open class WifiCallingPreferenceController @JvmOverloads constructor(
class WifiCallingSearchItem( class WifiCallingSearchItem(
private val context: Context, private val context: Context,
) : MobileNetworkSettingsSearchItem { ) : MobileNetworkSettingsSearchItem {
override val key: String = "wifi_calling" private fun isAvailable(subId: Int): Boolean = runBlocking {
override val title: String = context.getString(R.string.wifi_calling_settings_title)
override fun isAvailable(subId: Int): Boolean = runBlocking {
WifiCallingRepository(context, subId).wifiCallingReadyFlow().first() WifiCallingRepository(context, subId).wifiCallingReadyFlow().first()
} }
override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
if (!isAvailable(subId)) return null
return MobileNetworkSettingsSearchResult(
key = "wifi_calling",
title = context.getString(R.string.wifi_calling_settings_title),
)
}
} }
} }
} }

View File

@@ -124,9 +124,7 @@ public class SetNewPasswordActivity extends Activity implements SetNewPasswordCo
@Override @Override
public void launchChooseLock(Bundle chooseLockFingerprintExtras) { public void launchChooseLock(Bundle chooseLockFingerprintExtras) {
final boolean isInSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent()); final Intent intent = new Intent(this, SetupChooseLockGeneric.class);
Intent intent = isInSetupWizard ? new Intent(this, SetupChooseLockGeneric.class)
: new Intent(this, ChooseLockGeneric.class);
intent.setAction(mNewPasswordAction); intent.setAction(mNewPasswordAction);
intent.putExtras(chooseLockFingerprintExtras); intent.putExtras(chooseLockFingerprintExtras);
intent.putExtra(EXTRA_KEY_CHOOSE_LOCK_SCREEN_TITLE, intent.putExtra(EXTRA_KEY_CHOOSE_LOCK_SCREEN_TITLE,

View File

@@ -919,7 +919,7 @@ public class UserSettings extends SettingsPreferenceFragment
d = mCreateUserDialogController.createDialog( d = mCreateUserDialogController.createDialog(
getActivity(), getActivity(),
this::startActivityForResult, this::startActivityForResult,
UserManager.isMultipleAdminEnabled(), canCreateAdminUser(),
(userName, userIcon, isAdmin) -> { (userName, userIcon, isAdmin) -> {
mPendingUserIcon = userIcon; mPendingUserIcon = userIcon;
mPendingUserName = userName; mPendingUserName = userName;
@@ -937,6 +937,19 @@ public class UserSettings extends SettingsPreferenceFragment
return d; return d;
} }
/**
* Checks if the creation of a new admin user is allowed.
* @return {@code true} if creating a new admin is allowed, {@code false} otherwise.
*/
private boolean canCreateAdminUser() {
if (Flags.unicornModeRefactoringForHsumReadOnly()) {
return UserManager.isMultipleAdminEnabled()
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_GRANT_ADMIN);
} else {
return UserManager.isMultipleAdminEnabled();
}
}
@Override @Override
public int getDialogMetricsCategory(int dialogId) { public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) { switch (dialogId) {

View File

@@ -46,6 +46,7 @@ import android.util.Log;
* *
*/ */
public class WifiQrCode { public class WifiQrCode {
private static final String TAG = "WifiQrCode";
static final String SCHEME_DPP = "DPP"; static final String SCHEME_DPP = "DPP";
static final String SCHEME_ZXING_WIFI_NETWORK_CONFIG = "WIFI"; static final String SCHEME_ZXING_WIFI_NETWORK_CONFIG = "WIFI";
static final String PREFIX_DPP = "DPP:"; static final String PREFIX_DPP = "DPP:";
@@ -119,13 +120,13 @@ public class WifiQrCode {
try { try {
wifiQrCode = new WifiQrCode(qrCode); wifiQrCode = new WifiQrCode(qrCode);
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException e) {
Log.e(TAG, "Failed to create WifiQrCode!", e);
return null; return null;
} }
if (wifiQrCode.getScheme() != UriParserResults.URI_SCHEME_DPP) {
if (SCHEME_DPP.equals(wifiQrCode.getScheme())) { Log.e(TAG, "wifiQrCode scheme is not DPP!");
return wifiQrCode; return null;
} }
return wifiQrCode;
return null;
} }
} }

View File

@@ -18,10 +18,10 @@ package com.android.settings.bluetooth;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -32,22 +32,31 @@ import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.UserManager; import android.os.UserManager;
import android.util.Pair; import android.util.Pair;
import android.view.ContextThemeWrapper;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers;
@@ -57,18 +66,21 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowAlertDialogCompat.class}) @Config(shadows = {ShadowAlertDialogCompat.class,
com.android.settings.testutils.shadow.ShadowBluetoothUtils.class})
public class BluetoothDevicePreferenceTest { public class BluetoothDevicePreferenceTest {
private static final boolean SHOW_DEVICES_WITHOUT_NAMES = true; private static final boolean SHOW_DEVICES_WITHOUT_NAMES = true;
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS = "04:52:C7:0B:D8:3C";
private static final String MAC_ADDRESS_2 = "05:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_1 = "05:52:C7:0B:D8:3C";
private static final String MAC_ADDRESS_3 = "06:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_2 = "06:52:C7:0B:D8:3C";
private static final String MAC_ADDRESS_4 = "07:52:C7:0B:D8:3C"; private static final String TEST_MAC_ADDRESS_3 = "07:52:C7:0B:D8:3C";
private static final Comparator<BluetoothDevicePreference> COMPARATOR = private static final Comparator<BluetoothDevicePreference> COMPARATOR =
Comparator.naturalOrder(); Comparator.naturalOrder();
private static final String FAKE_DESCRIPTION = "fake_description"; private static final String FAKE_DESCRIPTION = "fake_description";
private static final int TEST_DEVICE_GROUP_ID = 1;
private Context mContext; @Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock @Mock
private CachedBluetoothDevice mCachedBluetoothDevice; private CachedBluetoothDevice mCachedBluetoothDevice;
@Mock @Mock
@@ -89,35 +101,37 @@ public class BluetoothDevicePreferenceTest {
private Drawable mDrawable; private Drawable mDrawable;
@Mock @Mock
private BluetoothAdapter mBluetoothAdapter; private BluetoothAdapter mBluetoothAdapter;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@Mock
private CachedBluetoothDeviceManager mDeviceManager;
private Context mContext = ApplicationProvider.getApplicationContext();
private FakeFeatureFactory mFakeFeatureFactory; private FakeFeatureFactory mFakeFeatureFactory;
private MetricsFeatureProvider mMetricsFeatureProvider; private MetricsFeatureProvider mMetricsFeatureProvider;
private BluetoothDevicePreference mPreference; private BluetoothDevicePreference mPreference;
private List<BluetoothDevicePreference> mPreferenceList = new ArrayList<>(); private List<BluetoothDevicePreference> mPreferenceList = new ArrayList<>();
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); mContext.setTheme(R.style.Theme_Settings);
Context context = spy(RuntimeEnvironment.application.getApplicationContext());
mContext = new ContextThemeWrapper(context, R.style.Theme_Settings);
mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider(); mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider();
when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
when(mCachedBluetoothDevice.getDrawableWithDescription()) mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
.thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); prepareCachedBluetoothDevice(mCachedBluetoothDevice, TEST_MAC_ADDRESS,
when(mCachedDevice1.getAddress()).thenReturn(MAC_ADDRESS_2); new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice);
when(mCachedDevice1.getDrawableWithDescription()) prepareCachedBluetoothDevice(mCachedDevice1, TEST_MAC_ADDRESS_1,
.thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice1);
when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); prepareCachedBluetoothDevice(mCachedDevice2, TEST_MAC_ADDRESS_2,
when(mCachedDevice2.getAddress()).thenReturn(MAC_ADDRESS_3); new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice2);
when(mCachedDevice2.getDrawableWithDescription()) prepareCachedBluetoothDevice(mCachedDevice3, TEST_MAC_ADDRESS_3,
.thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); new Pair<>(mDrawable, FAKE_DESCRIPTION), TEST_DEVICE_GROUP_ID, mBluetoothDevice3);
when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2); when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
when(mCachedDevice3.getAddress()).thenReturn(MAC_ADDRESS_4); ImmutableList.of(mCachedBluetoothDevice));
when(mCachedDevice3.getDrawableWithDescription())
.thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION));
when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3);
mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
mPreference.mBluetoothAdapter = mBluetoothAdapter; mPreference.mBluetoothAdapter = mBluetoothAdapter;
@@ -301,7 +315,8 @@ public class BluetoothDevicePreferenceTest {
// callback is not removed. // callback is not removed.
mPreference.onAttached(); mPreference.onAttached();
verify(mCachedBluetoothDevice, times(1)).registerCallback(any()); verify(mCachedBluetoothDevice, times(1)).registerCallback(eq(mContext.getMainExecutor()),
any());
verify(mBluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any()); verify(mBluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any());
} }
@@ -313,7 +328,99 @@ public class BluetoothDevicePreferenceTest {
mPreference.onAttached(); mPreference.onAttached();
verify(mCachedBluetoothDevice, times(1)).unregisterCallback(any()); verify(mCachedBluetoothDevice, times(1)).unregisterCallback(any());
verify(mCachedBluetoothDevice, times(2)).registerCallback(any()); verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()),
any());
verify(mBluetoothAdapter, times(2)).addOnMetadataChangedListener(any(), any(), any()); verify(mBluetoothAdapter, times(2)).addOnMetadataChangedListener(any(), any(), any());
} }
@Test
public void onDeviceAttributesChanged_updatePreference() {
when(mCachedBluetoothDevice.getName()).thenReturn("Name");
mPreference.onAttached();
final String updatedName = "updatedName";
when(mCachedBluetoothDevice.getName()).thenReturn(updatedName);
getCachedBluetoothDeviceCallback().onDeviceAttributesChanged();
assertThat(mPreference.getTitle().toString()).isEqualTo(updatedName);
}
@Test
public void onAttached_memberDevicesAdded_registerAllCallback() {
when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(
ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3));
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2,
mCachedDevice3));
mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
mPreference.onAttached();
verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()), any());
verify(mCachedDevice1).registerCallback(eq(mContext.getMainExecutor()), any());
verify(mCachedDevice2).registerCallback(eq(mContext.getMainExecutor()), any());
verify(mCachedDevice3).registerCallback(eq(mContext.getMainExecutor()), any());
}
@Test
public void onDetached_memberDevicesAdded_unregisterAllCallback() {
when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(
ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3));
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2,
mCachedDevice3));
mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
mPreference.onAttached();
mPreference.onDetached();
verify(mCachedBluetoothDevice).unregisterCallback(any());
verify(mCachedDevice1).unregisterCallback(any());
verify(mCachedDevice2).unregisterCallback(any());
verify(mCachedDevice3).unregisterCallback(any());
}
@Test
public void onDeviceAttributesChanged_memberDevicesChanged_registerOnlyExistDeviceCallback() {
when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(
ImmutableSet.of(mCachedDevice1, mCachedDevice2, mCachedDevice3));
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2,
mCachedDevice3));
mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
mPreference.onAttached();
when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(
ImmutableSet.of(mCachedDevice1, mCachedDevice2));
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
ImmutableList.of(mCachedBluetoothDevice, mCachedDevice1, mCachedDevice2));
getCachedBluetoothDeviceCallback().onDeviceAttributesChanged();
verify(mCachedBluetoothDevice, times(2)).registerCallback(eq(mContext.getMainExecutor()),
any());
verify(mCachedDevice1, times(2)).registerCallback(eq(mContext.getMainExecutor()), any());
verify(mCachedDevice2, times(2)).registerCallback(eq(mContext.getMainExecutor()), any());
verify(mCachedDevice3, times(1)).registerCallback(eq(mContext.getMainExecutor()), any());
}
private void prepareCachedBluetoothDevice(CachedBluetoothDevice cachedDevice, String address,
Pair<Drawable, String> drawableWithDescription, int groupId,
BluetoothDevice bluetoothDevice) {
when(cachedDevice.getAddress()).thenReturn(address);
when(cachedDevice.getDrawableWithDescription()).thenReturn(drawableWithDescription);
when(cachedDevice.getGroupId()).thenReturn(groupId);
when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
}
private CachedBluetoothDevice.Callback getCachedBluetoothDeviceCallback() {
ArgumentCaptor<CachedBluetoothDevice.Callback> callbackCaptor = ArgumentCaptor.forClass(
CachedBluetoothDevice.Callback.class);
verify(mCachedBluetoothDevice).registerCallback(eq(mContext.getMainExecutor()),
callbackCaptor.capture());
return callbackCaptor.getValue();
}
} }

View File

@@ -93,7 +93,6 @@ public class AudioSharingDialogFragmentTest {
new Pair[] {TEST_EVENT_DATA}; new Pair[] {TEST_EVENT_DATA};
private Fragment mParent; private Fragment mParent;
private AudioSharingDialogFragment mFragment;
private FakeFeatureFactory mFeatureFactory; private FakeFeatureFactory mFeatureFactory;
@Before @Before
@@ -107,7 +106,6 @@ public class AudioSharingDialogFragmentTest {
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED); BluetoothStatusCodes.FEATURE_SUPPORTED);
mFeatureFactory = FakeFeatureFactory.setupForTest(); mFeatureFactory = FakeFeatureFactory.setupForTest();
mFragment = new AudioSharingDialogFragment();
mParent = new Fragment(); mParent = new Fragment();
FragmentController.setupFragment( FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null); mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
@@ -120,7 +118,8 @@ public class AudioSharingDialogFragmentTest {
@Test @Test
public void getMetricsCategory_correctValue() { public void getMetricsCategory_correctValue() {
assertThat(mFragment.getMetricsCategory()) AudioSharingDialogFragment fragment = new AudioSharingDialogFragment();
assertThat(fragment.getMetricsCategory())
.isEqualTo(SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE); .isEqualTo(SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE);
} }
@@ -145,7 +144,7 @@ public class AudioSharingDialogFragmentTest {
} }
@Test @Test
public void onCreateDialog_flagOn_noConnectedDevice() { public void onCreateDialog_flagOn_noExtraConnectedDevice() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingDialogFragment.show( AudioSharingDialogFragment.show(
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST); mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
@@ -157,42 +156,67 @@ public class AudioSharingDialogFragmentTest {
assertThat(description).isNotNull(); assertThat(description).isNotNull();
ImageView image = dialog.findViewById(R.id.description_image); ImageView image = dialog.findViewById(R.id.description_image);
assertThat(image).isNotNull(); assertThat(image).isNotNull();
Button shareBtn = dialog.findViewById(R.id.positive_btn); Button positiveBtn = dialog.findViewById(R.id.positive_btn);
assertThat(shareBtn).isNotNull(); assertThat(positiveBtn).isNotNull();
Button cancelBtn = dialog.findViewById(R.id.negative_btn); Button negativeBtn = dialog.findViewById(R.id.negative_btn);
assertThat(cancelBtn).isNotNull(); assertThat(negativeBtn).isNotNull();
assertThat(dialog.isShowing()).isTrue(); assertThat(dialog.isShowing()).isTrue();
assertThat(description.getVisibility()).isEqualTo(View.VISIBLE); assertThat(description.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(description.getText().toString()) assertThat(description.getText().toString())
.isEqualTo(mParent.getString(R.string.audio_sharing_dialog_connect_device_content)); .isEqualTo(mParent.getString(R.string.audio_sharing_dialog_connect_device_content));
assertThat(image.getVisibility()).isEqualTo(View.VISIBLE); assertThat(image.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(shareBtn.getVisibility()).isEqualTo(View.GONE); assertThat(positiveBtn.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(cancelBtn.getVisibility()).isEqualTo(View.GONE); assertThat(positiveBtn.getText().toString())
.isEqualTo(mParent.getString(R.string.audio_sharing_pair_button_label));
assertThat(negativeBtn.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(negativeBtn.getText().toString())
.isEqualTo(mParent.getString(R.string.audio_sharing_qrcode_button_label));
} }
@Test @Test
public void onCreateDialog_noConnectedDevice_dialogDismiss() { public void onCreateDialog_noExtraConnectedDevice_pairNewDevice() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingDialogFragment.show( AudioSharingDialogFragment.show(
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST); mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
shadowMainLooper().idle(); shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull(); assertThat(dialog).isNotNull();
View btnView = dialog.findViewById(android.R.id.button2); Button pairBtn = dialog.findViewById(R.id.positive_btn);
assertThat(btnView).isNotNull(); assertThat(pairBtn).isNotNull();
btnView.performClick(); pairBtn.performClick();
shadowMainLooper().idle(); shadowMainLooper().idle();
verify(mFeatureFactory.metricsFeatureProvider)
.action(
any(Context.class),
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED),
eq(TEST_EVENT_DATA));
assertThat(dialog.isShowing()).isFalse(); assertThat(dialog.isShowing()).isFalse();
}
@Test
public void onCreateDialog_noExtraConnectedDevice_showQRCode() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingDialogFragment.show(
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
Button qrCodeBtn = dialog.findViewById(R.id.negative_btn);
assertThat(qrCodeBtn).isNotNull();
qrCodeBtn.performClick();
shadowMainLooper().idle();
verify(mFeatureFactory.metricsFeatureProvider) verify(mFeatureFactory.metricsFeatureProvider)
.action( .action(
any(Context.class), any(Context.class),
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED), eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
eq(TEST_EVENT_DATA)); eq(TEST_EVENT_DATA));
assertThat(dialog.isShowing()).isFalse();
} }
@Test @Test
public void onCreateDialog_flagOn_singleConnectedDevice() { public void onCreateDialog_flagOn_singleExtraConnectedDevice() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>(); ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1); list.add(TEST_DEVICE_ITEM1);
@@ -207,10 +231,10 @@ public class AudioSharingDialogFragmentTest {
assertThat(description).isNotNull(); assertThat(description).isNotNull();
ImageView image = dialog.findViewById(R.id.description_image); ImageView image = dialog.findViewById(R.id.description_image);
assertThat(image).isNotNull(); assertThat(image).isNotNull();
Button shareBtn = dialog.findViewById(R.id.positive_btn); Button positiveBtn = dialog.findViewById(R.id.positive_btn);
assertThat(shareBtn).isNotNull(); assertThat(positiveBtn).isNotNull();
Button cancelBtn = dialog.findViewById(R.id.negative_btn); Button negativeBtn = dialog.findViewById(R.id.negative_btn);
assertThat(cancelBtn).isNotNull(); assertThat(negativeBtn).isNotNull();
assertThat(dialog.isShowing()).isTrue(); assertThat(dialog.isShowing()).isTrue();
assertThat(title.getText().toString()) assertThat(title.getText().toString())
.isEqualTo( .isEqualTo(
@@ -220,12 +244,16 @@ public class AudioSharingDialogFragmentTest {
assertThat(description.getText().toString()) assertThat(description.getText().toString())
.isEqualTo(mParent.getString(R.string.audio_sharing_dialog_share_content)); .isEqualTo(mParent.getString(R.string.audio_sharing_dialog_share_content));
assertThat(image.getVisibility()).isEqualTo(View.GONE); assertThat(image.getVisibility()).isEqualTo(View.GONE);
assertThat(shareBtn.getVisibility()).isEqualTo(View.VISIBLE); assertThat(positiveBtn.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(cancelBtn.getVisibility()).isEqualTo(View.VISIBLE); assertThat(positiveBtn.getText().toString())
.isEqualTo(mParent.getString(R.string.audio_sharing_share_button_label));
assertThat(negativeBtn.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(negativeBtn.getText().toString())
.isEqualTo(mParent.getString(R.string.audio_sharing_no_thanks_button_label));
} }
@Test @Test
public void onCreateDialog_singleConnectedDevice_dialogDismiss() { public void onCreateDialog_singleExtraConnectedDevice_dialogDismiss() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>(); ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1); list.add(TEST_DEVICE_ITEM1);
@@ -248,7 +276,7 @@ public class AudioSharingDialogFragmentTest {
} }
@Test @Test
public void onCreateDialog_singleConnectedDevice_shareClicked() { public void onCreateDialog_singleExtraConnectedDevice_shareClicked() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>(); ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1); list.add(TEST_DEVICE_ITEM1);
@@ -285,7 +313,7 @@ public class AudioSharingDialogFragmentTest {
} }
@Test @Test
public void onCreateDialog_flagOn_multipleConnectedDevice() { public void onCreateDialog_flagOn_multipleExtraConnectedDevice() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>(); ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1); list.add(TEST_DEVICE_ITEM1);
@@ -313,12 +341,14 @@ public class AudioSharingDialogFragmentTest {
assertThat(image.getVisibility()).isEqualTo(View.GONE); assertThat(image.getVisibility()).isEqualTo(View.GONE);
assertThat(shareBtn.getVisibility()).isEqualTo(View.GONE); assertThat(shareBtn.getVisibility()).isEqualTo(View.GONE);
assertThat(cancelBtn.getVisibility()).isEqualTo(View.VISIBLE); assertThat(cancelBtn.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(cancelBtn.getText().toString())
.isEqualTo(mParent.getString(com.android.settings.R.string.cancel));
assertThat(recyclerView.getVisibility()).isEqualTo(View.VISIBLE); assertThat(recyclerView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(recyclerView.getAdapter().getItemCount()).isEqualTo(3); assertThat(recyclerView.getAdapter().getItemCount()).isEqualTo(3);
} }
@Test @Test
public void onCreateDialog_multipleConnectedDevice_dialogDismiss() { public void onCreateDialog_multipleExtraConnectedDevice_dialogDismiss() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>(); ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1); list.add(TEST_DEVICE_ITEM1);

View File

@@ -25,7 +25,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -164,8 +164,7 @@ public class AudioSharingReceiverTest {
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent); AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
audioSharingReceiver.onReceive(mContext, intent); audioSharingReceiver.onReceive(mContext, intent);
verify(mNm, times(1)) verify(mNm).notify(eq(R.drawable.ic_bt_le_audio_sharing), any(Notification.class));
.notify(eq(R.drawable.ic_bt_le_audio_sharing), any(Notification.class));
verify(mFeatureFactory.metricsFeatureProvider) verify(mFeatureFactory.metricsFeatureProvider)
.action(mContext, SettingsEnums.ACTION_SHOW_AUDIO_SHARING_NOTIFICATION); .action(mContext, SettingsEnums.ACTION_SHOW_AUDIO_SHARING_NOTIFICATION);
} }
@@ -181,7 +180,7 @@ public class AudioSharingReceiverTest {
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent); AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
audioSharingReceiver.onReceive(mContext, intent); audioSharingReceiver.onReceive(mContext, intent);
verify(mNm, times(1)).cancel(R.drawable.ic_bt_le_audio_sharing); verify(mNm).cancel(R.drawable.ic_bt_le_audio_sharing);
verify(mFeatureFactory.metricsFeatureProvider) verify(mFeatureFactory.metricsFeatureProvider)
.action(mContext, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION); .action(mContext, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION);
} }
@@ -199,8 +198,10 @@ public class AudioSharingReceiverTest {
} }
@Test @Test
public void broadcastReceiver_receiveAudioSharingStopIntent_stopBroadcast() { public void
broadcastReceiver_receiveAudioSharingStopIntent_notInBroadcast_cancelNotification() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(false);
int broadcastId = 1; int broadcastId = 1;
when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId); when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId);
@@ -209,7 +210,25 @@ public class AudioSharingReceiverTest {
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent); AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
audioSharingReceiver.onReceive(mContext, intent); audioSharingReceiver.onReceive(mContext, intent);
verify(mBroadcast, times(1)).stopBroadcast(broadcastId); verify(mBroadcast, never()).stopBroadcast(broadcastId);
verify(mNm).cancel(R.drawable.ic_bt_le_audio_sharing);
verify(mFeatureFactory.metricsFeatureProvider)
.action(mContext, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION);
}
@Test
public void broadcastReceiver_receiveAudioSharingStopIntent_inBroadcast_stopBroadcast() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
int broadcastId = 1;
when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId);
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STOP);
intent.setPackage(mContext.getPackageName());
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
audioSharingReceiver.onReceive(mContext, intent);
verify(mBroadcast).stopBroadcast(broadcastId);
verify(mFeatureFactory.metricsFeatureProvider) verify(mFeatureFactory.metricsFeatureProvider)
.action(mContext, SettingsEnums.ACTION_STOP_AUDIO_SHARING_FROM_NOTIFICATION); .action(mContext, SettingsEnums.ACTION_STOP_AUDIO_SHARING_FROM_NOTIFICATION);
} }

View File

@@ -0,0 +1,96 @@
/*
* 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.network.telephony
import android.content.Context
import android.telephony.CarrierConfigManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.spy
@RunWith(AndroidJUnit4::class)
class EnabledNetworkModePreferenceControllerHelperTest {
private var context: Context = spy(ApplicationProvider.getApplicationContext()) {}
@Before
fun setUp() {
CarrierConfigRepository.resetForTest()
CarrierConfigRepository.setBooleanForTest(
SUB_ID, CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true)
}
@Test
fun getNetworkModePreferenceType_hideCarrierNetworkSettings_returnNone() {
CarrierConfigRepository.setBooleanForTest(
SUB_ID, CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, true)
val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID)
assertThat(networkModePreferenceType).isEqualTo(NetworkModePreferenceType.None)
}
@Test
fun getNetworkModePreferenceType_hidePreferredNetworkType_returnNone() {
CarrierConfigRepository.setBooleanForTest(
SUB_ID, CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, true)
val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID)
assertThat(networkModePreferenceType).isEqualTo(NetworkModePreferenceType.None)
}
@Test
fun getNetworkModePreferenceType_carrierConfigNotReady_returnNone() {
CarrierConfigRepository.setBooleanForTest(
SUB_ID, CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, false)
val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID)
assertThat(networkModePreferenceType).isEqualTo(NetworkModePreferenceType.None)
}
@Test
fun getNetworkModePreferenceType_isWorldPhone_returnPreferredNetworkMode() {
CarrierConfigRepository.setBooleanForTest(
SUB_ID, CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true)
val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID)
assertThat(networkModePreferenceType)
.isEqualTo(NetworkModePreferenceType.PreferredNetworkMode)
}
@Test
fun getNetworkModePreferenceType_notWorldPhone_returnEnabledNetworkMode() {
CarrierConfigRepository.setBooleanForTest(
SUB_ID, CarrierConfigManager.KEY_WORLD_PHONE_BOOL, false)
val networkModePreferenceType = getNetworkModePreferenceType(context, SUB_ID)
assertThat(networkModePreferenceType)
.isEqualTo(NetworkModePreferenceType.EnabledNetworkMode)
}
private companion object {
const val SUB_ID = 10
}
}

View File

@@ -25,6 +25,7 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.Companion.isMobileNetworkSettingsSearchable import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.Companion.isMobileNetworkSettingsSearchable
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
import com.android.settings.spa.SpaSearchLanding.BundleValue import com.android.settings.spa.SpaSearchLanding.BundleValue
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
@@ -62,10 +63,12 @@ class MobileNetworkSettingsSearchIndexTest {
private val mobileNetworkSettingsSearchIndex = MobileNetworkSettingsSearchIndex { private val mobileNetworkSettingsSearchIndex = MobileNetworkSettingsSearchIndex {
listOf( listOf(
object : MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem { object : MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem {
override val key = KEY override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? =
override val title = TITLE if (subId == SUB_ID_1) {
MobileNetworkSettingsSearchResult(key = KEY, title = TITLE)
override fun isAvailable(subId: Int) = subId == SUB_ID_1 } else {
null
}
}) })
} }

View File

@@ -20,8 +20,8 @@ import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.onRoot
@@ -34,36 +34,35 @@ import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.notification.app.AppNotificationSettings import com.android.settings.notification.app.AppNotificationSettings
import com.android.settings.spa.notification.IAppNotificationRepository import com.android.settings.spa.notification.IAppNotificationRepository
import com.android.settingslib.spa.testutils.delay import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spa.testutils.waitUntilExists
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.MockitoSession import org.mockito.MockitoSession
import org.mockito.Spy
import org.mockito.quality.Strictness import org.mockito.quality.Strictness
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class AppNotificationPreferenceTest { class AppNotificationPreferenceTest {
@get:Rule @get:Rule val composeTestRule = createComposeRule()
val composeTestRule = createComposeRule()
private lateinit var mockSession: MockitoSession private lateinit var mockSession: MockitoSession
@Spy
private val context: Context = ApplicationProvider.getApplicationContext() private val context: Context = ApplicationProvider.getApplicationContext()
private val repository = object : IAppNotificationRepository { private val repository =
override fun getNotificationSummary(app: ApplicationInfo) = SUMMARY object : IAppNotificationRepository {
} override fun getNotificationSummary(app: ApplicationInfo) = SUMMARY
}
@Before @Before
fun setUp() { fun setUp() {
mockSession = ExtendedMockito.mockitoSession() mockSession =
.initMocks(this) ExtendedMockito.mockitoSession()
.mockStatic(AppInfoDashboardFragment::class.java) .mockStatic(AppInfoDashboardFragment::class.java)
.strictness(Strictness.LENIENT) .strictness(Strictness.LENIENT)
.startMocking() .startMocking()
} }
@After @After
@@ -75,25 +74,26 @@ class AppNotificationPreferenceTest {
fun title_displayed() { fun title_displayed() {
setContent(APP) setContent(APP)
composeTestRule.onNodeWithText(context.getString(R.string.notifications_label)) composeTestRule.waitUntilExists(hasText(context.getString(R.string.notifications_label)))
.assertIsDisplayed()
} }
@Test @Test
fun summary_displayed() { fun summary_displayed() {
setContent(APP) setContent(APP)
composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed() composeTestRule.waitUntilExists(hasText(SUMMARY))
} }
@Test @Test
fun whenNotInstalled_disable() { fun whenNotInstalled_disable() {
setContent(ApplicationInfo().apply { setContent(
packageName = PACKAGE_NAME ApplicationInfo().apply {
uid = UID packageName = PACKAGE_NAME
}) uid = UID
})
composeTestRule.onNodeWithText(context.getString(R.string.notifications_label)) composeTestRule
.onNodeWithText(context.getString(R.string.notifications_label))
.assertIsNotEnabled() .assertIsNotEnabled()
} }
@@ -125,11 +125,12 @@ class AppNotificationPreferenceTest {
private companion object { private companion object {
const val PACKAGE_NAME = "package.name" const val PACKAGE_NAME = "package.name"
const val UID = 123 const val UID = 123
val APP = ApplicationInfo().apply { val APP =
packageName = PACKAGE_NAME ApplicationInfo().apply {
uid = UID packageName = PACKAGE_NAME
flags = ApplicationInfo.FLAG_INSTALLED uid = UID
} flags = ApplicationInfo.FLAG_INSTALLED
}
const val SUMMARY = "Summary" const val SUMMARY = "Summary"
} }
} }

View File

@@ -18,9 +18,6 @@ package com.android.settings.network.telephony;
import static androidx.lifecycle.Lifecycle.Event.ON_START; import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.network.telephony.MobileNetworkUtils.getRafFromNetworkType; import static com.android.settings.network.telephony.MobileNetworkUtils.getRafFromNetworkType;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.CDMA; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.CDMA;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.EVDO; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.EVDO;
@@ -33,8 +30,6 @@ import static com.android.settings.network.telephony.TelephonyConstants.RadioAcc
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -123,79 +118,6 @@ public class EnabledNetworkModePreferenceControllerTest {
mPreference.setKey(mController.getPreferenceKey()); mPreference.setKey(mController.getPreferenceKey());
} }
@UiThreadTest
@Test
public void getAvailabilityStatus_hideCarrierNetworkSettings_returnUnavailable() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_hidePreferredNetworkType_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL,
true);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(
ServiceState.STATE_OUT_OF_SERVICE);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getRoaming()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getRoaming()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_carrierConfigNotReady_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_notWorldPhone_returnAvailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
false);
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_callStateIsIdle_returnAvailable() {
mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA);
mController.getTelephonyCallback().onCallStateChanged(TelephonyManager.CALL_STATE_IDLE);
mController.updateState(mPreference);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertTrue(mPreference.isEnabled());
}
@UiThreadTest
@Test
public void getAvailabilityStatus_duringCalling_returnAvailable() {
mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA);
mController.getTelephonyCallback().onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK);
mController.updateState(mPreference);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
assertFalse(mPreference.isEnabled());
}
@UiThreadTest @UiThreadTest
@Test @Test
public void updateState_LteWorldPhone_GlobalHasLte() { public void updateState_LteWorldPhone_GlobalHasLte() {

View File

@@ -16,8 +16,6 @@
package com.android.settings.network.telephony; package com.android.settings.network.telephony;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.GSM; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.GSM;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_TD_SCDMA; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_TD_SCDMA;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.WCDMA; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.WCDMA;
@@ -32,7 +30,6 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState; import android.telephony.ServiceState;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
@@ -91,43 +88,6 @@ public class PreferredNetworkModePreferenceControllerTest {
mPreference.setKey(mController.getPreferenceKey()); mPreference.setKey(mController.getPreferenceKey());
} }
@Test
public void getAvailabilityStatus_hideCarrierNetworkSettings_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_worldPhone_returnAvailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
false);
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_hidePreferredNetworkType_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL,
true);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(
ServiceState.STATE_OUT_OF_SERVICE);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getRoaming()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getRoaming()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test @Test
public void updateState_updateByNetworkMode() { public void updateState_updateByNetworkMode() {
// NETWORK_MODE_TDSCDMA_GSM_WCDMA = RAF_TD_SCDMA | GSM | WCDMA // NETWORK_MODE_TDSCDMA_GSM_WCDMA = RAF_TD_SCDMA | GSM | WCDMA