Home | History | Annotate | Download | only in phone
      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 
     59     public MobileDataPreference(Context context, AttributeSet attrs) {
     60         super(context, attrs, com.android.internal.R.attr.switchPreferenceStyle);
     61     }
     62 
     63     @Override
     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
     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
     87     protected void onAttachedToActivity() {
     88         super.onAttachedToActivity();
     89         mListener.setListener(true, mSubId, getContext());
     90     }
     91 
     92     @Override
     93     protected void onPrepareForRemoval() {
     94         mListener.setListener(false, mSubId, getContext());
     95         super.onPrepareForRemoval();
     96     }
     97 
     98     /**
     99      * Initialize this preference with subId.
    100      */
    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 
    114     private void updateChecked() {
    115         setChecked(mTelephonyManager.getDataEnabled(mSubId));
    116     }
    117 
    118     @Override
    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 
    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 
    170     private void setChecked(boolean checked) {
    171         if (mChecked == checked) return;
    172         mChecked = checked;
    173         notifyChanged();
    174     }
    175 
    176     @Override
    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
    185     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
    186         if (mMultiSimDialog) {
    187             showMultiSimDialog(builder);
    188         } else {
    189             showDisableDialog(builder);
    190         }
    191     }
    192 
    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 
    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 
    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
    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 {
    254         public DataStateListener() {
    255             super(new Handler(Looper.getMainLooper()));
    256         }
    257 
    258         /**
    259          * Set / Unset data state listening, specifying subId.
    260          */
    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 
    283         public CellDataState(Parcelable base) {
    284             super(base);
    285         }
    286 
    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
    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