DownloadProvider.java revision 7dd92fa94df0a13b4592ee636b7aa2b605f6b473
157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/*
257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project *
457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * you may not use this file except in compliance with the License.
657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * You may obtain a copy of the License at
757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project *
857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project *
1057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * See the License for the specific language governing permissions and
1457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * limitations under the License.
1557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */
1657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
1757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpackage com.android.providers.downloads;
1857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
1957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentProvider;
2057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentValues;
2157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Context;
2257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Intent;
2357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.UriMatcher;
2457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.pm.PackageManager;
251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CrossProcessCursor;
2657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.Cursor;
271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWindow;
281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWrapper;
29c6f5aad265cfc36a64cd2bdb5adf3cc9736bbd80Jean-Baptiste Queruimport android.database.SQLException;
3057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase;
3157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper;
3257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder;
3357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.net.Uri;
3457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Binder;
3557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.ParcelFileDescriptor;
3657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Process;
3757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.provider.Downloads;
3857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.util.Config;
3957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.util.Log;
4057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.io.File;
4257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport java.io.FileNotFoundException;
431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.util.HashSet;
441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
4557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
4657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/**
4757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Allows application to interact with the download manager.
4857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */
4957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpublic final class DownloadProvider extends ContentProvider {
5057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
5157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** Database filename */
5257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DB_NAME = "downloads.db";
531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    /** Current database version */
541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final int DB_VERSION = 100;
551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    /** Database version from which upgrading is a nop */
561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final int DB_VERSION_NOP_UPGRADE_FROM = 31;
571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    /** Database version to which upgrading is a nop */
581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final int DB_VERSION_NOP_UPGRADE_TO = 100;
5957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** Name of table in the database */
6057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DB_TABLE = "downloads";
6157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
6257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** MIME type for the entire download list */
6357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DOWNLOAD_LIST_TYPE = "vnd.android.cursor.dir/download";
6457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** MIME type for an individual download */
6557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DOWNLOAD_TYPE = "vnd.android.cursor.item/download";
6657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
6757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** URI matcher used to recognize URIs sent by applications */
6857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
6957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** URI matcher constant for the URI of the entire download list */
7057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final int DOWNLOADS = 1;
7157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** URI matcher constant for the URI of an individual download */
7257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final int DOWNLOADS_ID = 2;
7357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    static {
7457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        sURIMatcher.addURI("downloads", "download", DOWNLOADS);
7557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        sURIMatcher.addURI("downloads", "download/#", DOWNLOADS_ID);
7657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
7757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final String[] sAppReadableColumnsArray = new String[] {
797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl._ID,
807dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_APP_DATA,
817dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl._DATA,
827dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_MIME_TYPE,
837dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_VISIBILITY,
847dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_DESTINATION,
857dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_CONTROL,
867dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_STATUS,
877dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_LAST_MODIFICATION,
887dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
897dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_NOTIFICATION_CLASS,
907dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_TOTAL_BYTES,
917dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_CURRENT_BYTES,
927dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_TITLE,
937dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_DESCRIPTION
941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    };
951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static HashSet<String> sAppReadableColumnsSet;
971fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    static {
981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        sAppReadableColumnsSet = new HashSet<String>();
991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        for (int i = 0; i < sAppReadableColumnsArray.length; ++i) {
1001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            sAppReadableColumnsSet.add(sAppReadableColumnsArray[i]);
1011fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
1021fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
1031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
10457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** The database that lies underneath this content provider */
10557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private SQLiteOpenHelper mOpenHelper = null;
10657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
10757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
10857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Creates and updated database on demand when opening it.
10957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Helper class to create database the first time the provider is
11057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * initialized and upgrade it when a new version of the provider needs
11157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * an updated version of the database.
11257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
11357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private final class DatabaseHelper extends SQLiteOpenHelper {
11457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
11557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        public DatabaseHelper(final Context context) {
11657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            super(context, DB_NAME, null, DB_VERSION);
11757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
11857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
11957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        /**
12057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * Creates database the first time we try to open it.
12157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         */
12257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        @Override
12357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        public void onCreate(final SQLiteDatabase db) {
12457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Constants.LOGVV) {
12557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                Log.v(Constants.TAG, "populating new database");
12657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
12757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            createTable(db);
12857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
12957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
13057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        /* (not a javadoc comment)
13157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * Checks data integrity when opening the database.
13257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         */
13357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        /*
13457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * @Override
13557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * public void onOpen(final SQLiteDatabase db) {
13657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         *     super.onOpen(db);
13757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * }
13857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         */
13957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
14057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        /**
14157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * Updates the database format when a content provider is used
14257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * with a database that was created with a different format.
14357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         */
14457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        // Note: technically, this could also be a downgrade, so if we want
14557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        //       to gracefully handle upgrades we should be careful about
14657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        //       what to do on downgrades.
14757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        @Override
1481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public void onUpgrade(final SQLiteDatabase db, int oldV, final int newV) {
1491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (oldV == DB_VERSION_NOP_UPGRADE_FROM) {
1501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                if (newV == DB_VERSION_NOP_UPGRADE_TO) { // that's a no-op upgrade.
1511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    return;
1521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                }
1531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                // NOP_FROM and NOP_TO are identical, just in different codelines. Upgrading
1541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                //     from NOP_FROM is the same as upgrading from NOP_TO.
1551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                oldV = DB_VERSION_NOP_UPGRADE_TO;
1561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
1571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Log.i(Constants.TAG, "Upgrading downloads database from version " + oldV + " to " + newV
15857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    + ", which will destroy all old data");
15957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            dropTable(db);
16057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            createTable(db);
16157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
16257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
16357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
16457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
16557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Initializes the content provider when it is created.
16657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
16757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
16857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public boolean onCreate() {
16957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        mOpenHelper = new DatabaseHelper(getContext());
17057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return true;
17157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
17257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
17357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
17457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Returns the content-provider-style MIME types of the various
17557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * types accessible through this content provider.
17657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
17757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
17857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public String getType(final Uri uri) {
17957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
18057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
18157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS: {
18257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                return DOWNLOAD_LIST_TYPE;
18357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
18457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
18557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                return DOWNLOAD_TYPE;
18657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
18757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
18857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Constants.LOGV) {
18957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    Log.v(Constants.TAG, "calling getType on an unknown URI: " + uri);
19057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
19157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new IllegalArgumentException("Unknown URI: " + uri);
19257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
19357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
19457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
19557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
19657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
19757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Creates the table that'll hold the download information.
19857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
19957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private void createTable(SQLiteDatabase db) {
20057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        try {
20157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            db.execSQL("CREATE TABLE " + DB_TABLE + "(" +
2027dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
2037dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_URI + " TEXT, " +
204c6f5aad265cfc36a64cd2bdb5adf3cc9736bbd80Jean-Baptiste Queru                    Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " +
2057dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_APP_DATA + " TEXT, " +
2067dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " +
2077dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " +
2081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Constants.OTA_UPDATE + " BOOLEAN, " +
2097dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl._DATA + " TEXT, " +
2107dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " +
2117dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " +
2121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Constants.NO_SYSTEM_FILES + " BOOLEAN, " +
2137dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " +
2147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_CONTROL + " INTEGER, " +
2157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_STATUS + " INTEGER, " +
2161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Constants.FAILED_CONNECTIONS + " INTEGER, " +
2177dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " +
2187dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " +
2197dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " +
2207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " +
2217dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " +
2227dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " +
2237dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_REFERER + " TEXT, " +
2247dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " +
2257dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " +
2261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Constants.ETAG + " TEXT, " +
2271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Constants.UID + " INTEGER, " +
2287dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " +
2297dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_TITLE + " TEXT, " +
2307dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " +
2311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Constants.MEDIA_SCANNED + " BOOLEAN);");
23257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } catch (SQLException ex) {
23357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            Log.e(Constants.TAG, "couldn't create table in downloads database");
23457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            throw ex;
23557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
23657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
23757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
23857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
23957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Deletes the table that holds the download information.
24057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
24157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private void dropTable(SQLiteDatabase db) {
24257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        try {
24357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
24457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } catch (SQLException ex) {
24557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            Log.e(Constants.TAG, "couldn't drop table in downloads database");
24657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            throw ex;
24757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
24857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
24957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
25057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
25157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Inserts a row in the database
25257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
25357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
25457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public Uri insert(final Uri uri, final ContentValues values) {
25557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
25657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
25757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (sURIMatcher.match(uri) != DOWNLOADS) {
25857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Config.LOGD) {
25957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: " + uri);
26057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
26157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            throw new IllegalArgumentException("Unknown/Invalid URI " + uri);
26257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
26357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
2641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        ContentValues filteredValues = new ContentValues();
2651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
2667dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_URI, values, filteredValues);
2677dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues);
2687dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues);
2697dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues);
2707dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues);
2717dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION);
272ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        if (dest != null) {
2737dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
2741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    != PackageManager.PERMISSION_GRANTED
2757dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    && dest != Downloads.Impl.DESTINATION_EXTERNAL
2767dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    && dest != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE) {
2771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                throw new SecurityException("unauthorized destination code");
2781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
2797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest);
280ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        }
2817dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY);
282ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        if (vis == null) {
2837dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            if (dest == Downloads.Impl.DESTINATION_EXTERNAL) {
2847dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY,
2857dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                        Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
286ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru            } else {
2877dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY,
2887dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                        Downloads.Impl.VISIBILITY_HIDDEN);
2891fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
290ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        } else {
2917dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis);
29257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
2937dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues);
2947dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
2957dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
2967dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE);
2977dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS);
2981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (pckg != null && clazz != null) {
2991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            int uid = Binder.getCallingUid();
3001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            try {
3011fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                if (uid == 0 ||
3021fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        getContext().getPackageManager().getApplicationInfo(pckg, 0).uid == uid) {
3037dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg);
3047dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz);
3051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                }
3061fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            } catch (PackageManager.NameNotFoundException ex) {
3071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                /* ignored for now */
30857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
30957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
3107dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues);
3117dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues);
3127dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues);
3137dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues);
3147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
3151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
3167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues);
31757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
3181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        filteredValues.put(Constants.UID, Binder.getCallingUid());
3191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (Binder.getCallingUid() == 0) {
3201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            copyInteger(Constants.UID, values, filteredValues);
32157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
3227dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues);
3237dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues);
32457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
3251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (Constants.LOGVV) {
3261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Log.v(Constants.TAG, "initiating download with UID "
3271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    + filteredValues.getAsInteger(Constants.UID));
3287dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) {
3291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "other UID " +
3307dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                        filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID));
3311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
33257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
33357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
33457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        Context context = getContext();
33557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        context.startService(new Intent(context, DownloadService.class));
33657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
3371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        long rowID = db.insert(DB_TABLE, null, filteredValues);
33857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
33957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        Uri ret = null;
34057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
34157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (rowID != -1) {
34257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            context.startService(new Intent(context, DownloadService.class));
3437dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            ret = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + rowID);
34457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            context.getContentResolver().notifyChange(uri, null);
34557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } else {
34657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Config.LOGD) {
3471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.d(Constants.TAG, "couldn't insert into downloads database");
34857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
34957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
35057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
35157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return ret;
35257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
35357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
35457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
35557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Starts a database query
35657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
35757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
3581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    public Cursor query(final Uri uri, String[] projection,
35957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project             final String selection, final String[] selectionArgs,
36057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project             final String sort) {
3611fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
3621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Helpers.validateSelection(selection, sAppReadableColumnsSet);
3631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
36457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
36557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
36657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
36757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
36857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
36957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        boolean emptyWhere = true;
37057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
37157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS: {
37257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                qb.setTables(DB_TABLE);
37357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
37457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
37557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
37657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                qb.setTables(DB_TABLE);
3777dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                qb.appendWhere(Downloads.Impl._ID + "=");
37857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                qb.appendWhere(uri.getPathSegments().get(1));
37957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                emptyWhere = false;
38057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
38157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
38257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
38357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Constants.LOGV) {
3841fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "querying unknown URI: " + uri);
38557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
38657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new IllegalArgumentException("Unknown URI: " + uri);
38757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
38857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
38957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
390f8e520e6b7ba9533117d4805a29fb7321534d6ceJean-Baptiste Queru        if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0 &&
391f8e520e6b7ba9533117d4805a29fb7321534d6ceJean-Baptiste Queru                Process.supportsProcesses()) {
39257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (!emptyWhere) {
39357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                qb.appendWhere(" AND ");
39457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
3951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            qb.appendWhere("( " + Constants.UID + "=" +  Binder.getCallingUid() + " OR "
3967dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    + Downloads.Impl.COLUMN_OTHER_UID + "=" +  Binder.getCallingUid() + " )");
39757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            emptyWhere = false;
3981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
3991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (projection == null) {
4001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                projection = sAppReadableColumnsArray;
4011fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            } else {
4021fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                for (int i = 0; i < projection.length; ++i) {
4031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    if (!sAppReadableColumnsSet.contains(projection[i])) {
4041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        throw new IllegalArgumentException(
4051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                                "column " + projection[i] + " is not allowed in queries");
4061fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    }
4071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                }
4081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
40957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
41057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
41157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (Constants.LOGVV) {
41257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            java.lang.StringBuilder sb = new java.lang.StringBuilder();
41357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("starting query, database is ");
41457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (db != null) {
41557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("not ");
41657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
41757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("null; ");
41857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (projection == null) {
41957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("projection is null; ");
42057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else if (projection.length == 0) {
42157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("projection is empty; ");
42257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
42357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                for (int i = 0; i < projection.length; ++i) {
42457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("projection[");
42557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(i);
42657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("] is ");
42757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(projection[i]);
42857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("; ");
42957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
43057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
43157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("selection is ");
43257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append(selection);
43357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("; ");
43457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (selectionArgs == null) {
43557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("selectionArgs is null; ");
43657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else if (selectionArgs.length == 0) {
43757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("selectionArgs is empty; ");
43857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
43957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                for (int i = 0; i < selectionArgs.length; ++i) {
44057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("selectionArgs[");
44157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(i);
44257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("] is ");
44357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(selectionArgs[i]);
44457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("; ");
44557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
44657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
44757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("sort is ");
44857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append(sort);
44957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append(".");
4501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Log.v(Constants.TAG, sb.toString());
45157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
45257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
45357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        Cursor ret = qb.query(db, projection, selection, selectionArgs,
45457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                              null, null, sort);
45557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
45657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (ret != null) {
4571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project           ret = new ReadOnlyCursorWrapper(ret);
4581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
4591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
4601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (ret != null) {
46157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            ret.setNotificationUri(getContext().getContentResolver(), uri);
46257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Constants.LOGVV) {
46357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                Log.v(Constants.TAG,
46457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                        "created cursor " + ret + " on behalf of " + Binder.getCallingPid());
46557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
46657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } else {
46757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Constants.LOGV) {
4681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "query failed in downloads database");
46957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
47057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
47157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
47257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return ret;
47357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
47457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
47557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
47657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Updates a row in the database
47757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
47857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
47957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public int update(final Uri uri, final ContentValues values,
48057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            final String where, final String[] whereArgs) {
4811fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
4821fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Helpers.validateSelection(where, sAppReadableColumnsSet);
4831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
48457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
48557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
48657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int count;
48757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        long rowId = 0;
4881fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        boolean startService = false;
4891fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
4901fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        ContentValues filteredValues;
4911fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (Binder.getCallingPid() != Process.myPid()) {
4921fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            filteredValues = new ContentValues();
4937dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues);
4947dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues);
4957dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL);
4961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (i != null) {
4977dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i);
4981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                startService = true;
4991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
5007dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues);
5017dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues);
5027dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues);
5031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        } else {
5041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            filteredValues = values;
50557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
50657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
50757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
50857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS:
50957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
51057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                String myWhere;
51157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (where != null) {
51257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    if (match == DOWNLOADS) {
5131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " )";
51457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    } else {
5151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " ) AND ";
51657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    }
51757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
51857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    myWhere = "";
51957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
52057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (match == DOWNLOADS_ID) {
52157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    String segment = uri.getPathSegments().get(1);
52257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    rowId = Long.parseLong(segment);
5237dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) ";
52457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
5251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) {
5261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    myWhere += " AND ( " + Constants.UID + "=" +  Binder.getCallingUid() + " OR "
5277dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                            + Downloads.Impl.COLUMN_OTHER_UID + "=" +  Binder.getCallingUid() + " )";
52857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
5291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                if (filteredValues.size() > 0) {
5301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    count = db.update(DB_TABLE, filteredValues, myWhere, whereArgs);
5311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                } else {
5321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    count = 0;
5331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                }
53457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
53557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
53657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
53757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Config.LOGD) {
5381fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.d(Constants.TAG, "updating unknown/invalid URI: " + uri);
53957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
54057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new UnsupportedOperationException("Cannot update URI: " + uri);
54157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
54257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
54357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        getContext().getContentResolver().notifyChange(uri, null);
5441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (startService) {
5451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Context context = getContext();
5461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            context.startService(new Intent(context, DownloadService.class));
5471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
54857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return count;
54957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
55057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
55157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
55257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Deletes a row in the database
55357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
55457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
55557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public int delete(final Uri uri, final String where,
55657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            final String[] whereArgs) {
5571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
5581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Helpers.validateSelection(where, sAppReadableColumnsSet);
5591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
56057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
56157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int count;
56257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
56357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
56457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS:
56557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
56657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                String myWhere;
56757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (where != null) {
56857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    if (match == DOWNLOADS) {
5691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " )";
57057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    } else {
5711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " ) AND ";
57257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    }
57357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
57457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    myWhere = "";
57557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
57657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (match == DOWNLOADS_ID) {
57757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    String segment = uri.getPathSegments().get(1);
57857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    long rowId = Long.parseLong(segment);
5797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) ";
58057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
5811fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) {
5821fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    myWhere += " AND ( " + Constants.UID + "=" +  Binder.getCallingUid() + " OR "
5837dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                            + Downloads.Impl.COLUMN_OTHER_UID + "="
5847dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                            +  Binder.getCallingUid() + " )";
58557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
58657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                count = db.delete(DB_TABLE, myWhere, whereArgs);
58757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
58857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
58957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
59057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Config.LOGD) {
5911fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.d(Constants.TAG, "deleting unknown/invalid URI: " + uri);
59257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
59357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new UnsupportedOperationException("Cannot delete URI: " + uri);
59457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
59557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
59657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        getContext().getContentResolver().notifyChange(uri, null);
59757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return count;
59857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
59957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
60057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
60157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Remotely opens a file
60257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
60357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
60457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public ParcelFileDescriptor openFile(Uri uri, String mode)
60557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            throws FileNotFoundException {
60657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (Constants.LOGVV) {
6071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode
60857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    + ", uid: " + Binder.getCallingUid());
6097dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            Cursor cursor = query(Downloads.Impl.CONTENT_URI,
6107dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    new String[] { "_id" }, null, null, "_id");
61157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (cursor == null) {
6121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "null cursor in openFile");
61357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
61457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (!cursor.moveToFirst()) {
6151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "empty cursor in openFile");
61657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
61757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    do {
6181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available");
61957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    } while(cursor.moveToNext());
62057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
62157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                cursor.close();
62257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
62357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            cursor = query(uri, new String[] { "_data" }, null, null, null);
62457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (cursor == null) {
6251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "null cursor in openFile");
62657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
62757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (!cursor.moveToFirst()) {
6281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "empty cursor in openFile");
62957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
63057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    String filename = cursor.getString(0);
6311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "filename in openFile: " + filename);
63257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    if (new java.io.File(filename).isFile()) {
6331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        Log.v(Constants.TAG, "file exists in openFile");
63457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    }
63557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
63657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project               cursor.close();
63757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
63857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
6391fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
6401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        // This logic is mostly copied form openFileHelper. If openFileHelper eventually
6411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        //     gets split into small bits (to extract the filename and the modebits),
6421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        //     this code could use the separate bits and be deeply simplified.
6431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Cursor c = query(uri, new String[]{"_data"}, null, null, null);
6441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        int count = (c != null) ? c.getCount() : 0;
6451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (count != 1) {
6461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            // If there is not exactly one result, throw an appropriate exception.
6471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (c != null) {
6481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                c.close();
6491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
6501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (count == 0) {
6511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                throw new FileNotFoundException("No entry for " + uri);
6521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
6531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("Multiple items at " + uri);
6541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
6551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
6561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        c.moveToFirst();
6571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        String path = c.getString(0);
6581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        c.close();
6591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (path == null) {
6601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("No filename found.");
6611fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
6621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (!Helpers.isFilenameValid(path)) {
6631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("Invalid filename.");
6641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
6651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
6661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (!"r".equals(mode)) {
6671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("Bad mode for " + uri + ": " + mode);
6681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
6691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        ParcelFileDescriptor ret = ParcelFileDescriptor.open(new File(path),
6701fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                ParcelFileDescriptor.MODE_READ_ONLY);
6711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
67257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (ret == null) {
6731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (Constants.LOGV) {
6741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "couldn't open file");
67557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
6761fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("couldn't open file");
67757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } else {
67857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            ContentValues values = new ContentValues();
6797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
68057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            update(uri, values, null, null);
68157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
68257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return ret;
68357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
68457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
6851fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final void copyInteger(String key, ContentValues from, ContentValues to) {
6861fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Integer i = from.getAsInteger(key);
6871fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (i != null) {
6881fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            to.put(key, i);
6891fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
6901fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
6911fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
6921fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final void copyBoolean(String key, ContentValues from, ContentValues to) {
6931fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Boolean b = from.getAsBoolean(key);
6941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (b != null) {
6951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            to.put(key, b);
6961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
6971fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
6981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
6991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final void copyString(String key, ContentValues from, ContentValues to) {
7001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        String s = from.getAsString(key);
7011fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (s != null) {
7021fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            to.put(key, s);
7031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
7041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
7051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7061fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private class ReadOnlyCursorWrapper extends CursorWrapper implements CrossProcessCursor {
7071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public ReadOnlyCursorWrapper(Cursor cursor) {
7081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            super(cursor);
7091fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            mCursor = (CrossProcessCursor) cursor;
7101fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
7111fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public boolean deleteRow() {
7131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new SecurityException("Download manager cursors are read-only");
7141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
7151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public boolean commitUpdates() {
7171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new SecurityException("Download manager cursors are read-only");
7181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
7191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public void fillWindow(int pos, CursorWindow window) {
7211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            mCursor.fillWindow(pos, window);
7221fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
7231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public CursorWindow getWindow() {
7251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            return mCursor.getWindow();
7261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
7271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public boolean onMove(int oldPosition, int newPosition) {
7291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            return mCursor.onMove(oldPosition, newPosition);
7301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
7311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        private CrossProcessCursor mCursor;
7331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
7341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
73557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project}
736