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
17package com.android.ims;
18
19import java.util.HashMap;
20import java.util.Map;
21
22import android.os.AsyncResult;
23import android.os.Bundle;
24import android.os.Message;
25import android.os.RemoteException;
26import android.telephony.Rlog;
27
28import com.android.ims.internal.IImsUt;
29import com.android.ims.internal.IImsUtListener;
30
31/**
32 * Provides APIs for the supplementary service settings using IMS (Ut interface).
33 * It is created from 3GPP TS 24.623 (XCAP(XML Configuration Access Protocol)
34 * over the Ut interface for manipulating supplementary services).
35 *
36 * @hide
37 */
38public class ImsUt implements ImsUtInterface {
39    /**
40     * Key string for an additional supplementary service configurations.
41     */
42    /**
43     * Actions : string format of ImsUtInterface#ACTION_xxx
44     *      "0" (deactivation), "1" (activation), "2" (not_used),
45     *      "3" (registration), "4" (erasure), "5" (Interrogation)
46     */
47    public static final String KEY_ACTION = "action";
48    /**
49     * Categories :
50     *      "OIP", "OIR", "TIP", "TIR", "CDIV", "CB", "CW", "CONF",
51     *      "ACR", "MCID", "ECT", "CCBS", "AOC", "MWI", "FA", "CAT"
52     *
53     * Detailed parameter name will be determined according to the properties
54     * of the supplementary service configuration.
55     */
56    public static final String KEY_CATEGORY = "category";
57    public static final String CATEGORY_OIP = "OIP";
58    public static final String CATEGORY_OIR = "OIR";
59    public static final String CATEGORY_TIP = "TIP";
60    public static final String CATEGORY_TIR = "TIR";
61    public static final String CATEGORY_CDIV = "CDIV";
62    public static final String CATEGORY_CB = "CB";
63    public static final String CATEGORY_CW = "CW";
64    public static final String CATEGORY_CONF = "CONF";
65
66    private static final String TAG = "ImsUt";
67    private static final boolean DBG = true;
68
69    // For synchronization of private variables
70    private Object mLockObj = new Object();
71    private final IImsUt miUt;
72    private HashMap<Integer, Message> mPendingCmds =
73            new HashMap<Integer, Message>();
74
75    public ImsUt(IImsUt iUt) {
76        miUt = iUt;
77
78        if (miUt != null) {
79            try {
80                miUt.setListener(new IImsUtListenerProxy());
81            } catch (RemoteException e) {
82            }
83        }
84    }
85
86    public void close() {
87        synchronized(mLockObj) {
88            if (miUt != null) {
89                try {
90                    miUt.close();
91                } catch (RemoteException e) {
92                }
93            }
94
95            if (!mPendingCmds.isEmpty()) {
96                Map.Entry<Integer, Message>[] entries =
97                    mPendingCmds.entrySet().toArray(new Map.Entry[mPendingCmds.size()]);
98
99                for (Map.Entry<Integer, Message> entry : entries) {
100                    sendFailureReport(entry.getValue(),
101                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
102                }
103
104                mPendingCmds.clear();
105            }
106        }
107    }
108
109    /**
110     * Operations for the supplementary service configuration
111     */
112
113    /**
114     * Retrieves the configuration of the call barring.
115     *
116     * @param cbType type of call barring to be queried; ImsUtInterface#CB_XXX
117     * @param result message to pass the result of this operation
118     *      The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
119     */
120    @Override
121    public void queryCallBarring(int cbType, Message result) {
122        if (DBG) {
123            log("queryCallBarring :: Ut=" + miUt + ", cbType=" + cbType);
124        }
125
126        synchronized(mLockObj) {
127            try {
128                int id = miUt.queryCallBarring(cbType);
129
130                if (id < 0) {
131                    sendFailureReport(result,
132                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
133                    return;
134                }
135
136                mPendingCmds.put(Integer.valueOf(id), result);
137            } catch (RemoteException e) {
138                sendFailureReport(result,
139                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
140            }
141        }
142    }
143
144    /**
145     * Retrieves the configuration of the call forward.
146     * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
147     */
148    @Override
149    public void queryCallForward(int condition, String number, Message result) {
150        if (DBG) {
151            log("queryCallForward :: Ut=" + miUt + ", condition=" + condition
152                    + ", number=" + number);
153        }
154
155        synchronized(mLockObj) {
156            try {
157                int id = miUt.queryCallForward(condition, number);
158
159                if (id < 0) {
160                    sendFailureReport(result,
161                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
162                    return;
163                }
164
165                mPendingCmds.put(Integer.valueOf(id), result);
166            } catch (RemoteException e) {
167                sendFailureReport(result,
168                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
169            }
170        }
171    }
172
173    /**
174     * Retrieves the configuration of the call waiting.
175     * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
176     */
177    @Override
178    public void queryCallWaiting(Message result) {
179        if (DBG) {
180            log("queryCallWaiting :: Ut=" + miUt);
181        }
182
183        synchronized(mLockObj) {
184            try {
185                int id = miUt.queryCallWaiting();
186
187                if (id < 0) {
188                    sendFailureReport(result,
189                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
190                    return;
191                }
192
193                mPendingCmds.put(Integer.valueOf(id), result);
194            } catch (RemoteException e) {
195                sendFailureReport(result,
196                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
197            }
198        }
199    }
200
201    /**
202     * Retrieves the default CLIR setting.
203     */
204    @Override
205    public void queryCLIR(Message result) {
206        if (DBG) {
207            log("queryCLIR :: Ut=" + miUt);
208        }
209
210        synchronized(mLockObj) {
211            try {
212                int id = miUt.queryCLIR();
213
214                if (id < 0) {
215                    sendFailureReport(result,
216                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
217                    return;
218                }
219
220                mPendingCmds.put(Integer.valueOf(id), result);
221            } catch (RemoteException e) {
222                sendFailureReport(result,
223                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
224            }
225        }
226    }
227
228    /**
229     * Retrieves the CLIP call setting.
230     */
231    public void queryCLIP(Message result) {
232        if (DBG) {
233            log("queryCLIP :: Ut=" + miUt);
234        }
235
236        synchronized(mLockObj) {
237            try {
238                int id = miUt.queryCLIP();
239
240                if (id < 0) {
241                    sendFailureReport(result,
242                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
243                    return;
244                }
245
246                mPendingCmds.put(Integer.valueOf(id), result);
247            } catch (RemoteException e) {
248                sendFailureReport(result,
249                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
250            }
251        }
252    }
253
254    /**
255     * Retrieves the COLR call setting.
256     */
257    public void queryCOLR(Message result) {
258        if (DBG) {
259            log("queryCOLR :: Ut=" + miUt);
260        }
261
262        synchronized(mLockObj) {
263            try {
264                int id = miUt.queryCOLR();
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 COLP call setting.
282     */
283    public void queryCOLP(Message result) {
284        if (DBG) {
285            log("queryCOLP :: Ut=" + miUt);
286        }
287
288        synchronized(mLockObj) {
289            try {
290                int id = miUt.queryCOLP();
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     * Modifies the configuration of the call barring.
308     */
309    @Override
310    public void updateCallBarring(int cbType, int action, Message result, String[] barrList) {
311        if (DBG) {
312            if (barrList != null) {
313                String bList = new String();
314                for (int i = 0; i < barrList.length; i++) {
315                    bList.concat(barrList[i] + " ");
316                }
317                log("updateCallBarring :: Ut=" + miUt + ", cbType=" + cbType
318                        + ", action=" + action + ", barrList=" + bList);
319            }
320            else {
321                log("updateCallBarring :: Ut=" + miUt + ", cbType=" + cbType
322                        + ", action=" + action);
323            }
324        }
325
326        synchronized(mLockObj) {
327            try {
328                int id = miUt.updateCallBarring(cbType, action, barrList);
329
330                if (id < 0) {
331                    sendFailureReport(result,
332                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
333                    return;
334                }
335
336                mPendingCmds.put(Integer.valueOf(id), result);
337            } catch (RemoteException e) {
338                sendFailureReport(result,
339                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
340            }
341        }
342    }
343
344    /**
345     * Modifies the configuration of the call forward.
346     */
347    @Override
348    public void updateCallForward(int action, int condition, String number,
349            int serviceClass, int timeSeconds, Message result) {
350        if (DBG) {
351            log("updateCallForward :: Ut=" + miUt + ", action=" + action
352                    + ", condition=" + condition + ", number=" + number
353                    +  ", serviceClass=" + serviceClass + ", timeSeconds=" + timeSeconds);
354        }
355
356        synchronized(mLockObj) {
357            try {
358                int id = miUt.updateCallForward(action, condition, number, serviceClass, timeSeconds);
359
360                if (id < 0) {
361                    sendFailureReport(result,
362                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
363                    return;
364                }
365
366                mPendingCmds.put(Integer.valueOf(id), result);
367            } catch (RemoteException e) {
368                sendFailureReport(result,
369                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
370            }
371        }
372    }
373
374    /**
375     * Modifies the configuration of the call waiting.
376     */
377    @Override
378    public void updateCallWaiting(boolean enable, int serviceClass, Message result) {
379        if (DBG) {
380            log("updateCallWaiting :: Ut=" + miUt + ", enable=" + enable
381            + ",serviceClass="  + serviceClass);
382        }
383
384        synchronized(mLockObj) {
385            try {
386                int id = miUt.updateCallWaiting(enable, serviceClass);
387
388                if (id < 0) {
389                    sendFailureReport(result,
390                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
391                    return;
392                }
393
394                mPendingCmds.put(Integer.valueOf(id), result);
395            } catch (RemoteException e) {
396                sendFailureReport(result,
397                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
398            }
399        }
400    }
401
402    /**
403     * Updates the configuration of the CLIR supplementary service.
404     */
405    @Override
406    public void updateCLIR(int clirMode, Message result) {
407        if (DBG) {
408            log("updateCLIR :: Ut=" + miUt + ", clirMode=" + clirMode);
409        }
410
411        synchronized(mLockObj) {
412            try {
413                int id = miUt.updateCLIR(clirMode);
414
415                if (id < 0) {
416                    sendFailureReport(result,
417                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
418                    return;
419                }
420
421                mPendingCmds.put(Integer.valueOf(id), result);
422            } catch (RemoteException e) {
423                sendFailureReport(result,
424                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
425            }
426        }
427    }
428
429    /**
430     * Updates the configuration of the CLIP supplementary service.
431     */
432    @Override
433    public void updateCLIP(boolean enable, Message result) {
434        if (DBG) {
435            log("updateCLIP :: Ut=" + miUt + ", enable=" + enable);
436        }
437
438        synchronized(mLockObj) {
439            try {
440                int id = miUt.updateCLIP(enable);
441
442                if (id < 0) {
443                    sendFailureReport(result,
444                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
445                    return;
446                }
447
448                mPendingCmds.put(Integer.valueOf(id), result);
449            } catch (RemoteException e) {
450                sendFailureReport(result,
451                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
452            }
453        }
454    }
455
456    /**
457     * Updates the configuration of the COLR supplementary service.
458     */
459    @Override
460    public void updateCOLR(int presentation, Message result) {
461        if (DBG) {
462            log("updateCOLR :: Ut=" + miUt + ", presentation=" + presentation);
463        }
464
465        synchronized(mLockObj) {
466            try {
467                int id = miUt.updateCOLR(presentation);
468
469                if (id < 0) {
470                    sendFailureReport(result,
471                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
472                    return;
473                }
474
475                mPendingCmds.put(Integer.valueOf(id), result);
476            } catch (RemoteException e) {
477                sendFailureReport(result,
478                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
479            }
480        }
481    }
482
483    /**
484     * Updates the configuration of the COLP supplementary service.
485     */
486    @Override
487    public void updateCOLP(boolean enable, Message result) {
488        if (DBG) {
489            log("updateCallWaiting :: Ut=" + miUt + ", enable=" + enable);
490        }
491
492        synchronized(mLockObj) {
493            try {
494                int id = miUt.updateCOLP(enable);
495
496                if (id < 0) {
497                    sendFailureReport(result,
498                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
499                    return;
500                }
501
502                mPendingCmds.put(Integer.valueOf(id), result);
503            } catch (RemoteException e) {
504                sendFailureReport(result,
505                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
506            }
507        }
508    }
509
510    public void transact(Bundle ssInfo, Message result) {
511        if (DBG) {
512            log("transact :: Ut=" + miUt + ", ssInfo=" + ssInfo);
513        }
514
515        synchronized(mLockObj) {
516            try {
517                int id = miUt.transact(ssInfo);
518
519                if (id < 0) {
520                    sendFailureReport(result,
521                            new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
522                    return;
523                }
524
525                mPendingCmds.put(Integer.valueOf(id), result);
526            } catch (RemoteException e) {
527                sendFailureReport(result,
528                        new ImsReasonInfo(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, 0));
529            }
530        }
531    }
532
533    private void sendFailureReport(Message result, ImsReasonInfo error) {
534        if (result == null || error == null) {
535            return;
536        }
537
538        String errorString;
539        // If ImsReasonInfo object does not have a String error code, use a
540        // default error string.
541        if (error.mExtraMessage == null) {
542            errorString = new String("IMS UT exception");
543        }
544        else {
545            errorString = new String(error.mExtraMessage);
546        }
547        AsyncResult.forMessage(result, null, new ImsException(errorString, error.mCode));
548        result.sendToTarget();
549    }
550
551    private void sendSuccessReport(Message result) {
552        if (result == null) {
553            return;
554        }
555
556        AsyncResult.forMessage(result, null, null);
557        result.sendToTarget();
558    }
559
560    private void sendSuccessReport(Message result, Object ssInfo) {
561        if (result == null) {
562            return;
563        }
564
565        AsyncResult.forMessage(result, ssInfo, null);
566        result.sendToTarget();
567    }
568
569    private void log(String s) {
570        Rlog.d(TAG, s);
571    }
572
573    private void loge(String s) {
574        Rlog.e(TAG, s);
575    }
576
577    private void loge(String s, Throwable t) {
578        Rlog.e(TAG, s, t);
579    }
580
581    /**
582     * A listener type for the result of the supplementary service configuration.
583     */
584    private class IImsUtListenerProxy extends IImsUtListener.Stub {
585        /**
586         * Notifies the result of the supplementary service configuration udpate.
587         */
588        @Override
589        public void utConfigurationUpdated(IImsUt ut, int id) {
590            Integer key = Integer.valueOf(id);
591
592            synchronized(mLockObj) {
593                sendSuccessReport(mPendingCmds.get(key));
594                mPendingCmds.remove(key);
595            }
596        }
597
598        @Override
599        public void utConfigurationUpdateFailed(IImsUt ut, int id, ImsReasonInfo error) {
600            Integer key = Integer.valueOf(id);
601
602            synchronized(mLockObj) {
603                sendFailureReport(mPendingCmds.get(key), error);
604                mPendingCmds.remove(key);
605            }
606        }
607
608        /**
609         * Notifies the result of the supplementary service configuration query.
610         */
611        @Override
612        public void utConfigurationQueried(IImsUt ut, int id, Bundle ssInfo) {
613            Integer key = Integer.valueOf(id);
614
615            synchronized(mLockObj) {
616                sendSuccessReport(mPendingCmds.get(key), ssInfo);
617                mPendingCmds.remove(key);
618            }
619        }
620
621        @Override
622        public void utConfigurationQueryFailed(IImsUt ut, int id, ImsReasonInfo error) {
623            Integer key = Integer.valueOf(id);
624
625            synchronized(mLockObj) {
626                sendFailureReport(mPendingCmds.get(key), error);
627                mPendingCmds.remove(key);
628            }
629        }
630
631        /**
632         * Notifies the status of the call barring supplementary service.
633         */
634        @Override
635        public void utConfigurationCallBarringQueried(IImsUt ut,
636                int id, ImsSsInfo[] cbInfo) {
637            Integer key = Integer.valueOf(id);
638
639            synchronized(mLockObj) {
640                sendSuccessReport(mPendingCmds.get(key), cbInfo);
641                mPendingCmds.remove(key);
642            }
643        }
644
645        /**
646         * Notifies the status of the call forwarding supplementary service.
647         */
648        @Override
649        public void utConfigurationCallForwardQueried(IImsUt ut,
650                int id, ImsCallForwardInfo[] cfInfo) {
651            Integer key = Integer.valueOf(id);
652
653            synchronized(mLockObj) {
654                sendSuccessReport(mPendingCmds.get(key), cfInfo);
655                mPendingCmds.remove(key);
656            }
657        }
658
659        /**
660         * Notifies the status of the call waiting supplementary service.
661         */
662        @Override
663        public void utConfigurationCallWaitingQueried(IImsUt ut,
664                int id, ImsSsInfo[] cwInfo) {
665            Integer key = Integer.valueOf(id);
666
667            synchronized(mLockObj) {
668                sendSuccessReport(mPendingCmds.get(key), cwInfo);
669                mPendingCmds.remove(key);
670            }
671        }
672    }
673}
674