1/*
2 * Copyright (C) 2007 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 */
16package com.android.internal.telephony;
17
18import java.io.FileDescriptor;
19import java.io.PrintWriter;
20
21import android.content.Context;
22import android.content.pm.PackageManager;
23import android.os.Binder;
24import android.os.RemoteException;
25import android.telephony.PhoneNumberUtils;
26import android.telephony.Rlog;
27
28import com.android.internal.telephony.uicc.IsimRecords;
29import com.android.internal.telephony.uicc.UiccCard;
30import com.android.internal.telephony.uicc.UiccCardApplication;
31
32public class PhoneSubInfo {
33    static final String LOG_TAG = "PhoneSubInfo";
34    private static final boolean DBG = true;
35    private static final boolean VDBG = false; // STOPSHIP if true
36
37    private Phone mPhone;
38    private Context mContext;
39    private static final String READ_PHONE_STATE =
40        android.Manifest.permission.READ_PHONE_STATE;
41    // TODO: change getCompleteVoiceMailNumber() to require READ_PRIVILEGED_PHONE_STATE
42    private static final String CALL_PRIVILEGED =
43        android.Manifest.permission.CALL_PRIVILEGED;
44    private static final String READ_PRIVILEGED_PHONE_STATE =
45        android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
46
47    public PhoneSubInfo(Phone phone) {
48        mPhone = phone;
49        mContext = phone.getContext();
50    }
51
52    public void dispose() {
53    }
54
55    @Override
56    protected void finalize() {
57        try {
58            super.finalize();
59        } catch (Throwable throwable) {
60            loge("Error while finalizing:", throwable);
61        }
62        if (DBG) log("PhoneSubInfo finalized");
63    }
64
65    /**
66     * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones.
67     */
68    public String getDeviceId() {
69        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
70        return mPhone.getDeviceId();
71    }
72
73    /**
74     * Retrieves the IMEI.
75     */
76    public String getImei() {
77        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
78        return mPhone.getImei();
79    }
80
81    /**
82     * Retrieves the software version number for the device, e.g., IMEI/SV
83     * for GSM phones.
84     */
85    public String getDeviceSvn() {
86        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
87        return mPhone.getDeviceSvn();
88    }
89
90    /**
91     * Retrieves the unique subscriber ID, e.g., IMSI for GSM phones.
92     */
93    public String getSubscriberId() {
94        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
95        return mPhone.getSubscriberId();
96    }
97
98    /**
99     * Retrieves the Group Identifier Level1 for GSM phones.
100     */
101    public String getGroupIdLevel1() {
102        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
103        return mPhone.getGroupIdLevel1();
104    }
105
106    /**
107     * Retrieves the serial number of the ICC, if applicable.
108     */
109    public String getIccSerialNumber() {
110        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
111        return mPhone.getIccSerialNumber();
112    }
113
114    /**
115     * Retrieves the phone number string for line 1.
116     */
117    public String getLine1Number() {
118        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
119        return mPhone.getLine1Number();
120    }
121
122    /**
123     * Retrieves the alpha identifier for line 1.
124     */
125    public String getLine1AlphaTag() {
126        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
127        return mPhone.getLine1AlphaTag();
128    }
129
130    /**
131     * Retrieves the MSISDN string.
132     */
133    public String getMsisdn() {
134        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
135        return mPhone.getMsisdn();
136    }
137
138    /**
139     * Retrieves the voice mail number.
140     */
141    public String getVoiceMailNumber() {
142        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
143        String number = PhoneNumberUtils.extractNetworkPortion(mPhone.getVoiceMailNumber());
144        if (VDBG) log("VM: PhoneSubInfo.getVoiceMailNUmber: " + number);
145        return number;
146    }
147
148    /**
149     * Retrieves the complete voice mail number.
150     *
151     * @hide
152     */
153    public String getCompleteVoiceMailNumber() {
154        mContext.enforceCallingOrSelfPermission(CALL_PRIVILEGED,
155                "Requires CALL_PRIVILEGED");
156        String number = mPhone.getVoiceMailNumber();
157        if (VDBG) log("VM: PhoneSubInfo.getCompleteVoiceMailNUmber: " + number);
158        return number;
159    }
160
161    /**
162     * Retrieves the alpha identifier associated with the voice mail number.
163     */
164    public String getVoiceMailAlphaTag() {
165        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
166        return mPhone.getVoiceMailAlphaTag();
167    }
168
169    /**
170     * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
171     * @return the IMPI, or null if not present or not loaded
172     */
173    public String getIsimImpi() {
174        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
175                "Requires READ_PRIVILEGED_PHONE_STATE");
176        IsimRecords isim = mPhone.getIsimRecords();
177        if (isim != null) {
178            return isim.getIsimImpi();
179        } else {
180            return null;
181        }
182    }
183
184    /**
185     * Returns the IMS home network domain name that was loaded from the ISIM.
186     * @return the IMS domain name, or null if not present or not loaded
187     */
188    public String getIsimDomain() {
189        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
190                "Requires READ_PRIVILEGED_PHONE_STATE");
191        IsimRecords isim = mPhone.getIsimRecords();
192        if (isim != null) {
193            return isim.getIsimDomain();
194        } else {
195            return null;
196        }
197    }
198
199    /**
200     * Returns the IMS public user identities (IMPU) that were loaded from the ISIM.
201     * @return an array of IMPU strings, with one IMPU per string, or null if
202     *      not present or not loaded
203     */
204    public String[] getIsimImpu() {
205        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
206                "Requires READ_PRIVILEGED_PHONE_STATE");
207        IsimRecords isim = mPhone.getIsimRecords();
208        if (isim != null) {
209            return isim.getIsimImpu();
210        } else {
211            return null;
212        }
213    }
214
215    /**
216     * Returns the IMS Service Table (IST) that was loaded from the ISIM.
217     * @return IMS Service Table or null if not present or not loaded
218     */
219    public String getIsimIst(){
220        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
221                "Requires READ_PRIVILEGED_PHONE_STATE");
222        IsimRecords isim = mPhone.getIsimRecords();
223        if (isim != null) {
224            return isim.getIsimIst();
225        } else {
226            return null;
227        }
228     }
229
230    /**
231     * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
232     * @return an array of  PCSCF strings with one PCSCF per string, or null if
233     *      not present or not loaded
234     */
235    public String[] getIsimPcscf() {
236        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
237                "Requires READ_PRIVILEGED_PHONE_STATE");
238        IsimRecords isim = mPhone.getIsimRecords();
239        if (isim != null) {
240            return isim.getIsimPcscf();
241        } else {
242            return null;
243        }
244    }
245
246    /**
247     * Returns the response of ISIM Authetification through RIL.
248     * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo.
249     * @return the response of ISIM Authetification, or null if not available
250     */
251    public String getIsimChallengeResponse(String nonce){
252        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
253                "Requires READ_PRIVILEGED_PHONE_STATE");
254        IsimRecords isim = mPhone.getIsimRecords();
255        if (isim != null) {
256            return isim.getIsimChallengeResponse(nonce);
257        } else {
258            return null;
259        }
260    }
261
262    /**
263     * Returns the response of the SIM application on the UICC to authentication
264     * challenge/response algorithm. The data string and challenge response are
265     * Base64 encoded Strings.
266     * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
267     *
268     * @param appType ICC application family (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
269     * @param data authentication challenge data
270     * @return challenge response
271     */
272    public String getIccSimChallengeResponse(long subId, int appType, String data) {
273        // FIXME: use subId!!
274        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
275                "Requires READ_PRIVILEGED_PHONE_STATE");
276
277        UiccCard uiccCard = mPhone.getUiccCard();
278        if (uiccCard == null) {
279            Rlog.e(LOG_TAG, "getIccSimChallengeResponse() UiccCard is null");
280            return null;
281        }
282
283        UiccCardApplication uiccApp = uiccCard.getApplicationByType(appType);
284        if (uiccApp == null) {
285            Rlog.e(LOG_TAG, "getIccSimChallengeResponse() no app with specified type -- " +
286                    appType);
287            return null;
288        } else {
289            Rlog.e(LOG_TAG, "getIccSimChallengeResponse() found app " + uiccApp.getAid()
290                    + "specified type -- " + appType);
291        }
292
293        int authContext = uiccApp.getAuthContext();
294
295        if (data.length() < 32) {
296            /* must use EAP_SIM context */
297            Rlog.e(LOG_TAG, "data is too small to use EAP_AKA, using EAP_SIM instead");
298            authContext = UiccCardApplication.AUTH_CONTEXT_EAP_SIM;
299        }
300
301        if(authContext == UiccCardApplication.AUTH_CONTEXT_UNDEFINED) {
302            Rlog.e(LOG_TAG, "getIccSimChallengeResponse() authContext undefined for app type " +
303                    appType);
304            return null;
305        }
306
307        return uiccApp.getIccRecords().getIccSimChallengeResponse(authContext, data);
308    }
309
310    private void log(String s) {
311        Rlog.d(LOG_TAG, s);
312    }
313
314    private void loge(String s, Throwable e) {
315        Rlog.e(LOG_TAG, s, e);
316    }
317
318    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
319        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
320                != PackageManager.PERMISSION_GRANTED) {
321            pw.println("Permission Denial: can't dump PhoneSubInfo from from pid="
322                    + Binder.getCallingPid()
323                    + ", uid=" + Binder.getCallingUid());
324            return;
325        }
326
327        pw.println("Phone Subscriber Info:");
328        pw.println("  Phone Type = " + mPhone.getPhoneName());
329        pw.println("  Device ID = " + mPhone.getDeviceId());
330    }
331}
332