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