blob: 4e82f20c1fff98c2dc6af265d81988298f59ff8d [file] [log] [blame]
Malcolm Chen9ef63c62017-06-20 16:53:01 -07001/*
2 * Copyright (C) 2017 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
17package com.android.phone;
18
19import android.app.AlertDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.database.ContentObserver;
23import android.net.Uri;
24import android.os.Handler;
25import android.os.Looper;
26import android.os.Parcel;
27import android.os.Parcelable;
28import android.preference.DialogPreference;
29import android.preference.PreferenceScreen;
30import android.provider.Settings.Global;
31import android.telephony.SubscriptionInfo;
32import android.telephony.SubscriptionManager;
33import android.telephony.TelephonyManager;
34import android.util.AttributeSet;
35import android.util.Log;
36import android.view.View;
37import android.widget.Checkable;
38
Malcolm Chen3f2dd682017-07-24 16:44:32 -070039import com.android.internal.logging.MetricsLogger;
40import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
41
Malcolm Chen9ef63c62017-06-20 16:53:01 -070042import java.util.List;
43
44/**
45 * Customized Preference to enable / disable mobile data.
46 * Basically copy of with com.android.settings.CellDataPreference.
47 */
48public class MobileDataPreference extends DialogPreference {
49
50 private static final boolean DBG = false;
51 private static final String TAG = "MobileDataPreference";
52
53 public int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
54 public boolean mChecked;
Malcolm Chen06db82a2018-08-14 18:17:05 -070055 // Whether to show the dialog to ask switching default data subscription.
56 // Should be true only when a multi-sim phone only supports data connection on a single phone,
57 // and user is enabling data on the non-default phone.
Malcolm Chen9ef63c62017-06-20 16:53:01 -070058 public boolean mMultiSimDialog;
59 private TelephonyManager mTelephonyManager;
60 private SubscriptionManager mSubscriptionManager;
61
62 public MobileDataPreference(Context context, AttributeSet attrs) {
63 super(context, attrs, com.android.internal.R.attr.switchPreferenceStyle);
64 }
65
66 @Override
67 protected void onRestoreInstanceState(Parcelable s) {
68 CellDataState state = (CellDataState) s;
69 super.onRestoreInstanceState(state.getSuperState());
70 mTelephonyManager = TelephonyManager.from(getContext());
71 mChecked = state.mChecked;
72 mMultiSimDialog = state.mMultiSimDialog;
73 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
74 mSubId = state.mSubId;
75 setKey(getKey() + mSubId);
76 }
77 notifyChanged();
78 }
79
80 @Override
81 protected Parcelable onSaveInstanceState() {
82 CellDataState state = new CellDataState(super.onSaveInstanceState());
83 state.mChecked = mChecked;
84 state.mMultiSimDialog = mMultiSimDialog;
85 state.mSubId = mSubId;
86 return state;
87 }
88
89 @Override
90 protected void onAttachedToActivity() {
91 super.onAttachedToActivity();
92 mListener.setListener(true, mSubId, getContext());
93 }
94
95 @Override
96 protected void onPrepareForRemoval() {
97 mListener.setListener(false, mSubId, getContext());
98 super.onPrepareForRemoval();
99 }
100
101 /**
102 * Initialize this preference with subId.
103 */
104 public void initialize(int subId) {
105 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
106 throw new IllegalArgumentException("MobileDataPreference needs a SubscriptionInfo");
107 }
108 mSubscriptionManager = SubscriptionManager.from(getContext());
109 mTelephonyManager = TelephonyManager.from(getContext());
110 if (mSubId != subId) {
111 mSubId = subId;
112 setKey(getKey() + subId);
113 }
114 updateChecked();
115 }
116
117 private void updateChecked() {
118 setChecked(mTelephonyManager.getDataEnabled(mSubId));
119 }
120
121 @Override
122 public void performClick(PreferenceScreen preferenceScreen) {
Sanket Padawe4efc9242017-08-13 23:33:07 -0700123 if (!isEnabled() || !SubscriptionManager.isValidSubscriptionId(mSubId)) {
124 return;
125 }
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700126 final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(
127 mSubId);
128 final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
Malcolm Chen06db82a2018-08-14 18:17:05 -0700129 final boolean isMultiSim = (mTelephonyManager.getSimCount() > 1);
130 final boolean isMultipleDataOnCapable =
131 (mTelephonyManager.getNumberOfModemsWithSimultaneousDataConnections() > 1);
132 final boolean isDefaultDataSubscription = (nextSir != null && currentSir != null
133 && currentSir.getSubscriptionId() == nextSir.getSubscriptionId());
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700134 if (mChecked) {
Malcolm Chen06db82a2018-08-14 18:17:05 -0700135 if (!isMultiSim) {
136 // disabling data; show confirmation dialog which eventually
137 // calls setMobileDataEnabled() once user confirms.
138 mMultiSimDialog = false;
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700139 super.performClick(preferenceScreen);
140 } else {
Malcolm Chen06db82a2018-08-14 18:17:05 -0700141 // Don't show any dialog.
142 setMobileDataEnabled(false /* enabled */, false /* disableOtherSubscriptions */);
143 }
144 } else {
145 if (isMultiSim && !isMultipleDataOnCapable && !isDefaultDataSubscription) {
146 // enabling data and setting to default; show confirmation dialog which eventually
147 // calls setMobileDataEnabled() once user confirms.
148 mMultiSimDialog = true;
149 super.performClick(preferenceScreen);
150 } else {
151 // Don't show any dialog.
152 setMobileDataEnabled(true /* enabled */, false /* disableOtherSubscriptions */);
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700153 }
154 }
155 }
156
Malcolm Chen06db82a2018-08-14 18:17:05 -0700157 private void setMobileDataEnabled(boolean enabled, boolean disableOtherSubscriptions) {
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700158 if (DBG) Log.d(TAG, "setMobileDataEnabled(" + enabled + "," + mSubId + ")");
Malcolm Chen3f2dd682017-07-24 16:44:32 -0700159
160 MetricsLogger.action(getContext(), MetricsEvent.ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE,
161 enabled);
162
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700163 mTelephonyManager.setDataEnabled(mSubId, enabled);
Malcolm Chen06db82a2018-08-14 18:17:05 -0700164
165 if (disableOtherSubscriptions) {
166 disableDataForOtherSubscriptions(mSubId);
167 }
168
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700169 setChecked(enabled);
170 }
171
172 private void setChecked(boolean checked) {
173 if (mChecked == checked) return;
174 mChecked = checked;
175 notifyChanged();
176 }
177
178 @Override
179 protected void onBindView(View view) {
180 super.onBindView(view);
181 View checkableView = view.findViewById(com.android.internal.R.id.switch_widget);
182 checkableView.setClickable(false);
183 ((Checkable) checkableView).setChecked(mChecked);
184 }
185
186 @Override
187 protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
188 if (mMultiSimDialog) {
189 showMultiSimDialog(builder);
190 } else {
191 showDisableDialog(builder);
192 }
193 }
194
195 private void showDisableDialog(AlertDialog.Builder builder) {
196 builder.setTitle(null)
197 .setMessage(R.string.data_usage_disable_mobile)
198 .setPositiveButton(android.R.string.ok, this)
199 .setNegativeButton(android.R.string.cancel, null);
200 }
201
202 private void showMultiSimDialog(AlertDialog.Builder builder) {
203 final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
204 final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
205
206 final String previousName = (nextSir == null)
207 ? getContext().getResources().getString(R.string.sim_selection_required_pref)
208 : nextSir.getDisplayName().toString();
209
210 builder.setTitle(R.string.sim_change_data_title);
211 builder.setMessage(getContext().getString(R.string.sim_change_data_message,
212 String.valueOf(currentSir != null ? currentSir.getDisplayName() : null),
213 previousName));
214
215 builder.setPositiveButton(R.string.ok, this);
216 builder.setNegativeButton(R.string.cancel, null);
217 }
218
219 private void disableDataForOtherSubscriptions(int subId) {
220 List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
221 if (subInfoList != null) {
222 for (SubscriptionInfo subInfo : subInfoList) {
223 if (subInfo.getSubscriptionId() != subId) {
224 mTelephonyManager.setDataEnabled(subInfo.getSubscriptionId(), false);
225 }
226 }
227 }
228 }
229
230 @Override
231 public void onClick(DialogInterface dialog, int which) {
232 if (which != DialogInterface.BUTTON_POSITIVE) {
233 return;
234 }
235 if (mMultiSimDialog) {
236 mSubscriptionManager.setDefaultDataSubId(mSubId);
Malcolm Chen06db82a2018-08-14 18:17:05 -0700237 setMobileDataEnabled(true /* enabled */, true /* disableOtherSubscriptions */);
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700238 } else {
239 // TODO: extend to modify policy enabled flag.
Malcolm Chen06db82a2018-08-14 18:17:05 -0700240 setMobileDataEnabled(false /* enabled */, false /* disableOtherSubscriptions */);
Malcolm Chen9ef63c62017-06-20 16:53:01 -0700241 }
242 }
243
244 private final DataStateListener mListener = new DataStateListener() {
245 @Override
246 public void onChange(boolean selfChange) {
247 updateChecked();
248 }
249 };
250
251 /**
252 * Listener that listens mobile data state change.
253 */
254 public abstract static class DataStateListener extends ContentObserver {
255 public DataStateListener() {
256 super(new Handler(Looper.getMainLooper()));
257 }
258
259 /**
260 * Set / Unset data state listening, specifying subId.
261 */
262 public void setListener(boolean listening, int subId, Context context) {
263 if (listening) {
264 Uri uri = Global.getUriFor(Global.MOBILE_DATA);
265 if (TelephonyManager.getDefault().getSimCount() != 1) {
266 uri = Global.getUriFor(Global.MOBILE_DATA + subId);
267 }
268 context.getContentResolver().registerContentObserver(uri, false, this);
269 } else {
270 context.getContentResolver().unregisterContentObserver(this);
271 }
272 }
273 }
274
275 /**
276 * Class that represents state of mobile data state.
277 * Used by onSaveInstanceState and onRestoreInstanceState.
278 */
279 public static class CellDataState extends BaseSavedState {
280 public int mSubId;
281 public boolean mChecked;
282 public boolean mMultiSimDialog;
283
284 public CellDataState(Parcelable base) {
285 super(base);
286 }
287
288 public CellDataState(Parcel source) {
289 super(source);
290 mChecked = source.readByte() != 0;
291 mMultiSimDialog = source.readByte() != 0;
292 mSubId = source.readInt();
293 }
294
295 @Override
296 public void writeToParcel(Parcel dest, int flags) {
297 super.writeToParcel(dest, flags);
298 dest.writeByte((byte) (mChecked ? 1 : 0));
299 dest.writeByte((byte) (mMultiSimDialog ? 1 : 0));
300 dest.writeInt(mSubId);
301 }
302
303 public static final Creator<CellDataState> CREATOR = new Creator<CellDataState>() {
304 @Override
305 public CellDataState createFromParcel(Parcel source) {
306 return new CellDataState(source);
307 }
308
309 @Override
310 public CellDataState[] newArray(int size) {
311 return new CellDataState[size];
312 }
313 };
314 }
315}