1/*
2 * Copyright (C) 2011 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.cdma;
18
19import android.content.ContentValues;
20import android.content.Context;
21import android.content.SharedPreferences;
22import android.database.SQLException;
23import android.net.Uri;
24import android.os.AsyncResult;
25import android.os.Message;
26import android.preference.PreferenceManager;
27import android.provider.Telephony;
28import android.util.Log;
29
30import com.android.internal.telephony.CommandsInterface;
31import com.android.internal.telephony.OperatorInfo;
32import com.android.internal.telephony.Phone;
33import com.android.internal.telephony.PhoneConstants;
34import com.android.internal.telephony.PhoneNotifier;
35import com.android.internal.telephony.PhoneProxy;
36import com.android.internal.telephony.SMSDispatcher;
37import com.android.internal.telephony.UiccCardApplication;
38import com.android.internal.telephony.gsm.GsmSMSDispatcher;
39import com.android.internal.telephony.gsm.SIMRecords;
40import com.android.internal.telephony.gsm.SmsMessage;
41import com.android.internal.telephony.ims.IsimRecords;
42import com.android.internal.telephony.ims.IsimUiccRecords;
43import com.android.internal.telephony.uicc.UiccController;
44
45import java.io.FileDescriptor;
46import java.io.PrintWriter;
47
48public class CDMALTEPhone extends CDMAPhone {
49    static final String LOG_TAG = "CDMA";
50
51    private static final boolean DBG = true;
52
53    /** Secondary SMSDispatcher for 3GPP format messages. */
54    SMSDispatcher m3gppSMS;
55
56    /** CdmaLtePhone in addition to RuimRecords available from
57     * PhoneBase needs access to SIMRecords and IsimUiccRecords
58     */
59    private SIMRecords mSimRecords;
60    private IsimUiccRecords mIsimUiccRecords;
61
62    /**
63     * Small container class used to hold information relevant to
64     * the carrier selection process. operatorNumeric can be ""
65     * if we are looking for automatic selection. operatorAlphaLong is the
66     * corresponding operator name.
67     */
68    private static class NetworkSelectMessage {
69        public Message message;
70        public String operatorNumeric;
71        public String operatorAlphaLong;
72    }
73
74    // Constructors
75    public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
76        super(context, ci, notifier, false);
77        m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
78    }
79
80    @Override
81    public void handleMessage (Message msg) {
82        AsyncResult ar;
83        switch (msg.what) {
84            // handle the select network completion callbacks.
85            case EVENT_SET_NETWORK_MANUAL_COMPLETE:
86                handleSetSelectNetwork((AsyncResult) msg.obj);
87                break;
88            case EVENT_NEW_ICC_SMS:
89                ar = (AsyncResult)msg.obj;
90                m3gppSMS.dispatchMessage((SmsMessage)ar.result);
91                break;
92            default:
93                super.handleMessage(msg);
94        }
95    }
96
97    @Override
98    protected void initSstIcc() {
99        mSST = new CdmaLteServiceStateTracker(this);
100    }
101
102    @Override
103    public void dispose() {
104        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
105            super.dispose();
106            m3gppSMS.dispose();
107        }
108    }
109
110    @Override
111    public void removeReferences() {
112        super.removeReferences();
113        m3gppSMS = null;
114    }
115
116    @Override
117    public PhoneConstants.DataState getDataConnectionState(String apnType) {
118        PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
119
120        if (mSST == null) {
121            // Radio Technology Change is ongoing, dispose() and
122            // removeReferences() have already been called
123
124            ret = PhoneConstants.DataState.DISCONNECTED;
125        } else if (mDataConnectionTracker.isApnTypeEnabled(apnType) == false) {
126            ret = PhoneConstants.DataState.DISCONNECTED;
127        } else {
128            switch (mDataConnectionTracker.getState(apnType)) {
129                case FAILED:
130                case IDLE:
131                    ret = PhoneConstants.DataState.DISCONNECTED;
132                    break;
133
134                case CONNECTED:
135                case DISCONNECTING:
136                    if (mCT.state != PhoneConstants.State.IDLE &&
137                            !mSST.isConcurrentVoiceAndDataAllowed()) {
138                        ret = PhoneConstants.DataState.SUSPENDED;
139                    } else {
140                        ret = PhoneConstants.DataState.CONNECTED;
141                    }
142                    break;
143
144                case INITING:
145                case CONNECTING:
146                case SCANNING:
147                    ret = PhoneConstants.DataState.CONNECTING;
148                    break;
149            }
150        }
151
152        log("getDataConnectionState apnType=" + apnType + " ret=" + ret);
153        return ret;
154    }
155
156    @Override
157    public void
158    selectNetworkManually(OperatorInfo network,
159            Message response) {
160        // wrap the response message in our own message along with
161        // the operator's id.
162        NetworkSelectMessage nsm = new NetworkSelectMessage();
163        nsm.message = response;
164        nsm.operatorNumeric = network.getOperatorNumeric();
165        nsm.operatorAlphaLong = network.getOperatorAlphaLong();
166
167        // get the message
168        Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
169
170        mCM.setNetworkSelectionModeManual(network.getOperatorNumeric(), msg);
171    }
172
173    /**
174     * Used to track the settings upon completion of the network change.
175     */
176    private void handleSetSelectNetwork(AsyncResult ar) {
177        // look for our wrapper within the asyncresult, skip the rest if it
178        // is null.
179        if (!(ar.userObj instanceof NetworkSelectMessage)) {
180            Log.e(LOG_TAG, "unexpected result from user object.");
181            return;
182        }
183
184        NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj;
185
186        // found the object, now we send off the message we had originally
187        // attached to the request.
188        if (nsm.message != null) {
189            if (DBG) log("sending original message to recipient");
190            AsyncResult.forMessage(nsm.message, ar.result, ar.exception);
191            nsm.message.sendToTarget();
192        }
193
194        // open the shared preferences editor, and write the value.
195        // nsm.operatorNumeric is "" if we're in automatic.selection.
196        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
197        SharedPreferences.Editor editor = sp.edit();
198        editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric);
199        editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong);
200
201        // commit and log the result.
202        if (! editor.commit()) {
203            Log.e(LOG_TAG, "failed to commit network selection preference");
204        }
205
206    }
207
208    @Override
209    public boolean updateCurrentCarrierInProvider() {
210        if (mSimRecords != null) {
211            try {
212                Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
213                ContentValues map = new ContentValues();
214                String operatorNumeric = mSimRecords.getOperatorNumeric();
215                map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
216                if (DBG) log("updateCurrentCarrierInProvider from UICC: numeric=" +
217                        operatorNumeric);
218                mContext.getContentResolver().insert(uri, map);
219                return true;
220            } catch (SQLException e) {
221                Log.e(LOG_TAG, "[CDMALTEPhone] Can't store current operator ret false", e);
222            }
223        } else {
224            if (DBG) log("updateCurrentCarrierInProvider mIccRecords == null ret false");
225        }
226        return false;
227    }
228
229    // return IMSI from USIM as subscriber ID.
230    @Override
231    public String getSubscriberId() {
232        return (mSimRecords != null) ? mSimRecords.getIMSI() : "";
233    }
234
235    @Override
236    public String getImei() {
237        return mImei;
238    }
239
240    @Override
241    public String getDeviceSvn() {
242        return mImeiSv;
243    }
244
245    @Override
246    public IsimRecords getIsimRecords() {
247        return mIsimUiccRecords;
248    }
249
250    @Override
251    public String getMsisdn() {
252        return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null;
253    }
254
255    @Override
256    public void getAvailableNetworks(Message response) {
257        mCM.getAvailableNetworks(response);
258    }
259
260    @Override
261    public void requestIsimAuthentication(String nonce, Message result) {
262        mCM.requestIsimAuthentication(nonce, result);
263    }
264
265    @Override
266    protected void onUpdateIccAvailability() {
267        if (mUiccController == null ) {
268            return;
269        }
270
271        // Update IsimRecords
272        UiccCardApplication newUiccApplication =
273                mUiccController.getUiccCardApplication(UiccController.APP_FAM_IMS);
274        IsimUiccRecords newIsimUiccRecords = null;
275
276        if (newUiccApplication != null) {
277            newIsimUiccRecords = (IsimUiccRecords)newUiccApplication.getIccRecords();
278        }
279        mIsimUiccRecords = newIsimUiccRecords;
280
281        // Update UsimRecords
282        newUiccApplication = mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
283        SIMRecords newSimRecords = null;
284        if (newUiccApplication != null) {
285            newSimRecords = (SIMRecords)newUiccApplication.getIccRecords();
286        }
287        if (mSimRecords != newSimRecords) {
288            if (mSimRecords != null) {
289                log("Removing stale SIMRecords object.");
290                mSimRecords.unregisterForNewSms(this);
291                mSimRecords = null;
292            }
293            if (newSimRecords != null) {
294                log("New SIMRecords found");
295                mSimRecords = newSimRecords;
296                mSimRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
297            }
298        }
299
300        super.onUpdateIccAvailability();
301    }
302
303    @Override
304    protected void log(String s) {
305            Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
306    }
307
308    @Override
309    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
310        pw.println("CDMALTEPhone extends:");
311        super.dump(fd, pw, args);
312        pw.println(" m3gppSMS=" + m3gppSMS);
313    }
314}
315