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.car.settings.network; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.database.ContentObserver; 22 import android.net.Uri; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.provider.Settings; 26 import android.telephony.SubscriptionInfo; 27 import android.telephony.SubscriptionManager; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.preference.TwoStatePreference; 31 32 import com.android.car.settings.R; 33 import com.android.car.settings.common.ConfirmationDialogFragment; 34 import com.android.car.settings.common.FragmentController; 35 36 /** 37 * Business logic to control the toggle that enables/disables usage of mobile data. Does not have 38 * support for multi-sim. 39 */ 40 public class MobileDataTogglePreferenceController extends 41 NetworkBasePreferenceController<TwoStatePreference> implements 42 MobileNetworkUpdateManager.MobileNetworkUpdateListener { 43 44 @VisibleForTesting 45 static final String DISABLE_DIALOG_TAG = ConfirmationDialogFragment.TAG + "_DisableData"; 46 @VisibleForTesting 47 static final String ENABLE_MULTISIM_DIALOG_TAG = 48 ConfirmationDialogFragment.TAG + "_EnableMultisim"; 49 50 private final SubscriptionManager mSubscriptionManager; 51 52 private final ContentObserver mMobileDataChangeObserver = new ContentObserver( 53 new Handler(Looper.getMainLooper())) { 54 @Override 55 public void onChange(boolean selfChange) { 56 super.onChange(selfChange); 57 refreshUi(); 58 } 59 }; 60 61 private final ConfirmationDialogFragment.ConfirmListener mConfirmDisableListener = 62 arguments -> setMobileDataEnabled( 63 /* enabled= */ false, /* disableOtherSubscriptions= */ false); 64 private final ConfirmationDialogFragment.ConfirmListener mConfirmMultiSimListener = 65 arguments -> setMobileDataEnabled( 66 /* enabled= */ true, /* disableOtherSubscriptions= */ true); 67 private final ConfirmationDialogFragment.RejectListener mRejectRefreshListener = 68 arguments -> refreshUi(); 69 MobileDataTogglePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)70 public MobileDataTogglePreferenceController(Context context, String preferenceKey, 71 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 72 this(context, preferenceKey, fragmentController, uxRestrictions, 73 context.getSystemService(SubscriptionManager.class)); 74 } 75 76 @VisibleForTesting MobileDataTogglePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, SubscriptionManager subscriptionManager)77 MobileDataTogglePreferenceController(Context context, String preferenceKey, 78 FragmentController fragmentController, CarUxRestrictions uxRestrictions, 79 SubscriptionManager subscriptionManager) { 80 super(context, preferenceKey, fragmentController, uxRestrictions); 81 mSubscriptionManager = subscriptionManager; 82 } 83 84 @Override getPreferenceType()85 protected Class<TwoStatePreference> getPreferenceType() { 86 return TwoStatePreference.class; 87 } 88 89 @Override getDefaultAvailabilityStatus()90 protected int getDefaultAvailabilityStatus() { 91 return getSubId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID ? AVAILABLE 92 : CONDITIONALLY_UNAVAILABLE; 93 } 94 95 @Override onCreateInternal()96 protected void onCreateInternal() { 97 ConfirmationDialogFragment.resetListeners( 98 (ConfirmationDialogFragment) getFragmentController().findDialogByTag( 99 DISABLE_DIALOG_TAG), 100 mConfirmDisableListener, 101 mRejectRefreshListener, 102 /* neutralListener= */ null); 103 104 ConfirmationDialogFragment.resetListeners( 105 (ConfirmationDialogFragment) getFragmentController().findDialogByTag( 106 ENABLE_MULTISIM_DIALOG_TAG), 107 mConfirmMultiSimListener, 108 mRejectRefreshListener, 109 /* neutralListener= */ null); 110 } 111 112 @Override onStartInternal()113 protected void onStartInternal() { 114 if (getSubId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 115 getContext().getContentResolver().registerContentObserver(getObservableUri(getSubId()), 116 /* notifyForDescendants= */ false, mMobileDataChangeObserver); 117 } 118 } 119 120 @Override onStopInternal()121 protected void onStopInternal() { 122 if (getSubId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 123 getContext().getContentResolver().unregisterContentObserver(mMobileDataChangeObserver); 124 } 125 } 126 127 @Override updateState(TwoStatePreference preference)128 protected void updateState(TwoStatePreference preference) { 129 preference.setEnabled(!isOpportunistic()); 130 preference.setChecked( 131 getTelephonyManager() != null ? getTelephonyManager().isDataEnabled() : false); 132 } 133 134 @Override handlePreferenceChanged(TwoStatePreference preference, Object newValue)135 protected boolean handlePreferenceChanged(TwoStatePreference preference, Object newValue) { 136 boolean newToggleValue = (boolean) newValue; 137 boolean isMultiSim = (getTelephonyManager().getSimCount() > 1); 138 int defaultSubId = SubscriptionManager.getDefaultDataSubscriptionId(); 139 boolean needToDisableOthers = mSubscriptionManager.isActiveSubscriptionId(defaultSubId) 140 && getSubId() != defaultSubId; 141 142 if (!newToggleValue && !isMultiSim) { 143 getFragmentController().showDialog(getConfirmDataDisableDialog(), DISABLE_DIALOG_TAG); 144 } else if (newToggleValue && isMultiSim && needToDisableOthers) { 145 getFragmentController().showDialog(getConfirmMultisimEnableDialog(), 146 ENABLE_MULTISIM_DIALOG_TAG); 147 } else { 148 setMobileDataEnabled(newToggleValue, /* disableOtherSubscriptions= */ false); 149 } 150 return false; 151 } 152 153 @Override onMobileNetworkUpdated(int subId)154 public void onMobileNetworkUpdated(int subId) { 155 setFields(subId); 156 refreshUi(); 157 } 158 setMobileDataEnabled(boolean enabled, boolean disableOtherSubscriptions)159 private void setMobileDataEnabled(boolean enabled, boolean disableOtherSubscriptions) { 160 NetworkUtils.setMobileDataEnabled(getContext(), getSubId(), enabled, 161 disableOtherSubscriptions); 162 refreshUi(); 163 } 164 isOpportunistic()165 private boolean isOpportunistic() { 166 SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(getSubId()); 167 return info != null && info.isOpportunistic(); 168 } 169 getObservableUri(int subId)170 private Uri getObservableUri(int subId) { 171 Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); 172 if (getTelephonyManager().getSimCount() != 1) { 173 uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); 174 } 175 return uri; 176 } 177 getConfirmDataDisableDialog()178 private ConfirmationDialogFragment getConfirmDataDisableDialog() { 179 return new ConfirmationDialogFragment.Builder(getContext()) 180 .setMessage(R.string.confirm_mobile_data_disable) 181 .setPositiveButton(android.R.string.ok, mConfirmDisableListener) 182 .setNegativeButton(android.R.string.cancel, mRejectRefreshListener) 183 .build(); 184 } 185 getConfirmMultisimEnableDialog()186 private ConfirmationDialogFragment getConfirmMultisimEnableDialog() { 187 SubscriptionInfo previousSubInfo = 188 mSubscriptionManager.getDefaultDataSubscriptionInfo(); 189 SubscriptionInfo newSubInfo = 190 mSubscriptionManager.getActiveSubscriptionInfo(getSubId()); 191 192 String previousName = (previousSubInfo == null) 193 ? getContext().getResources().getString(R.string.sim_selection_required_pref) 194 : previousSubInfo.getDisplayName().toString(); 195 196 String newName = (newSubInfo == null) 197 ? getContext().getResources().getString(R.string.sim_selection_required_pref) 198 : newSubInfo.getDisplayName().toString(); 199 200 return new ConfirmationDialogFragment.Builder(getContext()) 201 .setTitle(getContext().getString(R.string.sim_change_data_title, newName)) 202 .setMessage(getContext().getString(R.string.sim_change_data_message, 203 newName, previousName)) 204 .setPositiveButton(getContext().getString(R.string.sim_change_data_ok, newName), 205 mConfirmMultiSimListener) 206 .setNegativeButton(android.R.string.cancel, mRejectRefreshListener) 207 .build(); 208 } 209 } 210