14b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee/*
24b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * Copyright (C) 2011 The Android Open Source Project
34b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee *
44b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * Licensed under the Apache License, Version 2.0 (the "License");
54b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * you may not use this file except in compliance with the License.
64b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * You may obtain a copy of the License at
74b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee *
84b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee *      http://www.apache.org/licenses/LICENSE-2.0
94b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee *
104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * Unless required by applicable law or agreed to in writing, software
114b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * distributed under the License is distributed on an "AS IS" BASIS,
124b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * See the License for the specific language governing permissions and
144b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * limitations under the License
154b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee */
164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeepackage com.android.providers.contacts;
174b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
184b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.checkForSupportedColumns;
194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.concatenateClauses;
204b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.getEqualityClause;
214b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.content.ContentUris;
234b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.content.ContentValues;
244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.content.Context;
254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.database.Cursor;
261e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudsonimport android.database.DatabaseUtils;
274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.database.sqlite.SQLiteDatabase;
284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.database.sqlite.SQLiteQueryBuilder;
294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.net.Uri;
304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.os.ParcelFileDescriptor;
314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.provider.CallLog.Calls;
321e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudsonimport android.provider.OpenableColumns;
334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.provider.VoicemailContract.Voicemails;
344b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.util.Log;
3538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.common.content.ProjectionMap;
3638210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.VoicemailContentProvider.UriData;
3738210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.CloseUtils;
38a0722de4886cdc06acf344052b70954415d25d80Ta-wei Yenimport com.google.common.collect.ImmutableSet;
394b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport java.io.File;
409cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjeeimport java.io.FileNotFoundException;
414b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport java.io.IOException;
424b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
434b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee/**
444b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * Implementation of {@link VoicemailTable.Delegate} for the voicemail content table.
454b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee */
464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeepublic class VoicemailContentTable implements VoicemailTable.Delegate {
47a0722de4886cdc06acf344052b70954415d25d80Ta-wei Yen
48a0722de4886cdc06acf344052b70954415d25d80Ta-wei Yen    private static final String TAG = "VmContentProvider";
491e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    private final ProjectionMap mVoicemailProjectionMap;
504b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
514b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** The private directory in which to store the data associated with the voicemail. */
524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private static final String DATA_DIRECTORY = "voicemail-data";
534b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
544b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private static final String[] FILENAME_ONLY_PROJECTION = new String[] { Voicemails._DATA };
554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
56ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng    private static final ImmutableSet<String> ALLOWED_COLUMNS = new ImmutableSet.Builder<String>()
57ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails._ID)
58ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.NUMBER)
59ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.DATE)
60ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.DURATION)
61ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.IS_READ)
62d372af60001602a8c6cccf6258b514360c69b513Yorke Lee            .add(Voicemails.TRANSCRIPTION)
63ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.STATE)
64ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.SOURCE_DATA)
65ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.SOURCE_PACKAGE)
66ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.HAS_CONTENT)
67dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen            .add(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME)
68dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen            .add(Voicemails.PHONE_ACCOUNT_ID)
69ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.MIME_TYPE)
700f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen            .add(Voicemails.DIRTY)
710f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen            .add(Voicemails.DELETED)
7252cb1f8391fdf93ad90d675585a9c7e385e4a8d6Ta-wei Yen            .add(Voicemails.LAST_MODIFIED)
7327bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen            .add(Voicemails.BACKED_UP)
7427bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen            .add(Voicemails.RESTORED)
7527bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen            .add(Voicemails.ARCHIVED)
7627bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen            .add(Voicemails.IS_OMTP_VOICEMAIL)
77ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(OpenableColumns.DISPLAY_NAME)
78ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(OpenableColumns.SIZE)
79ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .build();
80ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
814b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final String mTableName;
82dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki    private final CallLogDatabaseHelper mDbHelper;
834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final Context mContext;
844b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final VoicemailTable.DelegateHelper mDelegateHelper;
85aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    private final CallLogInsertionHelper mCallLogInsertionHelper;
864b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
87dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki    public VoicemailContentTable(String tableName, Context context, CallLogDatabaseHelper dbHelper,
88aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda            VoicemailTable.DelegateHelper contentProviderHelper,
89aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda            CallLogInsertionHelper callLogInsertionHelper) {
904b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mTableName = tableName;
914b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mContext = context;
924b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDbHelper = dbHelper;
934b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDelegateHelper = contentProviderHelper;
941e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        mVoicemailProjectionMap = new ProjectionMap.Builder()
951e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails._ID)
961e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.NUMBER)
971e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.DATE)
981e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.DURATION)
991e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.IS_READ)
100d372af60001602a8c6cccf6258b514360c69b513Yorke Lee                .add(Voicemails.TRANSCRIPTION)
1011e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.STATE)
1021e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.SOURCE_DATA)
1031e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.SOURCE_PACKAGE)
1041e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.HAS_CONTENT)
1051e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.MIME_TYPE)
1061e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails._DATA)
107dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen                .add(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME)
108dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen                .add(Voicemails.PHONE_ACCOUNT_ID)
1090f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen                .add(Voicemails.DIRTY)
1100f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen                .add(Voicemails.DELETED)
11152cb1f8391fdf93ad90d675585a9c7e385e4a8d6Ta-wei Yen                .add(Voicemails.LAST_MODIFIED)
11227bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen                .add(Voicemails.BACKED_UP)
11327bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen                .add(Voicemails.RESTORED)
11427bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen                .add(Voicemails.ARCHIVED)
11527bedb2f415f7bf33f351c6b2575a0087577c077Ta-wei Yen                .add(Voicemails.IS_OMTP_VOICEMAIL)
1161e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(OpenableColumns.DISPLAY_NAME, createDisplayName(context))
1171e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(OpenableColumns.SIZE, "NULL")
1181e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .build();
119aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda        mCallLogInsertionHelper = callLogInsertionHelper;
1201e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    }
1211e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson
1221e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    /**
1231e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * Calculate a suitable value for the display name column.
1241e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * <p>
1251e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * This is a bit of a hack, it uses a suitably localized string and uses SQL to combine this
1261e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * with the number column.
1271e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     */
1281e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    private static String createDisplayName(Context context) {
1291e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        String prefix = context.getString(R.string.voicemail_from_column);
1301e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        return DatabaseUtils.sqlEscapeString(prefix) + " || " + Voicemails.NUMBER;
1314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1344b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Uri insert(UriData uriData, ContentValues values) {
1351e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        checkForSupportedColumns(mVoicemailProjectionMap, values);
1364b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        ContentValues copiedValues = new ContentValues(values);
1374b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        checkInsertSupported(uriData);
1384b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDelegateHelper.checkAndAddSourcePackageIntoValues(uriData, copiedValues);
1394b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
140f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        // Add the computed fields to the copied values.
141f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        mCallLogInsertionHelper.addComputedValues(copiedValues);
142f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
1434b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // "_data" column is used by base ContentProvider's openFileHelper() to determine filename
1444b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // when Input/Output stream is requested to be opened.
1454b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        copiedValues.put(Voicemails._DATA, generateDataFile());
1464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1474b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // call type is always voicemail.
1484b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        copiedValues.put(Calls.TYPE, Calls.VOICEMAIL_TYPE);
1495638e7fa091fa925b539a54bbf63abf94ea4c257Nancy Chen        // A voicemail is marked as new unless it is marked as read or explicitly overridden.
1505638e7fa091fa925b539a54bbf63abf94ea4c257Nancy Chen        boolean isRead = values.containsKey(Calls.IS_READ) ?
1515c466282ff1ebecb37c93dcb6d6ccfc845330e65Nancy Chen                values.getAsBoolean(Calls.IS_READ) : false;
152eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee        if (!values.containsKey(Calls.NEW)) {
1535638e7fa091fa925b539a54bbf63abf94ea4c257Nancy Chen            copiedValues.put(Calls.NEW, !isRead);
154eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee        }
1554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteDatabase db = mDbHelper.getWritableDatabase();
157929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues);
1584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (rowId > 0) {
1594b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            Uri newUri = ContentUris.withAppendedId(uriData.getUri(), rowId);
1604b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            // Populate the 'voicemail_uri' field to be used by the call_log provider.
1614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            updateVoicemailUri(db, newUri);
1624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return newUri;
1634b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1644b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return null;
1654b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1674b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void checkInsertSupported(UriData uriData) {
1684b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (uriData.hasId()) {
1694b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new UnsupportedOperationException(String.format(
1704b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    "Cannot insert URI: %s. Inserted URIs should not contain an id.",
1714b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    uriData.getUri()));
1724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1734b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1744b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1754b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** Generates a random file for storing audio data. */
1764b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private String generateDataFile() {
1774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        try {
1784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            File dataDirectory = mContext.getDir(DATA_DIRECTORY, Context.MODE_PRIVATE);
1794b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            File voicemailFile = File.createTempFile("voicemail", "", dataDirectory);
1804b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return voicemailFile.getAbsolutePath();
1814b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        } catch (IOException e) {
1824b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            // If we are unable to create a temporary file, something went horribly wrong.
1834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new RuntimeException("unable to create temp file", e);
1844b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1854b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1864b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void updateVoicemailUri(SQLiteDatabase db, Uri newUri) {
1874b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        ContentValues values = new ContentValues();
1884b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        values.put(Calls.VOICEMAIL_URI, newUri.toString());
1894b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Directly update the db because we cannot update voicemail_uri through external
1904b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // update() due to projectionMap check. This also avoids unnecessary permission
1914b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // checks that are already done as part of insert request.
1929cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        db.update(mTableName, values, UriData.createUriData(newUri).getWhereClause(), null);
1934b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1944b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1954b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1964b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int delete(UriData uriData, String selection, String[] selectionArgs) {
1974b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
1989cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
1994b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
2004b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2014b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Delete all the files associated with this query.  Once we've deleted the rows, there will
2024b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // be no way left to get hold of the files.
2034b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        Cursor cursor = null;
2044b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        try {
2054b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            cursor = query(uriData, FILENAME_ONLY_PROJECTION, selection, selectionArgs, null);
2064b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            while (cursor.moveToNext()) {
2071c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                String filename = cursor.getString(0);
2081c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                if (filename == null) {
2091c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                    Log.w(TAG, "No filename for uri " + uriData.getUri() + ", cannot delete file");
2101c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                    continue;
2111c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                }
2121c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                File file = new File(filename);
2134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                if (file.exists()) {
2144b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    boolean success = file.delete();
2154b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    if (!success) {
2164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                        Log.e(TAG, "Failed to delete file: " + file.getAbsolutePath());
2174b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    }
2184b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                }
2194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            }
2204b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        } finally {
2214b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            CloseUtils.closeQuietly(cursor);
2224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2234b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Now delete the rows themselves.
225929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return getDatabaseModifier(db).delete(mTableName, combinedClause,
226929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                selectionArgs);
2274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Cursor query(UriData uriData, String[] projection, String selection,
2314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String[] selectionArgs, String sortOrder) {
2324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        qb.setTables(mTableName);
2341e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        qb.setProjectionMap(mVoicemailProjectionMap);
2354b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        qb.setStrict(true);
2364b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2379cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
2384b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
2394b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteDatabase db = mDbHelper.getReadableDatabase();
2404b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        Cursor c = qb.query(db, projection, combinedClause, selectionArgs, null, null, sortOrder);
2414b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (c != null) {
2424b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            c.setNotificationUri(mContext.getContentResolver(), Voicemails.CONTENT_URI);
2434b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2444b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return c;
2454b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2474b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2484b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int update(UriData uriData, ContentValues values, String selection,
2494b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String[] selectionArgs) {
250ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
251ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng        checkForSupportedColumns(ALLOWED_COLUMNS, values, "Updates are not allowed.");
2524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        checkUpdateSupported(uriData);
253ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
2544b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
2554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // TODO: This implementation does not allow bulk update because it only accepts
2564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // URI that include message Id. I think we do want to support bulk update.
2579cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
2584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
259a0722de4886cdc06acf344052b70954415d25d80Ta-wei Yen        return getDatabaseModifier(db).update(uriData.getUri(), mTableName, values, combinedClause,
260929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                selectionArgs);
2614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2634b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void checkUpdateSupported(UriData uriData) {
2644b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (!uriData.hasId()) {
2654b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new UnsupportedOperationException(String.format(
2664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    "Cannot update URI: %s.  Bulk update not supported", uriData.getUri()));
2674b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2684b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2694b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2704b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2714b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public String getType(UriData uriData) {
2724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (uriData.hasId()) {
273d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee            return Voicemails.ITEM_TYPE;
274d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee        } else {
275d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee            return Voicemails.DIR_TYPE;
2764b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2794b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2809cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    public ParcelFileDescriptor openFile(UriData uriData, String mode)
2819cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            throws FileNotFoundException {
2823ae32e20bc3f7a278471475efa300b6544b1112eDebashish Chatterjee        return mDelegateHelper.openDataFile(uriData, mode);
2834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2844b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2854b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** Creates a clause to restrict the selection to only voicemail call type.*/
2864b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private String getCallTypeClause() {
2879978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda        return getEqualityClause(Calls.TYPE, Calls.VOICEMAIL_TYPE);
2884b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
289929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
290929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
2912e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        return new DbModifierWithNotification(mTableName, db, mContext);
292929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
293a0722de4886cdc06acf344052b70954415d25d80Ta-wei Yen
2944b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee}
295