CallLogProvider.java revision 9978b26dd17bb2b20b91101f1e4682604336b5f6
1e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov/*
2e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Copyright (C) 2009 The Android Open Source Project
3e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *
4e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
5e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * you may not use this file except in compliance with the License.
6e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * You may obtain a copy of the License at
7e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *
8e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
9e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *
10e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
11e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
12e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * See the License for the specific language governing permissions and
14e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * limitations under the License
15e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov */
16e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
17e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovpackage com.android.providers.contacts;
18e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
1900e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.checkForSupportedColumns;
20aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.getEqualityClause;
21aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.getInequalityClause;
2200e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjee
23b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
24aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjeeimport com.android.providers.contacts.util.SelectionBuilder;
25aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerdaimport com.google.common.annotations.VisibleForTesting;
26e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
27e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentProvider;
28e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentUris;
29e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentValues;
30e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.Context;
31e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.UriMatcher;
32e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.Cursor;
33e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.DatabaseUtils;
34e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.sqlite.SQLiteDatabase;
35e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.sqlite.SQLiteQueryBuilder;
36e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.net.Uri;
37e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.CallLog;
38e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.CallLog.Calls;
39663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onukiimport android.util.Log;
40e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
41e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport java.util.HashMap;
42e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
43e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov/**
44e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Call log content provider.
45e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov */
46e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovpublic class CallLogProvider extends ContentProvider {
47aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /** Selection clause to use to exclude voicemail records.  */
48aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private static final String EXCLUDE_VOICEMAIL_SELECTION = getInequalityClause(
499978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda            Calls.TYPE, Calls.VOICEMAIL_TYPE);
50aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
51e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final int CALLS = 1;
52e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
53e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final int CALLS_ID = 2;
54e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
55e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final int CALLS_FILTER = 3;
56e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
57e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
58e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    static {
59e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sURIMatcher.addURI(CallLog.AUTHORITY, "calls", CALLS);
60e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sURIMatcher.addURI(CallLog.AUTHORITY, "calls/#", CALLS_ID);
61e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sURIMatcher.addURI(CallLog.AUTHORITY, "calls/filter/*", CALLS_FILTER);
62e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
63e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
64e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final HashMap<String, String> sCallsProjectionMap;
65e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    static {
66e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
67e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        // Calls projection map
68e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap = new HashMap<String, String>();
69e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls._ID, Calls._ID);
70e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.NUMBER, Calls.NUMBER);
71e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.DATE, Calls.DATE);
72e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.DURATION, Calls.DURATION);
73e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.TYPE, Calls.TYPE);
74e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.NEW, Calls.NEW);
7559f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        sCallsProjectionMap.put(Calls.VOICEMAIL_URI, Calls.VOICEMAIL_URI);
76b2197b235e3d96e7f70c24d548b7dac52dab88d8Flavio Lerda        sCallsProjectionMap.put(Calls.IS_READ, Calls.IS_READ);
77e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.CACHED_NAME, Calls.CACHED_NAME);
78e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.CACHED_NUMBER_TYPE, Calls.CACHED_NUMBER_TYPE);
79e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.CACHED_NUMBER_LABEL, Calls.CACHED_NUMBER_LABEL);
802530512f639c4979fd7371c7dd25dd67e8118124Bai Tao        sCallsProjectionMap.put(Calls.COUNTRY_ISO, Calls.COUNTRY_ISO);
81aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda        sCallsProjectionMap.put(Calls.GEOCODED_LOCATION, Calls.GEOCODED_LOCATION);
827a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_LOOKUP_URI, Calls.CACHED_LOOKUP_URI);
837a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_MATCHED_NUMBER, Calls.CACHED_MATCHED_NUMBER);
847a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_NORMALIZED_NUMBER, Calls.CACHED_NORMALIZED_NUMBER);
857a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_PHOTO_ID, Calls.CACHED_PHOTO_ID);
8613ed28505ed1af4f0b4a6297c4c6840d91f10c8cFlavio Lerda        sCallsProjectionMap.put(Calls.CACHED_FORMATTED_NUMBER, Calls.CACHED_FORMATTED_NUMBER);
87e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
88e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
89b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    private ContactsDatabaseHelper mDbHelper;
90e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private DatabaseUtils.InsertHelper mCallsInserter;
913a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa    private boolean mUseStrictPhoneNumberComparation;
92aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private VoicemailPermissions mVoicemailPermissions;
93aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    private CallLogInsertionHelper mCallLogInsertionHelper;
94e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
95e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
96e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public boolean onCreate() {
97663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
98663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki            Log.d(Constants.PERFORMANCE_TAG, "CallLogProvider.onCreate start");
99663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        }
100e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        final Context context = getContext();
101b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mDbHelper = getDatabaseHelper(context);
1023a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa        mUseStrictPhoneNumberComparation =
1033a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa            context.getResources().getBoolean(
1043a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa                    com.android.internal.R.bool.config_use_strict_phone_number_comparation);
105aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        mVoicemailPermissions = new VoicemailPermissions(context);
106aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda        mCallLogInsertionHelper = createCallLogInsertionHelper(context);
107663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
108663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki            Log.d(Constants.PERFORMANCE_TAG, "CallLogProvider.onCreate finish");
109663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        }
110e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return true;
111e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
112e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
113aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    @VisibleForTesting
114aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    protected CallLogInsertionHelper createCallLogInsertionHelper(final Context context) {
115c4144727cd740079f47e74ae5078d1613874f72aMakoto Onuki        return DefaultCallLogInsertionHelper.getInstance(context);
116aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    }
117aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda
118aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    @VisibleForTesting
119b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {
120b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        return ContactsDatabaseHelper.getInstance(context);
121e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
122e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
123e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
124e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
125e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            String sortOrder) {
126e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
12759f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        qb.setTables(Tables.CALLS);
12859f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        qb.setProjectionMap(sCallsProjectionMap);
12959f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        qb.setStrict(true);
13059f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee
131aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
132aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder);
133aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
134e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        int match = sURIMatcher.match(uri);
135e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (match) {
13659f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee            case CALLS:
137e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
138e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
139e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_ID: {
140aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                selectionBuilder.addClause(getEqualityClause(Calls._ID,
141aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                        parseCallIdFromUri(uri)));
142e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
143e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            }
144e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
145e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_FILTER: {
146e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                String phoneNumber = uri.getPathSegments().get(2);
147e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                qb.appendWhere("PHONE_NUMBERS_EQUAL(number, ");
148e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                qb.appendWhereEscapeString(phoneNumber);
1493a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa                qb.appendWhere(mUseStrictPhoneNumberComparation ? ", 1)" : ", 0)");
150e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
151e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            }
152e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
153e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
154e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                throw new IllegalArgumentException("Unknown URL " + uri);
155e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
156e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
157b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final SQLiteDatabase db = mDbHelper.getReadableDatabase();
158aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        Cursor c = qb.query(db, projection, selectionBuilder.build(), selectionArgs, null, null,
159aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                sortOrder, null);
160e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        if (c != null) {
161e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            c.setNotificationUri(getContext().getContentResolver(), CallLog.CONTENT_URI);
162e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
163e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return c;
164e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
165e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
166e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
167e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public String getType(Uri uri) {
168e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        int match = sURIMatcher.match(uri);
169e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (match) {
170e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS:
171e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                return Calls.CONTENT_TYPE;
172e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_ID:
173e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                return Calls.CONTENT_ITEM_TYPE;
174e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_FILTER:
175e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                return Calls.CONTENT_TYPE;
176e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
177e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                throw new IllegalArgumentException("Unknown URI: " + uri);
178e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
179e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
180e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
181e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
182e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public Uri insert(Uri uri, ContentValues values) {
18300e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjee        checkForSupportedColumns(sCallsProjectionMap, values);
184aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // Inserting a voicemail record through call_log requires the voicemail
185aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // permission and also requires the additional voicemail param set.
186aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (hasVoicemailValue(values)) {
187aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            checkIsAllowVoicemailRequest(uri);
188aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            mVoicemailPermissions.checkCallerHasFullAccess();
189aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
19037c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov        if (mCallsInserter == null) {
19137c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov            SQLiteDatabase db = mDbHelper.getWritableDatabase();
19237c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov            mCallsInserter = new DatabaseUtils.InsertHelper(db, Tables.CALLS);
19337c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov        }
194f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
195f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        ContentValues copiedValues = new ContentValues(values);
196f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
197f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        // Add the computed fields to the copied values.
198f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        mCallLogInsertionHelper.addComputedValues(copiedValues);
199f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
200f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        long rowId = getDatabaseModifier(mCallsInserter).insert(copiedValues);
201e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        if (rowId > 0) {
202e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            return ContentUris.withAppendedId(uri, rowId);
203e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
204e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return null;
205e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
206e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
207e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
208aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
20900e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjee        checkForSupportedColumns(sCallsProjectionMap, values);
210aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // Request that involves changing record type to voicemail requires the
211aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // voicemail param set in the uri.
212aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (hasVoicemailValue(values)) {
213aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            checkIsAllowVoicemailRequest(uri);
214aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
215aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
216aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
217aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder);
218aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
219b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
220aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        final int matchedUriId = sURIMatcher.match(uri);
221e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (matchedUriId) {
222e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS:
223e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
224e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
225e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_ID:
226aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                selectionBuilder.addClause(getEqualityClause(Calls._ID, parseCallIdFromUri(uri)));
227e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
228e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
229e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
230aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                throw new UnsupportedOperationException("Cannot update URL: " + uri);
231e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
232e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
2332e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        return getDatabaseModifier(db).update(Tables.CALLS, values, selectionBuilder.build(),
2342e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                selectionArgs);
235e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
236e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
237e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
238e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public int delete(Uri uri, String selection, String[] selectionArgs) {
239aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
240aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder);
241e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
242aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
243e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        final int matchedUriId = sURIMatcher.match(uri);
244e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (matchedUriId) {
245e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS:
2462e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                return getDatabaseModifier(db).delete(Tables.CALLS,
247929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                        selectionBuilder.build(), selectionArgs);
248e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
249e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                throw new UnsupportedOperationException("Cannot delete that URL: " + uri);
250e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
251e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
2526f157d1cfb219f80d375c1357bfbdc5bf599d91aDmitri Plotnikov
253929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    // Work around to let the test code override the context. getContext() is final so cannot be
254929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    // overridden.
255929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    protected Context context() {
256929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return getContext();
257929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
258929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
2592e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    /**
2602e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * Returns a {@link DatabaseModifier} that takes care of sending necessary notifications
2612e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * after the operation is performed.
2622e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     */
263929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
2642e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        return new DbModifierWithNotification(Tables.CALLS, db, context());
265929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
266929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
2672e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    /**
2682e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * Same as {@link #getDatabaseModifier(SQLiteDatabase)} but used for insert helper operations
2692e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * only.
2702e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     */
271929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private DatabaseModifier getDatabaseModifier(DatabaseUtils.InsertHelper insertHelper) {
2722e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        return new DbModifierWithNotification(Tables.CALLS, insertHelper, context());
273929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
274929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
275aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private boolean hasVoicemailValue(ContentValues values) {
276aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        return values.containsKey(Calls.TYPE) &&
277aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                values.getAsInteger(Calls.TYPE).equals(Calls.VOICEMAIL_TYPE);
278aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
279aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
280aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /**
281aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * Checks if the supplied uri requests to include voicemails and take appropriate
282aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * action.
283aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * <p> If voicemail is requested, then check for voicemail permissions. Otherwise
284aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * modify the selection to restrict to non-voicemail entries only.
285aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     */
286aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private void checkVoicemailPermissionAndAddRestriction(Uri uri,
287aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            SelectionBuilder selectionBuilder) {
288aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (isAllowVoicemailRequest(uri)) {
289aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            mVoicemailPermissions.checkCallerHasFullAccess();
290aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        } else {
291aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            selectionBuilder.addClause(EXCLUDE_VOICEMAIL_SELECTION);
292aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
293aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
294aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
295aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /**
296aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * Determines if the supplied uri has the request to allow voicemails to be
297aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * included.
298aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     */
299aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private boolean isAllowVoicemailRequest(Uri uri) {
30092d97071e56110e0df7f25e6ebc92ff4ebf74a88Flavio Lerda        return uri.getBooleanQueryParameter(Calls.ALLOW_VOICEMAILS_PARAM_KEY, false);
301aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
302aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
303aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /**
304aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * Checks to ensure that the given uri has allow_voicemail set. Used by
305aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * insert and update operations to check that ContentValues with voicemail
306aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * call type must use the voicemail uri.
307aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * @throws IllegalArgumentException if allow_voicemail is not set.
308aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     */
309aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private void checkIsAllowVoicemailRequest(Uri uri) {
310aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (!isAllowVoicemailRequest(uri)) {
311aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            throw new IllegalArgumentException(
312aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                    String.format("Uri %s cannot be used for voicemail record." +
31392d97071e56110e0df7f25e6ebc92ff4ebf74a88Flavio Lerda                            " Please set '%s=true' in the uri.", uri,
31492d97071e56110e0df7f25e6ebc92ff4ebf74a88Flavio Lerda                            Calls.ALLOW_VOICEMAILS_PARAM_KEY));
315aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
316aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
317aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
318aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee   /**
319aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    * Parses the call Id from the given uri, assuming that this is a uri that
320aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    * matches CALLS_ID. For other uri types the behaviour is undefined.
321aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    * @throws IllegalArgumentException if the id included in the Uri is not a valid long value.
322aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    */
3239978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda    private long parseCallIdFromUri(Uri uri) {
324aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        try {
3259978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda            return Long.parseLong(uri.getPathSegments().get(1));
326aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        } catch (NumberFormatException e) {
327aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            throw new IllegalArgumentException("Invalid call id in uri: " + uri, e);
328aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
329aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
330e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov}
331