• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     private boolean mCwEnabled = false;
39     private boolean mCwClicked = false;
40 
CallWaitingSwitchPreference(Context context, AttributeSet attrs, int defStyle)41     public CallWaitingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
42         super(context, attrs, defStyle);
43     }
44 
CallWaitingSwitchPreference(Context context, AttributeSet attrs)45     public CallWaitingSwitchPreference(Context context, AttributeSet attrs) {
46         this(context, attrs, com.android.internal.R.attr.switchPreferenceStyle);
47     }
48 
CallWaitingSwitchPreference(Context context)49     public CallWaitingSwitchPreference(Context context) {
50         this(context, null);
51     }
52 
init( TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone)53     /* package */ void init(
54             TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) {
55         mPhone = phone;
56         mTcpListener = listener;
57         mExecutor = Executors.newSingleThreadScheduledExecutor();
58         mTelephonyManager = getContext().getSystemService(
59                 TelephonyManager.class).createForSubscriptionId(phone.getSubId());
60         CarrierConfigManager configManager = getContext().getSystemService(
61                 CarrierConfigManager.class);
62         PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId());
63         mUssdMode = (bundle != null) ? bundle.getBoolean(
64                 CarrierConfigManager.KEY_USE_CALL_WAITING_USSD_BOOL, false) : false;
65         mCwEnabled = false;
66 
67         if (!skipReading) {
68             Log.d(LOG_TAG, "init getCallWaitingStatus");
69             mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack);
70             if (mTcpListener != null) {
71                 mTcpListener.onStarted(this, true);
72             }
73         }
74     }
75 
queryStatusCallBack(int result)76     private void queryStatusCallBack(int result) {
77         Log.d(LOG_TAG, "queryStatusCallBack: CW state " + result);
78         mQueryStatus = result;
79         mHandler.sendMessage(mHandler.obtainMessage(MyHandler.MESSAGE_UPDATE_CALL_WAITING));
80     }
81 
updateStatusCallBack(int result)82     private void updateStatusCallBack(int result) {
83         Log.d(LOG_TAG, "updateStatusCallBack: CW state " + result + ", and re get");
84         mUpdateStatus = result;
85         if (mUssdMode) {
86             Log.d(LOG_TAG, "updateStatusCallBack: USSD mode needs to wait 1s since Framework"
87                     + " has the limitation");
88             Consumer<Integer> resultListener = this::queryStatusCallBack;
89             try {
90                 mExecutor.schedule(new Runnable() {
91                     @Override
92                     public void run() {
93                         mTelephonyManager.getCallWaitingStatus(mExecutor, resultListener);
94                     }
95                 }, DELAY_MILLIS_FOR_USSD, TimeUnit.MILLISECONDS);
96             } catch (Exception e) {
97                 Log.d(LOG_TAG, "Exception while waiting: " + e);
98             }
99         } else {
100             mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack);
101         }
102     }
103 
104     @Override
onClick()105     protected void onClick() {
106         super.onClick();
107         mCwEnabled = isChecked();
108         mCwClicked = true;
109         mTelephonyManager.setCallWaitingEnabled(mCwEnabled, mExecutor, this::updateStatusCallBack);
110         if (mTcpListener != null) {
111             mIsDuringUpdateProcess = true;
112             mTcpListener.onStarted(this, false);
113         }
114     }
115 
116     private class MyHandler extends Handler {
117         static final int MESSAGE_UPDATE_CALL_WAITING = 0;
118 
119         @Override
handleMessage(Message msg)120         public void handleMessage(Message msg) {
121             switch (msg.what) {
122                 case MESSAGE_UPDATE_CALL_WAITING:
123                     updateUi();
124                     break;
125             }
126         }
127 
updateUi()128         private void updateUi() {
129             if (mTcpListener != null) {
130                 if (mIsDuringUpdateProcess) {
131                     mTcpListener.onFinished(CallWaitingSwitchPreference.this, false);
132                 } else {
133                     mTcpListener.onFinished(CallWaitingSwitchPreference.this, true);
134                 }
135             }
136 
137             if (mQueryStatus != TelephonyManager.CALL_WAITING_STATUS_ENABLED
138                     && mQueryStatus != TelephonyManager.CALL_WAITING_STATUS_DISABLED
139                     && mQueryStatus != TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR) {
140                 Log.d(LOG_TAG, "handleGetCallWaitingResponse: Exception:" + mQueryStatus);
141                 int error = EXCEPTION_ERROR;
142                 switch (mQueryStatus) {
143                     case TelephonyManager.CALL_WAITING_STATUS_FDN_CHECK_FAILURE:
144                         error = FDN_CHECK_FAILURE;
145                         break;
146                     default:
147                         error = EXCEPTION_ERROR;
148                         break;
149                 }
150                 if (mTcpListener != null) {
151                     mTcpListener.onError(CallWaitingSwitchPreference.this, error);
152                 }
153                 handleCwFallbackOnError();
154                 setChecked(mCwEnabled);
155             } else if (mQueryStatus == TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR
156                     || (mIsDuringUpdateProcess && (
157                     mUpdateStatus != TelephonyManager.CALL_WAITING_STATUS_ENABLED
158                             && mUpdateStatus != TelephonyManager.CALL_WAITING_STATUS_DISABLED))) {
159                 Log.d(LOG_TAG, "handleSetCallWaitingResponse: Exception");
160                 if (mTcpListener != null) {
161                     mTcpListener.onError(CallWaitingSwitchPreference.this, RESPONSE_ERROR);
162                 }
163                 handleCwFallbackOnError();
164                 setChecked(mCwEnabled);
165             } else {
166                 mCwEnabled = mQueryStatus == TelephonyManager.CALL_WAITING_STATUS_ENABLED;
167                 setChecked(mCwEnabled);
168             }
169             mIsDuringUpdateProcess = false;
170             mCwClicked = false;
171         }
172     }
173 
handleCwFallbackOnError()174     private void handleCwFallbackOnError() {
175         // Recover initial state before onClick.
176         if (mCwClicked) {
177             mCwEnabled = !mCwEnabled;
178         }
179     }
180 }
181