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