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.developeroptions.network.telephony; 18 19 import android.content.Context; 20 import android.database.ContentObserver; 21 import android.net.Uri; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.provider.Settings; 25 import android.telephony.SubscriptionInfo; 26 import android.telephony.SubscriptionManager; 27 import android.telephony.TelephonyManager; 28 import android.text.TextUtils; 29 30 import com.android.settingslib.core.lifecycle.LifecycleObserver; 31 import com.android.settingslib.core.lifecycle.events.OnStart; 32 import com.android.settingslib.core.lifecycle.events.OnStop; 33 34 import androidx.annotation.VisibleForTesting; 35 import androidx.fragment.app.FragmentManager; 36 import androidx.preference.Preference; 37 import androidx.preference.PreferenceScreen; 38 import androidx.preference.SwitchPreference; 39 40 /** 41 * Preference controller for "Mobile data" 42 */ 43 public class MobileDataPreferenceController extends TelephonyTogglePreferenceController 44 implements LifecycleObserver, OnStart, OnStop { 45 46 private static final String DIALOG_TAG = "MobileDataDialog"; 47 48 private SwitchPreference mPreference; 49 private TelephonyManager mTelephonyManager; 50 private SubscriptionManager mSubscriptionManager; 51 private DataContentObserver mDataContentObserver; 52 private FragmentManager mFragmentManager; 53 @VisibleForTesting 54 int mDialogType; 55 @VisibleForTesting 56 boolean mNeedDialog; 57 MobileDataPreferenceController(Context context, String key)58 public MobileDataPreferenceController(Context context, String key) { 59 super(context, key); 60 mSubscriptionManager = context.getSystemService(SubscriptionManager.class); 61 mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper())); 62 } 63 64 @Override getAvailabilityStatus(int subId)65 public int getAvailabilityStatus(int subId) { 66 return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 67 ? AVAILABLE 68 : CONDITIONALLY_UNAVAILABLE; 69 } 70 71 @Override displayPreference(PreferenceScreen screen)72 public void displayPreference(PreferenceScreen screen) { 73 super.displayPreference(screen); 74 mPreference = screen.findPreference(getPreferenceKey()); 75 } 76 77 @Override onStart()78 public void onStart() { 79 if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 80 mDataContentObserver.register(mContext, mSubId); 81 } 82 } 83 84 @Override onStop()85 public void onStop() { 86 if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 87 mDataContentObserver.unRegister(mContext); 88 } 89 } 90 91 @Override handlePreferenceTreeClick(Preference preference)92 public boolean handlePreferenceTreeClick(Preference preference) { 93 if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { 94 if (mNeedDialog) { 95 showDialog(mDialogType); 96 } 97 return true; 98 } 99 100 return false; 101 } 102 103 @Override setChecked(boolean isChecked)104 public boolean setChecked(boolean isChecked) { 105 mNeedDialog = isDialogNeeded(); 106 107 if (!mNeedDialog) { 108 // Update data directly if we don't need dialog 109 MobileNetworkUtils.setMobileDataEnabled(mContext, mSubId, isChecked, false); 110 return true; 111 } 112 113 return false; 114 } 115 116 @Override isChecked()117 public boolean isChecked() { 118 return mTelephonyManager.isDataEnabled(); 119 } 120 121 @Override updateState(Preference preference)122 public void updateState(Preference preference) { 123 super.updateState(preference); 124 preference.setEnabled(!isOpportunistic()); 125 } 126 isOpportunistic()127 private boolean isOpportunistic() { 128 SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(mSubId); 129 return info != null && info.isOpportunistic(); 130 } 131 getObservableUri(int subId)132 public static Uri getObservableUri(int subId) { 133 Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); 134 if (TelephonyManager.getDefault().getSimCount() != 1) { 135 uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); 136 } 137 return uri; 138 } 139 init(FragmentManager fragmentManager, int subId)140 public void init(FragmentManager fragmentManager, int subId) { 141 mFragmentManager = fragmentManager; 142 mSubId = subId; 143 mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); 144 } 145 146 @VisibleForTesting isDialogNeeded()147 boolean isDialogNeeded() { 148 final boolean enableData = !isChecked(); 149 final boolean isMultiSim = (mTelephonyManager.getSimCount() > 1); 150 final int defaultSubId = mSubscriptionManager.getDefaultDataSubscriptionId(); 151 final boolean needToDisableOthers = mSubscriptionManager 152 .isActiveSubscriptionId(defaultSubId) && defaultSubId != mSubId; 153 if (enableData) { 154 if (isMultiSim && needToDisableOthers) { 155 mDialogType = MobileDataDialogFragment.TYPE_MULTI_SIM_DIALOG; 156 return true; 157 } 158 } else { 159 if (!isMultiSim) { 160 mDialogType = MobileDataDialogFragment.TYPE_DISABLE_DIALOG; 161 return true; 162 } 163 } 164 165 return false; 166 } 167 showDialog(int type)168 private void showDialog(int type) { 169 final MobileDataDialogFragment dialogFragment = MobileDataDialogFragment.newInstance(type, 170 mSubId); 171 dialogFragment.show(mFragmentManager, DIALOG_TAG); 172 } 173 174 /** 175 * Listener that listens mobile data state change. 176 */ 177 public class DataContentObserver extends ContentObserver { 178 DataContentObserver(Handler handler)179 public DataContentObserver(Handler handler) { 180 super(handler); 181 } 182 183 @Override onChange(boolean selfChange)184 public void onChange(boolean selfChange) { 185 super.onChange(selfChange); 186 updateState(mPreference); 187 } 188 register(Context context, int subId)189 public void register(Context context, int subId) { 190 final Uri uri = getObservableUri(subId); 191 context.getContentResolver().registerContentObserver(uri, false, this); 192 193 } 194 unRegister(Context context)195 public void unRegister(Context context) { 196 context.getContentResolver().unregisterContentObserver(this); 197 } 198 } 199 } 200