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