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.SQLiteOpenHelper;
294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.database.sqlite.SQLiteQueryBuilder;
304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.net.Uri;
314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.os.ParcelFileDescriptor;
324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.provider.CallLog.Calls;
331e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudsonimport android.provider.OpenableColumns;
344b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.provider.VoicemailContract.Voicemails;
354b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport android.util.Log;
364b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
37ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Chengimport com.google.common.collect.ImmutableSet;
38ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
3938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.common.content.ProjectionMap;
4038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.VoicemailContentProvider.UriData;
4138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.CloseUtils;
42284f71646d1953f2d78b53e2cdb42cb93e1d9d6fChiao Chengimport com.google.common.collect.ImmutableSet;
4338210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki
444b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport java.io.File;
459cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjeeimport java.io.FileNotFoundException;
464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport java.io.IOException;
474b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
484b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee/**
494b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee * Implementation of {@link VoicemailTable.Delegate} for the voicemail content table.
504b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee */
514b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeepublic class VoicemailContentTable implements VoicemailTable.Delegate {
524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private static final String TAG = "VoicemailContentProvider";
531e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    private final ProjectionMap mVoicemailProjectionMap;
544b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** The private directory in which to store the data associated with the voicemail. */
564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private static final String DATA_DIRECTORY = "voicemail-data";
574b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private static final String[] FILENAME_ONLY_PROJECTION = new String[] { Voicemails._DATA };
594b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
60ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng    private static final ImmutableSet<String> ALLOWED_COLUMNS = new ImmutableSet.Builder<String>()
61ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails._ID)
62ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.NUMBER)
63ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.DATE)
64ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.DURATION)
65ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.IS_READ)
66d372af60001602a8c6cccf6258b514360c69b513Yorke Lee            .add(Voicemails.TRANSCRIPTION)
67ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.STATE)
68ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.SOURCE_DATA)
69ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.SOURCE_PACKAGE)
70ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.HAS_CONTENT)
71ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.MIME_TYPE)
72ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(OpenableColumns.DISPLAY_NAME)
73ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(OpenableColumns.SIZE)
74ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .build();
75ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
764b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final String mTableName;
774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final SQLiteOpenHelper mDbHelper;
784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final Context mContext;
794b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final VoicemailTable.DelegateHelper mDelegateHelper;
80aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    private final CallLogInsertionHelper mCallLogInsertionHelper;
814b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
824b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public VoicemailContentTable(String tableName, Context context, SQLiteOpenHelper dbHelper,
83aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda            VoicemailTable.DelegateHelper contentProviderHelper,
84aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda            CallLogInsertionHelper callLogInsertionHelper) {
854b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mTableName = tableName;
864b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mContext = context;
874b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDbHelper = dbHelper;
884b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDelegateHelper = contentProviderHelper;
891e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        mVoicemailProjectionMap = new ProjectionMap.Builder()
901e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails._ID)
911e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.NUMBER)
921e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.DATE)
931e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.DURATION)
941e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.IS_READ)
95d372af60001602a8c6cccf6258b514360c69b513Yorke Lee                .add(Voicemails.TRANSCRIPTION)
961e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.STATE)
971e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.SOURCE_DATA)
981e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.SOURCE_PACKAGE)
991e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.HAS_CONTENT)
1001e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.MIME_TYPE)
1011e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails._DATA)
1021e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(OpenableColumns.DISPLAY_NAME, createDisplayName(context))
1031e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(OpenableColumns.SIZE, "NULL")
1041e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .build();
105aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda        mCallLogInsertionHelper = callLogInsertionHelper;
1061e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    }
1071e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson
1081e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    /**
1091e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * Calculate a suitable value for the display name column.
1101e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * <p>
1111e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * This is a bit of a hack, it uses a suitably localized string and uses SQL to combine this
1121e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * with the number column.
1131e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     */
1141e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    private static String createDisplayName(Context context) {
1151e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        String prefix = context.getString(R.string.voicemail_from_column);
1161e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        return DatabaseUtils.sqlEscapeString(prefix) + " || " + Voicemails.NUMBER;
1174b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1184b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1204b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Uri insert(UriData uriData, ContentValues values) {
1211e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        checkForSupportedColumns(mVoicemailProjectionMap, values);
1224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        ContentValues copiedValues = new ContentValues(values);
1234b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        checkInsertSupported(uriData);
1244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDelegateHelper.checkAndAddSourcePackageIntoValues(uriData, copiedValues);
1254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
126f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        // Add the computed fields to the copied values.
127f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        mCallLogInsertionHelper.addComputedValues(copiedValues);
128f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
1294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // "_data" column is used by base ContentProvider's openFileHelper() to determine filename
1304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // when Input/Output stream is requested to be opened.
1314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        copiedValues.put(Voicemails._DATA, generateDataFile());
1324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // call type is always voicemail.
1344b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        copiedValues.put(Calls.TYPE, Calls.VOICEMAIL_TYPE);
135eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee        // By default marked as new, unless explicitly overridden.
136eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee        if (!values.containsKey(Calls.NEW)) {
137eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee            copiedValues.put(Calls.NEW, 1);
138eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee        }
1394b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1404b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteDatabase db = mDbHelper.getWritableDatabase();
141929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues);
1424b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (rowId > 0) {
1434b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            Uri newUri = ContentUris.withAppendedId(uriData.getUri(), rowId);
1444b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            // Populate the 'voicemail_uri' field to be used by the call_log provider.
1454b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            updateVoicemailUri(db, newUri);
1464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return newUri;
1474b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1484b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return null;
1494b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1504b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1514b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void checkInsertSupported(UriData uriData) {
1524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (uriData.hasId()) {
1534b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new UnsupportedOperationException(String.format(
1544b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    "Cannot insert URI: %s. Inserted URIs should not contain an id.",
1554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    uriData.getUri()));
1564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1574b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1594b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** Generates a random file for storing audio data. */
1604b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private String generateDataFile() {
1614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        try {
1624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            File dataDirectory = mContext.getDir(DATA_DIRECTORY, Context.MODE_PRIVATE);
1634b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            File voicemailFile = File.createTempFile("voicemail", "", dataDirectory);
1644b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return voicemailFile.getAbsolutePath();
1654b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        } catch (IOException e) {
1664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            // If we are unable to create a temporary file, something went horribly wrong.
1674b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new RuntimeException("unable to create temp file", e);
1684b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1694b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1704b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void updateVoicemailUri(SQLiteDatabase db, Uri newUri) {
1714b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        ContentValues values = new ContentValues();
1724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        values.put(Calls.VOICEMAIL_URI, newUri.toString());
1734b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Directly update the db because we cannot update voicemail_uri through external
1744b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // update() due to projectionMap check. This also avoids unnecessary permission
1754b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // checks that are already done as part of insert request.
1769cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        db.update(mTableName, values, UriData.createUriData(newUri).getWhereClause(), null);
1774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1794b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1804b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int delete(UriData uriData, String selection, String[] selectionArgs) {
1814b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
1829cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
1834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
1844b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1854b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Delete all the files associated with this query.  Once we've deleted the rows, there will
1864b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // be no way left to get hold of the files.
1874b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        Cursor cursor = null;
1884b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        try {
1894b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            cursor = query(uriData, FILENAME_ONLY_PROJECTION, selection, selectionArgs, null);
1904b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            while (cursor.moveToNext()) {
1911c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                String filename = cursor.getString(0);
1921c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                if (filename == null) {
1931c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                    Log.w(TAG, "No filename for uri " + uriData.getUri() + ", cannot delete file");
1941c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                    continue;
1951c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                }
1961c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                File file = new File(filename);
1974b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                if (file.exists()) {
1984b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    boolean success = file.delete();
1994b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    if (!success) {
2004b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                        Log.e(TAG, "Failed to delete file: " + file.getAbsolutePath());
2014b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    }
2024b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                }
2034b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            }
2044b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        } finally {
2054b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            CloseUtils.closeQuietly(cursor);
2064b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2074b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2084b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Now delete the rows themselves.
209929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return getDatabaseModifier(db).delete(mTableName, combinedClause,
210929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                selectionArgs);
2114b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2124b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2144b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Cursor query(UriData uriData, String[] projection, String selection,
2154b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String[] selectionArgs, String sortOrder) {
2164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2174b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        qb.setTables(mTableName);
2181e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        qb.setProjectionMap(mVoicemailProjectionMap);
2194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        qb.setStrict(true);
2204b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2219cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
2224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
2234b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteDatabase db = mDbHelper.getReadableDatabase();
2244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        Cursor c = qb.query(db, projection, combinedClause, selectionArgs, null, null, sortOrder);
2254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (c != null) {
2264b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            c.setNotificationUri(mContext.getContentResolver(), Voicemails.CONTENT_URI);
2274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return c;
2294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int update(UriData uriData, ContentValues values, String selection,
2334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String[] selectionArgs) {
234ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
235ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng        checkForSupportedColumns(ALLOWED_COLUMNS, values, "Updates are not allowed.");
2364b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        checkUpdateSupported(uriData);
237ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
2384b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
2394b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // TODO: This implementation does not allow bulk update because it only accepts
2404b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // URI that include message Id. I think we do want to support bulk update.
2419cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
2424b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
243929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return getDatabaseModifier(db).update(mTableName, values, combinedClause,
244929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                selectionArgs);
2454b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2474b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void checkUpdateSupported(UriData uriData) {
2484b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (!uriData.hasId()) {
2494b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new UnsupportedOperationException(String.format(
2504b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    "Cannot update URI: %s.  Bulk update not supported", uriData.getUri()));
2514b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2534b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2544b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public String getType(UriData uriData) {
2564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (uriData.hasId()) {
257d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee            return Voicemails.ITEM_TYPE;
258d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee        } else {
259d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee            return Voicemails.DIR_TYPE;
2604b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2634b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2649cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    public ParcelFileDescriptor openFile(UriData uriData, String mode)
2659cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            throws FileNotFoundException {
2663ae32e20bc3f7a278471475efa300b6544b1112eDebashish Chatterjee        return mDelegateHelper.openDataFile(uriData, mode);
2674b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2684b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2694b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** Creates a clause to restrict the selection to only voicemail call type.*/
2704b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private String getCallTypeClause() {
2719978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda        return getEqualityClause(Calls.TYPE, Calls.VOICEMAIL_TYPE);
2724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
273929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
274929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
2752e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        return new DbModifierWithNotification(mTableName, db, mContext);
276929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
2774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee}
278