1 /*
2  * Copyright (c) 2013 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.ims;
18 
19 import android.content.res.Resources;
20 import android.os.AsyncResult;
21 import android.os.Bundle;
22 import android.os.Handler;
23 import android.os.Message;
24 import android.os.Registrant;
25 import android.os.RemoteException;
26 import android.telephony.ims.ImsCallForwardInfo;
27 import android.telephony.ims.ImsReasonInfo;
28 import android.telephony.ims.ImsSsData;
29 import android.telephony.ims.ImsSsInfo;
30 import android.telephony.ims.ImsUtListener;
31 
32 import com.android.ims.internal.IImsUt;
33 import com.android.ims.internal.IImsUtListener;
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.telephony.Rlog;
36 import com.android.internal.telephony.util.TelephonyUtils;
37 
38 import java.util.HashMap;
39 import java.util.Map;
40 import java.util.concurrent.Executor;
41 
42 /**
43  * Provides APIs for the supplementary service settings using IMS (Ut interface).
44  * It is created from 3GPP TS 24.623 (XCAP(XML Configuration Access Protocol)
45  * over the Ut interface for manipulating supplementary services).
46  *
47  * @hide
48  */
49 public class ImsUt implements ImsUtInterface {
50     /**
51      * Key string for an additional supplementary service configurations.
52      */
53     /**
54      * Actions : string format of ImsUtInterface#ACTION_xxx
55      *      "0" (deactivation), "1" (activation), "2" (not_used),
56      *      "3" (registration), "4" (erasure), "5" (Interrogation)
57      */
58     public static final String KEY_ACTION = "action";
59     /**
60      * Categories :
61      *      "OIP", "OIR", "TIP", "TIR", "CDIV", "CB", "CW", "CONF",
62      *      "ACR", "MCID", "ECT", "CCBS", "AOC", "MWI", "FA", "CAT"
63      *
64      * Detailed parameter name will be determined according to the properties
65      * of the supplementary service configuration.
66      */
67     public static final String KEY_CATEGORY = "category";
68     public static final String CATEGORY_OIP = "OIP";
69     public static final String CATEGORY_OIR = "OIR";
70     public static final String CATEGORY_TIP = "TIP";
71     public static final String CATEGORY_TIR = "TIR";
72     public static final String CATEGORY_CDIV = "CDIV";
73     public static final String CATEGORY_CB = "CB";
74     public static final String CATEGORY_CW = "CW";
75     public static final String CATEGORY_CONF = "CONF";
76 
77     private static final String TAG = "ImsUt";
78     private static final boolean DBG = true;
79 
80     //These service class values are same as the one in CommandsInterface.java
81     private static final int SERVICE_CLASS_NONE = 0;
82     private static final int SERVICE_CLASS_VOICE = (1 << 0);
83 
84     // For synchronization of private variables
85     private Object mLockObj = new Object();
86     private final IImsUt miUt;
87     private HashMap<Integer, Message> mPendingCmds =
88             new HashMap<Integer, Message>();
89     private Registrant mSsIndicationRegistrant;
90     private Executor mExecutor = Runnable::run;
91 
ImsUt(IImsUt iUt, Executor executor)92     public ImsUt(IImsUt iUt, Executor executor) {
93         miUt = iUt;
94         if (executor != null) {
95             mExecutor = executor;
96         }
97 
98         if (miUt != null) {
99             try {
100                 miUt.setListener(new IImsUtListenerProxy());
101             } catch (RemoteException e) {
102             }
103         }
104     }
105 
close()106     public void close() {
107         synchronized(mLockObj) {
108             if (miUt != null) {
109                 try {
110                     miUt.close();
111                 } catch (RemoteException e) {
112                 }
113             }
114 
115             if (!mPendingCmds.isEmpty()) {
116                 Map.Entry<Integer, Message>[] entries =
117                     mPendingCmds.entrySet().toArray(new Map.Entry[mPendingCmds.size()]);
118 
119                 for (Map.Entry<Integer, Message> entry : entries) {
120                     sendFailureReport(entry.getValue(),
121                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
122                 }
123 
124                 mPendingCmds.clear();
125             }
126         }
127     }
128 
129     /**
130      * Registers a handler for Supplementary Service Indications. The
131      * result is returned in the {@link AsyncResult#result) field
132      * of the {@link AsyncResult} object returned by {@link Message.obj}.
133      * Value of ((AsyncResult)result.obj) is of {@link ImsSsData}.
134      */
registerForSuppServiceIndication(Handler h, int what, Object obj)135     public void registerForSuppServiceIndication(Handler h, int what, Object obj) {
136         mSsIndicationRegistrant = new Registrant (h, what, obj);
137     }
138 
139     /**
140      * UnRegisters a handler for Supplementary Service Indications.
141      */
unregisterForSuppServiceIndication(Handler h)142     public void unregisterForSuppServiceIndication(Handler h) {
143         mSsIndicationRegistrant.clear();
144     }
145 
146     /**
147      * Operations for the supplementary service configuration
148      */
149 
150     /**
151      * Retrieves the configuration of the call barring.
152      *
153      * @param cbType type of call barring to be queried; ImsUtInterface#CB_XXX
154      * @param result message to pass the result of this operation
155      *      The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
156      * @deprecated Use {@link #queryCallBarring(int, Message, int)} instead.
157      */
158     @Override
queryCallBarring(int cbType, Message result)159     public void queryCallBarring(int cbType, Message result) {
160         queryCallBarring(cbType, result, SERVICE_CLASS_NONE);
161     }
162 
163     /**
164      * Retrieves the configuration of the call barring for specified service class.
165      *
166      * @param cbType type of call barring to be queried; ImsUtInterface#CB_XXX
167      * @param result message to pass the result of this operation
168      *      The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
169      * @param serviceClass service class for e.g. voice/video
170      */
171     @Override
queryCallBarring(int cbType, Message result, int serviceClass)172     public void queryCallBarring(int cbType, Message result, int serviceClass) {
173         if (DBG) {
174             log("queryCallBarring :: Ut=" + miUt + ", cbType=" + cbType + ", serviceClass="
175                     + serviceClass);
176         }
177 
178         synchronized(mLockObj) {
179             try {
180                 int id = miUt.queryCallBarringForServiceClass(cbType, serviceClass);
181 
182                 if (id < 0) {
183                     sendFailureReport(result,
184                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
185                     return;
186                 }
187 
188                 mPendingCmds.put(Integer.valueOf(id), result);
189             } catch (RemoteException e) {
190                 sendFailureReport(result,
191                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
192             }
193         }
194     }
195 
196     /**
197      * Retrieves the configuration of the call forward.
198      * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
199      */
200     @Override
queryCallForward(int condition, String number, Message result)201     public void queryCallForward(int condition, String number, Message result) {
202         if (DBG) {
203             log("queryCallForward :: Ut=" + miUt + ", condition=" + condition
204                     + ", number=" + Rlog.pii(TAG, number));
205         }
206 
207         synchronized(mLockObj) {
208             try {
209                 int id = miUt.queryCallForward(condition, number);
210 
211                 if (id < 0) {
212                     sendFailureReport(result,
213                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
214                     return;
215                 }
216 
217                 mPendingCmds.put(Integer.valueOf(id), result);
218             } catch (RemoteException e) {
219                 sendFailureReport(result,
220                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
221             }
222         }
223     }
224 
225     /**
226      * Retrieves the configuration of the call waiting.
227      * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
228      */
229     @Override
queryCallWaiting(Message result)230     public void queryCallWaiting(Message result) {
231         if (DBG) {
232             log("queryCallWaiting :: Ut=" + miUt);
233         }
234 
235         synchronized(mLockObj) {
236             try {
237                 int id = miUt.queryCallWaiting();
238 
239                 if (id < 0) {
240                     sendFailureReport(result,
241                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
242                     return;
243                 }
244 
245                 mPendingCmds.put(Integer.valueOf(id), result);
246             } catch (RemoteException e) {
247                 sendFailureReport(result,
248                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
249             }
250         }
251     }
252 
253     /**
254      * Retrieves the default CLIR setting.
255      */
256     @Override
queryCLIR(Message result)257     public void queryCLIR(Message result) {
258         if (DBG) {
259             log("queryCLIR :: Ut=" + miUt);
260         }
261 
262         synchronized(mLockObj) {
263             try {
264                 int id = miUt.queryCLIR();
265 
266                 if (id < 0) {
267                     sendFailureReport(result,
268                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
269                     return;
270                 }
271 
272                 mPendingCmds.put(Integer.valueOf(id), result);
273             } catch (RemoteException e) {
274                 sendFailureReport(result,
275                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
276             }
277         }
278     }
279 
280     /**
281      * Retrieves the CLIP call setting.
282      */
queryCLIP(Message result)283     public void queryCLIP(Message result) {
284         if (DBG) {
285             log("queryCLIP :: Ut=" + miUt);
286         }
287 
288         synchronized(mLockObj) {
289             try {
290                 int id = miUt.queryCLIP();
291 
292                 if (id < 0) {
293                     sendFailureReport(result,
294                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
295                     return;
296                 }
297 
298                 mPendingCmds.put(Integer.valueOf(id), result);
299             } catch (RemoteException e) {
300                 sendFailureReport(result,
301                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
302             }
303         }
304     }
305 
306     /**
307      * Retrieves the COLR call setting.
308      */
queryCOLR(Message result)309     public void queryCOLR(Message result) {
310         if (DBG) {
311             log("queryCOLR :: Ut=" + miUt);
312         }
313 
314         synchronized(mLockObj) {
315             try {
316                 int id = miUt.queryCOLR();
317 
318                 if (id < 0) {
319                     sendFailureReport(result,
320                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
321                     return;
322                 }
323 
324                 mPendingCmds.put(Integer.valueOf(id), result);
325             } catch (RemoteException e) {
326                 sendFailureReport(result,
327                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
328             }
329         }
330     }
331 
332     /**
333      * Retrieves the COLP call setting.
334      */
queryCOLP(Message result)335     public void queryCOLP(Message result) {
336         if (DBG) {
337             log("queryCOLP :: Ut=" + miUt);
338         }
339 
340         synchronized(mLockObj) {
341             try {
342                 int id = miUt.queryCOLP();
343 
344                 if (id < 0) {
345                     sendFailureReport(result,
346                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
347                     return;
348                 }
349 
350                 mPendingCmds.put(Integer.valueOf(id), result);
351             } catch (RemoteException e) {
352                 sendFailureReport(result,
353                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
354             }
355         }
356     }
357 
358     /**
359      * Modifies the configuration of the call barring.
360      * @deprecated Use {@link #updateCallBarring(int, int, Message, String[], int)} instead.
361      */
362     @Override
updateCallBarring(int cbType, int action, Message result, String[] barrList)363     public void updateCallBarring(int cbType, int action, Message result, String[] barrList) {
364         updateCallBarring(cbType, action, result, barrList, SERVICE_CLASS_NONE);
365     }
366 
367     /**
368      * Modifies the configuration of the call barring for specified service class.
369      * @deprecated Use {@link #updateCallBarring(int, int, Message, String[], int, String)} instead.
370      */
371     @Override
updateCallBarring(int cbType, int action, Message result, String[] barrList, int serviceClass)372     public void updateCallBarring(int cbType, int action, Message result, String[] barrList,
373             int serviceClass) {
374         updateCallBarring(cbType, action, result, barrList, serviceClass, "");
375     }
376 
377     /**
378      * Modifies the configuration of the call barring for specified service class with password.
379      */
380     @Override
updateCallBarring(int cbType, int action, Message result, String[] barrList, int serviceClass, String password)381     public void updateCallBarring(int cbType, int action, Message result,
382             String[] barrList, int serviceClass, String password) {
383         if (DBG) {
384             if (barrList != null) {
385                 String bList = "";
386                 for (int i = 0; i < barrList.length; i++) {
387                     bList += barrList[i] + " ";
388                 }
389                 log("updateCallBarring :: Ut=" + miUt + ", cbType=" + cbType
390                         + ", action=" + action + ", serviceClass=" + serviceClass
391                         + ", barrList=" + bList);
392             }
393             else {
394                 log("updateCallBarring :: Ut=" + miUt + ", cbType=" + cbType
395                         + ", action=" + action + ", serviceClass=" + serviceClass);
396             }
397         }
398 
399         synchronized(mLockObj) {
400             try {
401                 int id = miUt.updateCallBarringWithPassword(cbType, action,
402                         barrList, serviceClass, password);
403 
404                 if (id < 0) {
405                     sendFailureReport(result,
406                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
407                     return;
408                 }
409 
410                 mPendingCmds.put(Integer.valueOf(id), result);
411             } catch (RemoteException e) {
412                 sendFailureReport(result,
413                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
414             }
415         }
416     }
417 
418     /**
419      * Modifies the configuration of the call forward.
420      */
421     @Override
updateCallForward(int action, int condition, String number, int serviceClass, int timeSeconds, Message result)422     public void updateCallForward(int action, int condition, String number,
423             int serviceClass, int timeSeconds, Message result) {
424         if (DBG) {
425             log("updateCallForward :: Ut=" + miUt + ", action=" + action
426                     + ", condition=" + condition + ", number=" + Rlog.pii(TAG, number)
427                     + ", serviceClass=" + serviceClass + ", timeSeconds=" + timeSeconds);
428         }
429 
430         synchronized(mLockObj) {
431             try {
432                 int id = miUt.updateCallForward(action, condition, number, serviceClass, timeSeconds);
433 
434                 if (id < 0) {
435                     sendFailureReport(result,
436                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
437                     return;
438                 }
439 
440                 mPendingCmds.put(Integer.valueOf(id), result);
441             } catch (RemoteException e) {
442                 sendFailureReport(result,
443                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
444             }
445         }
446     }
447 
448     /**
449      * Modifies the configuration of the call waiting.
450      */
451     @Override
updateCallWaiting(boolean enable, int serviceClass, Message result)452     public void updateCallWaiting(boolean enable, int serviceClass, Message result) {
453         if (DBG) {
454             log("updateCallWaiting :: Ut=" + miUt + ", enable=" + enable
455             + ",serviceClass="  + serviceClass);
456         }
457 
458         synchronized(mLockObj) {
459             try {
460                 int id = miUt.updateCallWaiting(enable, serviceClass);
461 
462                 if (id < 0) {
463                     sendFailureReport(result,
464                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
465                     return;
466                 }
467 
468                 mPendingCmds.put(Integer.valueOf(id), result);
469             } catch (RemoteException e) {
470                 sendFailureReport(result,
471                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
472             }
473         }
474     }
475 
476     /**
477      * Updates the configuration of the CLIR supplementary service.
478      */
479     @Override
updateCLIR(int clirMode, Message result)480     public void updateCLIR(int clirMode, Message result) {
481         if (DBG) {
482             log("updateCLIR :: Ut=" + miUt + ", clirMode=" + clirMode);
483         }
484 
485         synchronized(mLockObj) {
486             try {
487                 int id = miUt.updateCLIR(clirMode);
488 
489                 if (id < 0) {
490                     sendFailureReport(result,
491                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
492                     return;
493                 }
494 
495                 mPendingCmds.put(Integer.valueOf(id), result);
496             } catch (RemoteException e) {
497                 sendFailureReport(result,
498                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
499             }
500         }
501     }
502 
503     /**
504      * Updates the configuration of the CLIP supplementary service.
505      */
506     @Override
updateCLIP(boolean enable, Message result)507     public void updateCLIP(boolean enable, Message result) {
508         if (DBG) {
509             log("updateCLIP :: Ut=" + miUt + ", enable=" + enable);
510         }
511 
512         synchronized(mLockObj) {
513             try {
514                 int id = miUt.updateCLIP(enable);
515 
516                 if (id < 0) {
517                     sendFailureReport(result,
518                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
519                     return;
520                 }
521 
522                 mPendingCmds.put(Integer.valueOf(id), result);
523             } catch (RemoteException e) {
524                 sendFailureReport(result,
525                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
526             }
527         }
528     }
529 
530     /**
531      * Updates the configuration of the COLR supplementary service.
532      */
533     @Override
updateCOLR(int presentation, Message result)534     public void updateCOLR(int presentation, Message result) {
535         if (DBG) {
536             log("updateCOLR :: Ut=" + miUt + ", presentation=" + presentation);
537         }
538 
539         synchronized(mLockObj) {
540             try {
541                 int id = miUt.updateCOLR(presentation);
542 
543                 if (id < 0) {
544                     sendFailureReport(result,
545                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
546                     return;
547                 }
548 
549                 mPendingCmds.put(Integer.valueOf(id), result);
550             } catch (RemoteException e) {
551                 sendFailureReport(result,
552                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
553             }
554         }
555     }
556 
557     /**
558      * Updates the configuration of the COLP supplementary service.
559      */
560     @Override
updateCOLP(boolean enable, Message result)561     public void updateCOLP(boolean enable, Message result) {
562         if (DBG) {
563             log("updateCallWaiting :: Ut=" + miUt + ", enable=" + enable);
564         }
565 
566         synchronized(mLockObj) {
567             try {
568                 int id = miUt.updateCOLP(enable);
569 
570                 if (id < 0) {
571                     sendFailureReport(result,
572                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
573                     return;
574                 }
575 
576                 mPendingCmds.put(Integer.valueOf(id), result);
577             } catch (RemoteException e) {
578                 sendFailureReport(result,
579                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
580             }
581         }
582     }
583 
584     /**
585      * @return returns true if the binder is alive, false otherwise.
586      */
isBinderAlive()587     public boolean isBinderAlive() {
588         return miUt.asBinder().isBinderAlive();
589     }
590 
transact(Bundle ssInfo, Message result)591     public void transact(Bundle ssInfo, Message result) {
592         if (DBG) {
593             log("transact :: Ut=" + miUt + ", ssInfo=" + ssInfo);
594         }
595 
596         synchronized(mLockObj) {
597             try {
598                 int id = miUt.transact(ssInfo);
599 
600                 if (id < 0) {
601                     sendFailureReport(result,
602                             new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
603                     return;
604                 }
605 
606                 mPendingCmds.put(Integer.valueOf(id), result);
607             } catch (RemoteException e) {
608                 sendFailureReport(result,
609                         new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
610             }
611         }
612     }
613 
sendFailureReport(Message result, ImsReasonInfo error)614     private void sendFailureReport(Message result, ImsReasonInfo error) {
615         if (result == null || error == null) {
616             return;
617         }
618 
619         String errorString;
620         // If ImsReasonInfo object does not have a String error code, use a
621         // default error string.
622         if (error.mExtraMessage == null) {
623             errorString = Resources.getSystem().getString(
624                     com.android.internal.R.string.mmiError);
625         }
626         else {
627             errorString = new String(error.mExtraMessage);
628         }
629         AsyncResult.forMessage(result, null, new ImsException(errorString, error.mCode));
630         result.sendToTarget();
631     }
632 
sendSuccessReport(Message result)633     private void sendSuccessReport(Message result) {
634         if (result == null) {
635             return;
636         }
637 
638         AsyncResult.forMessage(result, null, null);
639         result.sendToTarget();
640     }
641 
sendSuccessReport(Message result, Object ssInfo)642     private void sendSuccessReport(Message result, Object ssInfo) {
643         if (result == null) {
644             return;
645         }
646 
647         AsyncResult.forMessage(result, ssInfo, null);
648         result.sendToTarget();
649     }
650 
log(String s)651     private void log(String s) {
652         Rlog.d(TAG, s);
653     }
654 
loge(String s)655     private void loge(String s) {
656         Rlog.e(TAG, s);
657     }
658 
loge(String s, Throwable t)659     private void loge(String s, Throwable t) {
660         Rlog.e(TAG, s, t);
661     }
662 
663     /**
664      * A listener type for the result of the supplementary service configuration.
665      */
666     @VisibleForTesting
667     public class IImsUtListenerProxy extends IImsUtListener.Stub {
668         /**
669          * Notifies the result of the supplementary service configuration udpate.
670          */
671         @Override
utConfigurationUpdated(IImsUt ut, int id)672         public void utConfigurationUpdated(IImsUt ut, int id) {
673             TelephonyUtils.runWithCleanCallingIdentity(()-> {
674                 Integer key = Integer.valueOf(id);
675 
676                 synchronized(mLockObj) {
677                     sendSuccessReport(mPendingCmds.get(key));
678                     mPendingCmds.remove(key);
679                 }
680             }, mExecutor);
681         }
682 
683         @Override
utConfigurationUpdateFailed(IImsUt ut, int id, ImsReasonInfo error)684         public void utConfigurationUpdateFailed(IImsUt ut, int id, ImsReasonInfo error) {
685             TelephonyUtils.runWithCleanCallingIdentity(()-> {
686                 Integer key = Integer.valueOf(id);
687 
688                 synchronized(mLockObj) {
689                     sendFailureReport(mPendingCmds.get(key), error);
690                     mPendingCmds.remove(key);
691                 }
692             }, mExecutor);
693         }
694 
695         /**
696          * Notifies the result of the supplementary service configuration query.
697          */
698         // API Deprecated, internally use new API to process query result.
699         @Override
utConfigurationQueried(IImsUt ut, int id, Bundle ssInfo)700         public void utConfigurationQueried(IImsUt ut, int id, Bundle ssInfo) {
701             int[] clirResponse = ssInfo.getIntArray(ImsUtListener.BUNDLE_KEY_CLIR);
702             if (clirResponse != null && clirResponse.length == 2) {
703                 // Deprecated functionality does not use status, set as NOT_REGISTERED.
704                 ImsSsInfo info = new ImsSsInfo.Builder(ImsSsInfo.NOT_REGISTERED)
705                         .setClirOutgoingState(clirResponse[0])
706                         .setClirInterrogationStatus(clirResponse[1]).build();
707                 lineIdentificationSupplementaryServiceResponse(id, info);
708                 return;
709             }
710             ImsSsInfo info = ssInfo.getParcelable(ImsUtListener.BUNDLE_KEY_SSINFO);
711             if (info != null) {
712                 lineIdentificationSupplementaryServiceResponse(id, info);
713                 return;
714             }
715             Rlog.w(TAG, "Invalid utConfigurationQueried response received for Bundle " + ssInfo);
716         }
717 
718         /**
719          * Notifies the result of a line identification supplementary service query.
720          */
721         @Override
lineIdentificationSupplementaryServiceResponse(int id, ImsSsInfo config)722         public void lineIdentificationSupplementaryServiceResponse(int id, ImsSsInfo config) {
723             TelephonyUtils.runWithCleanCallingIdentity(()-> {
724                 synchronized(mLockObj) {
725                     sendSuccessReport(mPendingCmds.get(id), config);
726                     mPendingCmds.remove(id);
727                 }
728             }, mExecutor);
729         }
730 
731         @Override
utConfigurationQueryFailed(IImsUt ut, int id, ImsReasonInfo error)732         public void utConfigurationQueryFailed(IImsUt ut, int id, ImsReasonInfo error) {
733             TelephonyUtils.runWithCleanCallingIdentity(()-> {
734                 Integer key = Integer.valueOf(id);
735 
736                 synchronized(mLockObj) {
737                     sendFailureReport(mPendingCmds.get(key), error);
738                     mPendingCmds.remove(key);
739                 }
740             }, mExecutor);
741         }
742 
743         /**
744          * Notifies the status of the call barring supplementary service.
745          */
746         @Override
utConfigurationCallBarringQueried(IImsUt ut, int id, ImsSsInfo[] cbInfo)747         public void utConfigurationCallBarringQueried(IImsUt ut,
748                 int id, ImsSsInfo[] cbInfo) {
749             TelephonyUtils.runWithCleanCallingIdentity(()-> {
750                 Integer key = Integer.valueOf(id);
751 
752                 synchronized(mLockObj) {
753                     sendSuccessReport(mPendingCmds.get(key), cbInfo);
754                     mPendingCmds.remove(key);
755                 }
756             }, mExecutor);
757         }
758 
759         /**
760          * Notifies the status of the call forwarding supplementary service.
761          */
762         @Override
utConfigurationCallForwardQueried(IImsUt ut, int id, ImsCallForwardInfo[] cfInfo)763         public void utConfigurationCallForwardQueried(IImsUt ut,
764                 int id, ImsCallForwardInfo[] cfInfo) {
765             TelephonyUtils.runWithCleanCallingIdentity(()-> {
766                 Integer key = Integer.valueOf(id);
767 
768                 synchronized(mLockObj) {
769                     sendSuccessReport(mPendingCmds.get(key), cfInfo);
770                     mPendingCmds.remove(key);
771                 }
772             }, mExecutor);
773         }
774 
775         /**
776          * Notifies the status of the call waiting supplementary service.
777          */
778         @Override
utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)779         public void utConfigurationCallWaitingQueried(IImsUt ut,
780                 int id, ImsSsInfo[] cwInfo) {
781             TelephonyUtils.runWithCleanCallingIdentity(()-> {
782                 Integer key = Integer.valueOf(id);
783 
784                 synchronized(mLockObj) {
785                     sendSuccessReport(mPendingCmds.get(key), cwInfo);
786                     mPendingCmds.remove(key);
787                 }
788             }, mExecutor);
789         }
790 
791         /**
792          * Notifies client when Supplementary Service indication is received
793          */
794         @Override
onSupplementaryServiceIndication(ImsSsData ssData)795         public void onSupplementaryServiceIndication(ImsSsData ssData) {
796             TelephonyUtils.runWithCleanCallingIdentity(()-> {
797                 if (mSsIndicationRegistrant != null) {
798                     mSsIndicationRegistrant.notifyResult(ssData);
799                 }
800             }, mExecutor);
801         }
802     }
803 }
804