1 package com.android.phone; 2 3 import static com.android.phone.TimeConsumingPreferenceActivity.EXCEPTION_ERROR; 4 import static com.android.phone.TimeConsumingPreferenceActivity.FDN_CHECK_FAILURE; 5 import static com.android.phone.TimeConsumingPreferenceActivity.RESPONSE_ERROR; 6 7 import android.content.Context; 8 import android.os.Handler; 9 import android.os.Message; 10 import android.os.PersistableBundle; 11 import android.preference.SwitchPreference; 12 import android.telephony.CarrierConfigManager; 13 import android.telephony.TelephonyManager; 14 import android.util.AttributeSet; 15 import android.util.Log; 16 17 import com.android.internal.telephony.Phone; 18 19 import java.util.concurrent.Executors; 20 import java.util.concurrent.ScheduledExecutorService; 21 import java.util.concurrent.TimeUnit; 22 import java.util.function.Consumer; 23 24 public class CallWaitingSwitchPreference extends SwitchPreference { 25 private static final String LOG_TAG = "CallWaitingSwitchPreference"; 26 private static final int DELAY_MILLIS_FOR_USSD = 1000; 27 private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2); 28 29 private final MyHandler mHandler = new MyHandler(); 30 private Phone mPhone; 31 private TimeConsumingPreferenceListener mTcpListener; 32 private ScheduledExecutorService mExecutor; 33 private TelephonyManager mTelephonyManager; 34 private boolean mIsDuringUpdateProcess = false; 35 private int mUpdateStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR; 36 private int mQueryStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR; 37 private boolean mUssdMode = false; 38 CallWaitingSwitchPreference(Context context, AttributeSet attrs, int defStyle)39 public CallWaitingSwitchPreference(Context context, AttributeSet attrs, int defStyle) { 40 super(context, attrs, defStyle); 41 } 42 CallWaitingSwitchPreference(Context context, AttributeSet attrs)43 public CallWaitingSwitchPreference(Context context, AttributeSet attrs) { 44 this(context, attrs, com.android.internal.R.attr.switchPreferenceStyle); 45 } 46 CallWaitingSwitchPreference(Context context)47 public CallWaitingSwitchPreference(Context context) { 48 this(context, null); 49 } 50 init( TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone)51 /* package */ void init( 52 TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) { 53 mPhone = phone; 54 mTcpListener = listener; 55 mExecutor = Executors.newSingleThreadScheduledExecutor(); 56 mTelephonyManager = getContext().getSystemService( 57 TelephonyManager.class).createForSubscriptionId(phone.getSubId()); 58 CarrierConfigManager configManager = getContext().getSystemService( 59 CarrierConfigManager.class); 60 PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId()); 61 mUssdMode = (bundle != null) ? bundle.getBoolean( 62 CarrierConfigManager.KEY_USE_CALL_WAITING_USSD_BOOL, false) : false; 63 64 if (!skipReading) { 65 Log.d(LOG_TAG, "init getCallWaitingStatus"); 66 mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack); 67 if (mTcpListener != null) { 68 mTcpListener.onStarted(this, true); 69 } 70 } 71 } 72 queryStatusCallBack(int result)73 private void queryStatusCallBack(int result) { 74 Log.d(LOG_TAG, "queryStatusCallBack: CW state " + result); 75 mQueryStatus = result; 76 mHandler.sendMessage(mHandler.obtainMessage(MyHandler.MESSAGE_UPDATE_CALL_WAITING)); 77 } 78 updateStatusCallBack(int result)79 private void updateStatusCallBack(int result) { 80 Log.d(LOG_TAG, "updateStatusCallBack: CW state " + result + ", and re get"); 81 mUpdateStatus = result; 82 if (mUssdMode) { 83 Log.d(LOG_TAG, "updateStatusCallBack: USSD mode needs to wait 1s since Framework" 84 + " has the limitation"); 85 Consumer<Integer> resultListener = this::queryStatusCallBack; 86 try { 87 mExecutor.schedule(new Runnable() { 88 @Override 89 public void run() { 90 mTelephonyManager.getCallWaitingStatus(mExecutor, resultListener); 91 } 92 }, DELAY_MILLIS_FOR_USSD, TimeUnit.MILLISECONDS); 93 } catch (Exception e) { 94 Log.d(LOG_TAG, "Exception while waiting: " + e); 95 } 96 } else { 97 mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack); 98 } 99 } 100 101 @Override onClick()102 protected void onClick() { 103 super.onClick(); 104 mTelephonyManager.setCallWaitingEnabled(isChecked(), mExecutor, this::updateStatusCallBack); 105 if (mTcpListener != null) { 106 mIsDuringUpdateProcess = true; 107 mTcpListener.onStarted(this, false); 108 } 109 } 110 111 private class MyHandler extends Handler { 112 static final int MESSAGE_UPDATE_CALL_WAITING = 0; 113 114 @Override handleMessage(Message msg)115 public void handleMessage(Message msg) { 116 switch (msg.what) { 117 case MESSAGE_UPDATE_CALL_WAITING: 118 updateUi(); 119 break; 120 } 121 } 122 updateUi()123 private void updateUi() { 124 if (mTcpListener != null) { 125 if (mIsDuringUpdateProcess) { 126 mTcpListener.onFinished(CallWaitingSwitchPreference.this, false); 127 } else { 128 mTcpListener.onFinished(CallWaitingSwitchPreference.this, true); 129 } 130 } 131 132 if (mQueryStatus != TelephonyManager.CALL_WAITING_STATUS_ENABLED 133 && mQueryStatus != TelephonyManager.CALL_WAITING_STATUS_DISABLED 134 && mQueryStatus != TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR) { 135 Log.d(LOG_TAG, "handleGetCallWaitingResponse: Exception:" + mQueryStatus); 136 int error = EXCEPTION_ERROR; 137 switch (mQueryStatus) { 138 case TelephonyManager.CALL_WAITING_STATUS_FDN_CHECK_FAILURE: 139 error = FDN_CHECK_FAILURE; 140 break; 141 default: 142 error = EXCEPTION_ERROR; 143 break; 144 } 145 if (mTcpListener != null) { 146 mTcpListener.onError(CallWaitingSwitchPreference.this, error); 147 } 148 } else if (mQueryStatus == TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR 149 || (mIsDuringUpdateProcess && ( 150 mUpdateStatus != TelephonyManager.CALL_WAITING_STATUS_ENABLED 151 && mUpdateStatus != TelephonyManager.CALL_WAITING_STATUS_DISABLED))) { 152 Log.d(LOG_TAG, "handleSetCallWaitingResponse: Exception"); 153 if (mTcpListener != null) { 154 mTcpListener.onError(CallWaitingSwitchPreference.this, RESPONSE_ERROR); 155 } 156 } else { 157 if (mQueryStatus == TelephonyManager.CALL_WAITING_STATUS_ENABLED) { 158 setChecked(true); 159 } else { 160 setChecked(false); 161 } 162 } 163 mIsDuringUpdateProcess = false; 164 } 165 } 166 } 167