1/*
2 * Copyright (C) 2006 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.internal.telephony.test;
18
19import android.os.AsyncResult;
20import android.os.HandlerThread;
21import android.os.Looper;
22import android.os.Message;
23import android.util.Log;
24
25import com.android.internal.telephony.BaseCommands;
26import com.android.internal.telephony.CommandException;
27import com.android.internal.telephony.CommandsInterface;
28import com.android.internal.telephony.DataCallState;
29import com.android.internal.telephony.Phone;
30import com.android.internal.telephony.UUSInfo;
31import com.android.internal.telephony.gsm.CallFailCause;
32import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
33import com.android.internal.telephony.gsm.SuppServiceNotification;
34
35import java.util.ArrayList;
36
37public final class SimulatedCommands extends BaseCommands
38        implements CommandsInterface, SimulatedRadioControl {
39    private final static String LOG_TAG = "SIM";
40
41    private enum SimLockState {
42        NONE,
43        REQUIRE_PIN,
44        REQUIRE_PUK,
45        SIM_PERM_LOCKED
46    }
47
48    private enum SimFdnState {
49        NONE,
50        REQUIRE_PIN2,
51        REQUIRE_PUK2,
52        SIM_PERM_LOCKED
53    }
54
55    private final static SimLockState INITIAL_LOCK_STATE = SimLockState.NONE;
56    private final static String DEFAULT_SIM_PIN_CODE = "1234";
57    private final static String SIM_PUK_CODE = "12345678";
58    private final static SimFdnState INITIAL_FDN_STATE = SimFdnState.NONE;
59    private final static String DEFAULT_SIM_PIN2_CODE = "5678";
60    private final static String SIM_PUK2_CODE = "87654321";
61
62    //***** Instance Variables
63
64    SimulatedGsmCallState simulatedCallState;
65    HandlerThread mHandlerThread;
66    SimLockState mSimLockedState;
67    boolean mSimLockEnabled;
68    int mPinUnlockAttempts;
69    int mPukUnlockAttempts;
70    String mPinCode;
71    SimFdnState mSimFdnEnabledState;
72    boolean mSimFdnEnabled;
73    int mPin2UnlockAttempts;
74    int mPuk2UnlockAttempts;
75    int mNetworkType;
76    String mPin2Code;
77    boolean mSsnNotifyOn = false;
78
79    int pausedResponseCount;
80    ArrayList<Message> pausedResponses = new ArrayList<Message>();
81
82    int nextCallFailCause = CallFailCause.NORMAL_CLEARING;
83
84    //***** Constructor
85
86    public
87    SimulatedCommands() {
88        super(null);  // Don't log statistics
89        mHandlerThread = new HandlerThread("SimulatedCommands");
90        mHandlerThread.start();
91        Looper looper = mHandlerThread.getLooper();
92
93        simulatedCallState = new SimulatedGsmCallState(looper);
94
95        setRadioState(RadioState.RADIO_OFF);
96        mSimLockedState = INITIAL_LOCK_STATE;
97        mSimLockEnabled = (mSimLockedState != SimLockState.NONE);
98        mPinCode = DEFAULT_SIM_PIN_CODE;
99        mSimFdnEnabledState = INITIAL_FDN_STATE;
100        mSimFdnEnabled = (mSimFdnEnabledState != SimFdnState.NONE);
101        mPin2Code = DEFAULT_SIM_PIN2_CODE;
102    }
103
104    //***** CommandsInterface implementation
105
106    public void getIccCardStatus(Message result) {
107        unimplemented(result);
108    }
109
110    public void supplyIccPin(String pin, Message result)  {
111        if (mSimLockedState != SimLockState.REQUIRE_PIN) {
112            Log.i(LOG_TAG, "[SimCmd] supplyIccPin: wrong state, state=" +
113                    mSimLockedState);
114            CommandException ex = new CommandException(
115                    CommandException.Error.PASSWORD_INCORRECT);
116            AsyncResult.forMessage(result, null, ex);
117            result.sendToTarget();
118            return;
119        }
120
121        if (pin != null && pin.equals(mPinCode)) {
122            Log.i(LOG_TAG, "[SimCmd] supplyIccPin: success!");
123            setRadioState(RadioState.SIM_READY);
124            mPinUnlockAttempts = 0;
125            mSimLockedState = SimLockState.NONE;
126
127            if (result != null) {
128                AsyncResult.forMessage(result, null, null);
129                result.sendToTarget();
130            }
131
132            return;
133        }
134
135        if (result != null) {
136            mPinUnlockAttempts ++;
137
138            Log.i(LOG_TAG, "[SimCmd] supplyIccPin: failed! attempt=" +
139                    mPinUnlockAttempts);
140            if (mPinUnlockAttempts >= 3) {
141                Log.i(LOG_TAG, "[SimCmd] supplyIccPin: set state to REQUIRE_PUK");
142                mSimLockedState = SimLockState.REQUIRE_PUK;
143            }
144
145            CommandException ex = new CommandException(
146                    CommandException.Error.PASSWORD_INCORRECT);
147            AsyncResult.forMessage(result, null, ex);
148            result.sendToTarget();
149        }
150    }
151
152    public void supplyIccPuk(String puk, String newPin, Message result)  {
153        if (mSimLockedState != SimLockState.REQUIRE_PUK) {
154            Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: wrong state, state=" +
155                    mSimLockedState);
156            CommandException ex = new CommandException(
157                    CommandException.Error.PASSWORD_INCORRECT);
158            AsyncResult.forMessage(result, null, ex);
159            result.sendToTarget();
160            return;
161        }
162
163        if (puk != null && puk.equals(SIM_PUK_CODE)) {
164            Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: success!");
165            setRadioState(RadioState.SIM_READY);
166            mSimLockedState = SimLockState.NONE;
167            mPukUnlockAttempts = 0;
168
169            if (result != null) {
170                AsyncResult.forMessage(result, null, null);
171                result.sendToTarget();
172            }
173
174            return;
175        }
176
177        if (result != null) {
178            mPukUnlockAttempts ++;
179
180            Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: failed! attempt=" +
181                    mPukUnlockAttempts);
182            if (mPukUnlockAttempts >= 10) {
183                Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: set state to SIM_PERM_LOCKED");
184                mSimLockedState = SimLockState.SIM_PERM_LOCKED;
185            }
186
187            CommandException ex = new CommandException(
188                    CommandException.Error.PASSWORD_INCORRECT);
189            AsyncResult.forMessage(result, null, ex);
190            result.sendToTarget();
191        }
192    }
193
194    public void supplyIccPin2(String pin2, Message result)  {
195        if (mSimFdnEnabledState != SimFdnState.REQUIRE_PIN2) {
196            Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: wrong state, state=" +
197                    mSimFdnEnabledState);
198            CommandException ex = new CommandException(
199                    CommandException.Error.PASSWORD_INCORRECT);
200            AsyncResult.forMessage(result, null, ex);
201            result.sendToTarget();
202            return;
203        }
204
205        if (pin2 != null && pin2.equals(mPin2Code)) {
206            Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: success!");
207            mPin2UnlockAttempts = 0;
208            mSimFdnEnabledState = SimFdnState.NONE;
209
210            if (result != null) {
211                AsyncResult.forMessage(result, null, null);
212                result.sendToTarget();
213            }
214
215            return;
216        }
217
218        if (result != null) {
219            mPin2UnlockAttempts ++;
220
221            Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: failed! attempt=" +
222                    mPin2UnlockAttempts);
223            if (mPin2UnlockAttempts >= 3) {
224                Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: set state to REQUIRE_PUK2");
225                mSimFdnEnabledState = SimFdnState.REQUIRE_PUK2;
226            }
227
228            CommandException ex = new CommandException(
229                    CommandException.Error.PASSWORD_INCORRECT);
230            AsyncResult.forMessage(result, null, ex);
231            result.sendToTarget();
232        }
233    }
234
235    public void supplyIccPuk2(String puk2, String newPin2, Message result)  {
236        if (mSimFdnEnabledState != SimFdnState.REQUIRE_PUK2) {
237            Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: wrong state, state=" +
238                    mSimLockedState);
239            CommandException ex = new CommandException(
240                    CommandException.Error.PASSWORD_INCORRECT);
241            AsyncResult.forMessage(result, null, ex);
242            result.sendToTarget();
243            return;
244        }
245
246        if (puk2 != null && puk2.equals(SIM_PUK2_CODE)) {
247            Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: success!");
248            mSimFdnEnabledState = SimFdnState.NONE;
249            mPuk2UnlockAttempts = 0;
250
251            if (result != null) {
252                AsyncResult.forMessage(result, null, null);
253                result.sendToTarget();
254            }
255
256            return;
257        }
258
259        if (result != null) {
260            mPuk2UnlockAttempts ++;
261
262            Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: failed! attempt=" +
263                    mPuk2UnlockAttempts);
264            if (mPuk2UnlockAttempts >= 10) {
265                Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: set state to SIM_PERM_LOCKED");
266                mSimFdnEnabledState = SimFdnState.SIM_PERM_LOCKED;
267            }
268
269            CommandException ex = new CommandException(
270                    CommandException.Error.PASSWORD_INCORRECT);
271            AsyncResult.forMessage(result, null, ex);
272            result.sendToTarget();
273        }
274    }
275
276    public void changeIccPin(String oldPin, String newPin, Message result)  {
277        if (oldPin != null && oldPin.equals(mPinCode)) {
278            mPinCode = newPin;
279            if (result != null) {
280                AsyncResult.forMessage(result, null, null);
281                result.sendToTarget();
282            }
283
284            return;
285        }
286
287        if (result != null) {
288            Log.i(LOG_TAG, "[SimCmd] changeIccPin: pin failed!");
289
290            CommandException ex = new CommandException(
291                    CommandException.Error.PASSWORD_INCORRECT);
292            AsyncResult.forMessage(result, null, ex);
293            result.sendToTarget();
294        }
295    }
296
297    public void changeIccPin2(String oldPin2, String newPin2, Message result)  {
298        if (oldPin2 != null && oldPin2.equals(mPin2Code)) {
299            mPin2Code = newPin2;
300            if (result != null) {
301                AsyncResult.forMessage(result, null, null);
302                result.sendToTarget();
303            }
304
305            return;
306        }
307
308        if (result != null) {
309            Log.i(LOG_TAG, "[SimCmd] changeIccPin2: pin2 failed!");
310
311            CommandException ex = new CommandException(
312                    CommandException.Error.PASSWORD_INCORRECT);
313            AsyncResult.forMessage(result, null, ex);
314            result.sendToTarget();
315        }
316    }
317
318    public void
319    changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) {
320        unimplemented(result);
321    }
322
323    public void
324    setSuppServiceNotifications(boolean enable, Message result) {
325        resultSuccess(result, null);
326
327        if (enable && mSsnNotifyOn) {
328            Log.w(LOG_TAG, "Supp Service Notifications already enabled!");
329        }
330
331        mSsnNotifyOn = enable;
332    }
333
334    @Override
335    public void queryFacilityLock(String facility, String pin,
336                                   int serviceClass, Message result) {
337        queryFacilityLockForApp(facility, pin, serviceClass, null, result);
338    }
339
340    @Override
341    public void queryFacilityLockForApp(String facility, String pin, int serviceClass,
342            String appId, Message result) {
343        if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) {
344            if (result != null) {
345                int[] r = new int[1];
346                r[0] = (mSimLockEnabled ? 1 : 0);
347                Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: SIM is "
348                        + (r[0] == 0 ? "unlocked" : "locked"));
349                AsyncResult.forMessage(result, r, null);
350                result.sendToTarget();
351            }
352            return;
353        } else if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) {
354            if (result != null) {
355                int[] r = new int[1];
356                r[0] = (mSimFdnEnabled ? 1 : 0);
357                Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: FDN is "
358                        + (r[0] == 0 ? "disabled" : "enabled"));
359                AsyncResult.forMessage(result, r, null);
360                result.sendToTarget();
361            }
362            return;
363        }
364
365        unimplemented(result);
366    }
367
368    @Override
369    public void setFacilityLock(String facility, boolean lockEnabled, String pin, int serviceClass,
370            Message result) {
371        setFacilityLockForApp(facility, lockEnabled, pin, serviceClass, null, result);
372    }
373
374    @Override
375    public void setFacilityLockForApp(String facility, boolean lockEnabled,
376                                 String pin, int serviceClass, String appId,
377                                 Message result) {
378        if (facility != null &&
379                facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) {
380            if (pin != null && pin.equals(mPinCode)) {
381                Log.i(LOG_TAG, "[SimCmd] setFacilityLock: pin is valid");
382                mSimLockEnabled = lockEnabled;
383
384                if (result != null) {
385                    AsyncResult.forMessage(result, null, null);
386                    result.sendToTarget();
387                }
388
389                return;
390            }
391
392            if (result != null) {
393                Log.i(LOG_TAG, "[SimCmd] setFacilityLock: pin failed!");
394
395                CommandException ex = new CommandException(
396                        CommandException.Error.GENERIC_FAILURE);
397                AsyncResult.forMessage(result, null, ex);
398                result.sendToTarget();
399            }
400
401            return;
402        }  else if (facility != null &&
403                facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) {
404            if (pin != null && pin.equals(mPin2Code)) {
405                Log.i(LOG_TAG, "[SimCmd] setFacilityLock: pin2 is valid");
406                mSimFdnEnabled = lockEnabled;
407
408                if (result != null) {
409                    AsyncResult.forMessage(result, null, null);
410                    result.sendToTarget();
411                }
412
413                return;
414            }
415
416            if (result != null) {
417                Log.i(LOG_TAG, "[SimCmd] setFacilityLock: pin2 failed!");
418
419                CommandException ex = new CommandException(
420                        CommandException.Error.GENERIC_FAILURE);
421                AsyncResult.forMessage(result, null, ex);
422                result.sendToTarget();
423            }
424
425            return;
426        }
427
428        unimplemented(result);
429    }
430
431    public void supplyNetworkDepersonalization(String netpin, Message result)  {
432        unimplemented(result);
433    }
434
435    /**
436     *  returned message
437     *  retMsg.obj = AsyncResult ar
438     *  ar.exception carries exception on failure
439     *  ar.userObject contains the original value of result.obj
440     *  ar.result contains a List of DriverCall
441     *      The ar.result List is sorted by DriverCall.index
442     */
443    public void getCurrentCalls (Message result) {
444        if (mState == RadioState.SIM_READY) {
445            //Log.i("GSM", "[SimCmds] getCurrentCalls");
446            resultSuccess(result, simulatedCallState.getDriverCalls());
447        } else {
448            //Log.i("GSM", "[SimCmds] getCurrentCalls: SIM not ready!");
449            resultFail(result,
450                new CommandException(
451                    CommandException.Error.RADIO_NOT_AVAILABLE));
452        }
453    }
454
455    /**
456     *  @deprecated
457     */
458    public void getPDPContextList(Message result) {
459        getDataCallList(result);
460    }
461
462    /**
463     *  returned message
464     *  retMsg.obj = AsyncResult ar
465     *  ar.exception carries exception on failure
466     *  ar.userObject contains the original value of result.obj
467     *  ar.result contains a List of DataCallState
468     */
469    public void getDataCallList(Message result) {
470        resultSuccess(result, new ArrayList<DataCallState>(0));
471    }
472
473    /**
474     *  returned message
475     *  retMsg.obj = AsyncResult ar
476     *  ar.exception carries exception on failure
477     *  ar.userObject contains the original value of result.obj
478     *  ar.result is null on success and failure
479     *
480     * CLIR_DEFAULT     == on "use subscription default value"
481     * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
482     * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
483     */
484    public void dial (String address, int clirMode, Message result) {
485        simulatedCallState.onDial(address);
486
487        resultSuccess(result, null);
488    }
489
490    /**
491     *  returned message
492     *  retMsg.obj = AsyncResult ar
493     *  ar.exception carries exception on failure
494     *  ar.userObject contains the original value of result.obj
495     *  ar.result is null on success and failure
496     *
497     * CLIR_DEFAULT     == on "use subscription default value"
498     * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
499     * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
500     */
501    public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
502        simulatedCallState.onDial(address);
503
504        resultSuccess(result, null);
505    }
506
507    /**
508     *  returned message
509     *  retMsg.obj = AsyncResult ar
510     *  ar.exception carries exception on failure
511     *  ar.userObject contains the original value of result.obj
512     *  ar.result is String containing IMSI on success
513     */
514    public void getIMSI(Message result) {
515        resultSuccess(result, "012345678901234");
516    }
517
518    /**
519     *  returned message
520     *  retMsg.obj = AsyncResult ar
521     *  ar.exception carries exception on failure
522     *  ar.userObject contains the original value of result.obj
523     *  ar.result is String containing IMEI on success
524     */
525    public void getIMEI(Message result) {
526        resultSuccess(result, "012345678901234");
527    }
528
529    /**
530     *  returned message
531     *  retMsg.obj = AsyncResult ar
532     *  ar.exception carries exception on failure
533     *  ar.userObject contains the original value of result.obj
534     *  ar.result is String containing IMEISV on success
535     */
536    public void getIMEISV(Message result) {
537        resultSuccess(result, "99");
538    }
539
540    /**
541     * Hang up one individual connection.
542     *  returned message
543     *  retMsg.obj = AsyncResult ar
544     *  ar.exception carries exception on failure
545     *  ar.userObject contains the original value of result.obj
546     *  ar.result is null on success and failure
547     *
548     *  3GPP 22.030 6.5.5
549     *  "Releases a specific active call X"
550     */
551    public void hangupConnection (int gsmIndex, Message result) {
552        boolean success;
553
554        success = simulatedCallState.onChld('1', (char)('0'+gsmIndex));
555
556        if (!success){
557            Log.i("GSM", "[SimCmd] hangupConnection: resultFail");
558            resultFail(result, new RuntimeException("Hangup Error"));
559        } else {
560            Log.i("GSM", "[SimCmd] hangupConnection: resultSuccess");
561            resultSuccess(result, null);
562        }
563    }
564
565    /**
566     * 3GPP 22.030 6.5.5
567     *  "Releases all held calls or sets User Determined User Busy (UDUB)
568     *   for a waiting call."
569     *  ar.exception carries exception on failure
570     *  ar.userObject contains the original value of result.obj
571     *  ar.result is null on success and failure
572     */
573    public void hangupWaitingOrBackground (Message result) {
574        boolean success;
575
576        success = simulatedCallState.onChld('0', '\0');
577
578        if (!success){
579            resultFail(result, new RuntimeException("Hangup Error"));
580        } else {
581            resultSuccess(result, null);
582        }
583    }
584
585    /**
586     * 3GPP 22.030 6.5.5
587     * "Releases all active calls (if any exist) and accepts
588     *  the other (held or waiting) call."
589     *
590     *  ar.exception carries exception on failure
591     *  ar.userObject contains the original value of result.obj
592     *  ar.result is null on success and failure
593     */
594    public void hangupForegroundResumeBackground (Message result) {
595        boolean success;
596
597        success = simulatedCallState.onChld('1', '\0');
598
599        if (!success){
600            resultFail(result, new RuntimeException("Hangup Error"));
601        } else {
602            resultSuccess(result, null);
603        }
604    }
605
606    /**
607     * 3GPP 22.030 6.5.5
608     * "Places all active calls (if any exist) on hold and accepts
609     *  the other (held or waiting) call."
610     *
611     *  ar.exception carries exception on failure
612     *  ar.userObject contains the original value of result.obj
613     *  ar.result is null on success and failure
614     */
615    public void switchWaitingOrHoldingAndActive (Message result) {
616        boolean success;
617
618        success = simulatedCallState.onChld('2', '\0');
619
620        if (!success){
621            resultFail(result, new RuntimeException("Hangup Error"));
622        } else {
623            resultSuccess(result, null);
624        }
625    }
626
627    /**
628     * 3GPP 22.030 6.5.5
629     * "Adds a held call to the conversation"
630     *
631     *  ar.exception carries exception on failure
632     *  ar.userObject contains the original value of result.obj
633     *  ar.result is null on success and failure
634     */
635    public void conference (Message result) {
636        boolean success;
637
638        success = simulatedCallState.onChld('3', '\0');
639
640        if (!success){
641            resultFail(result, new RuntimeException("Hangup Error"));
642        } else {
643            resultSuccess(result, null);
644        }
645    }
646
647    /**
648     * 3GPP 22.030 6.5.5
649     * "Connects the two calls and disconnects the subscriber from both calls"
650     *
651     *  ar.exception carries exception on failure
652     *  ar.userObject contains the original value of result.obj
653     *  ar.result is null on success and failure
654     */
655    public void explicitCallTransfer (Message result) {
656        boolean success;
657
658        success = simulatedCallState.onChld('4', '\0');
659
660        if (!success){
661            resultFail(result, new RuntimeException("Hangup Error"));
662        } else {
663            resultSuccess(result, null);
664        }
665    }
666
667    /**
668     * 3GPP 22.030 6.5.5
669     * "Places all active calls on hold except call X with which
670     *  communication shall be supported."
671     */
672    public void separateConnection (int gsmIndex, Message result) {
673        boolean success;
674
675        char ch = (char)(gsmIndex + '0');
676        success = simulatedCallState.onChld('2', ch);
677
678        if (!success){
679            resultFail(result, new RuntimeException("Hangup Error"));
680        } else {
681            resultSuccess(result, null);
682        }
683    }
684
685    /**
686     *
687     *  ar.exception carries exception on failure
688     *  ar.userObject contains the original value of result.obj
689     *  ar.result is null on success and failure
690     */
691    public void acceptCall (Message result) {
692        boolean success;
693
694        success = simulatedCallState.onAnswer();
695
696        if (!success){
697            resultFail(result, new RuntimeException("Hangup Error"));
698        } else {
699            resultSuccess(result, null);
700        }
701    }
702
703    /**
704     *  also known as UDUB
705     *  ar.exception carries exception on failure
706     *  ar.userObject contains the original value of result.obj
707     *  ar.result is null on success and failure
708     */
709    public void rejectCall (Message result) {
710        boolean success;
711
712        success = simulatedCallState.onChld('0', '\0');
713
714        if (!success){
715            resultFail(result, new RuntimeException("Hangup Error"));
716        } else {
717            resultSuccess(result, null);
718        }
719    }
720
721    /**
722     * cause code returned as Integer in Message.obj.response
723     * Returns integer cause code defined in TS 24.008
724     * Annex H or closest approximation.
725     * Most significant codes:
726     * - Any defined in 22.001 F.4 (for generating busy/congestion)
727     * - Cause 68: ACM >= ACMMax
728     */
729    public void getLastCallFailCause (Message result) {
730        int[] ret = new int[1];
731
732        ret[0] = nextCallFailCause;
733        resultSuccess(result, ret);
734    }
735
736    /**
737     * @deprecated
738     */
739    public void getLastPdpFailCause (Message result) {
740        unimplemented(result);
741    }
742
743    public void getLastDataCallFailCause(Message result) {
744        //
745        unimplemented(result);
746    }
747
748    public void setMute (boolean enableMute, Message result) {unimplemented(result);}
749
750    public void getMute (Message result) {unimplemented(result);}
751
752    /**
753     * response.obj is an AsyncResult
754     * response.obj.result is an int[2]
755     * response.obj.result[0] is received signal strength (0-31, 99)
756     * response.obj.result[1] is  bit error rate (0-7, 99)
757     * as defined in TS 27.007 8.5
758     */
759    public void getSignalStrength (Message result) {
760        int ret[] = new int[2];
761
762        ret[0] = 23;
763        ret[1] = 0;
764
765        resultSuccess(result, ret);
766    }
767
768     /**
769     * Assign a specified band for RF configuration.
770     *
771     * @param bandMode one of BM_*_BAND
772     * @param result is callback message
773     */
774    public void setBandMode (int bandMode, Message result) {
775        resultSuccess(result, null);
776    }
777
778    /**
779     * Query the list of band mode supported by RF.
780     *
781     * @param result is callback message
782     *        ((AsyncResult)response.obj).result  is an int[] with every
783     *        element representing one available BM_*_BAND
784     */
785    public void queryAvailableBandMode (Message result) {
786        int ret[] = new int [4];
787
788        ret[0] = 4;
789        ret[1] = Phone.BM_US_BAND;
790        ret[2] = Phone.BM_JPN_BAND;
791        ret[3] = Phone.BM_AUS_BAND;
792
793        resultSuccess(result, ret);
794    }
795
796    /**
797     * {@inheritDoc}
798     */
799    public void sendTerminalResponse(String contents, Message response) {
800        resultSuccess(response, null);
801    }
802
803    /**
804     * {@inheritDoc}
805     */
806    public void sendEnvelope(String contents, Message response) {
807        resultSuccess(response, null);
808    }
809
810    /**
811     * {@inheritDoc}
812     */
813    public void sendEnvelopeWithStatus(String contents, Message response) {
814        resultSuccess(response, null);
815    }
816
817    /**
818     * {@inheritDoc}
819     */
820    public void handleCallSetupRequestFromSim(
821            boolean accept, Message response) {
822        resultSuccess(response, null);
823    }
824
825    /**
826     * response.obj.result is an String[14]
827     * See ril.h for details
828     *
829     * Please note that registration state 4 ("unknown") is treated
830     * as "out of service" above
831     */
832    public void getVoiceRegistrationState (Message result) {
833        String ret[] = new String[14];
834
835        ret[0] = "5"; // registered roam
836        ret[1] = null;
837        ret[2] = null;
838        ret[3] = null;
839        ret[4] = null;
840        ret[5] = null;
841        ret[6] = null;
842        ret[7] = null;
843        ret[8] = null;
844        ret[9] = null;
845        ret[10] = null;
846        ret[11] = null;
847        ret[12] = null;
848        ret[13] = null;
849
850        resultSuccess(result, ret);
851    }
852
853    /**
854     * response.obj.result is an String[4]
855     * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2
856     * response.obj.result[1] is LAC if registered or NULL if not
857     * response.obj.result[2] is CID if registered or NULL if not
858     * response.obj.result[3] indicates the available radio technology, where:
859     *      0 == unknown
860     *      1 == GPRS only
861     *      2 == EDGE
862     *      3 == UMTS
863     *
864     * valid LAC are 0x0000 - 0xffff
865     * valid CID are 0x00000000 - 0xffffffff
866     *
867     * Please note that registration state 4 ("unknown") is treated
868     * as "out of service" in the Android telephony system
869     */
870    public void getDataRegistrationState (Message result) {
871        String ret[] = new String[4];
872
873        ret[0] = "5"; // registered roam
874        ret[1] = null;
875        ret[2] = null;
876        ret[3] = "2";
877
878        resultSuccess(result, ret);
879    }
880
881    /**
882     * response.obj.result is a String[3]
883     * response.obj.result[0] is long alpha or null if unregistered
884     * response.obj.result[1] is short alpha or null if unregistered
885     * response.obj.result[2] is numeric or null if unregistered
886     */
887    public void getOperator(Message result) {
888        String[] ret = new String[3];
889
890        ret[0] = "El Telco Loco";
891        ret[1] = "Telco Loco";
892        ret[2] = "001001";
893
894        resultSuccess(result, ret);
895    }
896
897    /**
898     *  ar.exception carries exception on failure
899     *  ar.userObject contains the original value of result.obj
900     *  ar.result is null on success and failure
901     */
902    public void sendDtmf(char c, Message result) {
903        resultSuccess(result, null);
904    }
905
906    /**
907     *  ar.exception carries exception on failure
908     *  ar.userObject contains the original value of result.obj
909     *  ar.result is null on success and failure
910     */
911    public void startDtmf(char c, Message result) {
912        resultSuccess(result, null);
913    }
914
915    /**
916     *  ar.exception carries exception on failure
917     *  ar.userObject contains the original value of result.obj
918     *  ar.result is null on success and failure
919     */
920    public void stopDtmf(Message result) {
921        resultSuccess(result, null);
922    }
923
924    /**
925     *  ar.exception carries exception on failure
926     *  ar.userObject contains the original value of result.obj
927     *  ar.result is null on success and failure
928     */
929    public void sendBurstDtmf(String dtmfString, int on, int off, Message result) {
930        resultSuccess(result, null);
931    }
932
933    /**
934     * smscPDU is smsc address in PDU form GSM BCD format prefixed
935     *      by a length byte (as expected by TS 27.005) or NULL for default SMSC
936     * pdu is SMS in PDU format as an ASCII hex string
937     *      less the SMSC address
938     */
939    public void sendSMS (String smscPDU, String pdu, Message result) {unimplemented(result);}
940
941    public void deleteSmsOnSim(int index, Message response) {
942        Log.d(LOG_TAG, "Delete message at index " + index);
943        unimplemented(response);
944    }
945
946    public void deleteSmsOnRuim(int index, Message response) {
947        Log.d(LOG_TAG, "Delete RUIM message at index " + index);
948        unimplemented(response);
949    }
950
951    public void writeSmsToSim(int status, String smsc, String pdu, Message response) {
952        Log.d(LOG_TAG, "Write SMS to SIM with status " + status);
953        unimplemented(response);
954    }
955
956    public void writeSmsToRuim(int status, String pdu, Message response) {
957        Log.d(LOG_TAG, "Write SMS to RUIM with status " + status);
958        unimplemented(response);
959    }
960
961    public void setupDataCall(String radioTechnology, String profile,
962            String apn, String user, String password, String authType,
963            String protocol, Message result) {
964        unimplemented(result);
965    }
966
967    public void deactivateDataCall(int cid, int reason, Message result) {unimplemented(result);}
968
969    public void setPreferredNetworkType(int networkType , Message result) {
970        mNetworkType = networkType;
971        resultSuccess(result, null);
972    }
973
974    public void getPreferredNetworkType(Message result) {
975        int ret[] = new int[1];
976
977        ret[0] = mNetworkType;
978        resultSuccess(result, ret);
979    }
980
981    public void getNeighboringCids(Message result) {
982        int ret[] = new int[7];
983
984        ret[0] = 6;
985        for (int i = 1; i<7; i++) {
986            ret[i] = i;
987        }
988        resultSuccess(result, ret);
989    }
990
991    public void setLocationUpdates(boolean enable, Message response) {
992        unimplemented(response);
993    }
994
995    public void getSmscAddress(Message result) {
996        unimplemented(result);
997    }
998
999    public void setSmscAddress(String address, Message result) {
1000        unimplemented(result);
1001    }
1002
1003    public void reportSmsMemoryStatus(boolean available, Message result) {
1004        unimplemented(result);
1005    }
1006
1007    public void reportStkServiceIsRunning(Message result) {
1008        resultSuccess(result, null);
1009    }
1010
1011    @Override
1012    public void getCdmaSubscriptionSource(Message result) {
1013        unimplemented(result);
1014    }
1015
1016    private boolean isSimLocked() {
1017        if (mSimLockedState != SimLockState.NONE) {
1018            return true;
1019        }
1020        return false;
1021    }
1022
1023    public void setRadioPower(boolean on, Message result) {
1024        if(on) {
1025            if (isSimLocked()) {
1026                Log.i("SIM", "[SimCmd] setRadioPower: SIM locked! state=" +
1027                        mSimLockedState);
1028                setRadioState(RadioState.SIM_LOCKED_OR_ABSENT);
1029            }
1030            else {
1031                setRadioState(RadioState.SIM_READY);
1032            }
1033        } else {
1034            setRadioState(RadioState.RADIO_OFF);
1035        }
1036    }
1037
1038
1039    public void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message result) {
1040        unimplemented(result);
1041    }
1042
1043    public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message result) {
1044        unimplemented(result);
1045    }
1046
1047    public void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu,
1048            Message result) {
1049        unimplemented(result);
1050    }
1051
1052    /**
1053     * parameters equivalent to 27.007 AT+CRSM command
1054     * response.obj will be an AsyncResult
1055     * response.obj.userObj will be a SimIoResult on success
1056     */
1057    public void iccIO (int command, int fileid, String path, int p1, int p2,
1058                       int p3, String data, String pin2, Message result) {
1059        unimplemented(result);
1060    }
1061
1062    /**
1063     * (AsyncResult)response.obj).result is an int[] with element [0] set to
1064     * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned".
1065     *
1066     * @param response is callback message
1067     */
1068    public void queryCLIP(Message response) { unimplemented(response); }
1069
1070
1071    /**
1072     * response.obj will be a an int[2]
1073     *
1074     * response.obj[0] will be TS 27.007 +CLIR parameter 'n'
1075     *  0 presentation indicator is used according to the subscription of the CLIR service
1076     *  1 CLIR invocation
1077     *  2 CLIR suppression
1078     *
1079     * response.obj[1] will be TS 27.007 +CLIR parameter 'm'
1080     *  0 CLIR not provisioned
1081     *  1 CLIR provisioned in permanent mode
1082     *  2 unknown (e.g. no network, etc.)
1083     *  3 CLIR temporary mode presentation restricted
1084     *  4 CLIR temporary mode presentation allowed
1085     */
1086
1087    public void getCLIR(Message result) {unimplemented(result);}
1088
1089    /**
1090     * clirMode is one of the CLIR_* constants above
1091     *
1092     * response.obj is null
1093     */
1094
1095    public void setCLIR(int clirMode, Message result) {unimplemented(result);}
1096
1097    /**
1098     * (AsyncResult)response.obj).result is an int[] with element [0] set to
1099     * 0 for disabled, 1 for enabled.
1100     *
1101     * @param serviceClass is a sum of SERVICE_CLASS_*
1102     * @param response is callback message
1103     */
1104
1105    public void queryCallWaiting(int serviceClass, Message response) {
1106        unimplemented(response);
1107    }
1108
1109    /**
1110     * @param enable is true to enable, false to disable
1111     * @param serviceClass is a sum of SERVICE_CLASS_*
1112     * @param response is callback message
1113     */
1114
1115    public void setCallWaiting(boolean enable, int serviceClass,
1116            Message response) {
1117        unimplemented(response);
1118    }
1119
1120    /**
1121     * @param action is one of CF_ACTION_*
1122     * @param cfReason is one of CF_REASON_*
1123     * @param serviceClass is a sum of SERVICE_CLASSS_*
1124     */
1125    public void setCallForward(int action, int cfReason, int serviceClass,
1126            String number, int timeSeconds, Message result) {unimplemented(result);}
1127
1128    /**
1129     * cfReason is one of CF_REASON_*
1130     *
1131     * ((AsyncResult)response.obj).result will be an array of
1132     * CallForwardInfo's
1133     *
1134     * An array of length 0 means "disabled for all codes"
1135     */
1136    public void queryCallForwardStatus(int cfReason, int serviceClass,
1137            String number, Message result) {unimplemented(result);}
1138
1139    public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);}
1140    public void exitEmergencyCallbackMode(Message result) {unimplemented(result);}
1141    public void setNetworkSelectionModeManual(
1142            String operatorNumeric, Message result) {unimplemented(result);}
1143
1144    /**
1145     * Queries whether the current network selection mode is automatic
1146     * or manual
1147     *
1148     * ((AsyncResult)response.obj).result  is an int[] with element [0] being
1149     * a 0 for automatic selection and a 1 for manual selection
1150     */
1151
1152    public void getNetworkSelectionMode(Message result) {
1153        int ret[] = new int[1];
1154
1155        ret[0] = 0;
1156        resultSuccess(result, ret);
1157    }
1158
1159    /**
1160     * Queries the currently available networks
1161     *
1162     * ((AsyncResult)response.obj).result  is a List of NetworkInfo objects
1163     */
1164    public void getAvailableNetworks(Message result) {unimplemented(result);}
1165
1166    public void getBasebandVersion (Message result) {
1167        resultSuccess(result, "SimulatedCommands");
1168    }
1169
1170    /**
1171     * Simulates an incoming USSD message
1172     * @param statusCode  Status code string. See <code>setOnUSSD</code>
1173     * in CommandsInterface.java
1174     * @param message Message text to send or null if none
1175     */
1176    public void triggerIncomingUssd(String statusCode, String message) {
1177        if (mUSSDRegistrant != null) {
1178            String[] result = {statusCode, message};
1179            mUSSDRegistrant.notifyResult(result);
1180        }
1181    }
1182
1183
1184    public void sendUSSD (String ussdString, Message result) {
1185
1186        // We simulate this particular sequence
1187        if (ussdString.equals("#646#")) {
1188            resultSuccess(result, null);
1189
1190            // 0 == USSD-Notify
1191            triggerIncomingUssd("0", "You have NNN minutes remaining.");
1192        } else {
1193            resultSuccess(result, null);
1194
1195            triggerIncomingUssd("0", "All Done");
1196        }
1197    }
1198
1199    // inherited javadoc suffices
1200    public void cancelPendingUssd (Message response) {
1201        resultSuccess(response, null);
1202    }
1203
1204
1205    public void resetRadio(Message result) {
1206        unimplemented(result);
1207    }
1208
1209    public void invokeOemRilRequestRaw(byte[] data, Message response) {
1210        // Just echo back data
1211        if (response != null) {
1212            AsyncResult.forMessage(response).result = data;
1213            response.sendToTarget();
1214        }
1215    }
1216
1217    public void invokeOemRilRequestStrings(String[] strings, Message response) {
1218        // Just echo back data
1219        if (response != null) {
1220            AsyncResult.forMessage(response).result = strings;
1221            response.sendToTarget();
1222        }
1223    }
1224
1225    //***** SimulatedRadioControl
1226
1227
1228    /** Start the simulated phone ringing */
1229    public void
1230    triggerRing(String number) {
1231        simulatedCallState.triggerRing(number);
1232        mCallStateRegistrants.notifyRegistrants();
1233    }
1234
1235    public void
1236    progressConnectingCallState() {
1237        simulatedCallState.progressConnectingCallState();
1238        mCallStateRegistrants.notifyRegistrants();
1239    }
1240
1241    /** If a call is DIALING or ALERTING, progress it all the way to ACTIVE */
1242    public void
1243    progressConnectingToActive() {
1244        simulatedCallState.progressConnectingToActive();
1245        mCallStateRegistrants.notifyRegistrants();
1246    }
1247
1248    /** automatically progress mobile originated calls to ACTIVE.
1249     *  default to true
1250     */
1251    public void
1252    setAutoProgressConnectingCall(boolean b) {
1253        simulatedCallState.setAutoProgressConnectingCall(b);
1254    }
1255
1256    public void
1257    setNextDialFailImmediately(boolean b) {
1258        simulatedCallState.setNextDialFailImmediately(b);
1259    }
1260
1261    public void
1262    setNextCallFailCause(int gsmCause) {
1263        nextCallFailCause = gsmCause;
1264    }
1265
1266    public void
1267    triggerHangupForeground() {
1268        simulatedCallState.triggerHangupForeground();
1269        mCallStateRegistrants.notifyRegistrants();
1270    }
1271
1272    /** hangup holding calls */
1273    public void
1274    triggerHangupBackground() {
1275        simulatedCallState.triggerHangupBackground();
1276        mCallStateRegistrants.notifyRegistrants();
1277    }
1278
1279    public void triggerSsn(int type, int code) {
1280        SuppServiceNotification not = new SuppServiceNotification();
1281        not.notificationType = type;
1282        not.code = code;
1283        mSsnRegistrant.notifyRegistrant(new AsyncResult(null, not, null));
1284    }
1285
1286    public void
1287    shutdown() {
1288        setRadioState(RadioState.RADIO_UNAVAILABLE);
1289        Looper looper = mHandlerThread.getLooper();
1290        if (looper != null) {
1291            looper.quit();
1292        }
1293    }
1294
1295    /** hangup all */
1296
1297    public void
1298    triggerHangupAll() {
1299        simulatedCallState.triggerHangupAll();
1300        mCallStateRegistrants.notifyRegistrants();
1301    }
1302
1303    public void
1304    triggerIncomingSMS(String message) {
1305        //TODO
1306    }
1307
1308    public void
1309    pauseResponses() {
1310        pausedResponseCount++;
1311    }
1312
1313    public void
1314    resumeResponses() {
1315        pausedResponseCount--;
1316
1317        if (pausedResponseCount == 0) {
1318            for (int i = 0, s = pausedResponses.size(); i < s ; i++) {
1319                pausedResponses.get(i).sendToTarget();
1320            }
1321            pausedResponses.clear();
1322        } else {
1323            Log.e("GSM", "SimulatedCommands.resumeResponses < 0");
1324        }
1325    }
1326
1327    //***** Private Methods
1328
1329    private void unimplemented(Message result) {
1330        if (result != null) {
1331            AsyncResult.forMessage(result).exception
1332                = new RuntimeException("Unimplemented");
1333
1334            if (pausedResponseCount > 0) {
1335                pausedResponses.add(result);
1336            } else {
1337                result.sendToTarget();
1338            }
1339        }
1340    }
1341
1342    private void resultSuccess(Message result, Object ret) {
1343        if (result != null) {
1344            AsyncResult.forMessage(result).result = ret;
1345            if (pausedResponseCount > 0) {
1346                pausedResponses.add(result);
1347            } else {
1348                result.sendToTarget();
1349            }
1350        }
1351    }
1352
1353    private void resultFail(Message result, Throwable tr) {
1354        if (result != null) {
1355            AsyncResult.forMessage(result).exception = tr;
1356            if (pausedResponseCount > 0) {
1357                pausedResponses.add(result);
1358            } else {
1359                result.sendToTarget();
1360            }
1361        }
1362    }
1363
1364    // ***** Methods for CDMA support
1365    public void
1366    getDeviceIdentity(Message response) {
1367        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1368        unimplemented(response);
1369    }
1370
1371    public void
1372    getCDMASubscription(Message response) {
1373        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1374        unimplemented(response);
1375    }
1376
1377    public void
1378    setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response) {
1379        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1380        unimplemented(response);
1381    }
1382
1383    public void queryCdmaRoamingPreference(Message response) {
1384        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1385        unimplemented(response);
1386    }
1387
1388    public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
1389        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1390        unimplemented(response);
1391    }
1392
1393    public void
1394    setPhoneType(int phoneType) {
1395        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1396    }
1397
1398    public void getPreferredVoicePrivacy(Message result) {
1399        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1400        unimplemented(result);
1401    }
1402
1403    public void setPreferredVoicePrivacy(boolean enable, Message result) {
1404        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1405        unimplemented(result);
1406    }
1407
1408    /**
1409     *  Set the TTY mode
1410     *
1411     * @param ttyMode is one of the following:
1412     * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
1413     * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
1414     * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
1415     * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
1416     * @param response is callback message
1417     */
1418    public void setTTYMode(int ttyMode, Message response) {
1419        Log.w(LOG_TAG, "Not implemented in SimulatedCommands");
1420        unimplemented(response);
1421    }
1422
1423    /**
1424     *  Query the TTY mode
1425     * (AsyncResult)response.obj).result is an int[] with element [0] set to
1426     * tty mode:
1427     * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
1428     * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
1429     * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
1430     * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
1431     * @param response is callback message
1432     */
1433    public void queryTTYMode(Message response) {
1434        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1435        unimplemented(response);
1436    }
1437
1438    /**
1439     * {@inheritDoc}
1440     */
1441    public void sendCDMAFeatureCode(String FeatureCode, Message response) {
1442        Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1443        unimplemented(response);
1444    }
1445
1446    /**
1447     * {@inheritDoc}
1448     */
1449    public void sendCdmaSms(byte[] pdu, Message response){
1450       Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
1451    }
1452
1453    public void setCdmaBroadcastActivation(boolean activate, Message response) {
1454        unimplemented(response);
1455
1456    }
1457
1458    public void getCdmaBroadcastConfig(Message response) {
1459        unimplemented(response);
1460
1461    }
1462
1463    public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) {
1464        unimplemented(response);
1465
1466    }
1467
1468    public void forceDataDormancy(Message response) {
1469        unimplemented(response);
1470    }
1471
1472
1473    public void setGsmBroadcastActivation(boolean activate, Message response) {
1474        unimplemented(response);
1475    }
1476
1477
1478    public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) {
1479        unimplemented(response);
1480    }
1481
1482    public void getGsmBroadcastConfig(Message response) {
1483        unimplemented(response);
1484    }
1485
1486    @Override
1487    public void supplyIccPinForApp(String pin, String aid, Message response) {
1488        unimplemented(response);
1489    }
1490
1491    @Override
1492    public void supplyIccPukForApp(String puk, String newPin, String aid, Message response) {
1493        unimplemented(response);
1494    }
1495
1496    @Override
1497    public void supplyIccPin2ForApp(String pin2, String aid, Message response) {
1498        unimplemented(response);
1499    }
1500
1501    @Override
1502    public void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message response) {
1503        unimplemented(response);
1504    }
1505
1506    @Override
1507    public void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message response) {
1508        unimplemented(response);
1509    }
1510
1511    @Override
1512    public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr,
1513            Message response) {
1514        unimplemented(response);
1515    }
1516
1517    public void requestIsimAuthentication(String nonce, Message response) {
1518        unimplemented(response);
1519    }
1520}
1521