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)
71dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen            .add(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME)
72dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen            .add(Voicemails.PHONE_ACCOUNT_ID)
73ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(Voicemails.MIME_TYPE)
740f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen            .add(Voicemails.DIRTY)
750f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen            .add(Voicemails.DELETED)
76ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(OpenableColumns.DISPLAY_NAME)
77ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .add(OpenableColumns.SIZE)
78ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng            .build();
79ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
804b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final String mTableName;
814b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final SQLiteOpenHelper mDbHelper;
824b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final Context mContext;
834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private final VoicemailTable.DelegateHelper mDelegateHelper;
84aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    private final CallLogInsertionHelper mCallLogInsertionHelper;
854b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
864b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public VoicemailContentTable(String tableName, Context context, SQLiteOpenHelper dbHelper,
87aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda            VoicemailTable.DelegateHelper contentProviderHelper,
88aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda            CallLogInsertionHelper callLogInsertionHelper) {
894b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mTableName = tableName;
904b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mContext = context;
914b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDbHelper = dbHelper;
924b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDelegateHelper = contentProviderHelper;
931e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        mVoicemailProjectionMap = new ProjectionMap.Builder()
941e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails._ID)
951e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.NUMBER)
961e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.DATE)
971e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.DURATION)
981e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.IS_READ)
99d372af60001602a8c6cccf6258b514360c69b513Yorke Lee                .add(Voicemails.TRANSCRIPTION)
1001e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.STATE)
1011e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.SOURCE_DATA)
1021e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.SOURCE_PACKAGE)
1031e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.HAS_CONTENT)
1041e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails.MIME_TYPE)
1051e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(Voicemails._DATA)
106dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen                .add(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME)
107dca8f302db8e661f13f3585bc67c53a5adf36617Nancy Chen                .add(Voicemails.PHONE_ACCOUNT_ID)
1080f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen                .add(Voicemails.DIRTY)
1090f74e8600ad744f2e4ba9c6a4cdadf5da5a20e83Nancy Chen                .add(Voicemails.DELETED)
1101e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(OpenableColumns.DISPLAY_NAME, createDisplayName(context))
1111e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .add(OpenableColumns.SIZE, "NULL")
1121e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson                .build();
113aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda        mCallLogInsertionHelper = callLogInsertionHelper;
1141e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    }
1151e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson
1161e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    /**
1171e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * Calculate a suitable value for the display name column.
1181e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * <p>
1191e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * This is a bit of a hack, it uses a suitably localized string and uses SQL to combine this
1201e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     * with the number column.
1211e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson     */
1221e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson    private static String createDisplayName(Context context) {
1231e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        String prefix = context.getString(R.string.voicemail_from_column);
1241e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        return DatabaseUtils.sqlEscapeString(prefix) + " || " + Voicemails.NUMBER;
1254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1264b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Uri insert(UriData uriData, ContentValues values) {
1291e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        checkForSupportedColumns(mVoicemailProjectionMap, values);
1304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        ContentValues copiedValues = new ContentValues(values);
1314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        checkInsertSupported(uriData);
1324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mDelegateHelper.checkAndAddSourcePackageIntoValues(uriData, copiedValues);
1334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
134f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        // Add the computed fields to the copied values.
135f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        mCallLogInsertionHelper.addComputedValues(copiedValues);
136f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
1374b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // "_data" column is used by base ContentProvider's openFileHelper() to determine filename
1384b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // when Input/Output stream is requested to be opened.
1394b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        copiedValues.put(Voicemails._DATA, generateDataFile());
1404b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1414b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // call type is always voicemail.
1424b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        copiedValues.put(Calls.TYPE, Calls.VOICEMAIL_TYPE);
1435638e7fa091fa925b539a54bbf63abf94ea4c257Nancy Chen        // A voicemail is marked as new unless it is marked as read or explicitly overridden.
1445638e7fa091fa925b539a54bbf63abf94ea4c257Nancy Chen        boolean isRead = values.containsKey(Calls.IS_READ) ?
1455c466282ff1ebecb37c93dcb6d6ccfc845330e65Nancy Chen                values.getAsBoolean(Calls.IS_READ) : false;
146eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee        if (!values.containsKey(Calls.NEW)) {
1475638e7fa091fa925b539a54bbf63abf94ea4c257Nancy Chen            copiedValues.put(Calls.NEW, !isRead);
148eaa7d851000e368a18be24bc816046ad9cf49d6eDebashish Chatterjee        }
1494b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1504b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteDatabase db = mDbHelper.getWritableDatabase();
151929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues);
1524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (rowId > 0) {
1534b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            Uri newUri = ContentUris.withAppendedId(uriData.getUri(), rowId);
1544b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            // Populate the 'voicemail_uri' field to be used by the call_log provider.
1554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            updateVoicemailUri(db, newUri);
1564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return newUri;
1574b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return null;
1594b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1604b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void checkInsertSupported(UriData uriData) {
1624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (uriData.hasId()) {
1634b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new UnsupportedOperationException(String.format(
1644b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    "Cannot insert URI: %s. Inserted URIs should not contain an id.",
1654b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    uriData.getUri()));
1664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1674b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1684b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1694b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** Generates a random file for storing audio data. */
1704b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private String generateDataFile() {
1714b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        try {
1724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            File dataDirectory = mContext.getDir(DATA_DIRECTORY, Context.MODE_PRIVATE);
1734b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            File voicemailFile = File.createTempFile("voicemail", "", dataDirectory);
1744b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return voicemailFile.getAbsolutePath();
1754b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        } catch (IOException e) {
1764b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            // If we are unable to create a temporary file, something went horribly wrong.
1774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new RuntimeException("unable to create temp file", e);
1784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
1794b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1804b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void updateVoicemailUri(SQLiteDatabase db, Uri newUri) {
1814b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        ContentValues values = new ContentValues();
1824b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        values.put(Calls.VOICEMAIL_URI, newUri.toString());
1834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Directly update the db because we cannot update voicemail_uri through external
1844b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // update() due to projectionMap check. This also avoids unnecessary permission
1854b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // checks that are already done as part of insert request.
1869cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        db.update(mTableName, values, UriData.createUriData(newUri).getWhereClause(), null);
1874b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
1884b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1894b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1904b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int delete(UriData uriData, String selection, String[] selectionArgs) {
1914b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
1929cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
1934b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
1944b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
1954b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Delete all the files associated with this query.  Once we've deleted the rows, there will
1964b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // be no way left to get hold of the files.
1974b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        Cursor cursor = null;
1984b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        try {
1994b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            cursor = query(uriData, FILENAME_ONLY_PROJECTION, selection, selectionArgs, null);
2004b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            while (cursor.moveToNext()) {
2011c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                String filename = cursor.getString(0);
2021c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                if (filename == null) {
2031c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                    Log.w(TAG, "No filename for uri " + uriData.getUri() + ", cannot delete file");
2041c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                    continue;
2051c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                }
2061c8e5fcdd6199f5959aaa6eab47e806b401efdd9Hugo Hudson                File file = new File(filename);
2074b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                if (file.exists()) {
2084b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    boolean success = file.delete();
2094b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    if (!success) {
2104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                        Log.e(TAG, "Failed to delete file: " + file.getAbsolutePath());
2114b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    }
2124b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                }
2134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            }
2144b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        } finally {
2154b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            CloseUtils.closeQuietly(cursor);
2164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2174b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2184b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // Now delete the rows themselves.
219929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return getDatabaseModifier(db).delete(mTableName, combinedClause,
220929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                selectionArgs);
2214b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2234b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Cursor query(UriData uriData, String[] projection, String selection,
2254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String[] selectionArgs, String sortOrder) {
2264b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        qb.setTables(mTableName);
2281e6310fcc55c8549c98018fc427b54e1619320a4Hugo Hudson        qb.setProjectionMap(mVoicemailProjectionMap);
2294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        qb.setStrict(true);
2304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2319cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
2324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
2334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SQLiteDatabase db = mDbHelper.getReadableDatabase();
2344b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        Cursor c = qb.query(db, projection, combinedClause, selectionArgs, null, null, sortOrder);
2354b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (c != null) {
2364b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            c.setNotificationUri(mContext.getContentResolver(), Voicemails.CONTENT_URI);
2374b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2384b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return c;
2394b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2404b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2414b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2424b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int update(UriData uriData, ContentValues values, String selection,
2434b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String[] selectionArgs) {
244ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
245ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng        checkForSupportedColumns(ALLOWED_COLUMNS, values, "Updates are not allowed.");
2464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        checkUpdateSupported(uriData);
247ab2a24c126f35ae4aefb469f91094e5972abd8f0Chiao Cheng
2484b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
2494b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // TODO: This implementation does not allow bulk update because it only accepts
2504b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // URI that include message Id. I think we do want to support bulk update.
2519cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
2524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getCallTypeClause());
253929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee        return getDatabaseModifier(db).update(mTableName, values, combinedClause,
254929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                selectionArgs);
2554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2574b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private void checkUpdateSupported(UriData uriData) {
2584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (!uriData.hasId()) {
2594b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new UnsupportedOperationException(String.format(
2604b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    "Cannot update URI: %s.  Bulk update not supported", uriData.getUri()));
2614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2634b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2644b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2654b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public String getType(UriData uriData) {
2664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (uriData.hasId()) {
267d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee            return Voicemails.ITEM_TYPE;
268d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee        } else {
269d558ccc921460ac382850a8e6e2e668f3a2b9b26Debashish Chatterjee            return Voicemails.DIR_TYPE;
2704b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2714b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2734b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2749cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    public ParcelFileDescriptor openFile(UriData uriData, String mode)
2759cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            throws FileNotFoundException {
2763ae32e20bc3f7a278471475efa300b6544b1112eDebashish Chatterjee        return mDelegateHelper.openDataFile(uriData, mode);
2774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
2784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee
2794b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** Creates a clause to restrict the selection to only voicemail call type.*/
2804b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private String getCallTypeClause() {
2819978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda        return getEqualityClause(Calls.TYPE, Calls.VOICEMAIL_TYPE);
2824b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
283929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
284929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
2852e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee        return new DbModifierWithNotification(mTableName, db, mContext);
286929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
2874b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee}
288