DownloadProvider.java revision 0a77c62a82503b38c484e0079648f0231dd85d53
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;
2491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.ApplicationInfo;
2557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.pm.PackageManager;
2691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.PackageManager.NameNotFoundException;
271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CrossProcessCursor;
2857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.Cursor;
291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWindow;
301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWrapper;
31c6f5aad265cfc36a64cd2bdb5adf3cc9736bbd80Jean-Baptiste Queruimport android.database.SQLException;
3257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase;
3357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper;
3457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder;
3557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.net.Uri;
3657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Binder;
3757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.ParcelFileDescriptor;
3857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Process;
3957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.provider.Downloads;
4057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.util.Config;
4157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.util.Log;
4257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport com.google.common.annotations.VisibleForTesting;
445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.io.File;
4657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport java.io.FileNotFoundException;
471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.util.HashSet;
485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport java.util.Map;
491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
5057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
5157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/**
5257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Allows application to interact with the download manager.
5357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */
5457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpublic final class DownloadProvider extends ContentProvider {
5557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
5657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** Database filename */
5757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DB_NAME = "downloads.db";
581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    /** Current database version */
590a77c62a82503b38c484e0079648f0231dd85d53Steve Howard    private static final int DB_VERSION = 102;
6057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** Name of table in the database */
6157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DB_TABLE = "downloads";
6257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
6357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** MIME type for the entire download list */
6457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DOWNLOAD_LIST_TYPE = "vnd.android.cursor.dir/download";
6557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** MIME type for an individual download */
6657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final String DOWNLOAD_TYPE = "vnd.android.cursor.item/download";
6757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
6857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** URI matcher used to recognize URIs sent by applications */
6957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
7057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** URI matcher constant for the URI of the entire download list */
7157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final int DOWNLOADS = 1;
7257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** URI matcher constant for the URI of an individual download */
7357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private static final int DOWNLOADS_ID = 2;
745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    /** URI matcher constant for the URI of a download's request headers */
755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    private static final int REQUEST_HEADERS_URI = 3;
7657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    static {
7757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        sURIMatcher.addURI("downloads", "download", DOWNLOADS);
7857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        sURIMatcher.addURI("downloads", "download/#", DOWNLOADS_ID);
795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        sURIMatcher.addURI("downloads", "download/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT,
805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                           REQUEST_HEADERS_URI);
8157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
8257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final String[] sAppReadableColumnsArray = new String[] {
847dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl._ID,
857dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_APP_DATA,
867dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl._DATA,
877dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_MIME_TYPE,
887dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_VISIBILITY,
897dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_DESTINATION,
907dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_CONTROL,
917dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_STATUS,
927dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_LAST_MODIFICATION,
937dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
947dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_NOTIFICATION_CLASS,
957dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_TOTAL_BYTES,
967dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_CURRENT_BYTES,
977dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Downloads.Impl.COLUMN_TITLE,
980a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        Downloads.Impl.COLUMN_DESCRIPTION,
991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    };
1001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
1011fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static HashSet<String> sAppReadableColumnsSet;
1021fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    static {
1031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        sAppReadableColumnsSet = new HashSet<String>();
1041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        for (int i = 0; i < sAppReadableColumnsArray.length; ++i) {
1051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            sAppReadableColumnsSet.add(sAppReadableColumnsArray[i]);
1061fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
1071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
1081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
10957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /** The database that lies underneath this content provider */
11057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private SQLiteOpenHelper mOpenHelper = null;
11157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
11291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu    /** List of uids that can access the downloads */
11391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu    private int mSystemUid = -1;
11491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu    private int mDefContainerUid = -1;
11591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu
1166d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard    @VisibleForTesting
1176d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard    SystemFacade mSystemFacade;
1186d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard
11957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
12057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Creates and updated database on demand when opening it.
12157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Helper class to create database the first time the provider is
12257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * initialized and upgrade it when a new version of the provider needs
12357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * an updated version of the database.
12457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
12557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    private final class DatabaseHelper extends SQLiteOpenHelper {
12657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        public DatabaseHelper(final Context context) {
12757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            super(context, DB_NAME, null, DB_VERSION);
12857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
12957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
13057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        /**
13157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * Creates database the first time we try to open it.
13257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         */
13357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        @Override
13457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        public void onCreate(final SQLiteDatabase db) {
13557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Constants.LOGVV) {
13657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                Log.v(Constants.TAG, "populating new database");
13757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
1385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            onUpgrade(db, 0, DB_VERSION);
13957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
14057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
14157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        /**
14257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * Updates the database format when a content provider is used
14357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         * with a database that was created with a different format.
1445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard         *
1455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard         * Note: to support downgrades, creating a table should always drop it first if it already
1465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard         * exists.
14757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project         */
14857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        @Override
1491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public void onUpgrade(final SQLiteDatabase db, int oldV, final int newV) {
1505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            if (oldV == 31) {
1515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                // 31 and 100 are identical, just in different codelines. Upgrading from 31 is the
1525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                // same as upgrading from 100.
1535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                oldV = 100;
1545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            } else if (oldV < 100) {
1555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                // no logic to upgrade from these older version, just recreate the DB
1565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                Log.i(Constants.TAG, "Upgrading downloads database from version " + oldV
1575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                      + " to version " + newV + ", which will destroy all old data");
1585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                oldV = 99;
1595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            } else if (oldV > newV) {
1605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                // user must have downgraded software; we have no way to know how to downgrade the
1615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                // DB, so just recreate it
1625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                Log.i(Constants.TAG, "Downgrading downloads database from version " + oldV
1635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                      + " (current version is " + newV + "), destroying all old data");
1645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                oldV = 99;
1655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            }
1665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
1675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            for (int version = oldV + 1; version <= newV; version++) {
1685224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                upgradeTo(db, version);
1695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            }
1705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        }
1715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
1725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        /**
1735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard         * Upgrade database from (version - 1) to version.
1745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard         */
1755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        private void upgradeTo(SQLiteDatabase db, int version) {
1765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            switch (version) {
1775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                case 100:
1785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    createDownloadsTable(db);
1795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    break;
1805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
1815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                case 101:
1825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    createHeadersTable(db);
1835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    break;
1845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
1850a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                case 102:
1860a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                    addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_PUBLIC_API,
1870a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                              "INTEGER NOT NULL DEFAULT 0");
1880a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                    addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_ROAMING,
1890a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                              "INTEGER NOT NULL DEFAULT 0");
1900a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                    addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES,
1910a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                              "INTEGER NOT NULL DEFAULT 0");
1920a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                    break;
1930a77c62a82503b38c484e0079648f0231dd85d53Steve Howard
1945224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                default:
1955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    throw new IllegalStateException("Don't know how to upgrade to " + version);
1965224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            }
1975224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        }
1985224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
1995224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        /**
2000a77c62a82503b38c484e0079648f0231dd85d53Steve Howard         * Add a column to a table using ALTER TABLE.
2010a77c62a82503b38c484e0079648f0231dd85d53Steve Howard         * @param dbTable name of the table
2020a77c62a82503b38c484e0079648f0231dd85d53Steve Howard         * @param columnName name of the column to add
2030a77c62a82503b38c484e0079648f0231dd85d53Steve Howard         * @param columnDefinition SQL for the column definition
2040a77c62a82503b38c484e0079648f0231dd85d53Steve Howard         */
2050a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        private void addColumn(SQLiteDatabase db, String dbTable, String columnName,
2060a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                               String columnDefinition) {
2070a77c62a82503b38c484e0079648f0231dd85d53Steve Howard            db.execSQL("ALTER TABLE " + dbTable + " ADD COLUMN " + columnName + " "
2080a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                       + columnDefinition);
2090a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        }
2100a77c62a82503b38c484e0079648f0231dd85d53Steve Howard
2110a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        /**
2125224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard         * Creates the table that'll hold the download information.
2135224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard         */
2145224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        private void createDownloadsTable(SQLiteDatabase db) {
2155224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            try {
2165224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
2175224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                db.execSQL("CREATE TABLE " + DB_TABLE + "(" +
2185224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
2195224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_URI + " TEXT, " +
2205224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " +
2215224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_APP_DATA + " TEXT, " +
2225224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " +
2235224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " +
2245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Constants.OTA_UPDATE + " BOOLEAN, " +
2255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl._DATA + " TEXT, " +
2265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " +
2275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " +
2285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Constants.NO_SYSTEM_FILES + " BOOLEAN, " +
2295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " +
2305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_CONTROL + " INTEGER, " +
2315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_STATUS + " INTEGER, " +
2325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Constants.FAILED_CONNECTIONS + " INTEGER, " +
2335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " +
2345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " +
2355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " +
2365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " +
2375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " +
2385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " +
2395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_REFERER + " TEXT, " +
2405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " +
2415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " +
2425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Constants.ETAG + " TEXT, " +
2435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Constants.UID + " INTEGER, " +
2445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " +
2455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_TITLE + " TEXT, " +
2465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " +
2475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                        Constants.MEDIA_SCANNED + " BOOLEAN);");
2485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            } catch (SQLException ex) {
2495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                Log.e(Constants.TAG, "couldn't create table in downloads database");
2505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                throw ex;
2515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            }
2525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        }
2535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
2545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        private void createHeadersTable(SQLiteDatabase db) {
2555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            db.execSQL("DROP TABLE IF EXISTS " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE);
2565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            db.execSQL("CREATE TABLE " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE + "(" +
2575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                       "id INTEGER PRIMARY KEY AUTOINCREMENT," +
2585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                       Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + " INTEGER NOT NULL," +
2595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                       Downloads.Impl.RequestHeaders.COLUMN_HEADER + " TEXT NOT NULL," +
2605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                       Downloads.Impl.RequestHeaders.COLUMN_VALUE + " TEXT NOT NULL" +
2615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                       ");");
26257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
26357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
26457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
26557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
26657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Initializes the content provider when it is created.
26757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
26857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
26957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public boolean onCreate() {
2706d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard        if (mSystemFacade == null) {
271af28400b74de05862b470412a5c92f68e99f59f8Steve Howard            mSystemFacade = new RealSystemFacade(getContext());
2726d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard        }
2736d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard
27457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        mOpenHelper = new DatabaseHelper(getContext());
27591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        // Initialize the system uid
27691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        mSystemUid = Process.SYSTEM_UID;
27791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        // Initialize the default container uid. Package name hardcoded
27891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        // for now.
27991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        ApplicationInfo appInfo = null;
28091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        try {
28191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu            appInfo = getContext().getPackageManager().
28291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                    getApplicationInfo("com.android.defcontainer", 0);
28391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        } catch (NameNotFoundException e) {
28491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu            // TODO Auto-generated catch block
28591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu            e.printStackTrace();
28691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        }
28791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        if (appInfo != null) {
28891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu            mDefContainerUid = appInfo.uid;
28991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu        }
29057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return true;
29157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
29257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
29357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
29457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Returns the content-provider-style MIME types of the various
29557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * types accessible through this content provider.
29657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
29757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
29857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public String getType(final Uri uri) {
29957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
30057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
30157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS: {
30257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                return DOWNLOAD_LIST_TYPE;
30357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
30457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
30557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                return DOWNLOAD_TYPE;
30657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
30757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
30857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Constants.LOGV) {
30957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    Log.v(Constants.TAG, "calling getType on an unknown URI: " + uri);
31057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
31157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new IllegalArgumentException("Unknown URI: " + uri);
31257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
31357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
31457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
31557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
31657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
31757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Inserts a row in the database
31857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
31957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
32057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public Uri insert(final Uri uri, final ContentValues values) {
32157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
32257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
32357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (sURIMatcher.match(uri) != DOWNLOADS) {
32457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Config.LOGD) {
32557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: " + uri);
32657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
32757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            throw new IllegalArgumentException("Unknown/Invalid URI " + uri);
32857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
32957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
3301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        ContentValues filteredValues = new ContentValues();
3311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
3327dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_URI, values, filteredValues);
3337dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues);
3347dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues);
3357dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues);
3367dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues);
3377dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION);
338ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        if (dest != null) {
3397dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
3401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    != PackageManager.PERMISSION_GRANTED
3417dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    && dest != Downloads.Impl.DESTINATION_EXTERNAL
3426d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard                    && dest != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE
3436d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard                    && dest != Downloads.Impl.DESTINATION_FILE_URI) {
3441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                throw new SecurityException("unauthorized destination code");
3451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
3466d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard            if (dest == Downloads.Impl.DESTINATION_FILE_URI) {
3476d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard                getContext().enforcePermission(
3486d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
3496d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard                        Binder.getCallingPid(), Binder.getCallingUid(),
3506d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard                        "need WRITE_EXTERNAL_STORAGE permission to use DESTINATION_FILE_URI");
3516d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard            }
3527dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest);
353ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        }
3547dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY);
355ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        if (vis == null) {
3567dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            if (dest == Downloads.Impl.DESTINATION_EXTERNAL) {
3577dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY,
3587dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                        Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
359ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru            } else {
3607dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY,
3617dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                        Downloads.Impl.VISIBILITY_HIDDEN);
3621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
363ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru        } else {
3647dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis);
36557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
3667dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues);
3677dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
3686d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard        filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION,
3696d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard                           mSystemFacade.currentTimeMillis());
3700a77c62a82503b38c484e0079648f0231dd85d53Steve Howard
3710a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        copyBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API, values, filteredValues);
3720a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        boolean isPublicApi =
3730a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                values.getAsBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API) == Boolean.TRUE;
3740a77c62a82503b38c484e0079648f0231dd85d53Steve Howard
3757dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE);
3767dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS);
3770a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        if (pckg != null && (clazz != null || isPublicApi)) {
3781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            int uid = Binder.getCallingUid();
3791fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            try {
3800a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                if (uid == 0 || mSystemFacade.userOwnsPackage(uid, pckg)) {
3817dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg);
3820a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                    if (clazz != null) {
3830a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                        filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz);
3840a77c62a82503b38c484e0079648f0231dd85d53Steve Howard                    }
3851fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                }
3861fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            } catch (PackageManager.NameNotFoundException ex) {
3871fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                /* ignored for now */
38857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
38957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
3907dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues);
3917dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues);
3927dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues);
3937dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues);
3947dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
3951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
3967dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues);
39757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
3981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        filteredValues.put(Constants.UID, Binder.getCallingUid());
3991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (Binder.getCallingUid() == 0) {
4001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            copyInteger(Constants.UID, values, filteredValues);
40157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
4027dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues);
4037dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru        copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues);
404b5629da794cb3c1ca1970d206343743b165b9644Steve Howard        filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1);
40557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
4060a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        if (isPublicApi) {
4070a77c62a82503b38c484e0079648f0231dd85d53Steve Howard            copyInteger(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, values, filteredValues);
4080a77c62a82503b38c484e0079648f0231dd85d53Steve Howard            copyBoolean(Downloads.Impl.COLUMN_ALLOW_ROAMING, values, filteredValues);
4090a77c62a82503b38c484e0079648f0231dd85d53Steve Howard        }
4100a77c62a82503b38c484e0079648f0231dd85d53Steve Howard
4111fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (Constants.LOGVV) {
4121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Log.v(Constants.TAG, "initiating download with UID "
4131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    + filteredValues.getAsInteger(Constants.UID));
4147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) {
4151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "other UID " +
4167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                        filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID));
4171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
41857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
41957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
42057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        Context context = getContext();
42157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        context.startService(new Intent(context, DownloadService.class));
42257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
4231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        long rowID = db.insert(DB_TABLE, null, filteredValues);
4245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        insertRequestHeaders(db, rowID, values);
42557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
42657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        Uri ret = null;
42757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
42857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (rowID != -1) {
42957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            context.startService(new Intent(context, DownloadService.class));
4307dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            ret = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + rowID);
43157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            context.getContentResolver().notifyChange(uri, null);
43257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } else {
43357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Config.LOGD) {
4341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.d(Constants.TAG, "couldn't insert into downloads database");
43557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
43657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
43757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
43857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return ret;
43957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
44057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
44157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
44257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Starts a database query
44357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
44457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
4451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    public Cursor query(final Uri uri, String[] projection,
44657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project             final String selection, final String[] selectionArgs,
44757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project             final String sort) {
4481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
4491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Helpers.validateSelection(selection, sAppReadableColumnsSet);
4501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
45157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
45257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
45357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
45457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
45557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
45657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        boolean emptyWhere = true;
45757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
45857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS: {
45957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                qb.setTables(DB_TABLE);
46057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
46157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
46257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
46357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                qb.setTables(DB_TABLE);
4647dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                qb.appendWhere(Downloads.Impl._ID + "=");
4655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                qb.appendWhere(getDownloadIdFromUri(uri));
46657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                emptyWhere = false;
46757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
46857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
4695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            case REQUEST_HEADERS_URI:
4705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                if (projection != null || selection != null || sort != null) {
4715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    throw new UnsupportedOperationException("Request header queries do not support "
4725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                                                            + "projections, selections or sorting");
4735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                }
4745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                return queryRequestHeaders(db, uri);
47557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
47657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Constants.LOGV) {
4771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "querying unknown URI: " + uri);
47857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
47957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new IllegalArgumentException("Unknown URI: " + uri);
48057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
48157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
48257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
4835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        if (shouldRestrictVisibility()) {
484a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            boolean canSeeAllExternal;
4851fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (projection == null) {
4861fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                projection = sAppReadableColumnsArray;
487a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                // sAppReadableColumnsArray includes _DATA, which is not allowed
488a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                // to be seen except by the initiating application
489a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                canSeeAllExternal = false;
4901fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            } else {
491a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                canSeeAllExternal = getContext().checkCallingPermission(
492a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                        Downloads.Impl.PERMISSION_SEE_ALL_EXTERNAL)
493a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                        == PackageManager.PERMISSION_GRANTED;
4941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                for (int i = 0; i < projection.length; ++i) {
4951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    if (!sAppReadableColumnsSet.contains(projection[i])) {
4961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        throw new IllegalArgumentException(
4971fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                                "column " + projection[i] + " is not allowed in queries");
4981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    }
499a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                    canSeeAllExternal = canSeeAllExternal
500a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                            && !projection[i].equals(Downloads.Impl._DATA);
5011fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                }
5021fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
503a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            if (!emptyWhere) {
504a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                qb.appendWhere(" AND ");
505a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                emptyWhere = false;
506a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            }
507a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            String validUid = "( " + Constants.UID + "="
508a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                    + Binder.getCallingUid() + " OR "
509a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                    + Downloads.Impl.COLUMN_OTHER_UID + "="
510a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                    + Binder.getCallingUid() + " )";
511a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            if (canSeeAllExternal) {
512a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                qb.appendWhere("( " + validUid + " OR "
513a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                        + Downloads.Impl.DESTINATION_EXTERNAL + " = "
514a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                        + Downloads.Impl.COLUMN_DESTINATION + " )");
515a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            } else {
516a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                qb.appendWhere(validUid);
517a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            }
51857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
51957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
52057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (Constants.LOGVV) {
52157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            java.lang.StringBuilder sb = new java.lang.StringBuilder();
52257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("starting query, database is ");
52357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (db != null) {
52457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("not ");
52557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
52657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("null; ");
52757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (projection == null) {
52857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("projection is null; ");
52957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else if (projection.length == 0) {
53057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("projection is empty; ");
53157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
53257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                for (int i = 0; i < projection.length; ++i) {
53357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("projection[");
53457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(i);
53557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("] is ");
53657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(projection[i]);
53757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("; ");
53857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
53957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
54057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("selection is ");
54157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append(selection);
54257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("; ");
54357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (selectionArgs == null) {
54457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("selectionArgs is null; ");
54557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else if (selectionArgs.length == 0) {
54657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                sb.append("selectionArgs is empty; ");
54757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
54857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                for (int i = 0; i < selectionArgs.length; ++i) {
54957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("selectionArgs[");
55057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(i);
55157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("] is ");
55257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append(selectionArgs[i]);
55357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    sb.append("; ");
55457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
55557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
55657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append("sort is ");
55757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append(sort);
55857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            sb.append(".");
5591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Log.v(Constants.TAG, sb.toString());
56057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
56157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
56257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        Cursor ret = qb.query(db, projection, selection, selectionArgs,
56357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                              null, null, sort);
56457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
56557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (ret != null) {
5661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project           ret = new ReadOnlyCursorWrapper(ret);
5671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
5681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
5691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (ret != null) {
57057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            ret.setNotificationUri(getContext().getContentResolver(), uri);
57157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Constants.LOGVV) {
57257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                Log.v(Constants.TAG,
57357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                        "created cursor " + ret + " on behalf of " + Binder.getCallingPid());
57457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
57557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } else {
57657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (Constants.LOGV) {
5771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "query failed in downloads database");
57857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
57957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
58057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
58157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return ret;
58257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
58357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
5845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    private String getDownloadIdFromUri(final Uri uri) {
5855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        return uri.getPathSegments().get(1);
5865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    }
5875224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
5885224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    /**
5895224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     * Insert request headers for a download into the DB.
5905224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     */
5915224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    private void insertRequestHeaders(SQLiteDatabase db, long downloadId, ContentValues values) {
5925224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        ContentValues rowValues = new ContentValues();
5935224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID, downloadId);
5945224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        for (Map.Entry<String, Object> entry : values.valueSet()) {
5955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            String key = entry.getKey();
5965224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) {
5975224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                String headerLine = entry.getValue().toString();
5985224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                if (!headerLine.contains(":")) {
5995224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    throw new IllegalArgumentException("Invalid HTTP header line: " + headerLine);
6005224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                }
6015224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                String[] parts = headerLine.split(":", 2);
6025224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_HEADER, parts[0].trim());
6035224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_VALUE, parts[1].trim());
6045224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                db.insert(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, null, rowValues);
6055224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            }
6065224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        }
6075224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    }
6085224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
6095224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    /**
6105224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     * Handle a query for the custom request headers registered for a download.
6115224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     */
6125224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    private Cursor queryRequestHeaders(SQLiteDatabase db, Uri uri) {
6135224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        String where = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "="
6145224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                       + getDownloadIdFromUri(uri);
6155224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        String[] projection = new String[] {Downloads.Impl.RequestHeaders.COLUMN_HEADER,
6165224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                                            Downloads.Impl.RequestHeaders.COLUMN_VALUE};
6175224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        Cursor cursor = db.query(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, projection, where,
6185224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                                 null, null, null, null);
6195224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        return new ReadOnlyCursorWrapper(cursor);
6205224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    }
6215224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
6225224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    /**
6235224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     * Delete request headers for downloads matching the given query.
6245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     */
6255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    private void deleteRequestHeaders(SQLiteDatabase db, String where, String[] whereArgs) {
6265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        String[] projection = new String[] {Downloads.Impl._ID};
6275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        Cursor cursor = db.query(DB_TABLE, projection , where, whereArgs, null, null, null, null);
6285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        try {
6295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
6305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                long id = cursor.getLong(0);
6315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                String idWhere = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" + id;
6325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                db.delete(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, idWhere, null);
6335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            }
6345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        } finally {
6355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard            cursor.close();
6365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        }
6375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    }
6385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
6395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    /**
6405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     * @return true if we should restrict this call to viewing only its own downloads
6415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard     */
6425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    private boolean shouldRestrictVisibility() {
6435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        int callingUid = Binder.getCallingUid();
6445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard        return Binder.getCallingPid() != Process.myPid() &&
6455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                callingUid != mSystemUid &&
6465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                callingUid != mDefContainerUid &&
6475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                Process.supportsProcesses();
6485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard    }
6495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard
65057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
65157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Updates a row in the database
65257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
65357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
65457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public int update(final Uri uri, final ContentValues values,
65557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            final String where, final String[] whereArgs) {
6561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
6571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Helpers.validateSelection(where, sAppReadableColumnsSet);
6581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
65957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
66057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
66157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int count;
66257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        long rowId = 0;
6631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        boolean startService = false;
6641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
6651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        ContentValues filteredValues;
6661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (Binder.getCallingPid() != Process.myPid()) {
6671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            filteredValues = new ContentValues();
6687dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues);
6697dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues);
6707dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL);
6711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (i != null) {
6727dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i);
6731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                startService = true;
6741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
6757dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues);
6767dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues);
6777dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues);
6781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        } else {
6791fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            filteredValues = values;
680a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            String filename = values.getAsString(Downloads.Impl._DATA);
681a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            if (filename != null) {
682a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                Cursor c = query(uri, new String[]
683a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                        { Downloads.Impl.COLUMN_TITLE }, null, null, null);
684a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                if (!c.moveToFirst() || c.getString(0) == null) {
685a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                    values.put(Downloads.Impl.COLUMN_TITLE,
686a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                            new File(filename).getName());
687a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                }
688a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins                c.close();
689a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins            }
69057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
69157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
69257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
69357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS:
69457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
69557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                String myWhere;
69657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (where != null) {
69757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    if (match == DOWNLOADS) {
6981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " )";
69957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    } else {
7001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " ) AND ";
70157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    }
70257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
70357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    myWhere = "";
70457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
70557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (match == DOWNLOADS_ID) {
7065224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    String segment = getDownloadIdFromUri(uri);
70757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    rowId = Long.parseLong(segment);
7087dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) ";
70957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
71091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                int callingUid = Binder.getCallingUid();
71191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                if (Binder.getCallingPid() != Process.myPid() &&
71291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                        callingUid != mSystemUid &&
71391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                        callingUid != mDefContainerUid) {
7141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    myWhere += " AND ( " + Constants.UID + "=" +  Binder.getCallingUid() + " OR "
7157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                            + Downloads.Impl.COLUMN_OTHER_UID + "=" +  Binder.getCallingUid() + " )";
71657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
7171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                if (filteredValues.size() > 0) {
7181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    count = db.update(DB_TABLE, filteredValues, myWhere, whereArgs);
7191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                } else {
7201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    count = 0;
7211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                }
72257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
72357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
72457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
72557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Config.LOGD) {
7261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.d(Constants.TAG, "updating unknown/invalid URI: " + uri);
72757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
72857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new UnsupportedOperationException("Cannot update URI: " + uri);
72957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
73057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
73157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        getContext().getContentResolver().notifyChange(uri, null);
7321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (startService) {
7331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Context context = getContext();
7341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            context.startService(new Intent(context, DownloadService.class));
7351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
73657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return count;
73757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
73857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
73957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
74057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Deletes a row in the database
74157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
74257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
74357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public int delete(final Uri uri, final String where,
74457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            final String[] whereArgs) {
7451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
7461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Helpers.validateSelection(where, sAppReadableColumnsSet);
7471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
74857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
74957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int count;
75057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        int match = sURIMatcher.match(uri);
75157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        switch (match) {
75257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS:
75357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            case DOWNLOADS_ID: {
75457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                String myWhere;
75557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (where != null) {
75657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    if (match == DOWNLOADS) {
7571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " )";
75857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    } else {
7591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        myWhere = "( " + where + " ) AND ";
76057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    }
76157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
76257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    myWhere = "";
76357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
76457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (match == DOWNLOADS_ID) {
7655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                    String segment = getDownloadIdFromUri(uri);
76657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    long rowId = Long.parseLong(segment);
7677dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) ";
76857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
76991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                int callingUid = Binder.getCallingUid();
77091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                if (Binder.getCallingPid() != Process.myPid() &&
77191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                        callingUid != mSystemUid &&
77291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu                        callingUid != mDefContainerUid) {
7731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    myWhere += " AND ( " + Constants.UID + "=" +  Binder.getCallingUid() + " OR "
7747dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                            + Downloads.Impl.COLUMN_OTHER_UID + "="
7757dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                            +  Binder.getCallingUid() + " )";
77657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
7775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard                deleteRequestHeaders(db, where, whereArgs);
77857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                count = db.delete(DB_TABLE, myWhere, whereArgs);
77957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                break;
78057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
78157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            default: {
78257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (Config.LOGD) {
7831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.d(Constants.TAG, "deleting unknown/invalid URI: " + uri);
78457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
78557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                throw new UnsupportedOperationException("Cannot delete URI: " + uri);
78657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
78757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
78857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        getContext().getContentResolver().notifyChange(uri, null);
78957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return count;
79057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
79157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
79257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    /**
79357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     * Remotely opens a file
79457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project     */
79557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    @Override
79657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    public ParcelFileDescriptor openFile(Uri uri, String mode)
79757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            throws FileNotFoundException {
79857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (Constants.LOGVV) {
7991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode
80057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    + ", uid: " + Binder.getCallingUid());
8017dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru            Cursor cursor = query(Downloads.Impl.CONTENT_URI,
8027dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru                    new String[] { "_id" }, null, null, "_id");
80357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (cursor == null) {
8041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "null cursor in openFile");
80557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
80657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (!cursor.moveToFirst()) {
8071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "empty cursor in openFile");
80857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
80957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    do {
8101fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available");
81157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    } while(cursor.moveToNext());
81257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
81357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                cursor.close();
81457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
81557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            cursor = query(uri, new String[] { "_data" }, null, null, null);
81657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            if (cursor == null) {
8171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "null cursor in openFile");
81857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            } else {
81957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                if (!cursor.moveToFirst()) {
8201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "empty cursor in openFile");
82157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                } else {
82257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    String filename = cursor.getString(0);
8231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                    Log.v(Constants.TAG, "filename in openFile: " + filename);
82457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    if (new java.io.File(filename).isFile()) {
8251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                        Log.v(Constants.TAG, "file exists in openFile");
82657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                    }
82757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project                }
82857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project               cursor.close();
82957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
83057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
8311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
8321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        // This logic is mostly copied form openFileHelper. If openFileHelper eventually
8331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        //     gets split into small bits (to extract the filename and the modebits),
8341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        //     this code could use the separate bits and be deeply simplified.
8351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Cursor c = query(uri, new String[]{"_data"}, null, null, null);
8361fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        int count = (c != null) ? c.getCount() : 0;
8371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (count != 1) {
8381fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            // If there is not exactly one result, throw an appropriate exception.
8391fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (c != null) {
8401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                c.close();
8411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
8421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (count == 0) {
8431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                throw new FileNotFoundException("No entry for " + uri);
8441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            }
8451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("Multiple items at " + uri);
8461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
8471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
8481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        c.moveToFirst();
8491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        String path = c.getString(0);
8501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        c.close();
8511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (path == null) {
8521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("No filename found.");
8531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
8541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (!Helpers.isFilenameValid(path)) {
8551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("Invalid filename.");
8561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
8571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
8581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (!"r".equals(mode)) {
8591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("Bad mode for " + uri + ": " + mode);
8601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
8611fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        ParcelFileDescriptor ret = ParcelFileDescriptor.open(new File(path),
8621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                ParcelFileDescriptor.MODE_READ_ONLY);
8631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
86457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        if (ret == null) {
8651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            if (Constants.LOGV) {
8661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project                Log.v(Constants.TAG, "couldn't open file");
86757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            }
8681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new FileNotFoundException("couldn't open file");
86957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        } else {
87057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            ContentValues values = new ContentValues();
8716d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard            values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, mSystemFacade.currentTimeMillis());
87257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project            update(uri, values, null, null);
87357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        }
87457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project        return ret;
87557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project    }
87657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project
8771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final void copyInteger(String key, ContentValues from, ContentValues to) {
8781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Integer i = from.getAsInteger(key);
8791fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (i != null) {
8801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            to.put(key, i);
8811fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
8821fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
8831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
8841fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final void copyBoolean(String key, ContentValues from, ContentValues to) {
8851fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        Boolean b = from.getAsBoolean(key);
8861fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (b != null) {
8871fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            to.put(key, b);
8881fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
8891fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
8901fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
8911fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private static final void copyString(String key, ContentValues from, ContentValues to) {
8921fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        String s = from.getAsString(key);
8931fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        if (s != null) {
8941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            to.put(key, s);
8951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
8961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
8971fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
8981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    private class ReadOnlyCursorWrapper extends CursorWrapper implements CrossProcessCursor {
8991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public ReadOnlyCursorWrapper(Cursor cursor) {
9001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            super(cursor);
9011fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            mCursor = (CrossProcessCursor) cursor;
9021fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
9031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
9041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public boolean deleteRow() {
9051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new SecurityException("Download manager cursors are read-only");
9061fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
9071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
9081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public boolean commitUpdates() {
9091fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            throw new SecurityException("Download manager cursors are read-only");
9101fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
9111fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
9121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public void fillWindow(int pos, CursorWindow window) {
9131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            mCursor.fillWindow(pos, window);
9141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
9151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
9161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public CursorWindow getWindow() {
9171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            return mCursor.getWindow();
9181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
9191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
9201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        public boolean onMove(int oldPosition, int newPosition) {
9211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project            return mCursor.onMove(oldPosition, newPosition);
9221fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        }
9231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
9241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project        private CrossProcessCursor mCursor;
9251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project    }
9261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project
92757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project}
928