Snap for 11892734 from f91bd7ba24 to 24Q3-release
Change-Id: I0bce0b28857093225c695c95eb8064adc6f0ca58
This commit is contained in:
@@ -5192,6 +5192,18 @@
|
||||
android:theme="@style/Theme.SpaLib.Dialog">
|
||||
</activity>
|
||||
|
||||
<activity android:name="Settings$BluetoothDashboardActivity"
|
||||
android:label="@string/bluetooth_settings_title"
|
||||
android:permission="android.permission.BLUETOOTH_CONNECT"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.settings.BLUETOOTH_DASHBOARD_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
android:value="com.android.settings.connecteddevice.BluetoothDashboardFragment"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.settings.connecteddevice.audiosharing.AudioSharingActivity"
|
||||
android:label="@string/audio_sharing_title"
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
android:key="calls_and_alarms"
|
||||
android:summary=""
|
||||
android:title="@string/audio_sharing_call_audio_title"
|
||||
settings:controller="com.android.settings.connecteddevice.audiosharing.CallsAndAlarmsPreferenceController" />
|
||||
settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingCallAudioPreferenceController" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_audio_play_sample"
|
||||
@@ -68,14 +68,14 @@
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="audio_streams_settings_category"
|
||||
android:title="@string/audio_streams_category_title"
|
||||
android:title="@string/audio_sharing_nearby_audio_title"
|
||||
settings:controller="com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsCategoryController">
|
||||
|
||||
<Preference
|
||||
android:fragment="com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsDashboardFragment"
|
||||
android:icon="@drawable/ic_chevron_right_24dp"
|
||||
android:key="audio_streams_settings"
|
||||
android:title="@string/audio_streams_pref_title" />
|
||||
android:title="@string/audio_streams_main_page_title" />
|
||||
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -47,6 +47,7 @@ public class Settings extends SettingsActivity {
|
||||
|
||||
public static class MemtagPageActivity extends SettingsActivity { /* empty */}
|
||||
public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class BluetoothDashboardActivity extends SettingsActivity { /* empty */ }
|
||||
public static class CreateShortcutActivity extends SettingsActivity { /* empty */ }
|
||||
public static class FaceSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/** Container for {@link FaceSettings} to use with a pre-defined task affinity. */
|
||||
|
||||
@@ -264,7 +264,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
|
||||
mIsSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
if (mCanAssumeUdfps || mCanAssumeSfps) {
|
||||
updateTitleAndDescription();
|
||||
updateTitleAndDescription(true);
|
||||
} else {
|
||||
setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
|
||||
}
|
||||
@@ -387,7 +387,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
updateProgress(false /* animate */);
|
||||
updateTitleAndDescription();
|
||||
updateTitleAndDescription(true);
|
||||
if (mRestoring) {
|
||||
startIconAnimation();
|
||||
}
|
||||
@@ -491,12 +491,14 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
return new Intent(this, FingerprintEnrollFinish.class);
|
||||
}
|
||||
|
||||
private void updateTitleAndDescription() {
|
||||
private void updateTitleAndDescription(boolean force) {
|
||||
if (mCanAssumeUdfps) {
|
||||
updateTitleAndDescriptionForUdfps();
|
||||
return;
|
||||
} else if (mCanAssumeSfps) {
|
||||
updateTitleAndDescriptionForSfps();
|
||||
if (force || mSfpsEnrollmentFeature.shouldUpdateTitleAndDescription()) {
|
||||
updateTitleAndDescriptionForSfps();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -814,12 +816,15 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
public void onEnrollmentProgressChange(int steps, int remaining) {
|
||||
updateProgress(true /* animate */);
|
||||
final int percent = (int) (((float) (steps - remaining) / (float) steps) * 100);
|
||||
if (mCanAssumeSfps && mIsAccessibilityEnabled) {
|
||||
CharSequence announcement = getString(
|
||||
R.string.security_settings_sfps_enroll_progress_a11y_message, percent);
|
||||
announceEnrollmentProgress(announcement);
|
||||
if (mCanAssumeSfps) {
|
||||
mSfpsEnrollmentFeature.handleOnEnrollmentProgressChange(steps, remaining);
|
||||
if (mIsAccessibilityEnabled) {
|
||||
CharSequence announcement = getString(
|
||||
R.string.security_settings_sfps_enroll_progress_a11y_message, percent);
|
||||
announceEnrollmentProgress(announcement);
|
||||
}
|
||||
}
|
||||
updateTitleAndDescription();
|
||||
updateTitleAndDescription(false);
|
||||
animateFlash();
|
||||
if (mCanAssumeUdfps) {
|
||||
if (mIsAccessibilityEnabled) {
|
||||
@@ -850,6 +855,9 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
if (mUdfpsEnrollHelper != null) {
|
||||
mUdfpsEnrollHelper.onAcquired(isAcquiredGood);
|
||||
}
|
||||
if (mCanAssumeSfps) {
|
||||
mSfpsEnrollmentFeature.handleOnAcquired(isAcquiredGood);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -177,6 +177,11 @@ public class MessageDisplayController extends FingerprintManager.EnrollmentCallb
|
||||
mEnrollmentCallback.onEnrollmentError(errMsgId, errString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAcquired(boolean isAcquiredGood) {
|
||||
mEnrollmentCallback.onAcquired(isAcquiredGood);
|
||||
}
|
||||
|
||||
private Message getMessageToDisplay(long timeStamp) {
|
||||
ProgressMessage progressMessageToDisplay = getProgressMessageToDisplay(timeStamp);
|
||||
if (mMustDisplayProgress) {
|
||||
|
||||
@@ -93,4 +93,25 @@ public interface SfpsEnrollmentFeature {
|
||||
* @param lottieView the view related to the lottie
|
||||
*/
|
||||
default void handleOnEnrollmentLottieComposition(LottieAnimationView lottieView) {}
|
||||
|
||||
/**
|
||||
* Indicates if the title and description should be updated.
|
||||
* @return true to update the title and description; false otherwise.
|
||||
*/
|
||||
default boolean shouldUpdateTitleAndDescription() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies an acquisition happens.
|
||||
* @param isAcquiredGood isAcquiredGood
|
||||
*/
|
||||
default void handleOnAcquired(boolean isAcquiredGood) {}
|
||||
|
||||
/**
|
||||
* Notifies an enrollment progress changes event.
|
||||
* @param steps steps
|
||||
* @param remaining remaining
|
||||
*/
|
||||
default void handleOnEnrollmentProgressChange(int steps, int remaining) {}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import java.util.List;
|
||||
|
||||
/** Provides a dialog to choose the active device for calls and alarms. */
|
||||
public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment {
|
||||
public class AudioSharingCallAudioDialogFragment extends InstrumentedDialogFragment {
|
||||
private static final String TAG = "CallsAndAlarmsDialog";
|
||||
private static final String BUNDLE_KEY_DEVICE_ITEMS = "bundle_key_device_items";
|
||||
|
||||
@@ -55,7 +55,7 @@ public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the {@link CallsAndAlarmsDialogFragment} dialog.
|
||||
* Display the {@link AudioSharingCallAudioDialogFragment} dialog.
|
||||
*
|
||||
* @param host The Fragment this dialog will be hosted.
|
||||
* @param deviceItems The connected device items in audio sharing session.
|
||||
@@ -71,7 +71,8 @@ public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment {
|
||||
if (manager.findFragmentByTag(TAG) == null) {
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putParcelableList(BUNDLE_KEY_DEVICE_ITEMS, deviceItems);
|
||||
final CallsAndAlarmsDialogFragment dialog = new CallsAndAlarmsDialogFragment();
|
||||
final AudioSharingCallAudioDialogFragment dialog =
|
||||
new AudioSharingCallAudioDialogFragment();
|
||||
dialog.setArguments(bundle);
|
||||
dialog.show(manager, TAG);
|
||||
}
|
||||
@@ -51,6 +51,8 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -60,7 +62,7 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/** PreferenceController to control the dialog to choose the active device for calls and alarms */
|
||||
public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferenceController
|
||||
public class AudioSharingCallAudioPreferenceController extends AudioSharingBasePreferenceController
|
||||
implements BluetoothCallback {
|
||||
private static final String TAG = "CallsAndAlarmsPreferenceController";
|
||||
private static final String PREF_KEY = "calls_and_alarms";
|
||||
@@ -131,7 +133,7 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen
|
||||
}
|
||||
};
|
||||
|
||||
public CallsAndAlarmsPreferenceController(Context context) {
|
||||
public AudioSharingCallAudioPreferenceController(Context context) {
|
||||
super(context, PREF_KEY);
|
||||
mBtManager = Utils.getLocalBtManager(mContext);
|
||||
mProfileManager = mBtManager == null ? null : mBtManager.getProfileManager();
|
||||
@@ -176,16 +178,13 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen
|
||||
}
|
||||
updateDeviceItemsInSharingSession();
|
||||
if (mDeviceItemsInSharingSession.size() >= 1) {
|
||||
CallsAndAlarmsDialogFragment.show(
|
||||
AudioSharingCallAudioDialogFragment.show(
|
||||
mFragment,
|
||||
mDeviceItemsInSharingSession,
|
||||
(AudioSharingDeviceItem item) -> {
|
||||
if (!mGroupedConnectedDevices.containsKey(
|
||||
item.getGroupId())) {
|
||||
return;
|
||||
}
|
||||
List<CachedBluetoothDevice> devices =
|
||||
mGroupedConnectedDevices.get(item.getGroupId());
|
||||
mGroupedConnectedDevices.getOrDefault(
|
||||
item.getGroupId(), ImmutableList.of());
|
||||
@Nullable
|
||||
CachedBluetoothDevice lead =
|
||||
AudioSharingUtils.getLeadDevice(devices);
|
||||
@@ -33,7 +33,7 @@ public class AudioSharingDashboardFragment extends DashboardFragment
|
||||
SettingsMainSwitchBar mMainSwitchBar;
|
||||
private AudioSharingSwitchBarController mSwitchBarController;
|
||||
private AudioSharingDeviceVolumeGroupController mAudioSharingDeviceVolumeGroupController;
|
||||
private CallsAndAlarmsPreferenceController mCallsAndAlarmsPreferenceController;
|
||||
private AudioSharingCallAudioPreferenceController mAudioSharingCallAudioPreferenceController;
|
||||
private AudioSharingPlaySoundPreferenceController mAudioSharingPlaySoundPreferenceController;
|
||||
private AudioStreamsCategoryController mAudioStreamsCategoryController;
|
||||
|
||||
@@ -67,8 +67,9 @@ public class AudioSharingDashboardFragment extends DashboardFragment
|
||||
mAudioSharingDeviceVolumeGroupController =
|
||||
use(AudioSharingDeviceVolumeGroupController.class);
|
||||
mAudioSharingDeviceVolumeGroupController.init(this);
|
||||
mCallsAndAlarmsPreferenceController = use(CallsAndAlarmsPreferenceController.class);
|
||||
mCallsAndAlarmsPreferenceController.init(this);
|
||||
mAudioSharingCallAudioPreferenceController =
|
||||
use(AudioSharingCallAudioPreferenceController.class);
|
||||
mAudioSharingCallAudioPreferenceController.init(this);
|
||||
mAudioSharingPlaySoundPreferenceController =
|
||||
use(AudioSharingPlaySoundPreferenceController.class);
|
||||
mAudioStreamsCategoryController = use(AudioStreamsCategoryController.class);
|
||||
@@ -100,7 +101,7 @@ public class AudioSharingDashboardFragment extends DashboardFragment
|
||||
|
||||
private void updateVisibilityForAttachedPreferences() {
|
||||
mAudioSharingDeviceVolumeGroupController.updateVisibility();
|
||||
mCallsAndAlarmsPreferenceController.updateVisibility();
|
||||
mAudioSharingCallAudioPreferenceController.updateVisibility();
|
||||
mAudioSharingPlaySoundPreferenceController.updateVisibility();
|
||||
mAudioStreamsCategoryController.updateVisibility();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.settings.bluetooth.Utils;
|
||||
import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
|
||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||
@@ -60,6 +61,7 @@ public class AudioStreamMediaService extends Service {
|
||||
private static final String LEAVE_BROADCAST_ACTION = "leave_broadcast_action";
|
||||
private static final String LEAVE_BROADCAST_TEXT = "Leave Broadcast";
|
||||
private static final String CHANNEL_ID = "bluetooth_notification_channel";
|
||||
private static final String DEFAULT_DEVICE_NAME = "";
|
||||
private static final int STATIC_PLAYBACK_DURATION = 100;
|
||||
private static final int STATIC_PLAYBACK_POSITION = 30;
|
||||
private static final int ZERO_PLAYBACK_SPEED = 0;
|
||||
@@ -355,16 +357,34 @@ public class AudioStreamMediaService extends Service {
|
||||
return mIsMuted ? mPlayStatePausingBuilder.build() : mPlayStatePlayingBuilder.build();
|
||||
}
|
||||
|
||||
private String getDeviceName() {
|
||||
if (mDevices == null || mDevices.isEmpty() || mLocalBtManager == null) {
|
||||
return DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
CachedBluetoothDeviceManager manager = mLocalBtManager.getCachedDeviceManager();
|
||||
if (manager == null) {
|
||||
return DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
CachedBluetoothDevice device = manager.findDevice(mDevices.get(0));
|
||||
return device != null ? device.getName() : DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
private Notification buildNotification() {
|
||||
String deviceName = getDeviceName();
|
||||
Notification.MediaStyle mediaStyle =
|
||||
new Notification.MediaStyle()
|
||||
.setMediaSession(
|
||||
mLocalSession != null ? mLocalSession.getSessionToken() : null);
|
||||
if (deviceName != null && !deviceName.isEmpty()) {
|
||||
mediaStyle.setRemotePlaybackInfo(
|
||||
deviceName, com.android.internal.R.drawable.ic_bt_headset_hfp, null);
|
||||
}
|
||||
Notification.Builder notificationBuilder =
|
||||
new Notification.Builder(this, CHANNEL_ID)
|
||||
.setSmallIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
||||
.setStyle(
|
||||
new Notification.MediaStyle()
|
||||
.setMediaSession(
|
||||
mLocalSession != null
|
||||
? mLocalSession.getSessionToken()
|
||||
: null))
|
||||
.setStyle(mediaStyle)
|
||||
.setContentText(this.getString(BROADCAST_CONTENT_TEXT))
|
||||
.setSilent(true);
|
||||
return notificationBuilder.build();
|
||||
|
||||
@@ -86,6 +86,7 @@ import com.android.settings.bluetooth.BluetoothPairingDetail;
|
||||
import com.android.settings.bugreporthandler.BugReportHandlerPicker;
|
||||
import com.android.settings.communal.CommunalDashboardFragment;
|
||||
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
|
||||
import com.android.settings.connecteddevice.BluetoothDashboardFragment;
|
||||
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
|
||||
import com.android.settings.connecteddevice.NfcAndPaymentFragment;
|
||||
import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment;
|
||||
@@ -213,6 +214,7 @@ public class SettingsGateway {
|
||||
AdvancedConnectedDeviceDashboardFragment.class.getName(),
|
||||
CreateShortcut.class.getName(),
|
||||
BluetoothPairingDetail.class.getName(),
|
||||
BluetoothDashboardFragment.class.getName(),
|
||||
WifiNetworkDetailsFragment.class.getName(),
|
||||
ConfigureWifiSettings.class.getName(),
|
||||
SavedAccessPointsWifiSettings2.class.getName(),
|
||||
|
||||
@@ -57,7 +57,8 @@ import java.util.List;
|
||||
|
||||
/** An implementation to backup and restore battery configurations. */
|
||||
public final class BatterySettingsStorage extends ObservableBackupRestoreStorage {
|
||||
public static final String TAG = "BatteryBackupHelper";
|
||||
private static final String NAME = "BatteryBackupHelper";
|
||||
private static final String TAG = "BatterySettingsStorage";
|
||||
|
||||
// Definition for the device build information.
|
||||
public static final String KEY_BUILD_BRAND = "device_build_brand";
|
||||
@@ -89,7 +90,7 @@ public final class BatterySettingsStorage extends ObservableBackupRestoreStorage
|
||||
*/
|
||||
public static @NonNull BatterySettingsStorage get(@NonNull Context context) {
|
||||
return (BatterySettingsStorage)
|
||||
BackupRestoreStorageManager.getInstance(context).getOrThrow(TAG);
|
||||
BackupRestoreStorageManager.getInstance(context).getOrThrow(NAME);
|
||||
}
|
||||
|
||||
public BatterySettingsStorage(@NonNull Context context) {
|
||||
@@ -99,7 +100,7 @@ public final class BatterySettingsStorage extends ObservableBackupRestoreStorage
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return TAG;
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,8 +28,8 @@ import kotlinx.coroutines.flow.merge
|
||||
*
|
||||
* Note: This flow can only notify enabled status changes, cannot provide the latest status.
|
||||
*/
|
||||
fun Context.mobileDataEnabledFlow(subId: Int): Flow<Unit> {
|
||||
val flow = settingsGlobalChangeFlow(Settings.Global.MOBILE_DATA)
|
||||
fun Context.mobileDataEnabledFlow(subId: Int, sendInitialValue: Boolean = true): Flow<Unit> {
|
||||
val flow = settingsGlobalChangeFlow(Settings.Global.MOBILE_DATA, sendInitialValue)
|
||||
return when (subId) {
|
||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID -> flow
|
||||
else -> {
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.telephony.SubscriptionManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
@@ -242,15 +241,6 @@ public class ProxySubscriptionManager implements LifecycleObserver {
|
||||
return mSubscriptionMonitor.getAccessibleSubscriptionInfo(subId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of active, visible subscription Id(s) of the currently active SIM(s).
|
||||
*
|
||||
* @return the list of subId's that are active and visible; the length may be 0.
|
||||
*/
|
||||
public @NonNull int[] getActiveSubscriptionIdList() {
|
||||
return mSubscriptionMonitor.getActiveSubscriptionIdList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear data cached within proxy
|
||||
*/
|
||||
|
||||
@@ -19,20 +19,14 @@ package com.android.settings.network.telephony;
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PersistableBundle;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.ims.ImsException;
|
||||
import android.telephony.ims.ImsManager;
|
||||
import android.telephony.ims.ImsMmTelManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
import androidx.preference.Preference;
|
||||
@@ -40,15 +34,11 @@ import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.datausage.DataUsageUtils;
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settings.network.MobileDataContentObserver;
|
||||
import com.android.settings.network.ProxySubscriptionManager;
|
||||
import com.android.settings.network.SubscriptionsChangeListener;
|
||||
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel;
|
||||
|
||||
/**
|
||||
* Controls whether switch mobile data to the non-default SIM if the non-default SIM has better
|
||||
@@ -63,25 +53,29 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenceController
|
||||
implements LifecycleObserver,
|
||||
SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
|
||||
private static final String LOG_TAG = "AutoDataSwitchPrefCtrl";
|
||||
|
||||
@Nullable
|
||||
private TwoStatePreference mPreference;
|
||||
@Nullable
|
||||
private SubscriptionsChangeListener mChangeListener;
|
||||
@Nullable
|
||||
private TelephonyManager mManager;
|
||||
@Nullable
|
||||
private MobileDataContentObserver mMobileDataContentObserver;
|
||||
@Nullable
|
||||
private CrossSimCallingViewModel mCrossSimCallingViewModel;
|
||||
@Nullable
|
||||
private PreferenceScreen mScreen;
|
||||
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
|
||||
public AutoDataSwitchPreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
public AutoDataSwitchPreferenceController(
|
||||
@NonNull Context context, @NonNull String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||
}
|
||||
|
||||
void init(int subId) {
|
||||
void init(int subId, @Nullable CrossSimCallingViewModel crossSimCallingViewModel) {
|
||||
this.mSubId = subId;
|
||||
mManager = mContext.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
|
||||
mCrossSimCallingViewModel = crossSimCallingViewModel;
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(ON_RESUME)
|
||||
@@ -121,35 +115,15 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc
|
||||
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH);
|
||||
}
|
||||
|
||||
private int getOtherSubId(@NonNull int[] subIds) {
|
||||
if (subIds.length > 1) {
|
||||
for (int subId : subIds) {
|
||||
if (subId != mSubId) {
|
||||
return subId;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
}
|
||||
|
||||
private boolean isEnabled(int subId) {
|
||||
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
return false;
|
||||
}
|
||||
TelephonyManager telephonyManager = mContext.getSystemService(
|
||||
TelephonyManager.class).createForSubscriptionId(subId);
|
||||
return telephonyManager != null && telephonyManager.isMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
mManager.setMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
|
||||
isChecked);
|
||||
if (mContext.getResources().getBoolean(
|
||||
R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
|
||||
trySetCrossSimCalling(mContext, getActiveSubscriptionIdList(), isChecked /* enabled */);
|
||||
if (mManager != null) {
|
||||
mManager.setMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
|
||||
isChecked);
|
||||
}
|
||||
if (mCrossSimCallingViewModel != null) {
|
||||
mCrossSimCallingViewModel.updateCrossSimCalling();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -159,40 +133,6 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc
|
||||
return DataUsageUtils.hasMobileData(mContext);
|
||||
}
|
||||
|
||||
private boolean isCrossSimCallingAllowedByPlatform(Context context, int subId) {
|
||||
if ((new WifiCallingQueryImsState(context, subId)).isWifiCallingSupported()) {
|
||||
PersistableBundle bundle = getCarrierConfigForSubId(subId);
|
||||
return (bundle != null) && bundle.getBoolean(
|
||||
CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL,
|
||||
false /*default*/);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected ImsMmTelManager getImsMmTelManager(Context context, int subId) {
|
||||
ImsManager imsMgr = context.getSystemService(ImsManager.class);
|
||||
return (imsMgr == null) ? null : imsMgr.getImsMmTelManager(subId);
|
||||
}
|
||||
|
||||
private void trySetCrossSimCallingPerSub(Context context, int subId, boolean enabled) {
|
||||
try {
|
||||
getImsMmTelManager(context, subId).setCrossSimCallingEnabled(enabled);
|
||||
} catch (ImsException | IllegalArgumentException | NullPointerException exception) {
|
||||
Log.w(LOG_TAG, "failed to change cross SIM calling configuration to " + enabled
|
||||
+ " for subID " + subId + "with exception: ", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void trySetCrossSimCalling(Context context, int[] subIds, boolean enabled) {
|
||||
mMetricsFeatureProvider.action(mContext,
|
||||
SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT, enabled);
|
||||
for (int subId : subIds) {
|
||||
if (isCrossSimCallingAllowedByPlatform(context, subId)) {
|
||||
trySetCrossSimCallingPerSub(context, subId, enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus(int subId) {
|
||||
if (Flags.isDualSimOnboardingEnabled()
|
||||
@@ -221,20 +161,11 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc
|
||||
updateState(mPreference);
|
||||
}
|
||||
|
||||
private int[] getActiveSubscriptionIdList() {
|
||||
return ProxySubscriptionManager.getInstance(mContext).getActiveSubscriptionIdList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger displaying preference when Mobile data content changed.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public void refreshPreference() {
|
||||
if (mContext.getResources().getBoolean(
|
||||
R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
|
||||
int[] subIds = getActiveSubscriptionIdList();
|
||||
trySetCrossSimCalling(mContext, subIds, isEnabled(getOtherSubId(subIds)));
|
||||
}
|
||||
if (mScreen != null) {
|
||||
super.displayPreference(mScreen);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -53,6 +54,7 @@ import com.android.settings.network.telephony.cdma.CdmaSubscriptionPreferenceCon
|
||||
import com.android.settings.network.telephony.cdma.CdmaSystemSelectPreferenceController;
|
||||
import com.android.settings.network.telephony.gsm.AutoSelectPreferenceController;
|
||||
import com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenceController;
|
||||
import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.wifi.WifiPickerTrackerHelper;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -240,7 +242,9 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme
|
||||
use(CarrierSettingsVersionPreferenceController.class).init(mSubId);
|
||||
use(BillingCyclePreferenceController.class).init(mSubId);
|
||||
use(MmsMessagePreferenceController.class).init(mSubId);
|
||||
use(AutoDataSwitchPreferenceController.class).init(mSubId);
|
||||
final var crossSimCallingViewModel =
|
||||
new ViewModelProvider(this).get(CrossSimCallingViewModel.class);
|
||||
use(AutoDataSwitchPreferenceController.class).init(mSubId, crossSimCallingViewModel);
|
||||
use(DisabledSubscriptionController.class).init(mSubId);
|
||||
use(DeleteSimProfilePreferenceController.class).init(mSubId);
|
||||
use(DisableSimFooterPreferenceController.class).init(mSubId);
|
||||
|
||||
@@ -124,6 +124,14 @@ fun Context.getSelectableSubscriptionInfoList(): List<SubscriptionInfo> {
|
||||
}
|
||||
}
|
||||
// Matching the sorting order in SubscriptionManagerService.getAvailableSubscriptionInfoList
|
||||
.sortedWith(compareBy({ it.simSlotIndex }, { it.subscriptionId }))
|
||||
.sortedWith(compareBy({ it.sortableSimSlotIndex }, { it.subscriptionId }))
|
||||
.also { Log.d(TAG, "getSelectableSubscriptionInfoList: $it") }
|
||||
}
|
||||
|
||||
/** Subscription with invalid sim slot index has lowest sort order. */
|
||||
private val SubscriptionInfo.sortableSimSlotIndex: Int
|
||||
get() = if (simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
|
||||
simSlotIndex
|
||||
} else {
|
||||
Int.MAX_VALUE
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ interface ImsMmTelRepository {
|
||||
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||
@AccessNetworkConstants.TransportType transportType: Int,
|
||||
): Boolean
|
||||
|
||||
suspend fun setCrossSimCallingEnabled(enabled: Boolean)
|
||||
}
|
||||
|
||||
class ImsMmTelRepositoryImpl(
|
||||
@@ -130,6 +132,7 @@ class ImsMmTelRepositoryImpl(
|
||||
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||
@AccessNetworkConstants.TransportType transportType: Int,
|
||||
): Boolean = withContext(Dispatchers.Default) {
|
||||
val logName = "isSupported(capability=$capability,transportType=$transportType)"
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
try {
|
||||
imsMmTelManager.isSupported(
|
||||
@@ -140,9 +143,18 @@ class ImsMmTelRepositoryImpl(
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
continuation.resume(false)
|
||||
Log.w(TAG, "[$subId] isSupported failed", e)
|
||||
Log.w(TAG, "[$subId] $logName failed", e)
|
||||
}
|
||||
}.also { Log.d(TAG, "[$subId] isSupported = $it") }
|
||||
}.also { Log.d(TAG, "[$subId] $logName = $it") }
|
||||
}
|
||||
|
||||
override suspend fun setCrossSimCallingEnabled(enabled: Boolean) {
|
||||
try {
|
||||
imsMmTelManager.setCrossSimCallingEnabled(enabled)
|
||||
Log.d(TAG, "[$subId] setCrossSimCallingEnabled: $enabled")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "[$subId] failed setCrossSimCallingEnabled to $enabled", e)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.wificalling
|
||||
|
||||
import android.app.Application
|
||||
import android.app.settings.SettingsEnums
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.android.settings.R
|
||||
import com.android.settings.network.mobileDataEnabledFlow
|
||||
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
||||
import com.android.settings.network.telephony.requireSubscriptionManager
|
||||
import com.android.settings.network.telephony.safeGetConfig
|
||||
import com.android.settings.network.telephony.subscriptionsChangedFlow
|
||||
import com.android.settings.network.telephony.telephonyManager
|
||||
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.plus
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class CrossSimCallingViewModel(
|
||||
private val application: Application,
|
||||
) : AndroidViewModel(application) {
|
||||
|
||||
private val subscriptionManager = application.requireSubscriptionManager()
|
||||
private val carrierConfigManager =
|
||||
application.getSystemService(CarrierConfigManager::class.java)!!
|
||||
private val scope = viewModelScope + Dispatchers.Default
|
||||
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
|
||||
private val updateChannel = Channel<Unit>()
|
||||
|
||||
init {
|
||||
val resources = application.resources
|
||||
if (resources.getBoolean(R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
|
||||
application.subscriptionsChangedFlow()
|
||||
.flatMapLatest {
|
||||
val activeSubIds = subscriptionManager.activeSubscriptionIdList.toList()
|
||||
merge(
|
||||
activeSubIds.anyMobileDataEnableChangedFlow(),
|
||||
updateChannel.receiveAsFlow(),
|
||||
).map {
|
||||
activeSubIds to crossSimCallNewEnabled(activeSubIds)
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.onEach { (activeSubIds, newEnabled) ->
|
||||
updateCrossSimCalling(activeSubIds, newEnabled)
|
||||
}
|
||||
.launchIn(scope)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCrossSimCalling() {
|
||||
updateChannel.trySend(Unit)
|
||||
}
|
||||
|
||||
private fun List<Int>.anyMobileDataEnableChangedFlow() = map { subId ->
|
||||
application.mobileDataEnabledFlow(subId = subId, sendInitialValue = false)
|
||||
}.merge()
|
||||
|
||||
private suspend fun updateCrossSimCalling(activeSubIds: List<Int>, newEnabled: Boolean) {
|
||||
metricsFeatureProvider.action(
|
||||
application,
|
||||
SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT,
|
||||
newEnabled,
|
||||
)
|
||||
activeSubIds.filter { crossSimAvailable(it) }.forEach { subId ->
|
||||
ImsMmTelRepositoryImpl(application, subId)
|
||||
.setCrossSimCallingEnabled(newEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun crossSimAvailable(subId: Int): Boolean =
|
||||
WifiCallingRepository(application, subId).isWifiCallingSupported() &&
|
||||
crossSimImsAvailable(subId)
|
||||
|
||||
private fun crossSimImsAvailable(subId: Int): Boolean =
|
||||
carrierConfigManager.safeGetConfig(
|
||||
keys = listOf(CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL),
|
||||
subId = subId,
|
||||
).getBoolean(CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, false)
|
||||
|
||||
private fun crossSimCallNewEnabled(activeSubscriptionIdList: List<Int>): Boolean {
|
||||
val defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId()
|
||||
return SubscriptionManager.isValidSubscriptionId(defaultDataSubId) &&
|
||||
activeSubscriptionIdList.any { subId ->
|
||||
subId != defaultDataSubId &&
|
||||
application.telephonyManager(subId).isMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,17 +29,19 @@ import com.android.settings.network.telephony.ims.ImsMmTelRepository
|
||||
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
||||
import com.android.settings.network.telephony.ims.imsFeatureProvisionedFlow
|
||||
import com.android.settings.network.telephony.subscriptionsChangedFlow
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class WifiCallingRepository(
|
||||
private val context: Context,
|
||||
private val subId: Int,
|
||||
private val imsMmTelRepository : ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
|
||||
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
|
||||
) {
|
||||
private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
|
||||
.createForSubscriptionId(subId)
|
||||
@@ -76,10 +78,14 @@ class WifiCallingRepository(
|
||||
|
||||
private fun isWifiCallingSupportedFlow(): Flow<Boolean> {
|
||||
return imsMmTelRepository.imsReadyFlow().map { imsReady ->
|
||||
imsReady && imsMmTelRepository.isSupported(
|
||||
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
|
||||
transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
|
||||
)
|
||||
imsReady && isWifiCallingSupported()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun isWifiCallingSupported(): Boolean = withContext(Dispatchers.Default) {
|
||||
imsMmTelRepository.isSupported(
|
||||
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
|
||||
transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ import android.telephony.TelephonyManager
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.android.settings.R
|
||||
import com.android.settings.network.telephony.TelephonyRepository
|
||||
import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -34,6 +36,7 @@ fun AutomaticDataSwitchingPreference(
|
||||
) {
|
||||
val autoDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val crossSimCallingViewModel = viewModel<CrossSimCallingViewModel>() // handles backup calling
|
||||
SwitchPreference(
|
||||
object : SwitchPreferenceModel {
|
||||
override val title = stringResource(id = R.string.primary_sim_automatic_data_title)
|
||||
@@ -42,6 +45,7 @@ fun AutomaticDataSwitchingPreference(
|
||||
override val onCheckedChange: (Boolean) -> Unit = { newEnabled ->
|
||||
coroutineScope.launch(Dispatchers.Default) {
|
||||
setAutoDataEnabled(newEnabled)
|
||||
crossSimCallingViewModel.updateCrossSimCalling()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,5 +58,4 @@ fun TelephonyRepository.setAutomaticData(subId: Int, newEnabled: Boolean) {
|
||||
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
|
||||
enabled = newEnabled,
|
||||
)
|
||||
//TODO: setup backup calling
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ import java.util.ArrayList;
|
||||
ShadowAlertDialogCompat.class,
|
||||
ShadowBluetoothAdapter.class,
|
||||
})
|
||||
public class CallsAndAlarmsDialogFragmentTest {
|
||||
public class AudioSharingCallAudioDialogFragmentTest {
|
||||
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
|
||||
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
|
||||
@@ -64,7 +64,7 @@ public class CallsAndAlarmsDialogFragmentTest {
|
||||
new AudioSharingDeviceItem(TEST_DEVICE_NAME2, /* groupId= */ 1, /* isActive= */ true);
|
||||
|
||||
private Fragment mParent;
|
||||
private CallsAndAlarmsDialogFragment mFragment;
|
||||
private AudioSharingCallAudioDialogFragment mFragment;
|
||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
||||
|
||||
@Before
|
||||
@@ -76,7 +76,7 @@ public class CallsAndAlarmsDialogFragmentTest {
|
||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||
mFragment = new CallsAndAlarmsDialogFragment();
|
||||
mFragment = new AudioSharingCallAudioDialogFragment();
|
||||
mParent = new Fragment();
|
||||
FragmentController.setupFragment(
|
||||
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
|
||||
@@ -88,7 +88,7 @@ import java.util.List;
|
||||
ShadowBluetoothUtils.class,
|
||||
ShadowThreadUtils.class,
|
||||
})
|
||||
public class CallsAndAlarmsPreferenceControllerTest {
|
||||
public class AudioSharingCallAudioPreferenceControllerTest {
|
||||
private static final String PREF_KEY = "calls_and_alarms";
|
||||
private static final String TEST_DEVICE_NAME1 = "test1";
|
||||
private static final String TEST_DEVICE_NAME2 = "test2";
|
||||
@@ -118,7 +118,7 @@ public class CallsAndAlarmsPreferenceControllerTest {
|
||||
@Mock private CachedBluetoothDevice mCachedDevice3;
|
||||
@Mock private BluetoothLeBroadcastReceiveState mState;
|
||||
@Mock private ContentResolver mContentResolver;
|
||||
private CallsAndAlarmsPreferenceController mController;
|
||||
private AudioSharingCallAudioPreferenceController mController;
|
||||
@Spy private ContentObserver mContentObserver;
|
||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
||||
private LocalBluetoothManager mBtManager;
|
||||
@@ -151,7 +151,7 @@ public class CallsAndAlarmsPreferenceControllerTest {
|
||||
bisSyncState.add(1L);
|
||||
when(mState.getBisSyncState()).thenReturn(bisSyncState);
|
||||
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||
mController = new CallsAndAlarmsPreferenceController(mContext);
|
||||
mController = new AudioSharingCallAudioPreferenceController(mContext);
|
||||
mController.init(null);
|
||||
mContentObserver = mController.getSettingsObserver();
|
||||
mPreference = new Preference(mContext);
|
||||
@@ -27,7 +27,7 @@ import org.robolectric.RobolectricTestRunner;
|
||||
public final class AppUsageEventEntityTest {
|
||||
@Test
|
||||
public void testBuilder_returnsExpectedResult() {
|
||||
final long uid = 101L;
|
||||
final int uid = 101;
|
||||
final long userId = 1001L;
|
||||
final long timestamp = 10001L;
|
||||
final int appUsageEventType = 1;
|
||||
|
||||
@@ -85,7 +85,7 @@ public class AutoDataSwitchPreferenceControllerTest {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
mController.init(SUB_ID_1);
|
||||
mController.init(SUB_ID_1, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -169,7 +169,7 @@ public class BatteryTestUtils {
|
||||
Context context, long userId, long timestamp, String packageName, boolean multiple) {
|
||||
final AppUsageEventEntity entity =
|
||||
new AppUsageEventEntity(
|
||||
/* uid= */ 101L,
|
||||
/* uid= */ 101,
|
||||
userId,
|
||||
timestamp,
|
||||
/* appUsageEventType= */ 2,
|
||||
|
||||
@@ -115,6 +115,27 @@ class SubscriptionRepositoryTest {
|
||||
.containsExactly(SIM_SLOT_INDEX_0, SIM_SLOT_INDEX_1).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSelectableSubscriptionInfoList_oneNotInSlot_inSlotSortedFirst() {
|
||||
mockSubscriptionManager.stub {
|
||||
on { getAvailableSubscriptionInfoList() } doReturn listOf(
|
||||
SubscriptionInfo.Builder().apply {
|
||||
setSimSlotIndex(SubscriptionManager.INVALID_SIM_SLOT_INDEX)
|
||||
setId(SUB_ID_3_NOT_IN_SLOT)
|
||||
}.build(),
|
||||
SubscriptionInfo.Builder().apply {
|
||||
setSimSlotIndex(SIM_SLOT_INDEX_1)
|
||||
setId(SUB_ID_IN_SLOT_1)
|
||||
}.build(),
|
||||
)
|
||||
}
|
||||
|
||||
val subInfos = context.getSelectableSubscriptionInfoList()
|
||||
|
||||
assertThat(subInfos.map { it.simSlotIndex })
|
||||
.containsExactly(SIM_SLOT_INDEX_1, SubscriptionManager.INVALID_SIM_SLOT_INDEX).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSelectableSubscriptionInfoList_sameGroupAndOneHasSlot_returnTheOneWithSimSlotIndex() {
|
||||
mockSubscriptionManager.stub {
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.stub
|
||||
import org.mockito.kotlin.verify
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ImsMmTelRepositoryTest {
|
||||
@@ -155,6 +156,13 @@ class ImsMmTelRepositoryTest {
|
||||
assertThat(isSupported).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setCrossSimCallingEnabled() = runBlocking {
|
||||
repository.setCrossSimCallingEnabled(true)
|
||||
|
||||
verify(mockImsMmTelManager).setCrossSimCallingEnabled(true)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SUB_ID = 1
|
||||
const val CAPABILITY = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE
|
||||
|
||||
@@ -17,15 +17,18 @@
|
||||
package com.android.settings.network.telephony.wificalling
|
||||
|
||||
import android.content.Context
|
||||
import android.telephony.AccessNetworkConstants
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
|
||||
import android.telephony.TelephonyManager
|
||||
import android.telephony.ims.ImsMmTelManager
|
||||
import android.telephony.ims.feature.MmTelFeature
|
||||
import androidx.core.os.persistableBundleOf
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.network.telephony.ims.ImsMmTelRepository
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
@@ -98,6 +101,22 @@ class WifiCallingRepositoryTest {
|
||||
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isWifiCallingSupported() = runBlocking {
|
||||
mockImsMmTelRepository.stub {
|
||||
onBlocking {
|
||||
isSupported(
|
||||
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
|
||||
transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
|
||||
)
|
||||
} doReturn true
|
||||
}
|
||||
|
||||
val isSupported = repository.isWifiCallingSupported()
|
||||
|
||||
assertThat(isSupported).isTrue()
|
||||
}
|
||||
|
||||
private fun mockUseWfcHomeModeForRoaming(config: Boolean) {
|
||||
mockCarrierConfigManager.stub {
|
||||
on {
|
||||
|
||||
Reference in New Issue
Block a user