/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.phone; import static com.android.phone.TimeConsumingPreferenceActivity.RESPONSE_ERROR; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; import android.os.AsyncResult; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.text.method.DigitsKeyListener; import android.text.method.PasswordTransformationMethod; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.phone.settings.fdn.EditPinPreference; import java.lang.ref.WeakReference; /** * This preference represents the status of call barring options, enabling/disabling * the call barring option will prompt the user for the current password. */ public class CallBarringEditPreference extends EditPinPreference { private static final String LOG_TAG = "CallBarringEditPreference"; private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2); private String mFacility; boolean mIsActivated = false; private CharSequence mEnableText; private CharSequence mDisableText; private CharSequence mSummaryOn; private CharSequence mSummaryOff; private int mButtonClicked; private final MyHandler mHandler = new MyHandler(this); private Phone mPhone; private TimeConsumingPreferenceListener mTcpListener; private static final int PW_LENGTH = 4; /** * CallBarringEditPreference constructor. * * @param context The context of view. * @param attrs The attributes of the XML tag that is inflating EditTextPreference. */ public CallBarringEditPreference(Context context, AttributeSet attrs) { super(context, attrs); // Get the summary settings, use CheckBoxPreference as the standard. TypedArray typedArray = context.obtainStyledAttributes(attrs, android.R.styleable.CheckBoxPreference, 0, 0); mSummaryOn = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOn); mSummaryOff = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOff); mDisableText = context.getText(R.string.disable); mEnableText = context.getText(R.string.enable); typedArray.recycle(); // Get default phone mPhone = PhoneFactory.getDefaultPhone(); typedArray = context.obtainStyledAttributes(attrs, R.styleable.CallBarringEditPreference, 0, R.style.EditPhoneNumberPreference); mFacility = typedArray.getString(R.styleable.CallBarringEditPreference_facility); typedArray.recycle(); } /** * CallBarringEditPreference constructor. * * @param context The context of view. */ public CallBarringEditPreference(Context context) { this(context, null); } void init(TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) { if (DBG) { Log.d(LOG_TAG, "init: phone id = " + phone.getPhoneId()); } mPhone = phone; mTcpListener = listener; if (!skipReading) { // Query call barring status mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage( MyHandler.MESSAGE_GET_CALL_BARRING), getServiceClassForCallBarring(mPhone)); if (mTcpListener != null) { mTcpListener.onStarted(this, true); } } } @Override public void onClick(DialogInterface dialog, int which) { super.onClick(dialog, which); mButtonClicked = which; } @Override protected void showDialog(Bundle state) { setDialogMessage(getContext().getString(R.string.messageCallBarring)); super.showDialog(state); } @Override protected void onBindView(View view) { super.onBindView(view); // Sync the summary view TextView summaryView = (TextView) view.findViewById(android.R.id.summary); if (summaryView != null) { CharSequence sum; int vis; // Set summary depending upon mode if (mIsActivated) { sum = (mSummaryOn == null) ? getSummary() : mSummaryOn; } else { sum = (mSummaryOff == null) ? getSummary() : mSummaryOff; } if (sum != null) { summaryView.setText(sum); vis = View.VISIBLE; } else { vis = View.GONE; } if (vis != summaryView.getVisibility()) { summaryView.setVisibility(vis); } } } @Override protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { builder.setPositiveButton(null, null); builder.setNeutralButton(mIsActivated ? mDisableText : mEnableText, this); } @Override protected void onBindDialogView(View view) { super.onBindDialogView(view); // Default the button clicked to be the cancel button. mButtonClicked = DialogInterface.BUTTON_NEGATIVE; final EditText editText = (EditText) view.findViewById(android.R.id.edit); if (editText != null) { editText.setSingleLine(true); editText.setTransformationMethod(PasswordTransformationMethod.getInstance()); editText.setKeyListener(DigitsKeyListener.getInstance()); editText.setVisibility(View.VISIBLE); } } @Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); if (DBG) { Log.d(LOG_TAG, "onDialogClosed: mButtonClicked=" + mButtonClicked + ", positiveResult=" + positiveResult); } if (mButtonClicked != DialogInterface.BUTTON_NEGATIVE) { String password = getEditText().getText().toString(); // Check if the password is valid. if (password == null || password.length() != PW_LENGTH) { Toast.makeText(getContext(), getContext().getString(R.string.call_barring_right_pwd_number), Toast.LENGTH_SHORT).show(); return; } if (DBG) { Log.d(LOG_TAG, "onDialogClosed: password=" + password); } // Send set call barring message to RIL layer. mPhone.setCallBarring(mFacility, !mIsActivated, password, mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), getServiceClassForCallBarring(mPhone)); if (mTcpListener != null) { mTcpListener.onStarted(this, false); } } } void handleCallBarringResult(boolean status) { mIsActivated = status; if (DBG) { Log.d(LOG_TAG, "handleCallBarringResult: mIsActivated=" + mIsActivated); } } private static int getServiceClassForCallBarring(Phone phone) { int serviceClass = CarrierConfigManager.SERVICE_CLASS_VOICE; PersistableBundle carrierConfig = PhoneGlobals.getInstance() .getCarrierConfigForSubId(phone.getSubId()); if (carrierConfig != null) { serviceClass = carrierConfig.getInt( CarrierConfigManager.KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT, CarrierConfigManager.SERVICE_CLASS_VOICE); } return serviceClass; } void updateSummaryText() { notifyChanged(); notifyDependencyChange(shouldDisableDependents()); } @Override public boolean shouldDisableDependents() { return mIsActivated; } // Message protocol: // what: get vs. set // arg1: action -- register vs. disable // arg2: get vs. set for the preceding request private static class MyHandler extends Handler { private static final int MESSAGE_GET_CALL_BARRING = 0; private static final int MESSAGE_SET_CALL_BARRING = 1; private final WeakReference mCallBarringEditPreference; private MyHandler(CallBarringEditPreference callBarringEditPreference) { mCallBarringEditPreference = new WeakReference(callBarringEditPreference); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_GET_CALL_BARRING: handleGetCallBarringResponse(msg); break; case MESSAGE_SET_CALL_BARRING: handleSetCallBarringResponse(msg); break; default: break; } } // Handle the response message for query CB status. private void handleGetCallBarringResponse(Message msg) { final CallBarringEditPreference pref = mCallBarringEditPreference.get(); if (pref == null) { return; } if (DBG) { Log.d(LOG_TAG, "handleGetCallBarringResponse: done"); } AsyncResult ar = (AsyncResult) msg.obj; if (msg.arg2 == MESSAGE_SET_CALL_BARRING) { pref.mTcpListener.onFinished(pref, false); } else { pref.mTcpListener.onFinished(pref, true); } // Unsuccessful query for call barring. if (ar.exception != null) { if (DBG) { Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.exception=" + ar.exception); } pref.mTcpListener.onException(pref, (CommandException) ar.exception); } else { if (ar.userObj instanceof Throwable) { pref.mTcpListener.onError(pref, RESPONSE_ERROR); } int[] ints = (int[]) ar.result; if (ints.length == 0) { if (DBG) { Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.result.length==0"); } pref.setEnabled(false); pref.mTcpListener.onError(pref, RESPONSE_ERROR); } else { pref.handleCallBarringResult(ints[0] != 0); if (DBG) { Log.d(LOG_TAG, "handleGetCallBarringResponse: CB state successfully queried: " + ints[0]); } } } // Update call barring status. pref.updateSummaryText(); } // Handle the response message for CB settings. private void handleSetCallBarringResponse(Message msg) { final CallBarringEditPreference pref = mCallBarringEditPreference.get(); if (pref == null) { return; } AsyncResult ar = (AsyncResult) msg.obj; if (ar.exception != null || ar.userObj instanceof Throwable) { if (DBG) { Log.d(LOG_TAG, "handleSetCallBarringResponse: ar.exception=" + ar.exception); } } if (DBG) { Log.d(LOG_TAG, "handleSetCallBarringResponse: re-get call barring option"); } pref.mPhone.getCallBarring( pref.mFacility, "", obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING, ar.exception), getServiceClassForCallBarring(pref.mPhone)); } } }