SettingsProvider.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.providers.settings;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentProvider;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentUris;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentValues;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.RingtoneManager;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ParcelFileDescriptor;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.DrmStore;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileNotFoundException;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class SettingsProvider extends ContentProvider {
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "SettingsProvider";
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean LOCAL_LOGV = false;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TABLE_FAVORITES = "favorites";
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TABLE_OLD_FAVORITES = "old_favorites";
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private DatabaseHelper mOpenHelper;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Decode a content URL into the table, projection, and arguments
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * used to access the corresponding database rows.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class SqlArguments {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String table;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final String where;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final String[] args;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Operate on existing rows. */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments(Uri url, String where, String[] args) {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (url.getPathSegments().size() == 1) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                this.table = url.getPathSegments().get(0);
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                this.where = where;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                this.args = args;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (url.getPathSegments().size() != 2) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Invalid URI: " + url);
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (!TextUtils.isEmpty(where)) {
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new UnsupportedOperationException("WHERE clause not supported: " + url);
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                this.table = url.getPathSegments().get(0);
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ("gservices".equals(this.table) || "system".equals(this.table)
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || "secure".equals(this.table)) {
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    this.where = Settings.NameValueTable.NAME + "=?";
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    this.args = new String[] { url.getPathSegments().get(1) };
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    this.where = "_id=" + ContentUris.parseId(url);
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    this.args = null;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Insert new rows (no where clause allowed). */
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments(Uri url) {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (url.getPathSegments().size() == 1) {
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                this.table = url.getPathSegments().get(0);
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                this.where = null;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                this.args = null;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Invalid URI: " + url);
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the content URI of a row added to a table.
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param tableUri of the entire table
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param values found in the row
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param rowId of the row
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the content URI for this particular row
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri getUriFor(Uri tableUri, ContentValues values, long rowId) {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tableUri.getPathSegments().size() != 1) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Invalid URI: " + tableUri);
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String table = tableUri.getPathSegments().get(0);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ("gservices".equals(table) || "system".equals(table)
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || "secure".equals(table)) {
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String name = values.getAsString(Settings.NameValueTable.NAME);
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return Uri.withAppendedPath(tableUri, name);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ContentUris.withAppendedId(tableUri, rowId);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Send a notification when a particular content URI changes.
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Modify the system property used to communicate the version of
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this table, for tables which have such a property.  (The Settings
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * contract class uses these to provide client-side caches.)
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param uri to send notifications for
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendNotify(Uri uri) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Update the system property *first*, so if someone is listening for
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // a notification and then using the contract class to get their data,
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the system property will be updated and they'll get the new data.
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String property = null, table = uri.getPathSegments().get(0);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (table.equals("system")) {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            property = Settings.System.SYS_PROP_SETTING_VERSION;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (table.equals("secure")) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            property = Settings.Secure.SYS_PROP_SETTING_VERSION;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (table.equals("gservices")) {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            property = Settings.Gservices.SYS_PROP_SETTING_VERSION;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (property != null) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long version = SystemProperties.getLong(property, 0) + 1;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (LOCAL_LOGV) Log.v(TAG, "property: " + property + "=" + version);
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SystemProperties.set(property, Long.toString(version));
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Now send the notification through the content framework.
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String notify = uri.getQueryParameter("notify");
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (notify == null || "true".equals(notify)) {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getContext().getContentResolver().notifyChange(uri, null);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (LOCAL_LOGV) Log.v(TAG, "notifying: " + uri);
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (LOCAL_LOGV) Log.v(TAG, "notification suppressed: " + uri);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Make sure the caller has permission to write this data.
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args supplied by the caller
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws SecurityException if the caller is forbidden to write.
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void checkWritePermissions(SqlArguments args) {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ("secure".equals(args.table) &&
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                getContext().checkCallingOrSelfPermission(
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    PackageManager.PERMISSION_GRANTED) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new SecurityException("Cannot write secure settings table");
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // TODO: Move gservices into its own provider so we don't need this nonsense.
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if ("gservices".equals(args.table) &&
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getContext().checkCallingOrSelfPermission(
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.Manifest.permission.WRITE_GSERVICES) !=
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PackageManager.PERMISSION_GRANTED) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Cannot write gservices table");
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onCreate() {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOpenHelper = new DatabaseHelper(getContext());
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) {
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments args = new SqlArguments(url, where, whereArgs);
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // The favorites table was moved from this provider to a provider inside Home
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Home still need to query this table to upgrade from pre-cupcake builds
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // However, a cupcake+ build with no data does not contain this table which will
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // cause an exception in the SQL stack. The following line is a special case to
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // let the caller of the query have a chance to recover and avoid the exception
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TABLE_FAVORITES.equals(args.table)) {
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.table = TABLE_FAVORITES;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Cursor cursor = db.rawQuery("PRAGMA table_info(favorites);", null);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cursor != null) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean exists = cursor.getCount() > 0;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cursor.close();
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!exists) return null;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        qb.setTables(args.table);
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Cursor ret = qb.query(db, select, args.where, args.args, null, null, sort);
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ret.setNotificationUri(getContext().getContentResolver(), url);
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String getType(Uri url) {
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If SqlArguments supplies a where clause, then it must be an item
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // (because we aren't supplying our own where clause).
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments args = new SqlArguments(url, null, null);
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TextUtils.isEmpty(args.where)) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "vnd.android.cursor.dir/" + args.table;
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "vnd.android.cursor.item/" + args.table;
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int bulkInsert(Uri uri, ContentValues[] values) {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments args = new SqlArguments(uri);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TABLE_FAVORITES.equals(args.table)) {
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkWritePermissions(args);
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        db.beginTransaction();
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numValues = values.length;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < numValues; i++) {
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (db.insert(args.table, null, values[i]) < 0) return 0;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + values[i]);
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            db.setTransactionSuccessful();
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            db.endTransaction();
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sendNotify(uri);
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return values.length;
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Uri insert(Uri url, ContentValues initialValues) {
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments args = new SqlArguments(url);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TABLE_FAVORITES.equals(args.table)) {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkWritePermissions(args);
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long rowId = db.insert(args.table, null, initialValues);
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rowId <= 0) return null;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues);
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        url = getUriFor(url, initialValues, rowId);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sendNotify(url);
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return url;
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int delete(Uri url, String where, String[] whereArgs) {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments args = new SqlArguments(url, where, whereArgs);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TABLE_FAVORITES.equals(args.table)) {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.table = TABLE_FAVORITES;
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkWritePermissions(args);
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = db.delete(args.table, args.where, args.args);
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) sendNotify(url);
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return count;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SqlArguments args = new SqlArguments(url, where, whereArgs);
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TABLE_FAVORITES.equals(args.table)) {
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkWritePermissions(args);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = db.update(args.table, initialValues, args.where, args.args);
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count > 0) sendNotify(url);
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return count;
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * When a client attempts to openFile the default ringtone or
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * notification setting Uri, we will proxy the call to the current
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * default ringtone's Uri (if it is in the DRM or media provider).
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ringtoneType = RingtoneManager.getDefaultType(uri);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Above call returns -1 if the Uri doesn't match a default type
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ringtoneType != -1) {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Context context = getContext();
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the current value for the default sound
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (soundUri == null) {
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Fallback on any valid ringtone Uri
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                soundUri = RingtoneManager.getValidRingtoneUri(context);
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (soundUri != null) {
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Only proxy the openFile call to drm or media providers
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String authority = soundUri.getAuthority();
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (isDrmAuthority) {
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // Check DRM access permission here, since once we
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // do the below call the DRM will be checking our
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // permission, not our caller's permission
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            DrmStore.enforceAccessDrmPermission(context);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } catch (SecurityException e) {
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            throw new FileNotFoundException(e.getMessage());
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return context.getContentResolver().openFileDescriptor(soundUri, mode);
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.openFile(uri, mode);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
342