IccProvider.java revision 34efc39f256d5833687c7bd7d83258d6394c9307
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony;
18
19import android.content.ContentProvider;
20import android.content.UriMatcher;
21import android.content.ContentValues;
22import com.android.internal.database.ArrayListCursor;
23import android.database.Cursor;
24import android.net.Uri;
25import android.os.SystemProperties;
26import android.os.RemoteException;
27import android.os.ServiceManager;
28import android.text.TextUtils;
29import android.util.Log;
30
31import java.util.ArrayList;
32import java.util.List;
33
34import com.android.internal.telephony.IccConstants;
35import com.android.internal.telephony.AdnRecord;
36import com.android.internal.telephony.IIccPhoneBook;
37
38
39/**
40 * {@hide}
41 */
42public class IccProvider extends ContentProvider {
43    private static final String TAG = "IccProvider";
44    private static final boolean DBG = false;
45
46
47    private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
48        "name",
49        "number",
50        "emails"
51    };
52
53    private static final int ADN = 1;
54    private static final int FDN = 2;
55    private static final int SDN = 3;
56
57    private static final String STR_TAG = "tag";
58    private static final String STR_NUMBER = "number";
59    private static final String STR_EMAILS = "emails";
60    private static final String STR_PIN2 = "pin2";
61
62    private static final UriMatcher URL_MATCHER =
63                            new UriMatcher(UriMatcher.NO_MATCH);
64
65    static {
66        URL_MATCHER.addURI("icc", "adn", ADN);
67        URL_MATCHER.addURI("icc", "fdn", FDN);
68        URL_MATCHER.addURI("icc", "sdn", SDN);
69    }
70
71
72    private boolean mSimulator;
73
74    @Override
75    public boolean onCreate() {
76        String device = SystemProperties.get("ro.product.device");
77        if (!TextUtils.isEmpty(device)) {
78            mSimulator = false;
79        } else {
80            // simulator
81            mSimulator = true;
82        }
83
84        return true;
85    }
86
87    @Override
88    public Cursor query(Uri url, String[] projection, String selection,
89            String[] selectionArgs, String sort) {
90        ArrayList<ArrayList> results;
91
92        if (!mSimulator) {
93            switch (URL_MATCHER.match(url)) {
94                case ADN:
95                    results = loadFromEf(IccConstants.EF_ADN);
96                    break;
97
98                case FDN:
99                    results = loadFromEf(IccConstants.EF_FDN);
100                    break;
101
102                case SDN:
103                    results = loadFromEf(IccConstants.EF_SDN);
104                    break;
105
106                default:
107                    throw new IllegalArgumentException("Unknown URL " + url);
108            }
109        } else {
110            // Fake up some data for the simulator
111            results = new ArrayList<ArrayList>(4);
112            ArrayList<String> contact;
113
114            contact = new ArrayList<String>();
115            contact.add("Ron Stevens/H");
116            contact.add("512-555-5038");
117            results.add(contact);
118
119            contact = new ArrayList<String>();
120            contact.add("Ron Stevens/M");
121            contact.add("512-555-8305");
122            results.add(contact);
123
124            contact = new ArrayList<String>();
125            contact.add("Melissa Owens");
126            contact.add("512-555-8305");
127            results.add(contact);
128
129            contact = new ArrayList<String>();
130            contact.add("Directory Assistence");
131            contact.add("411");
132            results.add(contact);
133        }
134
135        return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results);
136    }
137
138    @Override
139    public String getType(Uri url) {
140        switch (URL_MATCHER.match(url)) {
141            case ADN:
142            case FDN:
143            case SDN:
144                return "vnd.android.cursor.dir/sim-contact";
145
146            default:
147                throw new IllegalArgumentException("Unknown URL " + url);
148        }
149    }
150
151    @Override
152    public Uri insert(Uri url, ContentValues initialValues) {
153        Uri resultUri;
154        int efType;
155        String pin2 = null;
156
157        if (DBG) log("insert");
158
159        int match = URL_MATCHER.match(url);
160        switch (match) {
161            case ADN:
162                efType = IccConstants.EF_ADN;
163                break;
164
165            case FDN:
166                efType = IccConstants.EF_FDN;
167                pin2 = initialValues.getAsString("pin2");
168                break;
169
170            default:
171                throw new UnsupportedOperationException(
172                        "Cannot insert into URL: " + url);
173        }
174
175        String tag = initialValues.getAsString("tag");
176        String number = initialValues.getAsString("number");
177        // TODO(): Read email instead of sending null.
178        boolean success = addIccRecordToEf(efType, tag, number, null, pin2);
179
180        if (!success) {
181            return null;
182        }
183
184        StringBuilder buf = new StringBuilder("content://im/");
185        switch (match) {
186            case ADN:
187                buf.append("adn/");
188                break;
189
190            case FDN:
191                buf.append("fdn/");
192                break;
193        }
194
195        // TODO: we need to find out the rowId for the newly added record
196        buf.append(0);
197
198        resultUri = Uri.parse(buf.toString());
199
200        /*
201        // notify interested parties that an insertion happened
202        getContext().getContentResolver().notifyInsert(
203                resultUri, rowID, null);
204        */
205
206        return resultUri;
207    }
208
209    private String normalizeValue(String inVal) {
210        int len = inVal.length();
211        String retVal = inVal;
212
213        if (inVal.charAt(0) == '\'' && inVal.charAt(len-1) == '\'') {
214            retVal = inVal.substring(1, len-1);
215        }
216
217        return retVal;
218    }
219
220    @Override
221    public int delete(Uri url, String where, String[] whereArgs) {
222        int efType;
223
224        if (DBG) log("delete");
225
226        int match = URL_MATCHER.match(url);
227        switch (match) {
228            case ADN:
229                efType = IccConstants.EF_ADN;
230                break;
231
232            case FDN:
233                efType = IccConstants.EF_FDN;
234                break;
235
236            default:
237                throw new UnsupportedOperationException(
238                        "Cannot insert into URL: " + url);
239        }
240
241        // parse where clause
242        String tag = null;
243        String number = null;
244        String[] emails = null;
245        String pin2 = null;
246
247        String[] tokens = where.split("AND");
248        int n = tokens.length;
249
250        while (--n >= 0) {
251            String param = tokens[n];
252            if (DBG) log("parsing '" + param + "'");
253
254            String[] pair = param.split("=");
255
256            if (pair.length != 2) {
257                Log.e(TAG, "resolve: bad whereClause parameter: " + param);
258                continue;
259            }
260
261            String key = pair[0].trim();
262            String val = pair[1].trim();
263
264            if (STR_TAG.equals(key)) {
265                tag = normalizeValue(val);
266            } else if (STR_NUMBER.equals(key)) {
267                number = normalizeValue(val);
268            } else if (STR_EMAILS.equals(key)) {
269                //TODO(): Email is null.
270                emails = null;
271            } else if (STR_PIN2.equals(key)) {
272                pin2 = normalizeValue(val);
273            }
274        }
275
276        if (TextUtils.isEmpty(tag)) {
277            return 0;
278        }
279
280        if (efType == FDN && TextUtils.isEmpty(pin2)) {
281            return 0;
282        }
283
284        boolean success = deleteIccRecordFromEf(efType, tag, number, emails, pin2);
285        if (!success) {
286            return 0;
287        }
288
289        return 1;
290    }
291
292    @Override
293    public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
294        int efType;
295        String pin2 = null;
296
297        if (DBG) log("update");
298
299        int match = URL_MATCHER.match(url);
300        switch (match) {
301            case ADN:
302                efType = IccConstants.EF_ADN;
303                break;
304
305            case FDN:
306                efType = IccConstants.EF_FDN;
307                pin2 = values.getAsString("pin2");
308                break;
309
310            default:
311                throw new UnsupportedOperationException(
312                        "Cannot insert into URL: " + url);
313        }
314
315        String tag = values.getAsString("tag");
316        String number = values.getAsString("number");
317        String[] emails = null;
318        String newTag = values.getAsString("newTag");
319        String newNumber = values.getAsString("newNumber");
320        String[] newEmails = null;
321        // TODO(): Update for email.
322        boolean success = updateIccRecordInEf(efType, tag, number,
323                newTag, newNumber, pin2);
324
325        if (!success) {
326            return 0;
327        }
328
329        return 1;
330    }
331
332    private ArrayList<ArrayList> loadFromEf(int efType) {
333        ArrayList<ArrayList> results = new ArrayList<ArrayList>();
334        List<AdnRecord> adnRecords = null;
335
336        if (DBG) log("loadFromEf: efType=" + efType);
337
338        try {
339            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
340                    ServiceManager.getService("simphonebook"));
341            if (iccIpb != null) {
342                adnRecords = iccIpb.getAdnRecordsInEf(efType);
343            }
344        } catch (RemoteException ex) {
345            // ignore it
346        } catch (SecurityException ex) {
347            if (DBG) log(ex.toString());
348        }
349        if (adnRecords != null) {
350            // Load the results
351
352            int N = adnRecords.size();
353            if (DBG) log("adnRecords.size=" + N);
354            for (int i = 0; i < N ; i++) {
355                loadRecord(adnRecords.get(i), results);
356            }
357        } else {
358            // No results to load
359            Log.w(TAG, "Cannot load ADN records");
360            results.clear();
361        }
362        if (DBG) log("loadFromEf: return results");
363        return results;
364    }
365
366    private boolean
367    addIccRecordToEf(int efType, String name, String number, String[] emails, String pin2) {
368        if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name +
369                ", number=" + number + ", emails=" + emails);
370
371        boolean success = false;
372
373        // TODO: do we need to call getAdnRecordsInEf() before calling
374        // updateAdnRecordsInEfBySearch()? In any case, we will leave
375        // the UI level logic to fill that prereq if necessary. But
376        // hopefully, we can remove this requirement.
377
378        try {
379            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
380                    ServiceManager.getService("simphonebook"));
381            if (iccIpb != null) {
382                success = iccIpb.updateAdnRecordsInEfBySearch(efType, "", "",
383                        name, number, pin2);
384            }
385        } catch (RemoteException ex) {
386            // ignore it
387        } catch (SecurityException ex) {
388            if (DBG) log(ex.toString());
389        }
390        if (DBG) log("addIccRecordToEf: " + success);
391        return success;
392    }
393
394    private boolean
395    updateIccRecordInEf(int efType, String oldName, String oldNumber,
396            String newName, String newNumber, String pin2) {
397        if (DBG) log("updateIccRecordInEf: efType=" + efType +
398                ", oldname=" + oldName + ", oldnumber=" + oldNumber +
399                ", newname=" + newName + ", newnumber=" + newNumber);
400        boolean success = false;
401
402        try {
403            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
404                    ServiceManager.getService("simphonebook"));
405            if (iccIpb != null) {
406                success = iccIpb.updateAdnRecordsInEfBySearch(efType,
407                        oldName, oldNumber, newName, newNumber, pin2);
408            }
409        } catch (RemoteException ex) {
410            // ignore it
411        } catch (SecurityException ex) {
412            if (DBG) log(ex.toString());
413        }
414        if (DBG) log("updateIccRecordInEf: " + success);
415        return success;
416    }
417
418
419    private boolean deleteIccRecordFromEf(int efType, String name, String number, String[] emails,
420            String pin2) {
421        if (DBG) log("deleteIccRecordFromEf: efType=" + efType +
422                ", name=" + name + ", number=" + number + ", emails=" + emails + ", pin2=" + pin2);
423
424        boolean success = false;
425
426        try {
427            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
428                    ServiceManager.getService("simphonebook"));
429            if (iccIpb != null) {
430                success = iccIpb.updateAdnRecordsInEfBySearch(efType,
431                        name, number, "", "", pin2);
432            }
433        } catch (RemoteException ex) {
434            // ignore it
435        } catch (SecurityException ex) {
436            if (DBG) log(ex.toString());
437        }
438        if (DBG) log("deleteIccRecordFromEf: " + success);
439        return success;
440    }
441
442    /**
443     * Loads an AdnRecord into an ArrayList. Must be called with mLock held.
444     *
445     * @param record the ADN record to load from
446     * @param results the array list to put the results in
447     */
448    private void loadRecord(AdnRecord record,
449            ArrayList<ArrayList> results) {
450        if (!record.isEmpty()) {
451            ArrayList<String> contact = new ArrayList<String>();
452            String alphaTag = record.getAlphaTag();
453            String number = record.getNumber();
454            String[] emails = record.getEmails();
455
456            if (DBG) log("loadRecord: " + alphaTag + ", " + number + ",");
457            contact.add(alphaTag);
458            contact.add(number);
459            StringBuilder emailString = new StringBuilder();
460
461            if (emails != null) {
462                for (String email: emails) {
463                    if (DBG) log("Adding email:" + email);
464                    emailString.append(email);
465                    emailString.append(",");
466                }
467                contact.add(emailString.toString());
468            } else {
469                contact.add(null);
470            }
471            results.add(contact);
472        }
473    }
474
475    private void log(String msg) {
476        Log.d(TAG, "[IccProvider] " + msg);
477    }
478
479}
480