1a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville/*
22b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * Copyright (C) 2013 The Android Open Source Project
3a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville *
42b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
52b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * you may not use this file except in compliance with the License.
62b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * You may obtain a copy of the License at
7a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville *
82b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
92b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville *
102b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * Unless required by applicable law or agreed to in writing, software
112b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
122b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * See the License for the specific language governing permissions and
142b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville * limitations under the License.
15a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville */
16a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
17a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savillepackage com.android.internal.telephony;
18a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
192b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport java.util.ArrayList;
202b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport java.util.Random;
212b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
22a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport android.content.Context;
232b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport android.content.Intent;
242b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport android.os.AsyncResult;
25a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport android.os.Handler;
26a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport android.os.Message;
272b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport android.os.PowerManager;
282b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport android.os.PowerManager.WakeLock;
292b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport android.telephony.RadioAccessFamily;
30a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport android.telephony.Rlog;
31a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport android.telephony.TelephonyManager;
32a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
33a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.CommandsInterface;
34a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.Phone;
35a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.PhoneBase;
36a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.PhoneProxy;
37a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.dataconnection.DctController;
382b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport com.android.internal.telephony.RadioCapability;
39a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.uicc.UiccController;
402b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport com.android.internal.telephony.TelephonyIntents;
41a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
42e97be3971cb6b55e019433c32524cc60ce0d037bWink Savilleimport java.io.FileDescriptor;
43e97be3971cb6b55e019433c32524cc60ce0d037bWink Savilleimport java.io.PrintWriter;
442b40e6226b4b71408964bca46f0a9f256cd4f523Wink Savilleimport java.util.concurrent.atomic.AtomicInteger;
45e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville
46a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savillepublic class ProxyController {
47a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    static final String LOG_TAG = "ProxyController";
48a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
492b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int EVENT_NOTIFICATION_RC_CHANGED        = 1;
502b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int EVENT_START_RC_RESPONSE        = 2;
512b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int EVENT_APPLY_RC_RESPONSE        = 3;
522b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int EVENT_FINISH_RC_RESPONSE       = 4;
532b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
542b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int SET_RC_STATUS_IDLE             = 0;
552b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int SET_RC_STATUS_STARTING         = 1;
562b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int SET_RC_STATUS_STARTED          = 2;
572b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int SET_RC_STATUS_APPLYING         = 3;
582b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int SET_RC_STATUS_SUCCESS          = 4;
592b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int SET_RC_STATUS_FAIL             = 5;
602b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
612b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // The entire transaction must complete within this amount of time
622b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // or a FINISH will be issued to each Logical Modem with the old
632b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // Radio Access Family.
642b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private static final int SET_RC_TIMEOUT_WAITING_MSEC    = (45 * 1000);
652b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
66a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    //***** Class Variables
67a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private static ProxyController sProxyController;
68a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
692b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private PhoneProxy[] mProxyPhones;
70a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
71a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private UiccController mUiccController;
72a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
73a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private CommandsInterface[] mCi;
74a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
75a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private Context mContext;
76a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
77e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville    private DctController mDctController;
78a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
79a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    //UiccPhoneBookController to use proper IccPhoneBookInterfaceManagerProxy object
80a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private UiccPhoneBookController mUiccPhoneBookController;
81a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
82a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    //PhoneSubInfoController to use proper PhoneSubInfoProxy object
83a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private PhoneSubInfoController mPhoneSubInfoController;
84a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
85a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    //UiccSmsController to use proper IccSmsInterfaceManager object
86a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private UiccSmsController mUiccSmsController;
87a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
882b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    WakeLock mWakeLock;
892b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
902b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // record each phone's set radio capability status
912b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private int[] mSetRadioAccessFamilyStatus;
922b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private int mRadioAccessFamilyStatusCounter;
932b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
942b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private String[] mLogicalModemIds;
952b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
962b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // Allows the generation of unique Id's for radio capability request session  id
972b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private AtomicInteger mUniqueIdGenerator = new AtomicInteger(new Random().nextInt());
982b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
992b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // on-going radio capability request session id
1002b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private int mRadioCapabilitySessionId;
1012b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1022b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // Record new and old Radio Access Family (raf) configuration.
1032b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // The old raf configuration is used to restore each logical modem raf when FINISH is
1042b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // issued if any requests fail.
1052b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private int[] mNewRadioAccessFamily;
1062b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private int[] mOldRadioAccessFamily;
1072b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1082b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // runnable for radio capability request timeout handling
1092b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    RadioCapabilityRunnable mSetRadioCapabilityRunnable;
1102b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
111a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    //***** Class Methods
1122b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    public static ProxyController getInstance(Context context, PhoneProxy[] phoneProxy,
113a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            UiccController uiccController, CommandsInterface[] ci) {
114a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (sProxyController == null) {
115a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            sProxyController = new ProxyController(context, phoneProxy, uiccController, ci);
116a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
117a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        return sProxyController;
118a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
119a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
1204e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott    public static ProxyController getInstance() {
121a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        return sProxyController;
122a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
123a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
1242b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private ProxyController(Context context, PhoneProxy[] phoneProxy, UiccController uiccController,
125a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            CommandsInterface[] ci) {
126a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        logd("Constructor - Enter");
127a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
128a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mContext = context;
129a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mProxyPhones = phoneProxy;
130a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mUiccController = uiccController;
131a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mCi = ci;
132a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
1332b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mDctController = DctController.makeDctController(phoneProxy);
134a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mUiccPhoneBookController = new UiccPhoneBookController(mProxyPhones);
135a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mPhoneSubInfoController = new PhoneSubInfoController(mProxyPhones);
136a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mUiccSmsController = new UiccSmsController(mProxyPhones);
1372b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mSetRadioAccessFamilyStatus = new int[mProxyPhones.length];
1382b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mNewRadioAccessFamily = new int[mProxyPhones.length];
1392b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mOldRadioAccessFamily = new int[mProxyPhones.length];
1402b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mLogicalModemIds = new String[mProxyPhones.length];
1412b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1422b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // TODO Get logical modem ids assume its just the phoneId as a string for now
1432b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        for (int i = 0; i < mProxyPhones.length; i++) {
1442b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mLogicalModemIds[i] = Integer.toString(i);
1452b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
1462b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1472b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mSetRadioCapabilityRunnable = new RadioCapabilityRunnable();
1482b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1492b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // wake lock for set radio capability
1502b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
1512b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
1522b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mWakeLock.setReferenceCounted(false);
1532b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1542b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Clear to be sure we're in the initial state
1552b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        clearTransaction();
1564e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott        for (int i = 0; i < mProxyPhones.length; i++) {
1574e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott            mProxyPhones[i].registerForRadioCapabilityChanged(
1584e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                    mHandler, EVENT_NOTIFICATION_RC_CHANGED, null);
1594e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott        }
160a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        logd("Constructor - Exit");
161a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
162a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
1632b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    public void updateDataConnectionTracker(int sub) {
1642b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mProxyPhones[sub].updateDataConnectionTracker();
1652b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
1662b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1672b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    public void enableDataConnectivity(int sub) {
1682b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mProxyPhones[sub].setInternalDataEnabled(true);
1692b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
1702b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1712b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    public void disableDataConnectivity(int sub,
1722b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            Message dataCleanedUpMsg) {
1732b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mProxyPhones[sub].setInternalDataEnabled(false, dataCleanedUpMsg);
1742b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
1752b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
1762b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    public void updateCurrentCarrierInProvider(int sub) {
1772b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mProxyPhones[sub].updateCurrentCarrierInProvider();
1782b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
1792b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
180b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    public void registerForAllDataDisconnected(int subId, Handler h, int what, Object obj) {
181a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
182a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
183a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
1842b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mProxyPhones[phoneId].registerForAllDataDisconnected(h, what, obj);
185a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
186a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
187a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
188b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    public void unregisterForAllDataDisconnected(int subId, Handler h) {
189a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
190a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
191a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
1922b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mProxyPhones[phoneId].unregisterForAllDataDisconnected(h);
193a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
194a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
195a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
196b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    public boolean isDataDisconnected(int subId) {
197a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
198a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
199a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
2002b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            Phone activePhone = mProxyPhones[phoneId].getActivePhone();
201a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return ((PhoneBase) activePhone).mDcTracker.isDisconnected();
202a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        } else {
203a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return false;
204a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
205a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
206a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
2072b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    /**
2082b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * Get phone radio type and access technology.
2092b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     *
2102b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * @param phoneId which phone you want to get
2112b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * @return phone radio type and access technology for input phone ID
2122b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     */
2132b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    public int getRadioAccessFamily(int phoneId) {
2142b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        if (phoneId >= mProxyPhones.length) {
2152b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            return RadioAccessFamily.RAF_UNKNOWN;
2162b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        } else {
2172b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            return mProxyPhones[phoneId].getRadioAccessFamily();
2182b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
2192b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
2202b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2212b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    /**
2222b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * Set phone radio type and access technology for each phone.
2232b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     *
2242b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * @param rafs an RadioAccessFamily array to indicate all phone's
2252b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     *        new radio access family. The length of RadioAccessFamily
2262b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     *        must equal to phone count.
22712fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal     * @return false if another session is already active and the request is rejected.
2282b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     */
22912fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal    public boolean setRadioCapability(RadioAccessFamily[] rafs) {
2302b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        if (rafs.length != mProxyPhones.length) {
2312b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            throw new RuntimeException("Length of input rafs must equal to total phone count");
2322b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
2332b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2342b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Check if there is any ongoing transaction and throw an exception if there
2352b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // is one as this is a programming error.
2362b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized (mSetRadioAccessFamilyStatus) {
2372b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            for (int i = 0; i < mProxyPhones.length; i++) {
2384e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("setRadioCapability: mSetRadioAccessFamilyStatus[" + i + "]="
2394e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                        + mSetRadioAccessFamilyStatus[i]);
2402b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_IDLE) {
24112fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal                    // TODO: The right behaviour is to cancel previous request and send this.
24212fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal                    loge("setRadioCapability: Phone[" + i + "] is not idle. Rejecting request.");
24312fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal                    return false;
2442b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                }
2452b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
2462b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
2472b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2482b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Clear to be sure we're in the initial state
2492b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        clearTransaction();
2502b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2512b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // A new sessionId for this transaction
2522b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement();
2532b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2542b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Keep a wake lock until we finish radio capability changed
2552b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mWakeLock.acquire();
2562b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2572b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Start timer to make sure all phones respond within a specific time interval.
2582b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Will send FINISH if a timeout occurs.
2592b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mSetRadioCapabilityRunnable.setTimeoutState(mRadioCapabilitySessionId);
2602b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mHandler.postDelayed(mSetRadioCapabilityRunnable, SET_RC_TIMEOUT_WAITING_MSEC);
2612b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2622b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized (mSetRadioAccessFamilyStatus) {
2634e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott            logd("setRadioCapability: new request session id=" + mRadioCapabilitySessionId);
2642b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mRadioAccessFamilyStatusCounter = rafs.length;
2652b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            for (int i = 0; i < rafs.length; i++) {
2662b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                int phoneId = rafs[i].getPhoneId();
2674e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("setRadioCapability: phoneId=" + phoneId + " status=STARTING");
2682b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                mSetRadioAccessFamilyStatus[phoneId] = SET_RC_STATUS_STARTING;
2692b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                mOldRadioAccessFamily[phoneId] = mProxyPhones[phoneId].getRadioAccessFamily();
2707e7d2b34010bf24a70bbf40303c7a4606c438adaStuart Scott                int requestedRaf = rafs[i].getRadioAccessFamily();
271972efd34f867b7803688c3f831106f59244a11f0Stuart Scott                // TODO Set the new radio access family to the maximum of the requested & supported
272972efd34f867b7803688c3f831106f59244a11f0Stuart Scott                // int supportedRaf = mProxyPhones[i].getSupportedRadioAccessFamily();
273972efd34f867b7803688c3f831106f59244a11f0Stuart Scott                // mNewRadioAccessFamily[phoneId] = requestedRaf & supportedRaf;
274972efd34f867b7803688c3f831106f59244a11f0Stuart Scott                mNewRadioAccessFamily[phoneId] = requestedRaf;
2752b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("setRadioCapability: mOldRadioAccessFamily[" + phoneId + "]="
2762b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        + mOldRadioAccessFamily[phoneId]);
2772b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("setRadioCapability: mNewRadioAccessFamily[" + phoneId + "]="
2782b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        + mNewRadioAccessFamily[phoneId]);
2792b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                sendRadioCapabilityRequest(
2802b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        phoneId,
2812b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        mRadioCapabilitySessionId,
2822b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        RadioCapability.RC_PHASE_START,
2832b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        mOldRadioAccessFamily[phoneId],
2842b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        mLogicalModemIds[phoneId],
2852b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        RadioCapability.RC_STATUS_NONE,
2862b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        EVENT_START_RC_RESPONSE);
2872b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
2882b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
28912fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal
29012fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal        return true;
2912b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
2922b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
2932b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private Handler mHandler = new Handler() {
2942b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        @Override
2952b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        public void handleMessage(Message msg) {
2964e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott            logd("handleMessage msg.what=" + msg.what);
2972b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            switch (msg.what) {
2982b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                case EVENT_START_RC_RESPONSE:
2992b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    onStartRadioCapabilityResponse(msg);
3002b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    break;
3012b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3022b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                case EVENT_APPLY_RC_RESPONSE:
3032b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    onApplyRadioCapabilityResponse(msg);
3042b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    break;
3052b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3062b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                case EVENT_NOTIFICATION_RC_CHANGED:
3072b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    onNotificationRadioCapabilityChanged(msg);
3082b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    break;
3092b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3102b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                case EVENT_FINISH_RC_RESPONSE:
3112b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    onFinishRadioCapabilityResponse(msg);
3122b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    break;
3132b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3142b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                default:
3152b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    break;
3162b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
3172b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
3182b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    };
3192b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3202b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    /**
3212b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * Handle START response
3222b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * @param msg obj field isa RadioCapability
3232b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     */
3242b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void onStartRadioCapabilityResponse(Message msg) {
3252b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized (mSetRadioAccessFamilyStatus) {
3262b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
3272b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
3282b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("onStartRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId
3292b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        + " rc=" + rc);
3302b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                return;
3312b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
3322b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mRadioAccessFamilyStatusCounter--;
3334e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott            int id = rc.getPhoneId();
3342b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if (((AsyncResult) msg.obj).exception != null) {
3352b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("onStartRadioCapabilityResponse: Error response session=" + rc.getSession());
3364e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=FAIL");
3374e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
3382b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            } else {
3394e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=STARTED");
3404e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED;
3412b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
3422b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3432b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if (mRadioAccessFamilyStatusCounter == 0) {
3442b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                resetRadioAccessFamilyStatusCounter();
3452b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                boolean success = checkAllRadioCapabilitySuccess();
3464e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("onStartRadioCapabilityResponse: success=" + success);
3472b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                if (!success) {
3482b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    issueFinish(RadioCapability.RC_STATUS_FAIL,
3492b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            mRadioCapabilitySessionId);
3502b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                } else {
3512b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    // All logical modem accepted the new radio access family, issue the APPLY
3522b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    for (int i = 0; i < mProxyPhones.length; i++) {
3532b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        sendRadioCapabilityRequest(
3542b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            i,
3552b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            mRadioCapabilitySessionId,
3562b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            RadioCapability.RC_PHASE_APPLY,
3572b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            mNewRadioAccessFamily[i],
3582b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            mLogicalModemIds[i],
3592b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            RadioCapability.RC_STATUS_NONE,
3602b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            EVENT_APPLY_RC_RESPONSE);
3614e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott
3624e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                        logd("onStartRadioCapabilityResponse: phoneId=" + i + " status=APPLYING");
3632b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_APPLYING;
3642b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    }
3652b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                }
3662b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
3672b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
3682b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
3692b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3702b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    /**
3712b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * Handle APPLY response
3722b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * @param msg obj field isa RadioCapability
3732b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     */
3742b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void onApplyRadioCapabilityResponse(Message msg) {
3752b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
3762b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
3772b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            logd("onApplyRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId
3782b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    + " rc=" + rc);
3792b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            return;
3802b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
3812b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        logd("onApplyRadioCapabilityResponse: rc=" + rc);
3822b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        if (((AsyncResult) msg.obj).exception != null) {
3832b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            synchronized (mSetRadioAccessFamilyStatus) {
3842b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("onApplyRadioCapabilityResponse: Error response session=" + rc.getSession());
3854e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                int id = rc.getPhoneId();
3864e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("onApplyRadioCapabilityResponse: phoneId=" + id + " status=FAIL");
3874e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
3882b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
3892b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        } else {
3902b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            logd("onApplyRadioCapabilityResponse: Valid start expecting notification rc=" + rc);
3912b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
3922b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
3932b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
3942b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    /**
3952b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * Handle the notification unsolicited response associated with the APPLY
3962b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * @param msg obj field isa RadioCapability
3972b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     */
3982b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void onNotificationRadioCapabilityChanged(Message msg) {
3992b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
4002b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
4012b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            logd("onNotificationRadioCapabilityChanged: Ignore session=" + mRadioCapabilitySessionId
4022b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    + " rc=" + rc);
4032b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            return;
4042b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
4052b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized (mSetRadioAccessFamilyStatus) {
4062b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            logd("onNotificationRadioCapabilityChanged: rc=" + rc);
4072b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            // skip the overdue response by checking sessionId
4082b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if (rc.getSession() != mRadioCapabilitySessionId) {
4092b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("onNotificationRadioCapabilityChanged: Ignore session="
4102b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        + mRadioCapabilitySessionId + " rc=" + rc);
4112b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                return;
4122b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
4132b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
4144e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott            int id = rc.getPhoneId();
4152b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if ((((AsyncResult) msg.obj).exception != null) ||
4162b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    (rc.getStatus() == RadioCapability.RC_STATUS_FAIL)) {
4174e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=FAIL");
4184e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
4192b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            } else {
4204e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=SUCCESS");
4214e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS;
4222b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
4232b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
4242b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mRadioAccessFamilyStatusCounter--;
4252b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if (mRadioAccessFamilyStatusCounter == 0) {
4264e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("onNotificationRadioCapabilityChanged: removing callback from handler");
4272b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                mHandler.removeCallbacks(mSetRadioCapabilityRunnable);
4282b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                resetRadioAccessFamilyStatusCounter();
4292b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                boolean success = checkAllRadioCapabilitySuccess();
4302b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("onNotificationRadioCapabilityChanged: APPLY URC success=" + success);
4312b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                int status;
4322b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                if (success) {
4332b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    status = RadioCapability.RC_STATUS_SUCCESS;
4342b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                } else {
4352b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    status = RadioCapability.RC_STATUS_FAIL;
4362b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                }
4372b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                issueFinish(status, mRadioCapabilitySessionId);
4382b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
4392b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
4402b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
4412b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
4422b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    /**
4432b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * Handle the FINISH Phase response
4442b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * @param msg obj field isa RadioCapability
4452b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     */
4462b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    void onFinishRadioCapabilityResponse(Message msg) {
4472b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result;
4482b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) {
4492b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            logd("onFinishRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId
4502b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    + " rc=" + rc);
4512b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            return;
4522b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
4532b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized (mSetRadioAccessFamilyStatus) {
4544e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott            logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter="
4552b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    + mRadioAccessFamilyStatusCounter);
4562b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mRadioAccessFamilyStatusCounter--;
4572b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if (mRadioAccessFamilyStatusCounter == 0) {
4582b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                completeRadioCapabilityTransaction();
4592b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
4602b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
4612b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
4622b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
4632b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void issueFinish(int status, int sessionId) {
4642b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Issue FINISH
4652b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized(mSetRadioAccessFamilyStatus) {
4662b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            for (int i = 0; i < mProxyPhones.length; i++) {
4672b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_FAIL) {
4684e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                    logd("issueFinish: phoneId=" + i + " sessionId=" + sessionId
4692b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            + " status=" + status);
4702b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    sendRadioCapabilityRequest(
4712b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        i,
4722b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        sessionId,
4732b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        RadioCapability.RC_PHASE_FINISH,
4742b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        mOldRadioAccessFamily[i],
4752b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        mLogicalModemIds[i],
4762b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        status,
4772b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        EVENT_FINISH_RC_RESPONSE);
4782b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    if (status == RadioCapability.RC_STATUS_FAIL) {
4794e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                        logd("issueFinish: phoneId: " + i + " status: FAIL");
4802b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        // At least one failed, mark them all failed.
4812b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_FAIL;
4822b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    }
4832b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                } else {
4842b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    logd("issueFinish: Ignore already FAIL, Phone" + i + " sessionId=" + sessionId
4852b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            + " status=" + status);
4862b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                }
4872b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
4882b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
4892b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
4902b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
4912b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void completeRadioCapabilityTransaction() {
4922b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Create the intent to broadcast
4932b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        Intent intent;
4942b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        boolean success = checkAllRadioCapabilitySuccess();
4954e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott        logd("onFinishRadioCapabilityResponse: success=" + success);
4962b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        if (success) {
4972b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            ArrayList<RadioAccessFamily> phoneRAFList = new ArrayList<RadioAccessFamily>();
4982b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            for (int i = 0; i < mProxyPhones.length; i++) {
4992b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                int raf = mProxyPhones[i].getRadioAccessFamily();
5004e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("radioAccessFamily[" + i + "]=" + raf);
5012b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                RadioAccessFamily phoneRC = new RadioAccessFamily(i, raf);
5022b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                phoneRAFList.add(phoneRC);
5032b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
5042b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_DONE);
5052b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            intent.putParcelableArrayListExtra(TelephonyIntents.EXTRA_RADIO_ACCESS_FAMILY,
5062b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    phoneRAFList);
5072b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        } else {
5082b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED);
5092b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
5102b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5112b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Reinitialize
5122b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        clearTransaction();
5132b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5142b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        // Broadcast that we're done
5152b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mContext.sendBroadcast(intent);
5162b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
5172b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5182b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    // Clear this transaction
5192b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void clearTransaction() {
5204e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott        logd("clearTransaction");
5212b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized(mSetRadioAccessFamilyStatus) {
5222b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            for (int i = 0; i < mProxyPhones.length; i++) {
5234e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott                logd("clearTransaction: phoneId=" + i + " status=IDLE");
5242b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_IDLE;
5252b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                mOldRadioAccessFamily[i] = 0;
5262b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                mNewRadioAccessFamily[i] = 0;
5272b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
5284e7f34de0e226703fadd1f30f9976bb426c5166bStuart Scott
5292b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if (mWakeLock.isHeld()) {
5302b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                mWakeLock.release();
5312b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
5322b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
5332b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
5342b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5352b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private boolean checkAllRadioCapabilitySuccess() {
5362b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        synchronized(mSetRadioAccessFamilyStatus) {
5372b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            for (int i = 0; i < mProxyPhones.length; i++) {
5382b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                if (mSetRadioAccessFamilyStatus[i] == SET_RC_STATUS_FAIL) {
5392b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    return false;
5402b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                }
5412b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
5422b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            return true;
5432b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
5442b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
5452b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5462b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void resetRadioAccessFamilyStatusCounter() {
5472b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mRadioAccessFamilyStatusCounter = mProxyPhones.length;
5482b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
5492b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5502b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private void sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase,
5512b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            int radioFamily, String logicalModemId, int status, int eventId) {
5522b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        RadioCapability requestRC = new RadioCapability(
5532b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                phoneId, sessionId, rcPhase, radioFamily, logicalModemId, status);
5542b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        mProxyPhones[phoneId].setRadioCapability(
5552b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                requestRC, mHandler.obtainMessage(eventId));
5562b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
5572b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5582b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    /**
5592b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * RadioCapabilityRunnable is used to check
5602b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * if radio capability request's response is out of date.
5612b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * <p>
5622b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * Note that the setRadioCapability will be stopped directly and send FINISH
5632b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     * with fail status to all logical modems. and send out fail intent
5642b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     *
5652b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville     */
5662b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    private class RadioCapabilityRunnable implements Runnable {
5672b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        private int mSessionId;
5682b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        public  RadioCapabilityRunnable() {
5692b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
5702b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5712b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        public void setTimeoutState(int sessionId) {
5722b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            mSessionId = sessionId;
5732b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
5742b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5752b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        @Override
5762b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        public void run() {
5772b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            if (mSessionId != mRadioCapabilitySessionId) {
5782b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                logd("RadioCapability timeout: Ignore mSessionId=" + mSessionId
5792b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                       + "!= mRadioCapabilitySessionId=" + mRadioCapabilitySessionId);
5802b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                return;
5812b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
5822b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5832b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            synchronized(mSetRadioAccessFamilyStatus) {
5842b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                for (int i = 0; i < mProxyPhones.length; i++) {
5852b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                    logd("RadioCapability timeout: mSetRadioAccessFamilyStatus[" + i + "]=" +
5862b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                            mSetRadioAccessFamilyStatus[i]);
5872b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                }
5882b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5892b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                // Increment the sessionId as we are completing the transaction below
5902b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                // so we don't want it completed when the FINISH phase is done.
5912b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                int uniqueDifferentId = mUniqueIdGenerator.getAndIncrement();
5922b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
5932b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                // send FINISH request with fail status and then uniqueDifferentId
5942b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                issueFinish(RadioCapability.RC_STATUS_FAIL,
5952b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                        uniqueDifferentId);
5962b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville                completeRadioCapabilityTransaction();
5972b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville            }
5982b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville        }
5992b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville    }
6002b40e6226b4b71408964bca46f0a9f256cd4f523Wink Saville
601a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private void logd(String string) {
602a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        Rlog.d(LOG_TAG, string);
603a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
604e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville
60512fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal    private void loge(String string) {
60612fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal        Rlog.e(LOG_TAG, string);
60712fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal    }
60812fe7c9dce4807d482bf1bcb8472dacae9aa34fdShishir Agrawal
609e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
610e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville        try {
611e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville            mDctController.dump(fd, pw, args);
612e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville        } catch (Exception e) {
613e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville            e.printStackTrace();
614e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville        }
615e97be3971cb6b55e019433c32524cc60ce0d037bWink Saville    }
616a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville}
617