DownloadProvider.java revision 01d0182d86db003b2da5b831cb26820093888d9a
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 193ca67748bc92eac89f731796c5597ff1fbe9217bVasu Noriimport android.app.DownloadManager; 2057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentProvider; 213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howardimport android.content.ContentUris; 2257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentValues; 2357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Context; 2457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Intent; 2557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.UriMatcher; 2691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.ApplicationInfo; 2757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.pm.PackageManager; 2891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.PackageManager.NameNotFoundException; 2957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.Cursor; 303ca67748bc92eac89f731796c5597ff1fbe9217bVasu Noriimport android.database.DatabaseUtils; 31c6f5aad265cfc36a64cd2bdb5adf3cc9736bbd80Jean-Baptiste Queruimport android.database.SQLException; 3257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 3357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 3457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.net.Uri; 3557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Binder; 36b06b739b078ce4b00600487cfec31659647bf31fSteve Howardimport android.os.Environment; 3757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.ParcelFileDescriptor; 3857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Process; 3957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.provider.Downloads; 4057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.util.Log; 4157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport com.google.common.annotations.VisibleForTesting; 435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.io.File; 4557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport java.io.FileNotFoundException; 46e610c0502c00689411624c00c3f81497df93b202Steve Howardimport java.util.ArrayList; 4701d0182d86db003b2da5b831cb26820093888d9aVasu Noriimport java.util.Arrays; 481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.util.HashSet; 49e61798da80558450f580ed948d0d469bd6423d8eSteve Howardimport java.util.Iterator; 50e610c0502c00689411624c00c3f81497df93b202Steve Howardimport java.util.List; 515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport java.util.Map; 521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 5357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/** 5557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Allows application to interact with the download manager. 5657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 5757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpublic final class DownloadProvider extends ContentProvider { 5857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Database filename */ 5957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_NAME = "downloads.db"; 601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /** Current database version */ 619d27069a5453574824860ad3db179599d044e7bdVasu Nori private static final int DB_VERSION = 107; 6257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Name of table in the database */ 6357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_TABLE = "downloads"; 6457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 6557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for the entire download list */ 6657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_LIST_TYPE = "vnd.android.cursor.dir/download"; 6757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for an individual download */ 6857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_TYPE = "vnd.android.cursor.item/download"; 6957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher used to recognize URIs sent by applications */ 7157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads belonging to the calling UID */ 733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS = 1; 743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of an individual download belonging to the calling UID */ 753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS_ID = 2; 763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads in the system */ 773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS = 3; 7857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher constant for the URI of an individual download */ 793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS_ID = 4; 805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** URI matcher constant for the URI of a download's request headers */ 813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int REQUEST_HEADERS_URI = 5; 823ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori /** URI matcher constant for the public URI returned by 833ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori * {@link DownloadManager#getUriForDownloadedFile(long)} if the given downloaded file 843ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori * is publicly accessible. 853ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori */ 863ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori private static final int PUBLIC_DOWNLOAD_ID = 6; 8757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project static { 883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads", MY_DOWNLOADS); 893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads/#", MY_DOWNLOADS_ID); 903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads", ALL_DOWNLOADS); 913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads/#", ALL_DOWNLOADS_ID); 923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "my_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "all_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 984bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard // temporary, for backwards compatibility 994bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download", MY_DOWNLOADS); 1004bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download/#", MY_DOWNLOADS_ID); 1014bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", 1024bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard "download/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 1034bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard REQUEST_HEADERS_URI); 1043ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori sURIMatcher.addURI("downloads", 1053ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori Downloads.Impl.PUBLICLY_ACCESSIBLE_DOWNLOADS_URI_SEGMENT + "/#", 1063ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori PUBLIC_DOWNLOAD_ID); 10757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 1093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** Different base URIs that could be used to access an individual download */ 1103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final Uri[] BASE_URIS = new Uri[] { 1113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.CONTENT_URI, 1123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 1133d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard }; 1143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 1151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final String[] sAppReadableColumnsArray = new String[] { 1167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._ID, 1177dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_APP_DATA, 1187dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._DATA, 1197dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_MIME_TYPE, 1207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_VISIBILITY, 1217dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_DESTINATION, 1227dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CONTROL, 1237dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_STATUS, 1247dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_LAST_MODIFICATION, 1257dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, 1267dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_CLASS, 1277dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TOTAL_BYTES, 1287dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CURRENT_BYTES, 1297dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TITLE, 1300a77c62a82503b38c484e0079648f0231dd85d53Steve Howard Downloads.Impl.COLUMN_DESCRIPTION, 1310d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard Downloads.Impl.COLUMN_URI, 13271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 133b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard Downloads.Impl.COLUMN_FILE_NAME_HINT, 134e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, 135e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori Downloads.Impl.COLUMN_DELETED, 1361fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project }; 1371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1381fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static HashSet<String> sAppReadableColumnsSet; 1391fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project static { 1401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet = new HashSet<String>(); 1411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < sAppReadableColumnsArray.length; ++i) { 1421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet.add(sAppReadableColumnsArray[i]); 1431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 1441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 14501d0182d86db003b2da5b831cb26820093888d9aVasu Nori private static final List<String> downloadManagerColumnsList = 14601d0182d86db003b2da5b831cb26820093888d9aVasu Nori Arrays.asList(DownloadManager.UNDERLYING_COLUMNS); 1471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 14857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** The database that lies underneath this content provider */ 14957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private SQLiteOpenHelper mOpenHelper = null; 15057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 15191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu /** List of uids that can access the downloads */ 15291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mSystemUid = -1; 15391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mDefContainerUid = -1; 15491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu 1556d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard @VisibleForTesting 1566d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard SystemFacade mSystemFacade; 1576d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard 15857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 159e610c0502c00689411624c00c3f81497df93b202Steve Howard * This class encapsulates a SQL where clause and its parameters. It makes it possible for 160e610c0502c00689411624c00c3f81497df93b202Steve Howard * shared methods (like {@link DownloadProvider#getWhereClause(Uri, String, String[], int)}) 161e610c0502c00689411624c00c3f81497df93b202Steve Howard * to return both pieces of information, and provides some utility logic to ease piece-by-piece 162e610c0502c00689411624c00c3f81497df93b202Steve Howard * construction of selections. 163e610c0502c00689411624c00c3f81497df93b202Steve Howard */ 164e610c0502c00689411624c00c3f81497df93b202Steve Howard private static class SqlSelection { 165e610c0502c00689411624c00c3f81497df93b202Steve Howard public StringBuilder mWhereClause = new StringBuilder(); 166e610c0502c00689411624c00c3f81497df93b202Steve Howard public List<String> mParameters = new ArrayList<String>(); 167e610c0502c00689411624c00c3f81497df93b202Steve Howard 168e610c0502c00689411624c00c3f81497df93b202Steve Howard public <T> void appendClause(String newClause, final T... parameters) { 169e610c0502c00689411624c00c3f81497df93b202Steve Howard if (newClause == null || newClause.isEmpty()) { 170e610c0502c00689411624c00c3f81497df93b202Steve Howard return; 171e610c0502c00689411624c00c3f81497df93b202Steve Howard } 172e610c0502c00689411624c00c3f81497df93b202Steve Howard if (mWhereClause.length() != 0) { 173e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(" AND "); 174e610c0502c00689411624c00c3f81497df93b202Steve Howard } 175e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append("("); 176e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(newClause); 177e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(")"); 178e610c0502c00689411624c00c3f81497df93b202Steve Howard if (parameters != null) { 179e610c0502c00689411624c00c3f81497df93b202Steve Howard for (Object parameter : parameters) { 180e610c0502c00689411624c00c3f81497df93b202Steve Howard mParameters.add(parameter.toString()); 181e610c0502c00689411624c00c3f81497df93b202Steve Howard } 182e610c0502c00689411624c00c3f81497df93b202Steve Howard } 183e610c0502c00689411624c00c3f81497df93b202Steve Howard } 184e610c0502c00689411624c00c3f81497df93b202Steve Howard 185e610c0502c00689411624c00c3f81497df93b202Steve Howard public String getSelection() { 186e610c0502c00689411624c00c3f81497df93b202Steve Howard return mWhereClause.toString(); 187e610c0502c00689411624c00c3f81497df93b202Steve Howard } 188e610c0502c00689411624c00c3f81497df93b202Steve Howard 189e610c0502c00689411624c00c3f81497df93b202Steve Howard public String[] getParameters() { 190e610c0502c00689411624c00c3f81497df93b202Steve Howard String[] array = new String[mParameters.size()]; 191e610c0502c00689411624c00c3f81497df93b202Steve Howard return mParameters.toArray(array); 192e610c0502c00689411624c00c3f81497df93b202Steve Howard } 193e610c0502c00689411624c00c3f81497df93b202Steve Howard } 194e610c0502c00689411624c00c3f81497df93b202Steve Howard 195e610c0502c00689411624c00c3f81497df93b202Steve Howard /** 19657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates and updated database on demand when opening it. 19757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Helper class to create database the first time the provider is 19857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * initialized and upgrade it when a new version of the provider needs 19957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * an updated version of the database. 20057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 20157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private final class DatabaseHelper extends SQLiteOpenHelper { 20257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public DatabaseHelper(final Context context) { 20357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project super(context, DB_NAME, null, DB_VERSION); 20457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 20557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 20657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 20757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates database the first time we try to open it. 20857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 20957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 21057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public void onCreate(final SQLiteDatabase db) { 21157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 21257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, "populating new database"); 21357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 2145224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard onUpgrade(db, 0, DB_VERSION); 21557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 21657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 21757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 21857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates the database format when a content provider is used 21957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * with a database that was created with a different format. 2205224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * 2215224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Note: to support downgrades, creating a table should always drop it first if it already 2225224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * exists. 22357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 22457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 2251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public void onUpgrade(final SQLiteDatabase db, int oldV, final int newV) { 2265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (oldV == 31) { 2275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // 31 and 100 are identical, just in different codelines. Upgrading from 31 is the 2285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // same as upgrading from 100. 2295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 100; 2305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV < 100) { 2315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // no logic to upgrade from these older version, just recreate the DB 2325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.i(Constants.TAG, "Upgrading downloads database from version " + oldV 2335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " to version " + newV + ", which will destroy all old data"); 2345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 2355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV > newV) { 2365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // user must have downgraded software; we have no way to know how to downgrade the 2375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // DB, so just recreate it 2385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.i(Constants.TAG, "Downgrading downloads database from version " + oldV 2395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " (current version is " + newV + "), destroying all old data"); 2405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 2415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (int version = oldV + 1; version <= newV; version++) { 2445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard upgradeTo(db, version); 2455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 2495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Upgrade database from (version - 1) to version. 2505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 2515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void upgradeTo(SQLiteDatabase db, int version) { 2525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard switch (version) { 2535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 100: 2545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createDownloadsTable(db); 2555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 101: 2585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createHeadersTable(db); 2595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2610a77c62a82503b38c484e0079648f0231dd85d53Steve Howard case 102: 2620a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_PUBLIC_API, 2630a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2640a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_ROAMING, 2650a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2660a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, 2670a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2680a77c62a82503b38c484e0079648f0231dd85d53Steve Howard break; 2690a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 27071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard case 103: 27171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 27271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard "INTEGER NOT NULL DEFAULT 1"); 27371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard makeCacheDownloadsInvisible(db); 27471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard break; 27571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 276d319729622da1893e895f2e35f41d01ecdca3705Steve Howard case 104: 277d319729622da1893e895f2e35f41d01ecdca3705Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT, 278d319729622da1893e895f2e35f41d01ecdca3705Steve Howard "INTEGER NOT NULL DEFAULT 0"); 279d319729622da1893e895f2e35f41d01ecdca3705Steve Howard break; 280d319729622da1893e895f2e35f41d01ecdca3705Steve Howard 28173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard case 105: 28273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValues(db); 28373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard break; 28473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 285e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori case 106: 286e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, "TEXT"); 287e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_DELETED, 288e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori "BOOLEAN NOT NULL DEFAULT 0"); 289e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori break; 290e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 2919d27069a5453574824860ad3db179599d044e7bdVasu Nori case 107: 2929d27069a5453574824860ad3db179599d044e7bdVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ERROR_MSG, "TEXT"); 2939d27069a5453574824860ad3db179599d044e7bdVasu Nori break; 2949d27069a5453574824860ad3db179599d044e7bdVasu Nori 2955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard default: 2965224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalStateException("Don't know how to upgrade to " + version); 2975224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2985224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2995224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 3005224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 30173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard * insert() now ensures these four columns are never null for new downloads, so this method 30273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard * makes that true for existing columns, so that code can rely on this assumption. 30373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard */ 30473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard private void fillNullValues(SQLiteDatabase db) { 30573f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard ContentValues values = new ContentValues(); 30673f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0); 30773f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 30873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1); 30973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 31073f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_TITLE, ""); 31173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 31273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_DESCRIPTION, ""); 31373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 31473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard } 31573f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 31673f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard private void fillNullValuesForColumn(SQLiteDatabase db, ContentValues values) { 31773f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard String column = values.valueSet().iterator().next().getKey(); 31873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard db.update(DB_TABLE, values, column + " is null", null); 31973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.clear(); 32073f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard } 32173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 32273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard /** 32371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard * Set all existing downloads to the cache partition to be invisible in the downloads UI. 32471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard */ 32571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard private void makeCacheDownloadsInvisible(SQLiteDatabase db) { 32671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard ContentValues values = new ContentValues(); 32771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, false); 32871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard String cacheSelection = Downloads.Impl.COLUMN_DESTINATION 32971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard + " != " + Downloads.Impl.DESTINATION_EXTERNAL; 33071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard db.update(DB_TABLE, values, cacheSelection, null); 33171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 33271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 33371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard /** 3340a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * Add a column to a table using ALTER TABLE. 3350a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param dbTable name of the table 3360a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnName name of the column to add 3370a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnDefinition SQL for the column definition 3380a77c62a82503b38c484e0079648f0231dd85d53Steve Howard */ 3390a77c62a82503b38c484e0079648f0231dd85d53Steve Howard private void addColumn(SQLiteDatabase db, String dbTable, String columnName, 3400a77c62a82503b38c484e0079648f0231dd85d53Steve Howard String columnDefinition) { 3410a77c62a82503b38c484e0079648f0231dd85d53Steve Howard db.execSQL("ALTER TABLE " + dbTable + " ADD COLUMN " + columnName + " " 3420a77c62a82503b38c484e0079648f0231dd85d53Steve Howard + columnDefinition); 3430a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 3440a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 3450a77c62a82503b38c484e0079648f0231dd85d53Steve Howard /** 3465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Creates the table that'll hold the download information. 3475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 3485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createDownloadsTable(SQLiteDatabase db) { 3495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 3505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE); 3515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + DB_TABLE + "(" + 3525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 3535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_URI + " TEXT, " + 3545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " + 3555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_APP_DATA + " TEXT, " + 3565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " + 3575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " + 3585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.OTA_UPDATE + " BOOLEAN, " + 3595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._DATA + " TEXT, " + 3605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " + 3615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " + 3625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.NO_SYSTEM_FILES + " BOOLEAN, " + 3635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " + 3645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CONTROL + " INTEGER, " + 3655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_STATUS + " INTEGER, " + 3665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.FAILED_CONNECTIONS + " INTEGER, " + 3675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " + 3685224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " + 3695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " + 3705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " + 3715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " + 3725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " + 3735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_REFERER + " TEXT, " + 3745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " + 3755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " + 3765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.ETAG + " TEXT, " + 3775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.UID + " INTEGER, " + 3785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " + 3795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TITLE + " TEXT, " + 3805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " + 381a53c21edb5dc57d97dcddd03fbfa2022abf43787Vasu Nori Constants.MEDIA_SCANNED + " BOOLEAN);"); 3825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } catch (SQLException ex) { 3835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.e(Constants.TAG, "couldn't create table in downloads database"); 3845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw ex; 3855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 3865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 3875224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 3885224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createHeadersTable(SQLiteDatabase db) { 3895224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE); 3905224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE + "(" + 3915224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard "id INTEGER PRIMARY KEY AUTOINCREMENT," + 3925224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + " INTEGER NOT NULL," + 3935224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_HEADER + " TEXT NOT NULL," + 3945224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE + " TEXT NOT NULL" + 3955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ");"); 39657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 39757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 39857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 39957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 40057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Initializes the content provider when it is created. 40157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 40257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 40357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public boolean onCreate() { 4046d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (mSystemFacade == null) { 405af28400b74de05862b470412a5c92f68e99f59f8Steve Howard mSystemFacade = new RealSystemFacade(getContext()); 4066d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 4076d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard 40857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project mOpenHelper = new DatabaseHelper(getContext()); 40991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the system uid 41091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mSystemUid = Process.SYSTEM_UID; 41191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the default container uid. Package name hardcoded 41291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // for now. 41391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu ApplicationInfo appInfo = null; 41491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu try { 41591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu appInfo = getContext().getPackageManager(). 41691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu getApplicationInfo("com.android.defcontainer", 0); 41791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } catch (NameNotFoundException e) { 41891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // TODO Auto-generated catch block 41991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu e.printStackTrace(); 42091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 42191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu if (appInfo != null) { 42291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mDefContainerUid = appInfo.uid; 42391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 42457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return true; 42557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 42657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 42757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 42857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Returns the content-provider-style MIME types of the various 42957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * types accessible through this content provider. 43057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 43157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 43257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public String getType(final Uri uri) { 43357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 43457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 4353d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: { 43657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return DOWNLOAD_LIST_TYPE; 43757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 4383d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: { 43957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return DOWNLOAD_TYPE; 44057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 4413ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori case PUBLIC_DOWNLOAD_ID: { 4423ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori // return the mimetype of this id from the database 4433ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori final String id = getDownloadIdFromUri(uri); 4443ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 4453ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori return DatabaseUtils.stringForQuery(db, 4463ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori "SELECT " + Downloads.Impl.COLUMN_MIME_TYPE + " FROM " + DB_TABLE + 4473ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori " WHERE " + Downloads.Impl._ID + " = ?", 4483ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori new String[]{id}); 4493ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori } 45057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project default: { 45157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 45257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, "calling getType on an unknown URI: " + uri); 45357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 45457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown URI: " + uri); 45557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 45657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 45757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 45857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 45957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 46057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Inserts a row in the database 46157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 46257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 46357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public Uri insert(final Uri uri, final ContentValues values) { 464b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkInsertPermissions(values); 46557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 46657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 4673d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // note we disallow inserting into ALL_DOWNLOADS 4683d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int match = sURIMatcher.match(uri); 4693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match != MY_DOWNLOADS) { 4703d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: " + uri); 47157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown/Invalid URI " + uri); 47257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 47357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 4741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues = new ContentValues(); 4751fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 4767dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_URI, values, filteredValues); 4777dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 4787dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues); 4797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues); 4807dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues); 48171aab521efba9b28779541440c797220ec98ac97Steve Howard 48271aab521efba9b28779541440c797220ec98ac97Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API, values, filteredValues); 48371aab521efba9b28779541440c797220ec98ac97Steve Howard boolean isPublicApi = 48471aab521efba9b28779541440c797220ec98ac97Steve Howard values.getAsBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API) == Boolean.TRUE; 48571aab521efba9b28779541440c797220ec98ac97Steve Howard 4867dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION); 487ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (dest != null) { 4887dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 4891fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project != PackageManager.PERMISSION_GRANTED 4907dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru && dest != Downloads.Impl.DESTINATION_EXTERNAL 4916d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard && dest != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE 4926d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard && dest != Downloads.Impl.DESTINATION_FILE_URI) { 4931fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new SecurityException("unauthorized destination code"); 4941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 49571aab521efba9b28779541440c797220ec98ac97Steve Howard // for public API behavior, if an app has CACHE_NON_PURGEABLE permission, automatically 49671aab521efba9b28779541440c797220ec98ac97Steve Howard // switch to non-purgeable download 49771aab521efba9b28779541440c797220ec98ac97Steve Howard boolean hasNonPurgeablePermission = 49871aab521efba9b28779541440c797220ec98ac97Steve Howard getContext().checkCallingPermission( 49971aab521efba9b28779541440c797220ec98ac97Steve Howard Downloads.Impl.PERMISSION_CACHE_NON_PURGEABLE) 50071aab521efba9b28779541440c797220ec98ac97Steve Howard == PackageManager.PERMISSION_GRANTED; 50171aab521efba9b28779541440c797220ec98ac97Steve Howard if (isPublicApi && dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE 50271aab521efba9b28779541440c797220ec98ac97Steve Howard && hasNonPurgeablePermission) { 50371aab521efba9b28779541440c797220ec98ac97Steve Howard dest = Downloads.Impl.DESTINATION_CACHE_PARTITION; 50471aab521efba9b28779541440c797220ec98ac97Steve Howard } 5056d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (dest == Downloads.Impl.DESTINATION_FILE_URI) { 5066d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard getContext().enforcePermission( 5076d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 5086d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard Binder.getCallingPid(), Binder.getCallingUid(), 5096d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard "need WRITE_EXTERNAL_STORAGE permission to use DESTINATION_FILE_URI"); 510b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkFileUriDestination(values); 5116d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 5127dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest); 513ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } 5147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY); 515ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (vis == null) { 5167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (dest == Downloads.Impl.DESTINATION_EXTERNAL) { 5177dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 5187dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 519ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 5207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 5217dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_HIDDEN); 5221fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 523ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 5247dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis); 52557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 5267dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 5277dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING); 5286d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, 5296d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard mSystemFacade.currentTimeMillis()); 5300a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 5317dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); 5327dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS); 5330a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (pckg != null && (clazz != null || isPublicApi)) { 5341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project int uid = Binder.getCallingUid(); 5351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project try { 5360a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (uid == 0 || mSystemFacade.userOwnsPackage(uid, pckg)) { 5377dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg); 5380a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (clazz != null) { 5390a77c62a82503b38c484e0079648f0231dd85d53Steve Howard filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz); 5400a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 5411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 5421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } catch (PackageManager.NameNotFoundException ex) { 5431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /* ignored for now */ 54457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 54557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 5467dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues); 5477dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues); 5487dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues); 5497dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues); 5507dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 5511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project == PackageManager.PERMISSION_GRANTED) { 5527dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues); 55357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 5541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues.put(Constants.UID, Binder.getCallingUid()); 5551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingUid() == 0) { 5561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project copyInteger(Constants.UID, values, filteredValues); 55757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 558a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_TITLE, values, filteredValues, ""); 559a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues, ""); 560b5629da794cb3c1ca1970d206343743b165b9644Steve Howard filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1); 56173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard filteredValues.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0); 56257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 56371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard if (values.containsKey(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI)) { 56471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, values, filteredValues); 56571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } else { 56671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard // by default, make external downloads visible in the UI 56771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isExternal = (dest == null || dest == Downloads.Impl.DESTINATION_EXTERNAL); 56871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard filteredValues.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, isExternal); 56971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 57071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 5710a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (isPublicApi) { 5720a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyInteger(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, values, filteredValues); 5730a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyBoolean(Downloads.Impl.COLUMN_ALLOW_ROAMING, values, filteredValues); 5740a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 5750a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 5761fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Constants.LOGVV) { 5771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "initiating download with UID " 5781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project + filteredValues.getAsInteger(Constants.UID)); 5797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) { 5801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "other UID " + 5817dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID)); 5821fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 58357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 58457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 58557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Context context = getContext(); 58657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project context.startService(new Intent(context, DownloadService.class)); 58757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5881fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project long rowID = db.insert(DB_TABLE, null, filteredValues); 5893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (rowID == -1) { 5903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "couldn't insert into downloads database"); 5913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return null; 59257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 59357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard insertRequestHeaders(db, rowID, values); 5953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard context.startService(new Intent(context, DownloadService.class)); 5963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 5973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID); 59857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 59957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 60057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 601b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Check that the file URI provided for DESTINATION_FILE_URI is valid. 602b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 603b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkFileUriDestination(ContentValues values) { 604b06b739b078ce4b00600487cfec31659647bf31fSteve Howard String fileUri = values.getAsString(Downloads.Impl.COLUMN_FILE_NAME_HINT); 605b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (fileUri == null) { 606b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException( 607b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "DESTINATION_FILE_URI must include a file URI under COLUMN_FILE_NAME_HINT"); 608b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 609b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Uri uri = Uri.parse(fileUri); 6105d81e2447ed77860afecd71583e137178c2c6807Steve Howard String scheme = uri.getScheme(); 6115d81e2447ed77860afecd71583e137178c2c6807Steve Howard if (scheme == null || !scheme.equals("file")) { 612b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException("Not a file URI: " + uri); 613b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 614b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard String path = uri.getPath(); 615b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard if (path == null) { 616b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard throw new IllegalArgumentException("Invalid file URI: " + uri); 617b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard } 618b06b739b078ce4b00600487cfec31659647bf31fSteve Howard String externalPath = Environment.getExternalStorageDirectory().getAbsolutePath(); 619b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard if (!path.startsWith(externalPath)) { 620b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException("Destination must be on external storage: " + uri); 621b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 622b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 623b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 624b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 625b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Apps with the ACCESS_DOWNLOAD_MANAGER permission can access this provider freely, subject to 626b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * constraints in the rest of the code. Apps without that may still access this provider through 627b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * the public API, but additional restrictions are imposed. We check those restrictions here. 628b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * 629b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @param values ContentValues provided to insert() 630b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @throws SecurityException if the caller has insufficient permissions 631b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 632b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkInsertPermissions(ContentValues values) { 633b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS) 634b06b739b078ce4b00600487cfec31659647bf31fSteve Howard == PackageManager.PERMISSION_GRANTED) { 635b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 636b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 637b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 638b06b739b078ce4b00600487cfec31659647bf31fSteve Howard getContext().enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, 639b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "INTERNET permission is required to use the download manager"); 640b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 641b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // ensure the request fits within the bounds of a public API request 642b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // first copy so we can remove values 643b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values = new ContentValues(values); 644b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 645b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // check columns whose values are restricted 646b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_IS_PUBLIC_API, Boolean.TRUE); 647b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_DESTINATION, 648b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE, 649b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Downloads.Impl.DESTINATION_FILE_URI); 6509da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard 6519da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_NO_NOTIFICATION) 6529da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard == PackageManager.PERMISSION_GRANTED) { 6539da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 6549da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard Downloads.Impl.VISIBILITY_HIDDEN, Downloads.Impl.VISIBILITY_VISIBLE); 6559da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } else { 6569da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 6579da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard Downloads.Impl.VISIBILITY_VISIBLE); 6589da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } 659b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 660b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // remove the rest of the columns that are allowed (with any value) 661b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_URI); 662b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_TITLE); 663b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_DESCRIPTION); 664b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_MIME_TYPE); 665b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_FILE_NAME_HINT); // checked later in insert() 666b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); // checked later in insert() 667b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES); 668b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOW_ROAMING); 66971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.remove(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI); 6703002e1870d4ad76c260b4729a8d86212c8db3e78Vasu Nori values.remove(Downloads.Impl.COLUMN_MEDIA_SCANNED); 671e61798da80558450f580ed948d0d469bd6423d8eSteve Howard Iterator<Map.Entry<String, Object>> iterator = values.valueSet().iterator(); 672e61798da80558450f580ed948d0d469bd6423d8eSteve Howard while (iterator.hasNext()) { 673e61798da80558450f580ed948d0d469bd6423d8eSteve Howard String key = iterator.next().getKey(); 674e61798da80558450f580ed948d0d469bd6423d8eSteve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 675e61798da80558450f580ed948d0d469bd6423d8eSteve Howard iterator.remove(); 676e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 677e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 678b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 679b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // any extra columns are extraneous and disallowed 680b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (values.size() > 0) { 681b06b739b078ce4b00600487cfec31659647bf31fSteve Howard StringBuilder error = new StringBuilder("Invalid columns in request: "); 682b06b739b078ce4b00600487cfec31659647bf31fSteve Howard boolean first = true; 683b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 684b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (!first) { 685b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(", "); 686b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 687b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(entry.getKey()); 688b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 689b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException(error.toString()); 690b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 691b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 692b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 693b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 694b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Remove column from values, and throw a SecurityException if the value isn't within the 695b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * specified allowedValues. 696b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 697b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void enforceAllowedValues(ContentValues values, String column, 698b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object... allowedValues) { 699b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object value = values.get(column); 700b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(column); 701b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Object allowedValue : allowedValues) { 702b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value == null && allowedValue == null) { 703b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 704b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 705b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value != null && value.equals(allowedValue)) { 706b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 707b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 708b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 709b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException("Invalid value for " + column + ": " + value); 710b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 711b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 712b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 71357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Starts a database query 71457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 71557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 7161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public Cursor query(final Uri uri, String[] projection, 71757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String selection, final String[] selectionArgs, 71857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String sort) { 7191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 7201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(selection, sAppReadableColumnsSet); 7211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 72257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 72357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 72457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 7253d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == -1) { 7263d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (Constants.LOGV) { 7273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "querying unknown URI: " + uri); 72857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 7293d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new IllegalArgumentException("Unknown URI: " + uri); 7303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7313d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 7323d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == REQUEST_HEADERS_URI) { 7333d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection != null || selection != null || sort != null) { 7343d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new UnsupportedOperationException("Request header queries do not support " 7353d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + "projections, selections or sorting"); 73657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 7373d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return queryRequestHeaders(db, uri); 7383d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7393d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 740e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection fullSelection = getWhereClause(uri, selection, selectionArgs, match); 74157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (shouldRestrictVisibility()) { 7431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (projection == null) { 7441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project projection = sAppReadableColumnsArray; 7451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 74601d0182d86db003b2da5b831cb26820093888d9aVasu Nori // check the validity of the columns in projection 7471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < projection.length; ++i) { 74801d0182d86db003b2da5b831cb26820093888d9aVasu Nori if (!sAppReadableColumnsSet.contains(projection[i]) && 74901d0182d86db003b2da5b831cb26820093888d9aVasu Nori !downloadManagerColumnsList.contains(projection[i])) { 7501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new IllegalArgumentException( 7511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project "column " + projection[i] + " is not allowed in queries"); 7521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 7531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 7541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 75557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 75657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 75757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 7583d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseQueryInfo(projection, selection, selectionArgs, sort, db); 75957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 76057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 761e610c0502c00689411624c00c3f81497df93b202Steve Howard Cursor ret = db.query(DB_TABLE, projection, fullSelection.getSelection(), 762e610c0502c00689411624c00c3f81497df93b202Steve Howard fullSelection.getParameters(), null, null, sort); 76357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 76457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (ret != null) { 76557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project ret.setNotificationUri(getContext().getContentResolver(), uri); 76657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 76757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, 76857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project "created cursor " + ret + " on behalf of " + Binder.getCallingPid()); 76957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 77057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } else { 77157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 7721fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "query failed in downloads database"); 77357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 77457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 77557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 77657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return ret; 77757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 77857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseQueryInfo(String[] projection, final String selection, 7803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard final String[] selectionArgs, final String sort, SQLiteDatabase db) { 7813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard java.lang.StringBuilder sb = new java.lang.StringBuilder(); 7823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("starting query, database is "); 7833d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (db != null) { 7843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("not "); 7853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("null; "); 7873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection == null) { 7883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is null; "); 7893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (projection.length == 0) { 7903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is empty; "); 7913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 7923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < projection.length; ++i) { 7933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection["); 7943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 7953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 7963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(projection[i]); 7973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 7983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selection is "); 8013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selection); 8023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 8033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (selectionArgs == null) { 8043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is null; "); 8053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (selectionArgs.length == 0) { 8063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is empty; "); 8073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 8083d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < selectionArgs.length; ++i) { 8093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs["); 8103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 8113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 8123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selectionArgs[i]); 8133d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 8143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("sort is "); 8173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(sort); 8183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("."); 8193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, sb.toString()); 8203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 8225224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private String getDownloadIdFromUri(final Uri uri) { 8235224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return uri.getPathSegments().get(1); 8245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Insert request headers for a download into the DB. 8285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void insertRequestHeaders(SQLiteDatabase db, long downloadId, ContentValues values) { 8305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ContentValues rowValues = new ContentValues(); 8315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID, downloadId); 8325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 8335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String key = entry.getKey(); 8345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 8355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String headerLine = entry.getValue().toString(); 8365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (!headerLine.contains(":")) { 8375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalArgumentException("Invalid HTTP header line: " + headerLine); 8385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] parts = headerLine.split(":", 2); 8405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_HEADER, parts[0].trim()); 8415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_VALUE, parts[1].trim()); 8425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.insert(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, null, rowValues); 8435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Handle a query for the custom request headers registered for a download. 8495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private Cursor queryRequestHeaders(SQLiteDatabase db, Uri uri) { 8515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String where = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" 8525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + getDownloadIdFromUri(uri); 8535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl.RequestHeaders.COLUMN_HEADER, 8545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE}; 85553356ad554f53a093434161cb494b8e818c294fbSteve Howard return db.query(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, projection, where, 85653356ad554f53a093434161cb494b8e818c294fbSteve Howard null, null, null, null); 8575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Delete request headers for downloads matching the given query. 8615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void deleteRequestHeaders(SQLiteDatabase db, String where, String[] whereArgs) { 8635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl._ID}; 864b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Cursor cursor = db.query(DB_TABLE, projection, where, whereArgs, null, null, null, null); 8655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 8665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 8675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard long id = cursor.getLong(0); 8685224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String idWhere = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" + id; 8695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.delete(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, idWhere, null); 8705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } finally { 8725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard cursor.close(); 8735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @return true if we should restrict the columns readable by this caller 8785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private boolean shouldRestrictVisibility() { 8805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard int callingUid = Binder.getCallingUid(); 8815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return Binder.getCallingPid() != Process.myPid() && 8825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard callingUid != mSystemUid && 8835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard callingUid != mDefContainerUid && 8845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Process.supportsProcesses(); 8855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 88757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 88857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates a row in the database 88957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 89057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 89157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public int update(final Uri uri, final ContentValues values, 89257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String where, final String[] whereArgs) { 8931fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 8941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(where, sAppReadableColumnsSet); 8951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 89657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 89757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 89857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 8991fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project boolean startService = false; 9001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 901e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori if (values.containsKey(Downloads.Impl.COLUMN_DELETED)) { 902e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori if (values.getAsInteger(Downloads.Impl.COLUMN_DELETED) == 1) { 903e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori // some rows are to be 'deleted'. need to start DownloadService. 904e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori startService = true; 905e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori } 906e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori } 907e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 9081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues; 9091fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingPid() != Process.myPid()) { 9101fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = new ContentValues(); 9117dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 9127dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues); 9137dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL); 9141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 9157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i); 9161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project startService = true; 9171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 918e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 9197dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 9207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues); 921e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori copyString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, values, filteredValues); 9227dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues); 923e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori copyInteger(Downloads.Impl.COLUMN_DELETED, values, filteredValues); 9241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 9251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = values; 926a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins String filename = values.getAsString(Downloads.Impl._DATA); 927a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins if (filename != null) { 928a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins Cursor c = query(uri, new String[] 929a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins { Downloads.Impl.COLUMN_TITLE }, null, null, null); 9303398db8f3b195959faa2a7cf09918f364432ac28Steve Howard if (!c.moveToFirst() || c.getString(0).isEmpty()) { 9313398db8f3b195959faa2a7cf09918f364432ac28Steve Howard values.put(Downloads.Impl.COLUMN_TITLE, new File(filename).getName()); 932a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 933a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins c.close(); 934a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 93571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 93671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Integer status = values.getAsInteger(Downloads.Impl.COLUMN_STATUS); 93771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isRestart = status != null && status == Downloads.Impl.STATUS_PENDING; 938d319729622da1893e895f2e35f41d01ecdca3705Steve Howard boolean isUserBypassingSizeLimit = 939d319729622da1893e895f2e35f41d01ecdca3705Steve Howard values.containsKey(Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT); 940d319729622da1893e895f2e35f41d01ecdca3705Steve Howard if (isRestart || isUserBypassingSizeLimit) { 94171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard startService = true; 94271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 94357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9443d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 94557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 94657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 9473d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 9483d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 9493d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 9503d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 951e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection selection = getWhereClause(uri, where, whereArgs, match); 9521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (filteredValues.size() > 0) { 953e610c0502c00689411624c00c3f81497df93b202Steve Howard count = db.update(DB_TABLE, filteredValues, selection.getSelection(), 954e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.getParameters()); 9551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 9561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project count = 0; 9571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 95857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 9593d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9603d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 9613d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "updating unknown/invalid URI: " + uri); 96257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot update URI: " + uri); 96357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9643d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9653d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 9661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (startService) { 9671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Context context = getContext(); 9681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project context.startService(new Intent(context, DownloadService.class)); 9691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 97057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 97157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 97257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 9733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** 9743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * Notify of a change through both URIs (/my_downloads and /all_downloads) 9753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uri either URI for the changed download(s) 9763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uriMatch the match ID from {@link #sURIMatcher} 9773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard */ 9783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void notifyContentChanged(final Uri uri, int uriMatch) { 9793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Long downloadId = null; 9803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID) { 9813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard downloadId = Long.parseLong(getDownloadIdFromUri(uri)); 9823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9833d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (Uri uriToNotify : BASE_URIS) { 9843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (downloadId != null) { 9853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard uriToNotify = ContentUris.withAppendedId(uriToNotify, downloadId); 9863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard getContext().getContentResolver().notifyChange(uriToNotify, null); 9883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 991e610c0502c00689411624c00c3f81497df93b202Steve Howard private SqlSelection getWhereClause(final Uri uri, final String where, final String[] whereArgs, 992e610c0502c00689411624c00c3f81497df93b202Steve Howard int uriMatch) { 993e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection selection = new SqlSelection(); 994e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause(where, whereArgs); 9953ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID || 9963ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori uriMatch == PUBLIC_DOWNLOAD_ID) { 997e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause(Downloads.Impl._ID + " = ?", getDownloadIdFromUri(uri)); 998b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 9993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS || uriMatch == MY_DOWNLOADS_ID) { 1000e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause( 1001e610c0502c00689411624c00c3f81497df93b202Steve Howard Constants.UID + "= ? OR " + Downloads.Impl.COLUMN_OTHER_UID + "= ?", 1002e610c0502c00689411624c00c3f81497df93b202Steve Howard Binder.getCallingUid(), Binder.getCallingPid()); 1003b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 1004e610c0502c00689411624c00c3f81497df93b202Steve Howard return selection; 1005b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 1006b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 100757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 100857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Deletes a row in the database 100957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 101057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 101157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public int delete(final Uri uri, final String where, 101257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String[] whereArgs) { 10131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(where, sAppReadableColumnsSet); 10151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 101657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 101757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 101857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 101957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 10203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 10213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 10223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 10233d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 1024e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection selection = getWhereClause(uri, where, whereArgs, match); 1025e610c0502c00689411624c00c3f81497df93b202Steve Howard deleteRequestHeaders(db, selection.getSelection(), selection.getParameters()); 1026e610c0502c00689411624c00c3f81497df93b202Steve Howard count = db.delete(DB_TABLE, selection.getSelection(), selection.getParameters()); 102757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 10283d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10293d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 10303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "deleting unknown/invalid URI: " + uri); 103157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot delete URI: " + uri); 103257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10333d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 103457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 103557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 103671aab521efba9b28779541440c797220ec98ac97Steve Howard 103757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 103857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Remotely opens a file 103957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 104057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 10413d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 104257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 10433d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseOpenFileInfo(uri, mode); 104457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10463d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Cursor cursor = query(uri, new String[] {"_data"}, null, null, null); 10473d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String path; 10483d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard try { 10493d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int count = (cursor != null) ? cursor.getCount() : 0; 10503d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count != 1) { 10513d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // If there is not exactly one result, throw an appropriate exception. 10523d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count == 0) { 10533d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("No entry for " + uri); 10543d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10553d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("Multiple items at " + uri); 10561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10573d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10583d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.moveToFirst(); 10593d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard path = cursor.getString(0); 10603d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } finally { 10613d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor != null) { 10623d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 10631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (path == null) { 10671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("No filename found."); 10681fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!Helpers.isFilenameValid(path)) { 10701fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("Invalid filename."); 10711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10721fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!"r".equals(mode)) { 10731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("Bad mode for " + uri + ": " + mode); 10741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10761fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ParcelFileDescriptor ret = ParcelFileDescriptor.open(new File(path), 10771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 10781fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 107957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (ret == null) { 10801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Constants.LOGV) { 10811fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "couldn't open file"); 108257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("couldn't open file"); 108457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 108557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return ret; 108657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 108757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 10883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseOpenFileInfo(Uri uri, String mode) { 10893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode 10903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + ", uid: " + Binder.getCallingUid()); 10913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Cursor cursor = query(Downloads.Impl.CONTENT_URI, 10923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard new String[] { "_id" }, null, null, "_id"); 10933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 10943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "null cursor in openFile"); 10953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (!cursor.moveToFirst()) { 10973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "empty cursor in openFile"); 10983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard do { 11003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available"); 11013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } while(cursor.moveToNext()); 11023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 11043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor = query(uri, new String[] { "_data" }, null, null, null); 11063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 11073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "null cursor in openFile"); 11083d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 11093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (!cursor.moveToFirst()) { 11103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "empty cursor in openFile"); 11113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 11123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String filename = cursor.getString(0); 11133d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "filename in openFile: " + filename); 11143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (new java.io.File(filename).isFile()) { 11153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "file exists in openFile"); 11163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 11193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 11221fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyInteger(String key, ContentValues from, ContentValues to) { 11231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Integer i = from.getAsInteger(key); 11241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 11251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, i); 11261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyBoolean(String key, ContentValues from, ContentValues to) { 11301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Boolean b = from.getAsBoolean(key); 11311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (b != null) { 11321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, b); 11331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11361fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyString(String key, ContentValues from, ContentValues to) { 11371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project String s = from.getAsString(key); 11381fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (s != null) { 11391fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, s); 11401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1143a89321ea04ced76d06f60f5909be203cb654a830Steve Howard private static final void copyStringWithDefault(String key, ContentValues from, 1144a89321ea04ced76d06f60f5909be203cb654a830Steve Howard ContentValues to, String defaultValue) { 1145a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyString(key, from, to); 1146a89321ea04ced76d06f60f5909be203cb654a830Steve Howard if (!to.containsKey(key)) { 1147a89321ea04ced76d06f60f5909be203cb654a830Steve Howard to.put(key, defaultValue); 1148a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 1149a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 115057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project} 1151