DownloadProvider.java revision 4bebe75b3e2361d7fb0aa966598c41c45ad9317f
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; 203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howardimport android.content.ContentUris; 2157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentValues; 2257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Context; 2357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Intent; 2457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.UriMatcher; 2591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.ApplicationInfo; 2657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.pm.PackageManager; 2791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.PackageManager.NameNotFoundException; 281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CrossProcessCursor; 2957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.Cursor; 301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWindow; 311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWrapper; 32c6f5aad265cfc36a64cd2bdb5adf3cc9736bbd80Jean-Baptiste Queruimport android.database.SQLException; 3357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 3457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 3557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder; 3657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.net.Uri; 3757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Binder; 38b06b739b078ce4b00600487cfec31659647bf31fSteve Howardimport android.os.Environment; 3957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.ParcelFileDescriptor; 4057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Process; 4157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.provider.Downloads; 4257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.util.Log; 4357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport com.google.common.annotations.VisibleForTesting; 455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.io.File; 4757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport java.io.FileNotFoundException; 481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.util.HashSet; 49e61798da80558450f580ed948d0d469bd6423d8eSteve Howardimport java.util.Iterator; 505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport java.util.Map; 511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 5257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/** 5457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Allows application to interact with the download manager. 5557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 5657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpublic final class DownloadProvider extends ContentProvider { 5757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Database filename */ 5857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_NAME = "downloads.db"; 591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /** Current database version */ 6071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard private static final int DB_VERSION = 103; 6157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Name of table in the database */ 6257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_TABLE = "downloads"; 6357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 6457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for the entire download list */ 6557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_LIST_TYPE = "vnd.android.cursor.dir/download"; 6657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for an individual download */ 6757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_TYPE = "vnd.android.cursor.item/download"; 6857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 6957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher used to recognize URIs sent by applications */ 7057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 713d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads belonging to the calling UID */ 723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS = 1; 733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of an individual download belonging to the calling UID */ 743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS_ID = 2; 753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads in the system */ 763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS = 3; 7757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher constant for the URI of an individual download */ 783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS_ID = 4; 795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** URI matcher constant for the URI of a download's request headers */ 803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int REQUEST_HEADERS_URI = 5; 8157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project static { 823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads", MY_DOWNLOADS); 833d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads/#", MY_DOWNLOADS_ID); 843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads", ALL_DOWNLOADS); 853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads/#", ALL_DOWNLOADS_ID); 863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "my_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "all_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 924bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard // temporary, for backwards compatibility 934bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download", MY_DOWNLOADS); 944bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download/#", MY_DOWNLOADS_ID); 954bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", 964bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard "download/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 974bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard REQUEST_HEADERS_URI); 9857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 1003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** Different base URIs that could be used to access an individual download */ 1013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final Uri[] BASE_URIS = new Uri[] { 1023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.CONTENT_URI, 1033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 1043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard }; 1053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 1061fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final String[] sAppReadableColumnsArray = new String[] { 1077dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._ID, 1087dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_APP_DATA, 1097dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._DATA, 1107dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_MIME_TYPE, 1117dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_VISIBILITY, 1127dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_DESTINATION, 1137dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CONTROL, 1147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_STATUS, 1157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_LAST_MODIFICATION, 1167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, 1177dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_CLASS, 1187dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TOTAL_BYTES, 1197dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CURRENT_BYTES, 1207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TITLE, 1210a77c62a82503b38c484e0079648f0231dd85d53Steve Howard Downloads.Impl.COLUMN_DESCRIPTION, 1220d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard Downloads.Impl.COLUMN_URI, 12371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 1241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project }; 1251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static HashSet<String> sAppReadableColumnsSet; 1271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project static { 1281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet = new HashSet<String>(); 1291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < sAppReadableColumnsArray.length; ++i) { 1301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet.add(sAppReadableColumnsArray[i]); 1311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 1321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 1331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 13457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** The database that lies underneath this content provider */ 13557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private SQLiteOpenHelper mOpenHelper = null; 13657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 13791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu /** List of uids that can access the downloads */ 13891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mSystemUid = -1; 13991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mDefContainerUid = -1; 14091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu 1416d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard @VisibleForTesting 1426d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard SystemFacade mSystemFacade; 1436d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard 14457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 14557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates and updated database on demand when opening it. 14657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Helper class to create database the first time the provider is 14757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * initialized and upgrade it when a new version of the provider needs 14857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * an updated version of the database. 14957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 15057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private final class DatabaseHelper extends SQLiteOpenHelper { 15157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public DatabaseHelper(final Context context) { 15257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project super(context, DB_NAME, null, DB_VERSION); 15357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 15457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 15557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 15657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates database the first time we try to open it. 15757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 15857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 15957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public void onCreate(final SQLiteDatabase db) { 16057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 16157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, "populating new database"); 16257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 1635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard onUpgrade(db, 0, DB_VERSION); 16457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 16557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 16657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 16757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates the database format when a content provider is used 16857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * with a database that was created with a different format. 1695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * 1705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Note: to support downgrades, creating a table should always drop it first if it already 1715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * exists. 17257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 17357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 1741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public void onUpgrade(final SQLiteDatabase db, int oldV, final int newV) { 1755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (oldV == 31) { 1765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // 31 and 100 are identical, just in different codelines. Upgrading from 31 is the 1775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // same as upgrading from 100. 1785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 100; 1795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV < 100) { 1805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // no logic to upgrade from these older version, just recreate the DB 1815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.i(Constants.TAG, "Upgrading downloads database from version " + oldV 1825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " to version " + newV + ", which will destroy all old data"); 1835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 1845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV > newV) { 1855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // user must have downgraded software; we have no way to know how to downgrade the 1865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // DB, so just recreate it 1875224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.i(Constants.TAG, "Downgrading downloads database from version " + oldV 1885224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " (current version is " + newV + "), destroying all old data"); 1895224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 1905224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 1915224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 1925224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (int version = oldV + 1; version <= newV; version++) { 1935224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard upgradeTo(db, version); 1945224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 1955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 1965224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 1975224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 1985224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Upgrade database from (version - 1) to version. 1995224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 2005224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void upgradeTo(SQLiteDatabase db, int version) { 2015224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard switch (version) { 2025224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 100: 2035224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createDownloadsTable(db); 2045224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2055224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2065224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 101: 2075224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createHeadersTable(db); 2085224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2095224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2100a77c62a82503b38c484e0079648f0231dd85d53Steve Howard case 102: 2110a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_PUBLIC_API, 2120a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2130a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_ROAMING, 2140a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2150a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, 2160a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2170a77c62a82503b38c484e0079648f0231dd85d53Steve Howard break; 2180a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 21971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard case 103: 22071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 22171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard "INTEGER NOT NULL DEFAULT 1"); 22271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard makeCacheDownloadsInvisible(db); 22371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard break; 22471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 2255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard default: 2265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalStateException("Don't know how to upgrade to " + version); 2275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 23171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard * Set all existing downloads to the cache partition to be invisible in the downloads UI. 23271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard */ 23371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard private void makeCacheDownloadsInvisible(SQLiteDatabase db) { 23471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard ContentValues values = new ContentValues(); 23571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, false); 23671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard String cacheSelection = Downloads.Impl.COLUMN_DESTINATION 23771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard + " != " + Downloads.Impl.DESTINATION_EXTERNAL; 23871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard db.update(DB_TABLE, values, cacheSelection, null); 23971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 24071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 24171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard /** 2420a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * Add a column to a table using ALTER TABLE. 2430a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param dbTable name of the table 2440a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnName name of the column to add 2450a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnDefinition SQL for the column definition 2460a77c62a82503b38c484e0079648f0231dd85d53Steve Howard */ 2470a77c62a82503b38c484e0079648f0231dd85d53Steve Howard private void addColumn(SQLiteDatabase db, String dbTable, String columnName, 2480a77c62a82503b38c484e0079648f0231dd85d53Steve Howard String columnDefinition) { 2490a77c62a82503b38c484e0079648f0231dd85d53Steve Howard db.execSQL("ALTER TABLE " + dbTable + " ADD COLUMN " + columnName + " " 2500a77c62a82503b38c484e0079648f0231dd85d53Steve Howard + columnDefinition); 2510a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 2520a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 2530a77c62a82503b38c484e0079648f0231dd85d53Steve Howard /** 2545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Creates the table that'll hold the download information. 2555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 2565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createDownloadsTable(SQLiteDatabase db) { 2575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 2585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE); 2595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + DB_TABLE + "(" + 2605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 2615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_URI + " TEXT, " + 2625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " + 2635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_APP_DATA + " TEXT, " + 2645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " + 2655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " + 2665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.OTA_UPDATE + " BOOLEAN, " + 2675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._DATA + " TEXT, " + 2685224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " + 2695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " + 2705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.NO_SYSTEM_FILES + " BOOLEAN, " + 2715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " + 2725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CONTROL + " INTEGER, " + 2735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_STATUS + " INTEGER, " + 2745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.FAILED_CONNECTIONS + " INTEGER, " + 2755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " + 2765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " + 2775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " + 2785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " + 2795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " + 2805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " + 2815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_REFERER + " TEXT, " + 2825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " + 2835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " + 2845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.ETAG + " TEXT, " + 2855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.UID + " INTEGER, " + 2865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " + 2875224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TITLE + " TEXT, " + 2885224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " + 2895224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.MEDIA_SCANNED + " BOOLEAN);"); 2905224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } catch (SQLException ex) { 2915224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.e(Constants.TAG, "couldn't create table in downloads database"); 2925224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw ex; 2935224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2945224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2965224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createHeadersTable(SQLiteDatabase db) { 2975224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE); 2985224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE + "(" + 2995224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard "id INTEGER PRIMARY KEY AUTOINCREMENT," + 3005224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + " INTEGER NOT NULL," + 3015224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_HEADER + " TEXT NOT NULL," + 3025224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE + " TEXT NOT NULL" + 3035224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ");"); 30457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 30557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 30657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 30757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 30857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Initializes the content provider when it is created. 30957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 31057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 31157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public boolean onCreate() { 3126d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (mSystemFacade == null) { 313af28400b74de05862b470412a5c92f68e99f59f8Steve Howard mSystemFacade = new RealSystemFacade(getContext()); 3146d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 3156d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard 31657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project mOpenHelper = new DatabaseHelper(getContext()); 31791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the system uid 31891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mSystemUid = Process.SYSTEM_UID; 31991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the default container uid. Package name hardcoded 32091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // for now. 32191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu ApplicationInfo appInfo = null; 32291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu try { 32391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu appInfo = getContext().getPackageManager(). 32491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu getApplicationInfo("com.android.defcontainer", 0); 32591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } catch (NameNotFoundException e) { 32691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // TODO Auto-generated catch block 32791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu e.printStackTrace(); 32891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 32991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu if (appInfo != null) { 33091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mDefContainerUid = appInfo.uid; 33191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 33257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return true; 33357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 33457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 33557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 33657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Returns the content-provider-style MIME types of the various 33757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * types accessible through this content provider. 33857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 33957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 34057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public String getType(final Uri uri) { 34157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 34257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 3433d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: { 34457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return DOWNLOAD_LIST_TYPE; 34557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 3463d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: { 34757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return DOWNLOAD_TYPE; 34857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 34957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project default: { 35057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 35157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, "calling getType on an unknown URI: " + uri); 35257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 35357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown URI: " + uri); 35457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 35557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 35657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 35757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 35857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 35957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Inserts a row in the database 36057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 36157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 36257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public Uri insert(final Uri uri, final ContentValues values) { 363b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkInsertPermissions(values); 36457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 36557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 3663d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // note we disallow inserting into ALL_DOWNLOADS 3673d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int match = sURIMatcher.match(uri); 3683d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match != MY_DOWNLOADS) { 3693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: " + uri); 37057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown/Invalid URI " + uri); 37157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 37257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 3731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues = new ContentValues(); 3741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 3757dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_URI, values, filteredValues); 3767dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 3777dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues); 3787dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues); 3797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues); 38071aab521efba9b28779541440c797220ec98ac97Steve Howard 38171aab521efba9b28779541440c797220ec98ac97Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API, values, filteredValues); 38271aab521efba9b28779541440c797220ec98ac97Steve Howard boolean isPublicApi = 38371aab521efba9b28779541440c797220ec98ac97Steve Howard values.getAsBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API) == Boolean.TRUE; 38471aab521efba9b28779541440c797220ec98ac97Steve Howard 3857dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION); 386ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (dest != null) { 3877dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 3881fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project != PackageManager.PERMISSION_GRANTED 3897dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru && dest != Downloads.Impl.DESTINATION_EXTERNAL 3906d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard && dest != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE 3916d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard && dest != Downloads.Impl.DESTINATION_FILE_URI) { 3921fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new SecurityException("unauthorized destination code"); 3931fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 39471aab521efba9b28779541440c797220ec98ac97Steve Howard // for public API behavior, if an app has CACHE_NON_PURGEABLE permission, automatically 39571aab521efba9b28779541440c797220ec98ac97Steve Howard // switch to non-purgeable download 39671aab521efba9b28779541440c797220ec98ac97Steve Howard boolean hasNonPurgeablePermission = 39771aab521efba9b28779541440c797220ec98ac97Steve Howard getContext().checkCallingPermission( 39871aab521efba9b28779541440c797220ec98ac97Steve Howard Downloads.Impl.PERMISSION_CACHE_NON_PURGEABLE) 39971aab521efba9b28779541440c797220ec98ac97Steve Howard == PackageManager.PERMISSION_GRANTED; 40071aab521efba9b28779541440c797220ec98ac97Steve Howard if (isPublicApi && dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE 40171aab521efba9b28779541440c797220ec98ac97Steve Howard && hasNonPurgeablePermission) { 40271aab521efba9b28779541440c797220ec98ac97Steve Howard dest = Downloads.Impl.DESTINATION_CACHE_PARTITION; 40371aab521efba9b28779541440c797220ec98ac97Steve Howard } 4046d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (dest == Downloads.Impl.DESTINATION_FILE_URI) { 4056d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard getContext().enforcePermission( 4066d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 4076d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard Binder.getCallingPid(), Binder.getCallingUid(), 4086d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard "need WRITE_EXTERNAL_STORAGE permission to use DESTINATION_FILE_URI"); 409b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkFileUriDestination(values); 4106d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 4117dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest); 412ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } 4137dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY); 414ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (vis == null) { 4157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (dest == Downloads.Impl.DESTINATION_EXTERNAL) { 4167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 4177dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 418ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 4197dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 4207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_HIDDEN); 4211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 422ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 4237dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis); 42457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 4257dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 4267dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING); 4276d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, 4286d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard mSystemFacade.currentTimeMillis()); 4290a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 4307dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); 4317dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS); 4320a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (pckg != null && (clazz != null || isPublicApi)) { 4331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project int uid = Binder.getCallingUid(); 4341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project try { 4350a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (uid == 0 || mSystemFacade.userOwnsPackage(uid, pckg)) { 4367dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg); 4370a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (clazz != null) { 4380a77c62a82503b38c484e0079648f0231dd85d53Steve Howard filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz); 4390a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 4401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 4411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } catch (PackageManager.NameNotFoundException ex) { 4421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /* ignored for now */ 44357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 44457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 4457dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues); 4467dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues); 4477dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues); 4487dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues); 4497dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 4501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project == PackageManager.PERMISSION_GRANTED) { 4517dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues); 45257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 4531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues.put(Constants.UID, Binder.getCallingUid()); 4541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingUid() == 0) { 4551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project copyInteger(Constants.UID, values, filteredValues); 45657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 457a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_TITLE, values, filteredValues, ""); 458a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues, ""); 459b5629da794cb3c1ca1970d206343743b165b9644Steve Howard filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1); 46057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 46171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard if (values.containsKey(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI)) { 46271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, values, filteredValues); 46371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } else { 46471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard // by default, make external downloads visible in the UI 46571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isExternal = (dest == null || dest == Downloads.Impl.DESTINATION_EXTERNAL); 46671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard filteredValues.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, isExternal); 46771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 46871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 4690a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (isPublicApi) { 4700a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyInteger(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, values, filteredValues); 4710a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyBoolean(Downloads.Impl.COLUMN_ALLOW_ROAMING, values, filteredValues); 4720a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 4730a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 4741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Constants.LOGVV) { 4751fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "initiating download with UID " 4761fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project + filteredValues.getAsInteger(Constants.UID)); 4777dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) { 4781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "other UID " + 4797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID)); 4801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 48157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 48257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 48357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Context context = getContext(); 48457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project context.startService(new Intent(context, DownloadService.class)); 48557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 4861fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project long rowID = db.insert(DB_TABLE, null, filteredValues); 4873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (rowID == -1) { 4883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "couldn't insert into downloads database"); 4893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return null; 49057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 49157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 4923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard insertRequestHeaders(db, rowID, values); 4933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard context.startService(new Intent(context, DownloadService.class)); 4943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 4953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID); 49657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 49757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 49857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 499b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Check that the file URI provided for DESTINATION_FILE_URI is valid. 500b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 501b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkFileUriDestination(ContentValues values) { 502b06b739b078ce4b00600487cfec31659647bf31fSteve Howard String fileUri = values.getAsString(Downloads.Impl.COLUMN_FILE_NAME_HINT); 503b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (fileUri == null) { 504b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException( 505b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "DESTINATION_FILE_URI must include a file URI under COLUMN_FILE_NAME_HINT"); 506b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 507b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Uri uri = Uri.parse(fileUri); 508b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (!uri.getScheme().equals("file")) { 509b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException("Not a file URI: " + uri); 510b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 511b06b739b078ce4b00600487cfec31659647bf31fSteve Howard File path = new File(uri.getSchemeSpecificPart()); 512b06b739b078ce4b00600487cfec31659647bf31fSteve Howard String externalPath = Environment.getExternalStorageDirectory().getAbsolutePath(); 513b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (!path.getPath().startsWith(externalPath)) { 514b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException("Destination must be on external storage: " + uri); 515b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 516b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 517b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 518b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 519b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Apps with the ACCESS_DOWNLOAD_MANAGER permission can access this provider freely, subject to 520b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * constraints in the rest of the code. Apps without that may still access this provider through 521b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * the public API, but additional restrictions are imposed. We check those restrictions here. 522b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * 523b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @param values ContentValues provided to insert() 524b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @throws SecurityException if the caller has insufficient permissions 525b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 526b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkInsertPermissions(ContentValues values) { 527b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS) 528b06b739b078ce4b00600487cfec31659647bf31fSteve Howard == PackageManager.PERMISSION_GRANTED) { 529b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 530b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 531b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 532b06b739b078ce4b00600487cfec31659647bf31fSteve Howard getContext().enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, 533b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "INTERNET permission is required to use the download manager"); 534b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 535b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // ensure the request fits within the bounds of a public API request 536b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // first copy so we can remove values 537b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values = new ContentValues(values); 538b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 539b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // check columns whose values are restricted 540b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_IS_PUBLIC_API, Boolean.TRUE); 541b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_DESTINATION, 542b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE, 543b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Downloads.Impl.DESTINATION_FILE_URI); 5449da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard 5459da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_NO_NOTIFICATION) 5469da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard == PackageManager.PERMISSION_GRANTED) { 5479da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 5489da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard Downloads.Impl.VISIBILITY_HIDDEN, Downloads.Impl.VISIBILITY_VISIBLE); 5499da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } else { 5509da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 5519da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard Downloads.Impl.VISIBILITY_VISIBLE); 5529da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } 553b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 554b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // remove the rest of the columns that are allowed (with any value) 555b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_URI); 556b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_TITLE); 557b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_DESCRIPTION); 558b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_MIME_TYPE); 559b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_FILE_NAME_HINT); // checked later in insert() 560b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); // checked later in insert() 561b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES); 562b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOW_ROAMING); 56371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.remove(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI); 564e61798da80558450f580ed948d0d469bd6423d8eSteve Howard Iterator<Map.Entry<String, Object>> iterator = values.valueSet().iterator(); 565e61798da80558450f580ed948d0d469bd6423d8eSteve Howard while (iterator.hasNext()) { 566e61798da80558450f580ed948d0d469bd6423d8eSteve Howard String key = iterator.next().getKey(); 567e61798da80558450f580ed948d0d469bd6423d8eSteve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 568e61798da80558450f580ed948d0d469bd6423d8eSteve Howard iterator.remove(); 569e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 570e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 571b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 572b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // any extra columns are extraneous and disallowed 573b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (values.size() > 0) { 574b06b739b078ce4b00600487cfec31659647bf31fSteve Howard StringBuilder error = new StringBuilder("Invalid columns in request: "); 575b06b739b078ce4b00600487cfec31659647bf31fSteve Howard boolean first = true; 576b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 577b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (!first) { 578b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(", "); 579b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 580b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(entry.getKey()); 581b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 582b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException(error.toString()); 583b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 584b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 585b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 586b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 587b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Remove column from values, and throw a SecurityException if the value isn't within the 588b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * specified allowedValues. 589b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 590b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void enforceAllowedValues(ContentValues values, String column, 591b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object... allowedValues) { 592b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object value = values.get(column); 593b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(column); 594b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Object allowedValue : allowedValues) { 595b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value == null && allowedValue == null) { 596b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 597b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 598b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value != null && value.equals(allowedValue)) { 599b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 600b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 601b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 602b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException("Invalid value for " + column + ": " + value); 603b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 604b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 605b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 60657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Starts a database query 60757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 60857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 6091fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public Cursor query(final Uri uri, String[] projection, 61057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String selection, final String[] selectionArgs, 61157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String sort) { 6121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 6131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(selection, sAppReadableColumnsSet); 6141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 61557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 61657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 61757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard qb.setTables(DB_TABLE); 61957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 62057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 6213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == -1) { 6223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (Constants.LOGV) { 6233d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "querying unknown URI: " + uri); 62457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 6253d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new IllegalArgumentException("Unknown URI: " + uri); 6263d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 6273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 6283d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == REQUEST_HEADERS_URI) { 6293d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection != null || selection != null || sort != null) { 6303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new UnsupportedOperationException("Request header queries do not support " 6313d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + "projections, selections or sorting"); 63257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 6333d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return queryRequestHeaders(db, uri); 6343d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 6353d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 6363d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String where = getWhereClause(uri, null, match); 6373d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (!where.isEmpty()) { 6383d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard qb.appendWhere(where); 63957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 64057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 6415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (shouldRestrictVisibility()) { 6421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (projection == null) { 6431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project projection = sAppReadableColumnsArray; 6441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 6451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < projection.length; ++i) { 6461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!sAppReadableColumnsSet.contains(projection[i])) { 6471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new IllegalArgumentException( 6481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project "column " + projection[i] + " is not allowed in queries"); 6491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 6501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 6511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 65257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 65357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 65457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 6553d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseQueryInfo(projection, selection, selectionArgs, sort, db); 65657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 65757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 65857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Cursor ret = qb.query(db, projection, selection, selectionArgs, 65957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project null, null, sort); 66057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 66157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (ret != null) { 6621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ret = new ReadOnlyCursorWrapper(ret); 6631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 6641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 6651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (ret != null) { 66657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project ret.setNotificationUri(getContext().getContentResolver(), uri); 66757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 66857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, 66957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project "created cursor " + ret + " on behalf of " + Binder.getCallingPid()); 67057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 67157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } else { 67257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 6731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "query failed in downloads database"); 67457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 67557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 67657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 67757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return ret; 67857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 67957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 6803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseQueryInfo(String[] projection, final String selection, 6813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard final String[] selectionArgs, final String sort, SQLiteDatabase db) { 6823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard java.lang.StringBuilder sb = new java.lang.StringBuilder(); 6833d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("starting query, database is "); 6843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (db != null) { 6853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("not "); 6863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 6873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("null; "); 6883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection == null) { 6893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is null; "); 6903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (projection.length == 0) { 6913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is empty; "); 6923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 6933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < projection.length; ++i) { 6943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection["); 6953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 6963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 6973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(projection[i]); 6983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 6993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selection is "); 7023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selection); 7033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 7043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (selectionArgs == null) { 7053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is null; "); 7063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (selectionArgs.length == 0) { 7073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is empty; "); 7083d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 7093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < selectionArgs.length; ++i) { 7103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs["); 7113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 7123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 7133d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selectionArgs[i]); 7143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 7153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("sort is "); 7183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(sort); 7193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("."); 7203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, sb.toString()); 7213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 7235224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private String getDownloadIdFromUri(final Uri uri) { 7245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return uri.getPathSegments().get(1); 7255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 7275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 7285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Insert request headers for a download into the DB. 7295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 7305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void insertRequestHeaders(SQLiteDatabase db, long downloadId, ContentValues values) { 7315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ContentValues rowValues = new ContentValues(); 7325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID, downloadId); 7335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 7345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String key = entry.getKey(); 7355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 7365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String headerLine = entry.getValue().toString(); 7375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (!headerLine.contains(":")) { 7385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalArgumentException("Invalid HTTP header line: " + headerLine); 7395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] parts = headerLine.split(":", 2); 7415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_HEADER, parts[0].trim()); 7425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_VALUE, parts[1].trim()); 7435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.insert(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, null, rowValues); 7445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 7485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 7495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Handle a query for the custom request headers registered for a download. 7505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 7515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private Cursor queryRequestHeaders(SQLiteDatabase db, Uri uri) { 7525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String where = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" 7535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + getDownloadIdFromUri(uri); 7545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl.RequestHeaders.COLUMN_HEADER, 7555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE}; 7565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Cursor cursor = db.query(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, projection, where, 7575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard null, null, null, null); 7585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return new ReadOnlyCursorWrapper(cursor); 7595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 7615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 7625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Delete request headers for downloads matching the given query. 7635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 7645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void deleteRequestHeaders(SQLiteDatabase db, String where, String[] whereArgs) { 7655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl._ID}; 766b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Cursor cursor = db.query(DB_TABLE, projection, where, whereArgs, null, null, null, null); 7675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 7685224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 7695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard long id = cursor.getLong(0); 7705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String idWhere = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" + id; 7715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.delete(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, idWhere, null); 7725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } finally { 7745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard cursor.close(); 7755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 7785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 7793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @return true if we should restrict the columns readable by this caller 7805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 7815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private boolean shouldRestrictVisibility() { 7825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard int callingUid = Binder.getCallingUid(); 7835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return Binder.getCallingPid() != Process.myPid() && 7845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard callingUid != mSystemUid && 7855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard callingUid != mDefContainerUid && 7865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Process.supportsProcesses(); 7875224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 7885224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 78957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 7900d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard * @return a SQL WHERE clause to restrict the query to downloads accessible to the caller's UID 7910d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard */ 7920d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard private String getRestrictedUidClause() { 7930d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard return "( " + Constants.UID + "=" + Binder.getCallingUid() + " OR " 7940d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard + Downloads.Impl.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )"; 7950d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard } 7960d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard 7970d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard /** 79857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates a row in the database 79957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 80057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 80157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public int update(final Uri uri, final ContentValues values, 80257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String where, final String[] whereArgs) { 8031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 8041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(where, sAppReadableColumnsSet); 8051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 80657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 80757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 80857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 8091fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project boolean startService = false; 8101fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 8111fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues; 8121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingPid() != Process.myPid()) { 8131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = new ContentValues(); 8147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 8157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues); 8167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL); 8171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 8187dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i); 8191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project startService = true; 8201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 8217dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 8227dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues); 8237dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues); 8241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 8251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = values; 826a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins String filename = values.getAsString(Downloads.Impl._DATA); 827a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins if (filename != null) { 828a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins Cursor c = query(uri, new String[] 829a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins { Downloads.Impl.COLUMN_TITLE }, null, null, null); 830a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins if (!c.moveToFirst() || c.getString(0) == null) { 831a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins values.put(Downloads.Impl.COLUMN_TITLE, 832a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins new File(filename).getName()); 833a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 834a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins c.close(); 835a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 83671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 83771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Integer status = values.getAsInteger(Downloads.Impl.COLUMN_STATUS); 83871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isRestart = status != null && status == Downloads.Impl.STATUS_PENDING; 83971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard if (isRestart) { 84071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard startService = true; 84171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 84257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 8433d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 84457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 84557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 8463d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 8473d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 8483d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 8493d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 8503d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String fullWhere = getWhereClause(uri, where, match); 8511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (filteredValues.size() > 0) { 852b06b739b078ce4b00600487cfec31659647bf31fSteve Howard count = db.update(DB_TABLE, filteredValues, fullWhere, whereArgs); 8531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 8541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project count = 0; 8551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 85657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 8573d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 8583d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 8593d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "updating unknown/invalid URI: " + uri); 86057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot update URI: " + uri); 86157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 8623d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 8633d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 8641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (startService) { 8651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Context context = getContext(); 8661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project context.startService(new Intent(context, DownloadService.class)); 8671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 86857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 86957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 87057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 8713d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** 8723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * Notify of a change through both URIs (/my_downloads and /all_downloads) 8733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uri either URI for the changed download(s) 8743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uriMatch the match ID from {@link #sURIMatcher} 8753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard */ 8763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void notifyContentChanged(final Uri uri, int uriMatch) { 8773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Long downloadId = null; 8783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID) { 8793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard downloadId = Long.parseLong(getDownloadIdFromUri(uri)); 8803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (Uri uriToNotify : BASE_URIS) { 8823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (downloadId != null) { 8833d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard uriToNotify = ContentUris.withAppendedId(uriToNotify, downloadId); 8843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard getContext().getContentResolver().notifyChange(uriToNotify, null); 8863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 8893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private String getWhereClause(final Uri uri, final String where, int uriMatch) { 890b06b739b078ce4b00600487cfec31659647bf31fSteve Howard StringBuilder myWhere = new StringBuilder(); 891b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (where != null) { 892b06b739b078ce4b00600487cfec31659647bf31fSteve Howard myWhere.append("( " + where + " )"); 893b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 8943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID) { 8953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard appendClause(myWhere, 8963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard " ( " + Downloads.Impl._ID + " = " + getDownloadIdFromUri(uri) + " ) "); 897b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 8983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS || uriMatch == MY_DOWNLOADS_ID) { 899b06b739b078ce4b00600487cfec31659647bf31fSteve Howard appendClause(myWhere, getRestrictedUidClause()); 900b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 901b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return myWhere.toString(); 902b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 903b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 90457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 90557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Deletes a row in the database 90657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 90757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 90857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public int delete(final Uri uri, final String where, 90957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String[] whereArgs) { 9101fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 9111fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(where, sAppReadableColumnsSet); 9121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 91357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 91457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 91557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 91657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 9173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 9183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 9193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 9203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 9213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String fullWhere = getWhereClause(uri, where, match); 922b06b739b078ce4b00600487cfec31659647bf31fSteve Howard deleteRequestHeaders(db, fullWhere, whereArgs); 923b06b739b078ce4b00600487cfec31659647bf31fSteve Howard count = db.delete(DB_TABLE, fullWhere, whereArgs); 92457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 9253d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9263d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 9273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "deleting unknown/invalid URI: " + uri); 92857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot delete URI: " + uri); 92957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 93157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 93257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 93371aab521efba9b28779541440c797220ec98ac97Steve Howard 934b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void appendClause(StringBuilder whereClause, String newClause) { 935b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (whereClause.length() != 0) { 936b06b739b078ce4b00600487cfec31659647bf31fSteve Howard whereClause.append(" AND "); 937b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 938b06b739b078ce4b00600487cfec31659647bf31fSteve Howard whereClause.append(newClause); 939b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 94057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 94157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 94257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Remotely opens a file 94357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 94457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 9453d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 94657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 9473d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseOpenFileInfo(uri, mode); 94857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 9503d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Cursor cursor = query(uri, new String[] {"_data"}, null, null, null); 9513d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String path; 9523d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard try { 9533d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int count = (cursor != null) ? cursor.getCount() : 0; 9543d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count != 1) { 9553d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // If there is not exactly one result, throw an appropriate exception. 9563d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count == 0) { 9573d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("No entry for " + uri); 9583d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9593d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("Multiple items at " + uri); 9601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9613d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9623d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.moveToFirst(); 9633d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard path = cursor.getString(0); 9643d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } finally { 9653d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor != null) { 9663d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 9671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 9701fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (path == null) { 9711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("No filename found."); 9721fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!Helpers.isFilenameValid(path)) { 9741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("Invalid filename."); 9751fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9761fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!"r".equals(mode)) { 9771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("Bad mode for " + uri + ": " + mode); 9781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ParcelFileDescriptor ret = ParcelFileDescriptor.open(new File(path), 9811fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 9821fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 98357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (ret == null) { 9841fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Constants.LOGV) { 9851fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "couldn't open file"); 98657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9871fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("couldn't open file"); 98857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 98957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return ret; 99057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 99157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 9923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseOpenFileInfo(Uri uri, String mode) { 9933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode 9943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + ", uid: " + Binder.getCallingUid()); 9953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Cursor cursor = query(Downloads.Impl.CONTENT_URI, 9963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard new String[] { "_id" }, null, null, "_id"); 9973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 9983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "null cursor in openFile"); 9993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (!cursor.moveToFirst()) { 10013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "empty cursor in openFile"); 10023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard do { 10043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available"); 10053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } while(cursor.moveToNext()); 10063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 10083d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor = query(uri, new String[] { "_data" }, null, null, null); 10103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 10113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "null cursor in openFile"); 10123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10133d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (!cursor.moveToFirst()) { 10143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "empty cursor in openFile"); 10153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String filename = cursor.getString(0); 10173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "filename in openFile: " + filename); 10183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (new java.io.File(filename).isFile()) { 10193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "file exists in openFile"); 10203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 10233d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10243d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10253d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyInteger(String key, ContentValues from, ContentValues to) { 10271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Integer i = from.getAsInteger(key); 10281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 10291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, i); 10301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyBoolean(String key, ContentValues from, ContentValues to) { 10341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Boolean b = from.getAsBoolean(key); 10351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (b != null) { 10361fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, b); 10371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10381fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10391fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyString(String key, ContentValues from, ContentValues to) { 10411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project String s = from.getAsString(key); 10421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (s != null) { 10431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, s); 10441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1047a89321ea04ced76d06f60f5909be203cb654a830Steve Howard private static final void copyStringWithDefault(String key, ContentValues from, 1048a89321ea04ced76d06f60f5909be203cb654a830Steve Howard ContentValues to, String defaultValue) { 1049a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyString(key, from, to); 1050a89321ea04ced76d06f60f5909be203cb654a830Steve Howard if (!to.containsKey(key)) { 1051a89321ea04ced76d06f60f5909be203cb654a830Steve Howard to.put(key, defaultValue); 1052a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 1053a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 1054a89321ea04ced76d06f60f5909be203cb654a830Steve Howard 10551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private class ReadOnlyCursorWrapper extends CursorWrapper implements CrossProcessCursor { 10561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public ReadOnlyCursorWrapper(Cursor cursor) { 10571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project super(cursor); 10581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project mCursor = (CrossProcessCursor) cursor; 10591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10611fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public boolean deleteRow() { 10621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new SecurityException("Download manager cursors are read-only"); 10631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public boolean commitUpdates() { 10661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new SecurityException("Download manager cursors are read-only"); 10671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public void fillWindow(int pos, CursorWindow window) { 10701fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project mCursor.fillWindow(pos, window); 10711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10721fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public CursorWindow getWindow() { 10741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project return mCursor.getWindow(); 10751fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10761fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public boolean onMove(int oldPosition, int newPosition) { 10781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project return mCursor.onMove(oldPosition, newPosition); 10791fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10811fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private CrossProcessCursor mCursor; 10821fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 108457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project} 1085