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.internal.telephony;
18
19import java.util.ArrayList;
20import java.util.Random;
21
22import android.content.Context;
23import android.content.Intent;
24import android.os.AsyncResult;
25import android.os.Handler;
26import android.os.Message;
27import android.os.PowerManager;
28import android.os.PowerManager.WakeLock;
29import android.telephony.RadioAccessFamily;
30import android.telephony.Rlog;
31import android.telephony.TelephonyManager;
32
33import com.android.internal.telephony.CommandsInterface;
34import com.android.internal.telephony.Phone;
35import com.android.internal.telephony.PhoneBase;
36import com.android.internal.telephony.PhoneProxy;
37import com.android.internal.telephony.dataconnection.DctController;
38import com.android.internal.telephony.RadioCapability;
39import com.android.internal.telephony.uicc.UiccController;
40import com.android.internal.telephony.TelephonyIntents;
41
42import java.io.FileDescriptor;
43import java.io.PrintWriter;
44import java.util.concurrent.atomic.AtomicInteger;
45
46public class ProxyController {
47    static final String LOG_TAG = "ProxyController";
48
49    private static final int EVENT_NOTIFICATION_RC_CHANGED        = 1;
50    private static final int EVENT_START_RC_RESPONSE        = 2;
51    private static final int EVENT_APPLY_RC_RESPONSE        = 3;
52    private static final int EVENT_FINISH_RC_RESPONSE       = 4;
53
54    private static final int SET_RC_STATUS_IDLE             = 0;
55    private static final int SET_RC_STATUS_STARTING         = 1;
56    private static final int SET_RC_STATUS_STARTED          = 2;
57    private static final int SET_RC_STATUS_APPLYING         = 3;
58    private static final int SET_RC_STATUS_SUCCESS          = 4;
59    private static final int SET_RC_STATUS_FAIL             = 5;
60
61    // The entire transaction must complete within this amount of time
62    // or a FINISH will be issued to each Logical Modem with the old
63    // Radio Access Family.
64    private static final int SET_RC_TIMEOUT_WAITING_MSEC    = (45 * 1000);
65
66    //***** Class Variables
67    private static ProxyController sProxyController;
68
69    private PhoneProxy[] mProxyPhones;
70
71    private UiccController mUiccController;
72
73    private CommandsInterface[] mCi;
74
75    private Context mContext;
76
77    private DctController mDctController;
78
79    //UiccPhoneBookController to use proper IccPhoneBookInterfaceManagerProxy object
80    private UiccPhoneBookController mUiccPhoneBookController;
81
82    //PhoneSubInfoController to use proper PhoneSubInfoProxy object
83    private PhoneSubInfoController mPhoneSubInfoController;
84
85    //UiccSmsController to use proper IccSmsInterfaceManager object
86    private UiccSmsController mUiccSmsController;
87
88    WakeLock mWakeLock;
89
90    // record each phone's set radio capability status
91    private int[] mSetRadioAccessFamilyStatus;
92    private int mRadioAccessFamilyStatusCounter;
93
94    private String[] mLogicalModemIds;
95
96    // Allows the generation of unique Id's for radio capability request session  id
97    private AtomicInteger mUniqueIdGenerator = new AtomicInteger(new Random().nextInt());
98
99    // on-going radio capability request session id
100    private int mRadioCapabilitySessionId;
101
102    // Record new and old Radio Access Family (raf) configuration.
103    // The old raf configuration is used to restore each logical modem raf when FINISH is
104    // issued if any requests fail.
105    private int[] mNewRadioAccessFamily;
106    private int[] mOldRadioAccessFamily;
107
108    // runnable for radio capability request timeout handling
109    RadioCapabilityRunnable mSetRadioCapabilityRunnable;
110
111    //***** Class Methods
112    public static ProxyController getInstance(Context context, PhoneProxy[] phoneProxy,
113            UiccController uiccController, CommandsInterface[] ci) {
114        if (sProxyController == null) {
115            sProxyController = new ProxyController(context, phoneProxy, uiccController, ci);
116        }
117        return sProxyController;
118    }
119
120    public static ProxyController getInstance() {
121        return sProxyController;
122    }
123
124    private ProxyController(Context context, PhoneProxy[] phoneProxy, UiccController uiccController,
125            CommandsInterface[] ci) {
126        logd("Constructor - Enter");
127
128        mContext = context;
129        mProxyPhones = phoneProxy;
130        mUiccController = uiccController;
131        mCi = ci;
132
133        mDctController = DctController.makeDctController(phoneProxy);
134        mUiccPhoneBookController = new UiccPhoneBookController(mProxyPhones);
135        mPhoneSubInfoController = new PhoneSubInfoController(mProxyPhones);
136        mUiccSmsController = new UiccSmsController(mProxyPhones);
137        mSetRadioAccessFamilyStatus = new int[mProxyPhones.length];
138        mNewRadioAccessFamily = new int[mProxyPhones.length];
139        mOldRadioAccessFamily = new int[mProxyPhones.length];
140        mLogicalModemIds = new String[mProxyPhones.length];
141
142        // TODO Get logical modem ids assume its just the phoneId as a string for now
143        for (int i = 0; i < mProxyPhones.length; i++) {
144            mLogicalModemIds[i] = Integer.toString(i);
145        }
146
147        mSetRadioCapabilityRunnable = new RadioCapabilityRunnable();
148
149        // wake lock for set radio capability
150        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
151        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
152        mWakeLock.setReferenceCounted(false);
153
154        // Clear to be sure we're in the initial state
155        clearTransaction();
156        for (int i = 0; i < mProxyPhones.length; i++) {
157            mProxyPhones[i].registerForRadioCapabilityChanged(
158                    mHandler, EVENT_NOTIFICATION_RC_CHANGED, null);
159        }
160        logd("Constructor - Exit");
161    }
162
163    public void updateDataConnectionTracker(int sub) {
164        mProxyPhones[sub].updateDataConnectionTracker();
165    }
166
167    public void enableDataConnectivity(int sub) {
168        mProxyPhones[sub].setInternalDataEnabled(true);
169    }
170
171    public void disableDataConnectivity(int sub,
172            Message dataCleanedUpMsg) {
173        mProxyPhones[sub].setInternalDataEnabled(false, dataCleanedUpMsg);
174    }
175
176    public void updateCurrentCarrierInProvider(int sub) {
177        mProxyPhones[sub].updateCurrentCarrierInProvider();
178    }
179
180    public void registerForAllDataDisconnected(int subId, Handler h, int what, Object obj) {
181        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
182
183        if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
184            mProxyPhones[phoneId].registerForAllDataDisconnected(h, what, obj);
185        }
186    }
187
188    public void unregisterForAllDataDisconnected(int subId, Handler h) {
189        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
190
191        if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
192            mProxyPhones[phoneId].unregisterForAllDataDisconnected(h);
193        }
194    }
195
196    public boolean isDataDisconnected(int subId) {
197        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
198
199        if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
200            Phone activePhone = mProxyPhones[phoneId].getActivePhone();
201            return ((PhoneBase) activePhone).mDcTracker.isDisconnected();
202        } else {
203            return false;
204        }
205    }
206
207    /**
208     * Get phone radio type and access technology.
209     *
210     * @param phoneId which phone you want to get
211     * @return phone radio type and access technology for input phone ID
212     */
213    public int getRadioAccessFamily(int phoneId) {
214        if (phoneId >= mProxyPhones.length) {
215            return RadioAccessFamily.RAF_UNKNOWN;
216        } else {
217            return mProxyPhones[phoneId].getRadioAccessFamily();
218        }
219    }
220
221    /**
222     * Set phone radio type and access technology for each phone.
223     *
224     * @param rafs an RadioAccessFamily array to indicate all phone's
225     *        new radio access family. The length of RadioAccessFamily
226     *        must equal to phone count.
227     * @return false if another session is already active and the request is rejected.
228     */
229    public boolean setRadioCapability(RadioAccessFamily[] rafs) {
230        if (rafs.length != mProxyPhones.length) {
231            throw new RuntimeException("Length of input rafs must equal to total phone count");
232        }
233
234        // Check if there is any ongoing transaction and throw an exception if there
235        // is one as this is a programming error.
236        synchronized (mSetRadioAccessFamilyStatus) {
237            for (int i = 0; i < mProxyPhones.length; i++) {
238                logd("setRadioCapability: mSetRadioAccessFamilyStatus[" + i + "]="
239                        + mSetRadioAccessFamilyStatus[i]);
240                if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_IDLE) {
241                    // TODO: The right behaviour is to cancel previous request and send this.
242                    loge("setRadioCapability: Phone[" + i + "] is not idle. Rejecting request.");
243                    return false;
244                }
245            }
246        }
247
248        // Clear to be sure we're in the initial state
249        clearTransaction();
250
251        // A new sessionId for this transaction
252        mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement();
253
254        // Keep a wake lock until we finish radio capability changed
255        mWakeLock.acquire();
256
257        // Start timer to make sure all phones respond within a specific time interval.
258        // Will send FINISH if a timeout occurs.
259        mSetRadioCapabilityRunnable.setTimeoutState(mRadioCapabilitySessionId);
260        mHandler.postDelayed(mSetRadioCapabilityRunnable, SET_RC_TIMEOUT_WAITING_MSEC);
261
262        synchronized (mSetRadioAccessFamilyStatus) {
263            logd("setRadioCapability: new request session id=" + mRadioCapabilitySessionId);
264            mRadioAccessFamilyStatusCounter = rafs.length;
265            for (int i = 0; i < rafs.length; i++) {
266                int phoneId = rafs[i].getPhoneId();
267                logd("setRadioCapability: phoneId=" + phoneId + " status=STARTING");
268                mSetRadioAccessFamilyStatus[phoneId] = SET_RC_STATUS_STARTING;
269                mOldRadioAccessFamily[phoneId] = mProxyPhones[phoneId].getRadioAccessFamily();
270                int requestedRaf = rafs[i].getRadioAccessFamily();
271                // TODO Set the new radio access family to the maximum of the requested & supported
272                // int supportedRaf = mProxyPhones[i].getSupportedRadioAccessFamily();
273                // mNewRadioAccessFamily[phoneId] = requestedRaf & supportedRaf;
274                mNewRadioAccessFamily[phoneId] = requestedRaf;
275                logd("setRadioCapability: mOldRadioAccessFamily[" + phoneId + "]="
276                        + mOldRadioAccessFamily[phoneId]);
277                logd("setRadioCapability: mNewRadioAccessFamily[" + phoneId + "]="
278                        + mNewRadioAccessFamily[phoneId]);
279                sendRadioCapabilityRequest(
280                        phoneId,
281                        mRadioCapabilitySessionId,
282                        RadioCapability.RC_PHASE_START,
283                        mOldRadioAccessFamily[phoneId],
284                        mLogicalModemIds[phoneId],
285                        RadioCapability.RC_STATUS_NONE,
286                        EVENT_START_RC_RESPONSE);
287            }
288        }
289
290        return true;
291    }
292
293    private Handler mHandler = new Handler() {
294        @Override
295        public void handleMessage(Message msg) {
296            logd("handleMessage msg.what=" + msg.what);
297            switch (msg.what) {
298                case EVENT_START_RC_RESPONSE:
299                    onStartRadioCapabilityResponse(msg);
300                    break;
301
302                case EVENT_APPLY_RC_RESPONSE:
303                    onApplyRadioCapabilityResponse(msg);
304                    break;
305
306                case EVENT_NOTIFICATION_RC_CHANGED:
307                    onNotificationRadioCapabilityChanged(msg);
308                    break;
309
310                case EVENT_FINISH_RC_RESPONSE:
311                    onFinishRadioCapabilityResponse(msg);
312                    break;
313
314                default:
315                    break;
316            }
317        }
318    };
319
320    /**
321     * Handle START response
322     * @param msg obj field isa RadioCapability
323     */
324    private void onStartRadioCapabilityResponse(Message msg) {
325        synchronized (mSetRadioAccessFamilyStatus) {
326            RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
327            if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
328                logd("onStartRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId
329                        + " rc=" + rc);
330                return;
331            }
332            mRadioAccessFamilyStatusCounter--;
333            int id = rc.getPhoneId();
334            if (((AsyncResult) msg.obj).exception != null) {
335                logd("onStartRadioCapabilityResponse: Error response session=" + rc.getSession());
336                logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=FAIL");
337                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
338            } else {
339                logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=STARTED");
340                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED;
341            }
342
343            if (mRadioAccessFamilyStatusCounter == 0) {
344                resetRadioAccessFamilyStatusCounter();
345                boolean success = checkAllRadioCapabilitySuccess();
346                logd("onStartRadioCapabilityResponse: success=" + success);
347                if (!success) {
348                    issueFinish(RadioCapability.RC_STATUS_FAIL,
349                            mRadioCapabilitySessionId);
350                } else {
351                    // All logical modem accepted the new radio access family, issue the APPLY
352                    for (int i = 0; i < mProxyPhones.length; i++) {
353                        sendRadioCapabilityRequest(
354                            i,
355                            mRadioCapabilitySessionId,
356                            RadioCapability.RC_PHASE_APPLY,
357                            mNewRadioAccessFamily[i],
358                            mLogicalModemIds[i],
359                            RadioCapability.RC_STATUS_NONE,
360                            EVENT_APPLY_RC_RESPONSE);
361
362                        logd("onStartRadioCapabilityResponse: phoneId=" + i + " status=APPLYING");
363                        mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_APPLYING;
364                    }
365                }
366            }
367        }
368    }
369
370    /**
371     * Handle APPLY response
372     * @param msg obj field isa RadioCapability
373     */
374    private void onApplyRadioCapabilityResponse(Message msg) {
375        RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
376        if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
377            logd("onApplyRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId
378                    + " rc=" + rc);
379            return;
380        }
381        logd("onApplyRadioCapabilityResponse: rc=" + rc);
382        if (((AsyncResult) msg.obj).exception != null) {
383            synchronized (mSetRadioAccessFamilyStatus) {
384                logd("onApplyRadioCapabilityResponse: Error response session=" + rc.getSession());
385                int id = rc.getPhoneId();
386                logd("onApplyRadioCapabilityResponse: phoneId=" + id + " status=FAIL");
387                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
388            }
389        } else {
390            logd("onApplyRadioCapabilityResponse: Valid start expecting notification rc=" + rc);
391        }
392    }
393
394    /**
395     * Handle the notification unsolicited response associated with the APPLY
396     * @param msg obj field isa RadioCapability
397     */
398    private void onNotificationRadioCapabilityChanged(Message msg) {
399        RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
400        if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
401            logd("onNotificationRadioCapabilityChanged: Ignore session=" + mRadioCapabilitySessionId
402                    + " rc=" + rc);
403            return;
404        }
405        synchronized (mSetRadioAccessFamilyStatus) {
406            logd("onNotificationRadioCapabilityChanged: rc=" + rc);
407            // skip the overdue response by checking sessionId
408            if (rc.getSession() != mRadioCapabilitySessionId) {
409                logd("onNotificationRadioCapabilityChanged: Ignore session="
410                        + mRadioCapabilitySessionId + " rc=" + rc);
411                return;
412            }
413
414            int id = rc.getPhoneId();
415            if ((((AsyncResult) msg.obj).exception != null) ||
416                    (rc.getStatus() == RadioCapability.RC_STATUS_FAIL)) {
417                logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=FAIL");
418                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
419            } else {
420                logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=SUCCESS");
421                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS;
422            }
423
424            mRadioAccessFamilyStatusCounter--;
425            if (mRadioAccessFamilyStatusCounter == 0) {
426                logd("onNotificationRadioCapabilityChanged: removing callback from handler");
427                mHandler.removeCallbacks(mSetRadioCapabilityRunnable);
428                resetRadioAccessFamilyStatusCounter();
429                boolean success = checkAllRadioCapabilitySuccess();
430                logd("onNotificationRadioCapabilityChanged: APPLY URC success=" + success);
431                int status;
432                if (success) {
433                    status = RadioCapability.RC_STATUS_SUCCESS;
434                } else {
435                    status = RadioCapability.RC_STATUS_FAIL;
436                }
437                issueFinish(status, mRadioCapabilitySessionId);
438            }
439        }
440    }
441
442    /**
443     * Handle the FINISH Phase response
444     * @param msg obj field isa RadioCapability
445     */
446    void onFinishRadioCapabilityResponse(Message msg) {
447        RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
448        if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
449            logd("onFinishRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId
450                    + " rc=" + rc);
451            return;
452        }
453        synchronized (mSetRadioAccessFamilyStatus) {
454            logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter="
455                    + mRadioAccessFamilyStatusCounter);
456            mRadioAccessFamilyStatusCounter--;
457            if (mRadioAccessFamilyStatusCounter == 0) {
458                completeRadioCapabilityTransaction();
459            }
460        }
461    }
462
463    private void issueFinish(int status, int sessionId) {
464        // Issue FINISH
465        synchronized(mSetRadioAccessFamilyStatus) {
466            for (int i = 0; i < mProxyPhones.length; i++) {
467                if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_FAIL) {
468                    logd("issueFinish: phoneId=" + i + " sessionId=" + sessionId
469                            + " status=" + status);
470                    sendRadioCapabilityRequest(
471                        i,
472                        sessionId,
473                        RadioCapability.RC_PHASE_FINISH,
474                        mOldRadioAccessFamily[i],
475                        mLogicalModemIds[i],
476                        status,
477                        EVENT_FINISH_RC_RESPONSE);
478                    if (status == RadioCapability.RC_STATUS_FAIL) {
479                        logd("issueFinish: phoneId: " + i + " status: FAIL");
480                        // At least one failed, mark them all failed.
481                        mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_FAIL;
482                    }
483                } else {
484                    logd("issueFinish: Ignore already FAIL, Phone" + i + " sessionId=" + sessionId
485                            + " status=" + status);
486                }
487            }
488        }
489    }
490
491    private void completeRadioCapabilityTransaction() {
492        // Create the intent to broadcast
493        Intent intent;
494        boolean success = checkAllRadioCapabilitySuccess();
495        logd("onFinishRadioCapabilityResponse: success=" + success);
496        if (success) {
497            ArrayList<RadioAccessFamily> phoneRAFList = new ArrayList<RadioAccessFamily>();
498            for (int i = 0; i < mProxyPhones.length; i++) {
499                int raf = mProxyPhones[i].getRadioAccessFamily();
500                logd("radioAccessFamily[" + i + "]=" + raf);
501                RadioAccessFamily phoneRC = new RadioAccessFamily(i, raf);
502                phoneRAFList.add(phoneRC);
503            }
504            intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_DONE);
505            intent.putParcelableArrayListExtra(TelephonyIntents.EXTRA_RADIO_ACCESS_FAMILY,
506                    phoneRAFList);
507        } else {
508            intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED);
509        }
510
511        // Reinitialize
512        clearTransaction();
513
514        // Broadcast that we're done
515        mContext.sendBroadcast(intent);
516    }
517
518    // Clear this transaction
519    private void clearTransaction() {
520        logd("clearTransaction");
521        synchronized(mSetRadioAccessFamilyStatus) {
522            for (int i = 0; i < mProxyPhones.length; i++) {
523                logd("clearTransaction: phoneId=" + i + " status=IDLE");
524                mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_IDLE;
525                mOldRadioAccessFamily[i] = 0;
526                mNewRadioAccessFamily[i] = 0;
527            }
528
529            if (mWakeLock.isHeld()) {
530                mWakeLock.release();
531            }
532        }
533    }
534
535    private boolean checkAllRadioCapabilitySuccess() {
536        synchronized(mSetRadioAccessFamilyStatus) {
537            for (int i = 0; i < mProxyPhones.length; i++) {
538                if (mSetRadioAccessFamilyStatus[i] == SET_RC_STATUS_FAIL) {
539                    return false;
540                }
541            }
542            return true;
543        }
544    }
545
546    private void resetRadioAccessFamilyStatusCounter() {
547        mRadioAccessFamilyStatusCounter = mProxyPhones.length;
548    }
549
550    private void sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase,
551            int radioFamily, String logicalModemId, int status, int eventId) {
552        RadioCapability requestRC = new RadioCapability(
553                phoneId, sessionId, rcPhase, radioFamily, logicalModemId, status);
554        mProxyPhones[phoneId].setRadioCapability(
555                requestRC, mHandler.obtainMessage(eventId));
556    }
557
558    /**
559     * RadioCapabilityRunnable is used to check
560     * if radio capability request's response is out of date.
561     * <p>
562     * Note that the setRadioCapability will be stopped directly and send FINISH
563     * with fail status to all logical modems. and send out fail intent
564     *
565     */
566    private class RadioCapabilityRunnable implements Runnable {
567        private int mSessionId;
568        public  RadioCapabilityRunnable() {
569        }
570
571        public void setTimeoutState(int sessionId) {
572            mSessionId = sessionId;
573        }
574
575        @Override
576        public void run() {
577            if (mSessionId != mRadioCapabilitySessionId) {
578                logd("RadioCapability timeout: Ignore mSessionId=" + mSessionId
579                       + "!= mRadioCapabilitySessionId=" + mRadioCapabilitySessionId);
580                return;
581            }
582
583            synchronized(mSetRadioAccessFamilyStatus) {
584                for (int i = 0; i < mProxyPhones.length; i++) {
585                    logd("RadioCapability timeout: mSetRadioAccessFamilyStatus[" + i + "]=" +
586                            mSetRadioAccessFamilyStatus[i]);
587                }
588
589                // Increment the sessionId as we are completing the transaction below
590                // so we don't want it completed when the FINISH phase is done.
591                int uniqueDifferentId = mUniqueIdGenerator.getAndIncrement();
592
593                // send FINISH request with fail status and then uniqueDifferentId
594                issueFinish(RadioCapability.RC_STATUS_FAIL,
595                        uniqueDifferentId);
596                completeRadioCapabilityTransaction();
597            }
598        }
599    }
600
601    private void logd(String string) {
602        Rlog.d(LOG_TAG, string);
603    }
604
605    private void loge(String string) {
606        Rlog.e(LOG_TAG, string);
607    }
608
609    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
610        try {
611            mDctController.dump(fd, pw, args);
612        } catch (Exception e) {
613            e.printStackTrace();
614        }
615    }
616}
617