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