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