1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.settings.datausage; 16 17 import android.app.AlertDialog; 18 import android.content.Context; 19 import android.content.DialogInterface; 20 import android.database.ContentObserver; 21 import android.net.NetworkTemplate; 22 import android.net.Uri; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.provider.Settings.Global; 28 import android.support.v7.preference.PreferenceViewHolder; 29 import android.telephony.SubscriptionInfo; 30 import android.telephony.SubscriptionManager; 31 import android.telephony.TelephonyManager; 32 import android.util.AttributeSet; 33 import android.util.Log; 34 import android.view.View; 35 import android.widget.Checkable; 36 import com.android.internal.logging.MetricsLogger; 37 import com.android.internal.logging.MetricsProto.MetricsEvent; 38 import com.android.settings.CustomDialogPreference; 39 import com.android.settings.R; 40 import com.android.settings.Utils; 41 42 import java.util.List; 43 44 public class CellDataPreference extends CustomDialogPreference implements TemplatePreference { 45 46 private static final String TAG = "CellDataPreference"; 47 48 public int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 49 public boolean mChecked; 50 public boolean mMultiSimDialog; 51 private TelephonyManager mTelephonyManager; 52 private SubscriptionManager mSubscriptionManager; 53 54 public CellDataPreference(Context context, AttributeSet attrs) { 55 super(context, attrs, android.R.attr.switchPreferenceStyle); 56 } 57 58 @Override 59 protected void onRestoreInstanceState(Parcelable s) { 60 CellDataState state = (CellDataState) s; 61 super.onRestoreInstanceState(state.getSuperState()); 62 mTelephonyManager = TelephonyManager.from(getContext()); 63 mChecked = state.mChecked; 64 mMultiSimDialog = state.mMultiSimDialog; 65 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 66 mSubId = state.mSubId; 67 setKey(getKey() + mSubId); 68 } 69 notifyChanged(); 70 } 71 72 @Override 73 protected Parcelable onSaveInstanceState() { 74 CellDataState state = new CellDataState(super.onSaveInstanceState()); 75 state.mChecked = mChecked; 76 state.mMultiSimDialog = mMultiSimDialog; 77 state.mSubId = mSubId; 78 return state; 79 } 80 81 @Override 82 public void onAttached() { 83 super.onAttached(); 84 mListener.setListener(true, mSubId, getContext()); 85 } 86 87 @Override 88 public void onDetached() { 89 mListener.setListener(false, mSubId, getContext()); 90 super.onDetached(); 91 } 92 93 @Override 94 public void setTemplate(NetworkTemplate template, int subId, NetworkServices services) { 95 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 96 throw new IllegalArgumentException("CellDataPreference needs a SubscriptionInfo"); 97 } 98 mSubscriptionManager = SubscriptionManager.from(getContext()); 99 mTelephonyManager = TelephonyManager.from(getContext()); 100 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 101 mSubId = subId; 102 setKey(getKey() + subId); 103 } 104 updateChecked(); 105 } 106 107 private void updateChecked() { 108 setChecked(mTelephonyManager.getDataEnabled(mSubId)); 109 } 110 111 @Override 112 protected void performClick(View view) { 113 MetricsLogger.action(getContext(), MetricsEvent.ACTION_CELL_DATA_TOGGLE, !mChecked); 114 if (mChecked) { 115 final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo( 116 mSubId); 117 final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo(); 118 119 // If the device is single SIM or is enabling data on the active data SIM then forgo 120 // the pop-up. 121 if (!Utils.showSimCardTile(getContext()) || 122 (nextSir != null && currentSir != null && 123 currentSir.getSubscriptionId() == nextSir.getSubscriptionId())) { 124 setMobileDataEnabled(false); 125 if (nextSir != null && currentSir != null && 126 currentSir.getSubscriptionId() == nextSir.getSubscriptionId()) { 127 disableDataForOtherSubscriptions(mSubId); 128 } 129 return; 130 } 131 // disabling data; show confirmation dialog which eventually 132 // calls setMobileDataEnabled() once user confirms. 133 mMultiSimDialog = false; 134 super.performClick(view); 135 } else { 136 // If we are showing the Sim Card tile then we are a Multi-Sim device. 137 if (Utils.showSimCardTile(getContext())) { 138 mMultiSimDialog = true; 139 super.performClick(view); 140 } else { 141 setMobileDataEnabled(true); 142 } 143 } 144 } 145 146 private void setMobileDataEnabled(boolean enabled) { 147 if (DataUsageSummary.LOGD) Log.d(TAG, "setMobileDataEnabled(" + enabled + "," 148 + mSubId + ")"); 149 mTelephonyManager.setDataEnabled(mSubId, enabled); 150 setChecked(enabled); 151 } 152 153 private void setChecked(boolean checked) { 154 if (mChecked == checked) return; 155 mChecked = checked; 156 notifyChanged(); 157 } 158 159 @Override 160 public void onBindViewHolder(PreferenceViewHolder holder) { 161 super.onBindViewHolder(holder); 162 View switchView = holder.findViewById(android.R.id.switch_widget); 163 switchView.setClickable(false); 164 ((Checkable) switchView).setChecked(mChecked); 165 } 166 167 @Override 168 protected void onPrepareDialogBuilder(AlertDialog.Builder builder, 169 DialogInterface.OnClickListener listener) { 170 if (mMultiSimDialog) { 171 showMultiSimDialog(builder, listener); 172 } else { 173 showDisableDialog(builder, listener); 174 } 175 } 176 177 private void showDisableDialog(AlertDialog.Builder builder, 178 DialogInterface.OnClickListener listener) { 179 builder.setTitle(null) 180 .setMessage(R.string.data_usage_disable_mobile) 181 .setPositiveButton(android.R.string.ok, listener) 182 .setNegativeButton(android.R.string.cancel, null); 183 } 184 185 private void showMultiSimDialog(AlertDialog.Builder builder, 186 DialogInterface.OnClickListener listener) { 187 final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(mSubId); 188 final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo(); 189 190 final String previousName = (nextSir == null) 191 ? getContext().getResources().getString(R.string.sim_selection_required_pref) 192 : nextSir.getDisplayName().toString(); 193 194 builder.setTitle(R.string.sim_change_data_title); 195 builder.setMessage(getContext().getString(R.string.sim_change_data_message, 196 String.valueOf(currentSir != null ? currentSir.getDisplayName() : null), 197 previousName)); 198 199 builder.setPositiveButton(R.string.okay, listener); 200 builder.setNegativeButton(R.string.cancel, null); 201 } 202 203 private void disableDataForOtherSubscriptions(int subId) { 204 List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); 205 if (subInfoList != null) { 206 for (SubscriptionInfo subInfo : subInfoList) { 207 if (subInfo.getSubscriptionId() != subId) { 208 mTelephonyManager.setDataEnabled(subInfo.getSubscriptionId(), false); 209 } 210 } 211 } 212 } 213 214 @Override 215 protected void onClick(DialogInterface dialog, int which) { 216 if (which != DialogInterface.BUTTON_POSITIVE) { 217 return; 218 } 219 if (mMultiSimDialog) { 220 mSubscriptionManager.setDefaultDataSubId(mSubId); 221 setMobileDataEnabled(true); 222 disableDataForOtherSubscriptions(mSubId); 223 } else { 224 // TODO: extend to modify policy enabled flag. 225 setMobileDataEnabled(false); 226 } 227 } 228 229 private final DataStateListener mListener = new DataStateListener() { 230 @Override 231 public void onChange(boolean selfChange) { 232 updateChecked(); 233 } 234 }; 235 236 public abstract static class DataStateListener extends ContentObserver { 237 public DataStateListener() { 238 super(new Handler(Looper.getMainLooper())); 239 } 240 241 public void setListener(boolean listening, int subId, Context context) { 242 if (listening) { 243 Uri uri = Global.getUriFor(Global.MOBILE_DATA); 244 if (TelephonyManager.getDefault().getSimCount() != 1) { 245 uri = Global.getUriFor(Global.MOBILE_DATA + subId); 246 } 247 context.getContentResolver().registerContentObserver(uri, false, this); 248 } else { 249 context.getContentResolver().unregisterContentObserver(this); 250 } 251 } 252 } 253 254 public static class CellDataState extends BaseSavedState { 255 public int mSubId; 256 public boolean mChecked; 257 public boolean mMultiSimDialog; 258 259 public CellDataState(Parcelable base) { 260 super(base); 261 } 262 263 public CellDataState(Parcel source) { 264 super(source); 265 mChecked = source.readByte() != 0; 266 mMultiSimDialog = source.readByte() != 0; 267 mSubId = source.readInt(); 268 } 269 270 @Override 271 public void writeToParcel(Parcel dest, int flags) { 272 super.writeToParcel(dest, flags); 273 dest.writeByte((byte) (mChecked ? 1 : 0)); 274 dest.writeByte((byte) (mMultiSimDialog ? 1 : 0)); 275 dest.writeInt(mSubId); 276 } 277 278 public static final Creator<CellDataState> CREATOR = new Creator<CellDataState>() { 279 @Override 280 public CellDataState createFromParcel(Parcel source) { 281 return new CellDataState(source); 282 } 283 284 @Override 285 public CellDataState[] newArray(int size) { 286 return new CellDataState[size]; 287 } 288 }; 289 } 290 } 291