Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2018 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 static com.android.phone.TimeConsumingPreferenceActivity.RESPONSE_ERROR;
     20 
     21 import android.app.AlertDialog;
     22 import android.content.Context;
     23 import android.content.DialogInterface;
     24 import android.content.res.TypedArray;
     25 import android.os.AsyncResult;
     26 import android.os.Bundle;
     27 import android.os.Handler;
     28 import android.os.Message;
     29 import android.telephony.ServiceState;
     30 import android.text.method.DigitsKeyListener;
     31 import android.text.method.PasswordTransformationMethod;
     32 import android.util.AttributeSet;
     33 import android.util.Log;
     34 import android.view.View;
     35 import android.widget.EditText;
     36 import android.widget.TextView;
     37 import android.widget.Toast;
     38 
     39 import com.android.internal.telephony.CommandException;
     40 import com.android.internal.telephony.Phone;
     41 import com.android.internal.telephony.PhoneFactory;
     42 import com.android.internal.telephony.imsphone.ImsPhone;
     43 import com.android.phone.settings.fdn.EditPinPreference;
     44 
     45 import java.lang.ref.WeakReference;
     46 
     47 /**
     48  * This preference represents the status of call barring options, enabling/disabling
     49  * the call barring option will prompt the user for the current password.
     50  */
     51 public class CallBarringEditPreference extends EditPinPreference {
     52     private static final String LOG_TAG = "CallBarringEditPreference";
     53     private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
     54 
     55     private String mFacility;
     56     boolean mIsActivated = false;
     57     private CharSequence mEnableText;
     58     private CharSequence mDisableText;
     59     private CharSequence mSummaryOn;
     60     private CharSequence mSummaryOff;
     61     private CharSequence mDialogMessageEnabled;
     62     private CharSequence mDialogMessageDisabled;
     63     private int mButtonClicked;
     64     private boolean mShowPassword;
     65     private final MyHandler mHandler = new MyHandler(this);
     66     private Phone mPhone;
     67     private TimeConsumingPreferenceListener mTcpListener;
     68 
     69     private static final int PW_LENGTH = 4;
     70 
     71     /**
     72      * CallBarringEditPreference constructor.
     73      *
     74      * @param context The context of view.
     75      * @param attrs The attributes of the XML tag that is inflating EditTextPreference.
     76      */
     77     public CallBarringEditPreference(Context context, AttributeSet attrs) {
     78         super(context, attrs);
     79         // Get the summary settings, use CheckBoxPreference as the standard.
     80         TypedArray typedArray = context.obtainStyledAttributes(attrs,
     81                 android.R.styleable.CheckBoxPreference, 0, 0);
     82         mSummaryOn = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOn);
     83         mSummaryOff = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOff);
     84         mDisableText = context.getText(R.string.disable);
     85         mEnableText = context.getText(R.string.enable);
     86         typedArray.recycle();
     87 
     88         // Get default phone
     89         mPhone = PhoneFactory.getDefaultPhone();
     90 
     91         typedArray = context.obtainStyledAttributes(attrs,
     92                 R.styleable.CallBarringEditPreference, 0, R.style.EditPhoneNumberPreference);
     93         mFacility = typedArray.getString(R.styleable.CallBarringEditPreference_facility);
     94         mDialogMessageEnabled = typedArray.getString(
     95                 R.styleable.CallBarringEditPreference_dialogMessageEnabledNoPwd);
     96         mDialogMessageDisabled = typedArray.getString(
     97                 R.styleable.CallBarringEditPreference_dialogMessageDisabledNoPwd);
     98         typedArray.recycle();
     99     }
    100 
    101     /**
    102      * CallBarringEditPreference constructor.
    103      *
    104      * @param context The context of view.
    105      */
    106     public CallBarringEditPreference(Context context) {
    107         this(context, null);
    108     }
    109 
    110     void init(TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) {
    111         if (DBG) {
    112             Log.d(LOG_TAG, "init: phone id = " + phone.getPhoneId());
    113         }
    114         mPhone = phone;
    115 
    116         mTcpListener = listener;
    117         if (!skipReading) {
    118             // Query call barring status
    119             mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage(
    120                     MyHandler.MESSAGE_GET_CALL_BARRING), 0);
    121             if (mTcpListener != null) {
    122                 mTcpListener.onStarted(this, true);
    123             }
    124         }
    125     }
    126 
    127     @Override
    128     public void onClick(DialogInterface dialog, int which) {
    129         super.onClick(dialog, which);
    130         mButtonClicked = which;
    131     }
    132 
    133     @Override
    134     protected boolean needInputMethod() {
    135         // Input method should only be displayed if the password-field is shown.
    136         return mShowPassword;
    137     }
    138 
    139     void setInputMethodNeeded(boolean needed) {
    140         mShowPassword = needed;
    141     }
    142 
    143     @Override
    144     protected void showDialog(Bundle state) {
    145         setShowPassword();
    146         if (mShowPassword) {
    147             setDialogMessage(getContext().getString(R.string.messageCallBarring));
    148         } else {
    149             setDialogMessage(mIsActivated ? mDialogMessageEnabled : mDialogMessageDisabled);
    150         }
    151 
    152         if (DBG) {
    153             Log.d(LOG_TAG, "showDialog: mShowPassword: " + mShowPassword
    154                     + ", mIsActivated: " + mIsActivated);
    155         }
    156 
    157         super.showDialog(state);
    158     }
    159 
    160     @Override
    161     protected void onBindView(View view) {
    162         super.onBindView(view);
    163 
    164         // Sync the summary view
    165         TextView summaryView = (TextView) view.findViewById(android.R.id.summary);
    166         if (summaryView != null) {
    167             CharSequence sum;
    168             int vis;
    169 
    170             // Set summary depending upon mode
    171             if (mIsActivated) {
    172                 sum = (mSummaryOn == null) ? getSummary() : mSummaryOn;
    173             } else {
    174                 sum = (mSummaryOff == null) ? getSummary() : mSummaryOff;
    175             }
    176 
    177             if (sum != null) {
    178                 summaryView.setText(sum);
    179                 vis = View.VISIBLE;
    180             } else {
    181                 vis = View.GONE;
    182             }
    183 
    184             if (vis != summaryView.getVisibility()) {
    185                 summaryView.setVisibility(vis);
    186             }
    187         }
    188     }
    189 
    190     @Override
    191     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
    192         builder.setPositiveButton(null, null);
    193         builder.setNeutralButton(mIsActivated ? mDisableText : mEnableText, this);
    194     }
    195 
    196     @Override
    197     protected void onBindDialogView(View view) {
    198         super.onBindDialogView(view);
    199         // Default the button clicked to be the cancel button.
    200         mButtonClicked = DialogInterface.BUTTON_NEGATIVE;
    201 
    202         final EditText editText = (EditText) view.findViewById(android.R.id.edit);
    203         if (editText != null) {
    204             editText.setSingleLine(true);
    205             editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
    206             editText.setKeyListener(DigitsKeyListener.getInstance());
    207 
    208             // Hide the input-text-line if the password is not shown.
    209             editText.setVisibility(mShowPassword ? View.VISIBLE : View.GONE);
    210         }
    211     }
    212 
    213     @Override
    214     protected void onDialogClosed(boolean positiveResult) {
    215         super.onDialogClosed(positiveResult);
    216         if (DBG) {
    217             Log.d(LOG_TAG, "onDialogClosed: mButtonClicked=" + mButtonClicked + ", positiveResult="
    218                     + positiveResult);
    219         }
    220         if (mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
    221             String password = null;
    222             if (mShowPassword) {
    223                 password = getEditText().getText().toString();
    224 
    225                 // Check if the password is valid.
    226                 if (password == null || password.length() != PW_LENGTH) {
    227                     Toast.makeText(getContext(),
    228                             getContext().getString(R.string.call_barring_right_pwd_number),
    229                             Toast.LENGTH_SHORT).show();
    230                     return;
    231                 }
    232             }
    233 
    234             if (DBG) {
    235                 Log.d(LOG_TAG, "onDialogClosed: password=" + password);
    236             }
    237             // Send set call barring message to RIL layer.
    238             mPhone.setCallBarring(mFacility, !mIsActivated, password,
    239                     mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 0);
    240             if (mTcpListener != null) {
    241                 mTcpListener.onStarted(this, false);
    242             }
    243         }
    244     }
    245 
    246     void handleCallBarringResult(boolean status) {
    247         mIsActivated = status;
    248         if (DBG) {
    249             Log.d(LOG_TAG, "handleCallBarringResult: mIsActivated=" + mIsActivated);
    250         }
    251     }
    252 
    253     void updateSummaryText() {
    254         notifyChanged();
    255         notifyDependencyChange(shouldDisableDependents());
    256     }
    257 
    258     private void setShowPassword() {
    259         ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
    260         mShowPassword = !(imsPhone != null
    261                 && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
    262                         || imsPhone.isUtEnabled()));
    263     }
    264 
    265     @Override
    266     public boolean shouldDisableDependents() {
    267         return mIsActivated;
    268     }
    269 
    270     // Message protocol:
    271     // what: get vs. set
    272     // arg1: action -- register vs. disable
    273     // arg2: get vs. set for the preceding request
    274     private static class MyHandler extends Handler {
    275         private static final int MESSAGE_GET_CALL_BARRING = 0;
    276         private static final int MESSAGE_SET_CALL_BARRING = 1;
    277 
    278         private final WeakReference<CallBarringEditPreference> mCallBarringEditPreference;
    279 
    280         private MyHandler(CallBarringEditPreference callBarringEditPreference) {
    281             mCallBarringEditPreference =
    282                     new WeakReference<CallBarringEditPreference>(callBarringEditPreference);
    283         }
    284 
    285         @Override
    286         public void handleMessage(Message msg) {
    287             switch (msg.what) {
    288                 case MESSAGE_GET_CALL_BARRING:
    289                     handleGetCallBarringResponse(msg);
    290                     break;
    291                 case MESSAGE_SET_CALL_BARRING:
    292                     handleSetCallBarringResponse(msg);
    293                     break;
    294                 default:
    295                     break;
    296             }
    297         }
    298 
    299         // Handle the response message for query CB status.
    300         private void handleGetCallBarringResponse(Message msg) {
    301             final CallBarringEditPreference pref = mCallBarringEditPreference.get();
    302             if (pref == null) {
    303                 return;
    304             }
    305 
    306             if (DBG) {
    307                 Log.d(LOG_TAG, "handleGetCallBarringResponse: done");
    308             }
    309 
    310             AsyncResult ar = (AsyncResult) msg.obj;
    311 
    312             if (msg.arg2 == MESSAGE_SET_CALL_BARRING) {
    313                 pref.mTcpListener.onFinished(pref, false);
    314             } else {
    315                 pref.mTcpListener.onFinished(pref, true);
    316                 ImsPhone imsPhone = pref.mPhone != null
    317                         ? (ImsPhone) pref.mPhone.getImsPhone() : null;
    318                 if (!pref.mShowPassword && (imsPhone == null || !imsPhone.isUtEnabled())) {
    319                     // Re-enable password when rejected from NW and modem would perform CSFB
    320                     pref.mShowPassword = true;
    321                     if (DBG) {
    322                         Log.d(LOG_TAG,
    323                                 "handleGetCallBarringResponse: mShowPassword changed for CSFB");
    324                     }
    325                 }
    326             }
    327 
    328             // Unsuccessful query for call barring.
    329             if (ar.exception != null) {
    330                 if (DBG) {
    331                     Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.exception=" + ar.exception);
    332                 }
    333                 pref.mTcpListener.onException(pref, (CommandException) ar.exception);
    334             } else {
    335                 if (ar.userObj instanceof Throwable) {
    336                     pref.mTcpListener.onError(pref, RESPONSE_ERROR);
    337                 }
    338                 int[] ints = (int[]) ar.result;
    339                 if (ints.length == 0) {
    340                     if (DBG) {
    341                         Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.result.length==0");
    342                     }
    343                     pref.setEnabled(false);
    344                     pref.mTcpListener.onError(pref, RESPONSE_ERROR);
    345                 } else {
    346                     pref.handleCallBarringResult(ints[0] != 0);
    347                     if (DBG) {
    348                         Log.d(LOG_TAG,
    349                                 "handleGetCallBarringResponse: CB state successfully queried: "
    350                                         + ints[0]);
    351                     }
    352                 }
    353             }
    354             // Update call barring status.
    355             pref.updateSummaryText();
    356         }
    357 
    358         // Handle the response message for CB settings.
    359         private void handleSetCallBarringResponse(Message msg) {
    360             final CallBarringEditPreference pref = mCallBarringEditPreference.get();
    361             if (pref == null) {
    362                 return;
    363             }
    364 
    365             AsyncResult ar = (AsyncResult) msg.obj;
    366 
    367             if (ar.exception != null || ar.userObj instanceof Throwable) {
    368                 if (DBG) {
    369                     Log.d(LOG_TAG, "handleSetCallBarringResponse: ar.exception=" + ar.exception);
    370                 }
    371             }
    372             if (DBG) {
    373                 Log.d(LOG_TAG, "handleSetCallBarringResponse: re-get call barring option");
    374             }
    375             pref.mPhone.getCallBarring(
    376                     pref.mFacility,
    377                     "",
    378                     obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING,
    379                             ar.exception),
    380                     0);
    381         }
    382     }
    383 }
    384