1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.network.telephony; 18 19 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; 20 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; 21 22 import android.content.Context; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.telephony.SubscriptionManager; 26 import android.telephony.TelephonyManager; 27 28 import androidx.annotation.NonNull; 29 import androidx.annotation.Nullable; 30 import androidx.lifecycle.LifecycleObserver; 31 import androidx.lifecycle.OnLifecycleEvent; 32 import androidx.preference.Preference; 33 import androidx.preference.PreferenceScreen; 34 import androidx.preference.TwoStatePreference; 35 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.settings.datausage.DataUsageUtils; 38 import com.android.settings.flags.Flags; 39 import com.android.settings.network.MobileDataContentObserver; 40 import com.android.settings.network.SubscriptionsChangeListener; 41 import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel; 42 43 /** 44 * Controls whether switch mobile data to the non-default SIM if the non-default SIM has better 45 * availability. 46 * 47 * This is used for temporarily allowing data on the non-default data SIM when on-default SIM 48 * has better availability on DSDS devices, where better availability means strong 49 * signal/connectivity. 50 * If this feature is enabled, data will be temporarily enabled on the non-default data SIM, 51 * including during any voice calls. 52 */ 53 public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenceController 54 implements LifecycleObserver, 55 SubscriptionsChangeListener.SubscriptionsChangeListenerClient { 56 57 @Nullable 58 private TwoStatePreference mPreference; 59 @Nullable 60 private SubscriptionsChangeListener mChangeListener; 61 @Nullable 62 private TelephonyManager mManager; 63 @Nullable 64 private MobileDataContentObserver mMobileDataContentObserver; 65 @Nullable 66 private CrossSimCallingViewModel mCrossSimCallingViewModel; 67 @Nullable 68 private PreferenceScreen mScreen; 69 AutoDataSwitchPreferenceController( @onNull Context context, @NonNull String preferenceKey)70 public AutoDataSwitchPreferenceController( 71 @NonNull Context context, @NonNull String preferenceKey) { 72 super(context, preferenceKey); 73 } 74 init(int subId, @Nullable CrossSimCallingViewModel crossSimCallingViewModel)75 void init(int subId, @Nullable CrossSimCallingViewModel crossSimCallingViewModel) { 76 this.mSubId = subId; 77 mManager = mContext.getSystemService(TelephonyManager.class).createForSubscriptionId(subId); 78 mCrossSimCallingViewModel = crossSimCallingViewModel; 79 } 80 81 @OnLifecycleEvent(ON_RESUME) onResume()82 public void onResume() { 83 if (mChangeListener == null) { 84 mChangeListener = new SubscriptionsChangeListener(mContext, this); 85 } 86 mChangeListener.start(); 87 if (mMobileDataContentObserver == null) { 88 mMobileDataContentObserver = new MobileDataContentObserver( 89 new Handler(Looper.getMainLooper())); 90 mMobileDataContentObserver.setOnMobileDataChangedListener(() -> refreshPreference()); 91 } 92 mMobileDataContentObserver.register(mContext, mSubId); 93 } 94 95 @OnLifecycleEvent(ON_PAUSE) onPause()96 public void onPause() { 97 if (mChangeListener != null) { 98 mChangeListener.stop(); 99 } 100 if (mMobileDataContentObserver != null) { 101 mMobileDataContentObserver.unRegister(mContext); 102 } 103 } 104 105 @Override displayPreference(PreferenceScreen screen)106 public void displayPreference(PreferenceScreen screen) { 107 super.displayPreference(screen); 108 mPreference = screen.findPreference(getPreferenceKey()); 109 mScreen = screen; 110 } 111 112 @Override isChecked()113 public boolean isChecked() { 114 return mManager != null && mManager.isMobileDataPolicyEnabled( 115 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH); 116 } 117 118 @Override setChecked(boolean isChecked)119 public boolean setChecked(boolean isChecked) { 120 if (mManager != null) { 121 mManager.setMobileDataPolicyEnabled( 122 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, 123 isChecked); 124 } 125 if (mCrossSimCallingViewModel != null) { 126 mCrossSimCallingViewModel.updateCrossSimCalling(); 127 } 128 return true; 129 } 130 131 @VisibleForTesting hasMobileData()132 protected boolean hasMobileData() { 133 return DataUsageUtils.hasMobileData(mContext); 134 } 135 136 @Override getAvailabilityStatus(int subId)137 public int getAvailabilityStatus(int subId) { 138 if (Flags.isDualSimOnboardingEnabled() 139 || !SubscriptionManager.isValidSubscriptionId(subId) 140 || SubscriptionManager.getDefaultDataSubscriptionId() == subId 141 || (!hasMobileData())) { 142 return CONDITIONALLY_UNAVAILABLE; 143 } 144 return AVAILABLE; 145 } 146 147 @Override updateState(Preference preference)148 public void updateState(Preference preference) { 149 super.updateState(preference); 150 if (preference == null) { 151 return; 152 } 153 preference.setVisible(isAvailable()); 154 } 155 156 @Override onAirplaneModeChanged(boolean airplaneModeEnabled)157 public void onAirplaneModeChanged(boolean airplaneModeEnabled) {} 158 159 @Override onSubscriptionsChanged()160 public void onSubscriptionsChanged() { 161 updateState(mPreference); 162 } 163 164 /** 165 * Trigger displaying preference when Mobile data content changed. 166 */ 167 @VisibleForTesting refreshPreference()168 public void refreshPreference() { 169 if (mScreen != null) { 170 super.displayPreference(mScreen); 171 } 172 } 173 } 174