Home | History | Annotate | Download | only in datausage
      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.v4.content.res.TypedArrayUtils;
     29 import android.support.v7.preference.PreferenceViewHolder;
     30 import android.telephony.SubscriptionInfo;
     31 import android.telephony.SubscriptionManager;
     32 import android.telephony.TelephonyManager;
     33 import android.util.AttributeSet;
     34 import android.util.Log;
     35 import android.view.View;
     36 import android.widget.Checkable;
     37 
     38 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     39 import com.android.settings.R;
     40 import com.android.settings.Utils;
     41 import com.android.settings.overlay.FeatureFactory;
     42 import com.android.settingslib.CustomDialogPreference;
     43 
     44 import java.util.List;
     45 
     46 public class CellDataPreference extends CustomDialogPreference implements TemplatePreference {
     47 
     48     private static final String TAG = "CellDataPreference";
     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 CellDataPreference(Context context, AttributeSet attrs) {
     57         super(context, attrs, TypedArrayUtils.getAttr(context,
     58                 android.support.v7.preference.R.attr.switchPreferenceStyle,
     59                 android.R.attr.switchPreferenceStyle));
     60     }
     61 
     62     @Override
     63     protected void onRestoreInstanceState(Parcelable s) {
     64         CellDataState state = (CellDataState) s;
     65         super.onRestoreInstanceState(state.getSuperState());
     66         mTelephonyManager = TelephonyManager.from(getContext());
     67         mChecked = state.mChecked;
     68         mMultiSimDialog = state.mMultiSimDialog;
     69         if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
     70             mSubId = state.mSubId;
     71             setKey(getKey() + mSubId);
     72         }
     73         notifyChanged();
     74     }
     75 
     76     @Override
     77     protected Parcelable onSaveInstanceState() {
     78         CellDataState state = new CellDataState(super.onSaveInstanceState());
     79         state.mChecked = mChecked;
     80         state.mMultiSimDialog = mMultiSimDialog;
     81         state.mSubId = mSubId;
     82         return state;
     83     }
     84 
     85     @Override
     86     public void onAttached() {
     87         super.onAttached();
     88         mListener.setListener(true, mSubId, getContext());
     89     }
     90 
     91     @Override
     92     public void onDetached() {
     93         mListener.setListener(false, mSubId, getContext());
     94         super.onDetached();
     95     }
     96 
     97     @Override
     98     public void setTemplate(NetworkTemplate template, int subId, NetworkServices services) {
     99         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
    100             throw new IllegalArgumentException("CellDataPreference needs a SubscriptionInfo");
    101         }
    102         mSubscriptionManager = SubscriptionManager.from(getContext());
    103         mTelephonyManager = TelephonyManager.from(getContext());
    104         if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
    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     protected void performClick(View view) {
    117         final Context context = getContext();
    118         FeatureFactory.getFactory(context).getMetricsFeatureProvider()
    119                 .action(context, MetricsEvent.ACTION_CELL_DATA_TOGGLE, !mChecked);
    120         final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(
    121                 mSubId);
    122         final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
    123         if (mChecked) {
    124             // If the device is single SIM or is enabling data on the active data SIM then forgo
    125             // the pop-up.
    126             if (!Utils.showSimCardTile(getContext()) ||
    127                     (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(view);
    140         } else {
    141             // If we are showing the Sim Card tile then we are a Multi-Sim device.
    142             if (Utils.showSimCardTile(getContext())) {
    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(view);
    151             } else {
    152                 setMobileDataEnabled(true);
    153             }
    154         }
    155     }
    156 
    157     private void setMobileDataEnabled(boolean enabled) {
    158         if (DataUsageSummary.LOGD) Log.d(TAG, "setMobileDataEnabled(" + enabled + ","
    159                 + mSubId + ")");
    160         mTelephonyManager.setDataEnabled(mSubId, enabled);
    161         setChecked(enabled);
    162     }
    163 
    164     private void setChecked(boolean checked) {
    165         if (mChecked == checked) return;
    166         mChecked = checked;
    167         notifyChanged();
    168     }
    169 
    170     @Override
    171     public void onBindViewHolder(PreferenceViewHolder holder) {
    172         super.onBindViewHolder(holder);
    173         View switchView = holder.findViewById(android.R.id.switch_widget);
    174         switchView.setClickable(false);
    175         ((Checkable) switchView).setChecked(mChecked);
    176     }
    177 
    178     @Override
    179     protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
    180             DialogInterface.OnClickListener listener) {
    181         if (mMultiSimDialog) {
    182             showMultiSimDialog(builder, listener);
    183         } else {
    184             showDisableDialog(builder, listener);
    185         }
    186     }
    187 
    188     private void showDisableDialog(AlertDialog.Builder builder,
    189             DialogInterface.OnClickListener listener) {
    190         builder.setTitle(null)
    191                 .setMessage(R.string.data_usage_disable_mobile)
    192                 .setPositiveButton(android.R.string.ok, listener)
    193                 .setNegativeButton(android.R.string.cancel, null);
    194     }
    195 
    196     private void showMultiSimDialog(AlertDialog.Builder builder,
    197             DialogInterface.OnClickListener listener) {
    198         final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
    199         final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
    200 
    201         final String previousName = (nextSir == null)
    202             ? getContext().getResources().getString(R.string.sim_selection_required_pref)
    203             : nextSir.getDisplayName().toString();
    204 
    205         builder.setTitle(R.string.sim_change_data_title);
    206         builder.setMessage(getContext().getString(R.string.sim_change_data_message,
    207                 String.valueOf(currentSir != null ? currentSir.getDisplayName() : null),
    208                 previousName));
    209 
    210         builder.setPositiveButton(R.string.okay, listener);
    211         builder.setNegativeButton(R.string.cancel, null);
    212     }
    213 
    214     private void disableDataForOtherSubscriptions(int subId) {
    215         List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
    216         if (subInfoList != null) {
    217             for (SubscriptionInfo subInfo : subInfoList) {
    218                 if (subInfo.getSubscriptionId() != subId) {
    219                     mTelephonyManager.setDataEnabled(subInfo.getSubscriptionId(), false);
    220                 }
    221             }
    222         }
    223     }
    224 
    225     @Override
    226     protected void onClick(DialogInterface dialog, int which) {
    227         if (which != DialogInterface.BUTTON_POSITIVE) {
    228             return;
    229         }
    230         if (mMultiSimDialog) {
    231             mSubscriptionManager.setDefaultDataSubId(mSubId);
    232             setMobileDataEnabled(true);
    233             disableDataForOtherSubscriptions(mSubId);
    234         } else {
    235             // TODO: extend to modify policy enabled flag.
    236             setMobileDataEnabled(false);
    237         }
    238     }
    239 
    240     private final DataStateListener mListener = new DataStateListener() {
    241         @Override
    242         public void onChange(boolean selfChange) {
    243             updateChecked();
    244         }
    245     };
    246 
    247     public abstract static class DataStateListener extends ContentObserver {
    248         public DataStateListener() {
    249             super(new Handler(Looper.getMainLooper()));
    250         }
    251 
    252         public void setListener(boolean listening, int subId, Context context) {
    253             if (listening) {
    254                 Uri uri = Global.getUriFor(Global.MOBILE_DATA);
    255                 if (TelephonyManager.getDefault().getSimCount() != 1) {
    256                     uri = Global.getUriFor(Global.MOBILE_DATA + subId);
    257                 }
    258                 context.getContentResolver().registerContentObserver(uri, false, this);
    259             } else {
    260                 context.getContentResolver().unregisterContentObserver(this);
    261             }
    262         }
    263     }
    264 
    265     public static class CellDataState extends BaseSavedState {
    266         public int mSubId;
    267         public boolean mChecked;
    268         public boolean mMultiSimDialog;
    269 
    270         public CellDataState(Parcelable base) {
    271             super(base);
    272         }
    273 
    274         public CellDataState(Parcel source) {
    275             super(source);
    276             mChecked = source.readByte() != 0;
    277             mMultiSimDialog = source.readByte() != 0;
    278             mSubId = source.readInt();
    279         }
    280 
    281         @Override
    282         public void writeToParcel(Parcel dest, int flags) {
    283             super.writeToParcel(dest, flags);
    284             dest.writeByte((byte) (mChecked ? 1 : 0));
    285             dest.writeByte((byte) (mMultiSimDialog ? 1 : 0));
    286             dest.writeInt(mSubId);
    287         }
    288 
    289         public static final Creator<CellDataState> CREATOR = new Creator<CellDataState>() {
    290             @Override
    291             public CellDataState createFromParcel(Parcel source) {
    292                 return new CellDataState(source);
    293             }
    294 
    295             @Override
    296             public CellDataState[] newArray(int size) {
    297                 return new CellDataState[size];
    298             }
    299         };
    300     }
    301 }
    302