DownloadProvider.java revision e1823c84698006aa26a8c5dcfa5c4034858dfbe3
157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/* 257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * 457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * you may not use this file except in compliance with the License. 657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * You may obtain a copy of the License at 757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * 857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * 1057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * See the License for the specific language governing permissions and 1457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * limitations under the License. 1557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 1657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 1757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpackage com.android.providers.downloads; 1857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 1957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentProvider; 203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howardimport android.content.ContentUris; 2157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentValues; 2257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Context; 2357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Intent; 2457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.UriMatcher; 2591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.ApplicationInfo; 2657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.pm.PackageManager; 2791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.PackageManager.NameNotFoundException; 281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CrossProcessCursor; 2957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.Cursor; 301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWindow; 311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport android.database.CursorWrapper; 32c6f5aad265cfc36a64cd2bdb5adf3cc9736bbd80Jean-Baptiste Queruimport android.database.SQLException; 3357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 3457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 3557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.net.Uri; 3657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Binder; 37b06b739b078ce4b00600487cfec31659647bf31fSteve Howardimport android.os.Environment; 3857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.ParcelFileDescriptor; 3957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Process; 4057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.provider.Downloads; 4157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.util.Log; 4257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport com.google.common.annotations.VisibleForTesting; 445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.io.File; 4657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport java.io.FileNotFoundException; 47e610c0502c00689411624c00c3f81497df93b202Steve Howardimport java.util.ArrayList; 481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.util.HashSet; 49e61798da80558450f580ed948d0d469bd6423d8eSteve Howardimport java.util.Iterator; 50e610c0502c00689411624c00c3f81497df93b202Steve Howardimport java.util.List; 515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport java.util.Map; 52e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Noriimport java.util.Set; 531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 5457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/** 5657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Allows application to interact with the download manager. 5757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 5857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpublic final class DownloadProvider extends ContentProvider { 5957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Database filename */ 6057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_NAME = "downloads.db"; 611fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /** Current database version */ 62e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori private static final int DB_VERSION = 106; 6357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Name of table in the database */ 6457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_TABLE = "downloads"; 6557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 6657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for the entire download list */ 6757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_LIST_TYPE = "vnd.android.cursor.dir/download"; 6857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for an individual download */ 6957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_TYPE = "vnd.android.cursor.item/download"; 7057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher used to recognize URIs sent by applications */ 7257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads belonging to the calling UID */ 743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS = 1; 753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of an individual download belonging to the calling UID */ 763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS_ID = 2; 773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads in the system */ 783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS = 3; 7957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher constant for the URI of an individual download */ 803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS_ID = 4; 815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** URI matcher constant for the URI of a download's request headers */ 823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int REQUEST_HEADERS_URI = 5; 8357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project static { 843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads", MY_DOWNLOADS); 853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads/#", MY_DOWNLOADS_ID); 863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads", ALL_DOWNLOADS); 873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads/#", ALL_DOWNLOADS_ID); 883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "my_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "all_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 944bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard // temporary, for backwards compatibility 954bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download", MY_DOWNLOADS); 964bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download/#", MY_DOWNLOADS_ID); 974bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", 984bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard "download/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 994bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard REQUEST_HEADERS_URI); 10057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 1023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** Different base URIs that could be used to access an individual download */ 1033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final Uri[] BASE_URIS = new Uri[] { 1043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.CONTENT_URI, 1053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 1063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard }; 1073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 1081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final String[] sAppReadableColumnsArray = new String[] { 1097dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._ID, 1107dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_APP_DATA, 1117dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._DATA, 1127dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_MIME_TYPE, 1137dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_VISIBILITY, 1147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_DESTINATION, 1157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CONTROL, 1167dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_STATUS, 1177dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_LAST_MODIFICATION, 1187dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, 1197dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_CLASS, 1207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TOTAL_BYTES, 1217dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CURRENT_BYTES, 1227dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TITLE, 1230a77c62a82503b38c484e0079648f0231dd85d53Steve Howard Downloads.Impl.COLUMN_DESCRIPTION, 1240d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard Downloads.Impl.COLUMN_URI, 12571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 126b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard Downloads.Impl.COLUMN_FILE_NAME_HINT, 127e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, 128e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori Downloads.Impl.COLUMN_DELETED, 1291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project }; 1301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static HashSet<String> sAppReadableColumnsSet; 1321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project static { 1331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet = new HashSet<String>(); 1341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < sAppReadableColumnsArray.length; ++i) { 1351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet.add(sAppReadableColumnsArray[i]); 1361fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 1371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 1381fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 13957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** The database that lies underneath this content provider */ 14057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private SQLiteOpenHelper mOpenHelper = null; 14157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 14291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu /** List of uids that can access the downloads */ 14391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mSystemUid = -1; 14491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mDefContainerUid = -1; 14591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu 1466d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard @VisibleForTesting 1476d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard SystemFacade mSystemFacade; 1486d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard 14957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 150e610c0502c00689411624c00c3f81497df93b202Steve Howard * This class encapsulates a SQL where clause and its parameters. It makes it possible for 151e610c0502c00689411624c00c3f81497df93b202Steve Howard * shared methods (like {@link DownloadProvider#getWhereClause(Uri, String, String[], int)}) 152e610c0502c00689411624c00c3f81497df93b202Steve Howard * to return both pieces of information, and provides some utility logic to ease piece-by-piece 153e610c0502c00689411624c00c3f81497df93b202Steve Howard * construction of selections. 154e610c0502c00689411624c00c3f81497df93b202Steve Howard */ 155e610c0502c00689411624c00c3f81497df93b202Steve Howard private static class SqlSelection { 156e610c0502c00689411624c00c3f81497df93b202Steve Howard public StringBuilder mWhereClause = new StringBuilder(); 157e610c0502c00689411624c00c3f81497df93b202Steve Howard public List<String> mParameters = new ArrayList<String>(); 158e610c0502c00689411624c00c3f81497df93b202Steve Howard 159e610c0502c00689411624c00c3f81497df93b202Steve Howard public <T> void appendClause(String newClause, final T... parameters) { 160e610c0502c00689411624c00c3f81497df93b202Steve Howard if (newClause == null || newClause.isEmpty()) { 161e610c0502c00689411624c00c3f81497df93b202Steve Howard return; 162e610c0502c00689411624c00c3f81497df93b202Steve Howard } 163e610c0502c00689411624c00c3f81497df93b202Steve Howard if (mWhereClause.length() != 0) { 164e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(" AND "); 165e610c0502c00689411624c00c3f81497df93b202Steve Howard } 166e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append("("); 167e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(newClause); 168e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(")"); 169e610c0502c00689411624c00c3f81497df93b202Steve Howard if (parameters != null) { 170e610c0502c00689411624c00c3f81497df93b202Steve Howard for (Object parameter : parameters) { 171e610c0502c00689411624c00c3f81497df93b202Steve Howard mParameters.add(parameter.toString()); 172e610c0502c00689411624c00c3f81497df93b202Steve Howard } 173e610c0502c00689411624c00c3f81497df93b202Steve Howard } 174e610c0502c00689411624c00c3f81497df93b202Steve Howard } 175e610c0502c00689411624c00c3f81497df93b202Steve Howard 176e610c0502c00689411624c00c3f81497df93b202Steve Howard public String getSelection() { 177e610c0502c00689411624c00c3f81497df93b202Steve Howard return mWhereClause.toString(); 178e610c0502c00689411624c00c3f81497df93b202Steve Howard } 179e610c0502c00689411624c00c3f81497df93b202Steve Howard 180e610c0502c00689411624c00c3f81497df93b202Steve Howard public String[] getParameters() { 181e610c0502c00689411624c00c3f81497df93b202Steve Howard String[] array = new String[mParameters.size()]; 182e610c0502c00689411624c00c3f81497df93b202Steve Howard return mParameters.toArray(array); 183e610c0502c00689411624c00c3f81497df93b202Steve Howard } 184e610c0502c00689411624c00c3f81497df93b202Steve Howard } 185e610c0502c00689411624c00c3f81497df93b202Steve Howard 186e610c0502c00689411624c00c3f81497df93b202Steve Howard /** 18757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates and updated database on demand when opening it. 18857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Helper class to create database the first time the provider is 18957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * initialized and upgrade it when a new version of the provider needs 19057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * an updated version of the database. 19157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 19257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private final class DatabaseHelper extends SQLiteOpenHelper { 19357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public DatabaseHelper(final Context context) { 19457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project super(context, DB_NAME, null, DB_VERSION); 19557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 19657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 19757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 19857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates database the first time we try to open it. 19957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 20057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 20157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public void onCreate(final SQLiteDatabase db) { 20257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 20357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, "populating new database"); 20457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 2055224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard onUpgrade(db, 0, DB_VERSION); 20657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 20757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 20857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 20957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates the database format when a content provider is used 21057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * with a database that was created with a different format. 2115224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * 2125224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Note: to support downgrades, creating a table should always drop it first if it already 2135224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * exists. 21457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 21557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 2161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public void onUpgrade(final SQLiteDatabase db, int oldV, final int newV) { 2175224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (oldV == 31) { 2185224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // 31 and 100 are identical, just in different codelines. Upgrading from 31 is the 2195224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // same as upgrading from 100. 2205224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 100; 2215224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV < 100) { 2225224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // no logic to upgrade from these older version, just recreate the DB 2235224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.i(Constants.TAG, "Upgrading downloads database from version " + oldV 2245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " to version " + newV + ", which will destroy all old data"); 2255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 2265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV > newV) { 2275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // user must have downgraded software; we have no way to know how to downgrade the 2285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // DB, so just recreate it 2295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.i(Constants.TAG, "Downgrading downloads database from version " + oldV 2305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " (current version is " + newV + "), destroying all old data"); 2315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 2325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (int version = oldV + 1; version <= newV; version++) { 2355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard upgradeTo(db, version); 2365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 2405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Upgrade database from (version - 1) to version. 2415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 2425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void upgradeTo(SQLiteDatabase db, int version) { 2435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard switch (version) { 2445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 100: 2455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createDownloadsTable(db); 2465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 101: 2495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createHeadersTable(db); 2505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2520a77c62a82503b38c484e0079648f0231dd85d53Steve Howard case 102: 2530a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_PUBLIC_API, 2540a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2550a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_ROAMING, 2560a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2570a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, 2580a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 2590a77c62a82503b38c484e0079648f0231dd85d53Steve Howard break; 2600a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 26171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard case 103: 26271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 26371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard "INTEGER NOT NULL DEFAULT 1"); 26471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard makeCacheDownloadsInvisible(db); 26571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard break; 26671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 267d319729622da1893e895f2e35f41d01ecdca3705Steve Howard case 104: 268d319729622da1893e895f2e35f41d01ecdca3705Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT, 269d319729622da1893e895f2e35f41d01ecdca3705Steve Howard "INTEGER NOT NULL DEFAULT 0"); 270d319729622da1893e895f2e35f41d01ecdca3705Steve Howard break; 271d319729622da1893e895f2e35f41d01ecdca3705Steve Howard 27273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard case 105: 27373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValues(db); 27473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard break; 27573f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 276e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori case 106: 277e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, "TEXT"); 278e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_DELETED, 279e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori "BOOLEAN NOT NULL DEFAULT 0"); 280e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori break; 281e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 2825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard default: 2835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalStateException("Don't know how to upgrade to " + version); 2845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2875224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 28873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard * insert() now ensures these four columns are never null for new downloads, so this method 28973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard * makes that true for existing columns, so that code can rely on this assumption. 29073f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard */ 29173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard private void fillNullValues(SQLiteDatabase db) { 29273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard ContentValues values = new ContentValues(); 29373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0); 29473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 29573f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1); 29673f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 29773f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_TITLE, ""); 29873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 29973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_DESCRIPTION, ""); 30073f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 30173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard } 30273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 30373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard private void fillNullValuesForColumn(SQLiteDatabase db, ContentValues values) { 30473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard String column = values.valueSet().iterator().next().getKey(); 30573f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard db.update(DB_TABLE, values, column + " is null", null); 30673f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.clear(); 30773f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard } 30873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 30973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard /** 31071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard * Set all existing downloads to the cache partition to be invisible in the downloads UI. 31171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard */ 31271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard private void makeCacheDownloadsInvisible(SQLiteDatabase db) { 31371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard ContentValues values = new ContentValues(); 31471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, false); 31571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard String cacheSelection = Downloads.Impl.COLUMN_DESTINATION 31671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard + " != " + Downloads.Impl.DESTINATION_EXTERNAL; 31771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard db.update(DB_TABLE, values, cacheSelection, null); 31871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 31971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 32071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard /** 3210a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * Add a column to a table using ALTER TABLE. 3220a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param dbTable name of the table 3230a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnName name of the column to add 3240a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnDefinition SQL for the column definition 3250a77c62a82503b38c484e0079648f0231dd85d53Steve Howard */ 3260a77c62a82503b38c484e0079648f0231dd85d53Steve Howard private void addColumn(SQLiteDatabase db, String dbTable, String columnName, 3270a77c62a82503b38c484e0079648f0231dd85d53Steve Howard String columnDefinition) { 3280a77c62a82503b38c484e0079648f0231dd85d53Steve Howard db.execSQL("ALTER TABLE " + dbTable + " ADD COLUMN " + columnName + " " 3290a77c62a82503b38c484e0079648f0231dd85d53Steve Howard + columnDefinition); 3300a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 3310a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 3320a77c62a82503b38c484e0079648f0231dd85d53Steve Howard /** 3335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Creates the table that'll hold the download information. 3345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 3355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createDownloadsTable(SQLiteDatabase db) { 3365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 3375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE); 3385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + DB_TABLE + "(" + 3395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 3405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_URI + " TEXT, " + 3415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " + 3425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_APP_DATA + " TEXT, " + 3435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " + 3445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " + 3455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.OTA_UPDATE + " BOOLEAN, " + 3465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._DATA + " TEXT, " + 3475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " + 3485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " + 3495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.NO_SYSTEM_FILES + " BOOLEAN, " + 3505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " + 3515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CONTROL + " INTEGER, " + 3525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_STATUS + " INTEGER, " + 3535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.FAILED_CONNECTIONS + " INTEGER, " + 3545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " + 3555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " + 3565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " + 3575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " + 3585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " + 3595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " + 3605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_REFERER + " TEXT, " + 3615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " + 3625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " + 3635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.ETAG + " TEXT, " + 3645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.UID + " INTEGER, " + 3655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " + 3665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TITLE + " TEXT, " + 3675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " + 368a53c21edb5dc57d97dcddd03fbfa2022abf43787Vasu Nori Constants.MEDIA_SCANNED + " BOOLEAN);"); 3695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } catch (SQLException ex) { 3705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Log.e(Constants.TAG, "couldn't create table in downloads database"); 3715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw ex; 3725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 3735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 3745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 3755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createHeadersTable(SQLiteDatabase db) { 3765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE); 3775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE + "(" + 3785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard "id INTEGER PRIMARY KEY AUTOINCREMENT," + 3795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + " INTEGER NOT NULL," + 3805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_HEADER + " TEXT NOT NULL," + 3815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE + " TEXT NOT NULL" + 3825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ");"); 38357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 38457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 38557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 38657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 38757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Initializes the content provider when it is created. 38857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 38957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 39057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public boolean onCreate() { 3916d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (mSystemFacade == null) { 392af28400b74de05862b470412a5c92f68e99f59f8Steve Howard mSystemFacade = new RealSystemFacade(getContext()); 3936d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 3946d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard 39557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project mOpenHelper = new DatabaseHelper(getContext()); 39691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the system uid 39791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mSystemUid = Process.SYSTEM_UID; 39891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the default container uid. Package name hardcoded 39991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // for now. 40091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu ApplicationInfo appInfo = null; 40191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu try { 40291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu appInfo = getContext().getPackageManager(). 40391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu getApplicationInfo("com.android.defcontainer", 0); 40491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } catch (NameNotFoundException e) { 40591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // TODO Auto-generated catch block 40691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu e.printStackTrace(); 40791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 40891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu if (appInfo != null) { 40991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mDefContainerUid = appInfo.uid; 41091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 41157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return true; 41257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 41357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 41457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 41557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Returns the content-provider-style MIME types of the various 41657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * types accessible through this content provider. 41757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 41857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 41957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public String getType(final Uri uri) { 42057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 42157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 4223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: { 42357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return DOWNLOAD_LIST_TYPE; 42457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 4253d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: { 42657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return DOWNLOAD_TYPE; 42757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 42857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project default: { 42957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 43057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, "calling getType on an unknown URI: " + uri); 43157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 43257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown URI: " + uri); 43357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 43457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 43557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 43657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 43757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 43857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Inserts a row in the database 43957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 44057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 44157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public Uri insert(final Uri uri, final ContentValues values) { 442b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkInsertPermissions(values); 44357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 44457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 4453d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // note we disallow inserting into ALL_DOWNLOADS 4463d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int match = sURIMatcher.match(uri); 4473d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match != MY_DOWNLOADS) { 4483d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: " + uri); 44957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown/Invalid URI " + uri); 45057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 45157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 4521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues = new ContentValues(); 4531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 4547dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_URI, values, filteredValues); 4557dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 4567dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues); 4577dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues); 4587dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues); 45971aab521efba9b28779541440c797220ec98ac97Steve Howard 46071aab521efba9b28779541440c797220ec98ac97Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API, values, filteredValues); 46171aab521efba9b28779541440c797220ec98ac97Steve Howard boolean isPublicApi = 46271aab521efba9b28779541440c797220ec98ac97Steve Howard values.getAsBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API) == Boolean.TRUE; 46371aab521efba9b28779541440c797220ec98ac97Steve Howard 4647dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION); 465ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (dest != null) { 4667dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 4671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project != PackageManager.PERMISSION_GRANTED 4687dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru && dest != Downloads.Impl.DESTINATION_EXTERNAL 4696d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard && dest != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE 4706d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard && dest != Downloads.Impl.DESTINATION_FILE_URI) { 4711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new SecurityException("unauthorized destination code"); 4721fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 47371aab521efba9b28779541440c797220ec98ac97Steve Howard // for public API behavior, if an app has CACHE_NON_PURGEABLE permission, automatically 47471aab521efba9b28779541440c797220ec98ac97Steve Howard // switch to non-purgeable download 47571aab521efba9b28779541440c797220ec98ac97Steve Howard boolean hasNonPurgeablePermission = 47671aab521efba9b28779541440c797220ec98ac97Steve Howard getContext().checkCallingPermission( 47771aab521efba9b28779541440c797220ec98ac97Steve Howard Downloads.Impl.PERMISSION_CACHE_NON_PURGEABLE) 47871aab521efba9b28779541440c797220ec98ac97Steve Howard == PackageManager.PERMISSION_GRANTED; 47971aab521efba9b28779541440c797220ec98ac97Steve Howard if (isPublicApi && dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE 48071aab521efba9b28779541440c797220ec98ac97Steve Howard && hasNonPurgeablePermission) { 48171aab521efba9b28779541440c797220ec98ac97Steve Howard dest = Downloads.Impl.DESTINATION_CACHE_PARTITION; 48271aab521efba9b28779541440c797220ec98ac97Steve Howard } 4836d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (dest == Downloads.Impl.DESTINATION_FILE_URI) { 4846d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard getContext().enforcePermission( 4856d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 4866d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard Binder.getCallingPid(), Binder.getCallingUid(), 4876d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard "need WRITE_EXTERNAL_STORAGE permission to use DESTINATION_FILE_URI"); 488b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkFileUriDestination(values); 4896d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 4907dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest); 491ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } 4927dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY); 493ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (vis == null) { 4947dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (dest == Downloads.Impl.DESTINATION_EXTERNAL) { 4957dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 4967dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 497ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 4987dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 4997dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_HIDDEN); 5001fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 501ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 5027dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis); 50357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 5047dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 5057dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING); 5066d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, 5076d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard mSystemFacade.currentTimeMillis()); 5080a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 5097dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); 5107dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS); 5110a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (pckg != null && (clazz != null || isPublicApi)) { 5121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project int uid = Binder.getCallingUid(); 5131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project try { 5140a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (uid == 0 || mSystemFacade.userOwnsPackage(uid, pckg)) { 5157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg); 5160a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (clazz != null) { 5170a77c62a82503b38c484e0079648f0231dd85d53Steve Howard filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz); 5180a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 5191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 5201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } catch (PackageManager.NameNotFoundException ex) { 5211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /* ignored for now */ 52257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 52357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 5247dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues); 5257dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues); 5267dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues); 5277dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues); 5287dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 5291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project == PackageManager.PERMISSION_GRANTED) { 5307dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues); 53157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 5321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues.put(Constants.UID, Binder.getCallingUid()); 5331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingUid() == 0) { 5341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project copyInteger(Constants.UID, values, filteredValues); 53557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 536a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_TITLE, values, filteredValues, ""); 537a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues, ""); 538b5629da794cb3c1ca1970d206343743b165b9644Steve Howard filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1); 53973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard filteredValues.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0); 54057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 54171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard if (values.containsKey(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI)) { 54271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, values, filteredValues); 54371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } else { 54471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard // by default, make external downloads visible in the UI 54571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isExternal = (dest == null || dest == Downloads.Impl.DESTINATION_EXTERNAL); 54671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard filteredValues.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, isExternal); 54771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 54871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 5490a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (isPublicApi) { 5500a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyInteger(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, values, filteredValues); 5510a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyBoolean(Downloads.Impl.COLUMN_ALLOW_ROAMING, values, filteredValues); 5520a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 5530a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 5541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Constants.LOGVV) { 5551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "initiating download with UID " 5561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project + filteredValues.getAsInteger(Constants.UID)); 5577dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) { 5581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "other UID " + 5597dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID)); 5601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 56157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 56257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 56357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Context context = getContext(); 56457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project context.startService(new Intent(context, DownloadService.class)); 56557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project long rowID = db.insert(DB_TABLE, null, filteredValues); 5673d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (rowID == -1) { 5683d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "couldn't insert into downloads database"); 5693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return null; 57057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 57157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard insertRequestHeaders(db, rowID, values); 5733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard context.startService(new Intent(context, DownloadService.class)); 5743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 5753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID); 57657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 57757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 57857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 579b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Check that the file URI provided for DESTINATION_FILE_URI is valid. 580b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 581b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkFileUriDestination(ContentValues values) { 582b06b739b078ce4b00600487cfec31659647bf31fSteve Howard String fileUri = values.getAsString(Downloads.Impl.COLUMN_FILE_NAME_HINT); 583b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (fileUri == null) { 584b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException( 585b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "DESTINATION_FILE_URI must include a file URI under COLUMN_FILE_NAME_HINT"); 586b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 587b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Uri uri = Uri.parse(fileUri); 5885d81e2447ed77860afecd71583e137178c2c6807Steve Howard String scheme = uri.getScheme(); 5895d81e2447ed77860afecd71583e137178c2c6807Steve Howard if (scheme == null || !scheme.equals("file")) { 590b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException("Not a file URI: " + uri); 591b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 592b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard String path = uri.getPath(); 593b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard if (path == null) { 594b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard throw new IllegalArgumentException("Invalid file URI: " + uri); 595b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard } 596b06b739b078ce4b00600487cfec31659647bf31fSteve Howard String externalPath = Environment.getExternalStorageDirectory().getAbsolutePath(); 597b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard if (!path.startsWith(externalPath)) { 598b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException("Destination must be on external storage: " + uri); 599b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 600b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 601b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 602b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 603b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Apps with the ACCESS_DOWNLOAD_MANAGER permission can access this provider freely, subject to 604b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * constraints in the rest of the code. Apps without that may still access this provider through 605b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * the public API, but additional restrictions are imposed. We check those restrictions here. 606b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * 607b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @param values ContentValues provided to insert() 608b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @throws SecurityException if the caller has insufficient permissions 609b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 610b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkInsertPermissions(ContentValues values) { 611b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS) 612b06b739b078ce4b00600487cfec31659647bf31fSteve Howard == PackageManager.PERMISSION_GRANTED) { 613b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 614b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 615b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 616b06b739b078ce4b00600487cfec31659647bf31fSteve Howard getContext().enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, 617b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "INTERNET permission is required to use the download manager"); 618b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 619b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // ensure the request fits within the bounds of a public API request 620b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // first copy so we can remove values 621b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values = new ContentValues(values); 622b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 623b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // check columns whose values are restricted 624b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_IS_PUBLIC_API, Boolean.TRUE); 625b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_DESTINATION, 626b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE, 627b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Downloads.Impl.DESTINATION_FILE_URI); 6289da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard 6299da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_NO_NOTIFICATION) 6309da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard == PackageManager.PERMISSION_GRANTED) { 6319da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 6329da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard Downloads.Impl.VISIBILITY_HIDDEN, Downloads.Impl.VISIBILITY_VISIBLE); 6339da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } else { 6349da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 6359da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard Downloads.Impl.VISIBILITY_VISIBLE); 6369da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } 637b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 638b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // remove the rest of the columns that are allowed (with any value) 639b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_URI); 640b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_TITLE); 641b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_DESCRIPTION); 642b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_MIME_TYPE); 643b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_FILE_NAME_HINT); // checked later in insert() 644b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); // checked later in insert() 645b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES); 646b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOW_ROAMING); 64771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.remove(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI); 648e61798da80558450f580ed948d0d469bd6423d8eSteve Howard Iterator<Map.Entry<String, Object>> iterator = values.valueSet().iterator(); 649e61798da80558450f580ed948d0d469bd6423d8eSteve Howard while (iterator.hasNext()) { 650e61798da80558450f580ed948d0d469bd6423d8eSteve Howard String key = iterator.next().getKey(); 651e61798da80558450f580ed948d0d469bd6423d8eSteve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 652e61798da80558450f580ed948d0d469bd6423d8eSteve Howard iterator.remove(); 653e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 654e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 655b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 656b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // any extra columns are extraneous and disallowed 657b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (values.size() > 0) { 658b06b739b078ce4b00600487cfec31659647bf31fSteve Howard StringBuilder error = new StringBuilder("Invalid columns in request: "); 659b06b739b078ce4b00600487cfec31659647bf31fSteve Howard boolean first = true; 660b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 661b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (!first) { 662b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(", "); 663b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 664b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(entry.getKey()); 665b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 666b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException(error.toString()); 667b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 668b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 669b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 670b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 671b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Remove column from values, and throw a SecurityException if the value isn't within the 672b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * specified allowedValues. 673b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 674b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void enforceAllowedValues(ContentValues values, String column, 675b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object... allowedValues) { 676b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object value = values.get(column); 677b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(column); 678b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Object allowedValue : allowedValues) { 679b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value == null && allowedValue == null) { 680b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 681b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 682b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value != null && value.equals(allowedValue)) { 683b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 684b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 685b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 686b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException("Invalid value for " + column + ": " + value); 687b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 688b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 689b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 69057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Starts a database query 69157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 69257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 6931fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public Cursor query(final Uri uri, String[] projection, 69457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String selection, final String[] selectionArgs, 69557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String sort) { 6961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 6971fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(selection, sAppReadableColumnsSet); 6981fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 69957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 70057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 70157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 7023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == -1) { 7033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (Constants.LOGV) { 7043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "querying unknown URI: " + uri); 70557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 7063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new IllegalArgumentException("Unknown URI: " + uri); 7073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7083d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 7093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == REQUEST_HEADERS_URI) { 7103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection != null || selection != null || sort != null) { 7113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new UnsupportedOperationException("Request header queries do not support " 7123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + "projections, selections or sorting"); 71357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 7143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return queryRequestHeaders(db, uri); 7153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 717e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection fullSelection = getWhereClause(uri, selection, selectionArgs, match); 71857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7195224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (shouldRestrictVisibility()) { 7201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (projection == null) { 7211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project projection = sAppReadableColumnsArray; 7221fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 7231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < projection.length; ++i) { 7241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!sAppReadableColumnsSet.contains(projection[i])) { 7251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new IllegalArgumentException( 7261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project "column " + projection[i] + " is not allowed in queries"); 7271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 7281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 7291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 73057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 73157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 73257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 7333d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseQueryInfo(projection, selection, selectionArgs, sort, db); 73457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 73557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 736e610c0502c00689411624c00c3f81497df93b202Steve Howard Cursor ret = db.query(DB_TABLE, projection, fullSelection.getSelection(), 737e610c0502c00689411624c00c3f81497df93b202Steve Howard fullSelection.getParameters(), null, null, sort); 73857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 73957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (ret != null) { 7401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ret = new ReadOnlyCursorWrapper(ret); 7411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 7421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 7431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (ret != null) { 74457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project ret.setNotificationUri(getContext().getContentResolver(), uri); 74557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 74657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project Log.v(Constants.TAG, 74757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project "created cursor " + ret + " on behalf of " + Binder.getCallingPid()); 74857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 74957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } else { 75057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 7511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "query failed in downloads database"); 75257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 75357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 75457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 75557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return ret; 75657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 75757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7583d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseQueryInfo(String[] projection, final String selection, 7593d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard final String[] selectionArgs, final String sort, SQLiteDatabase db) { 7603d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard java.lang.StringBuilder sb = new java.lang.StringBuilder(); 7613d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("starting query, database is "); 7623d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (db != null) { 7633d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("not "); 7643d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7653d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("null; "); 7663d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection == null) { 7673d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is null; "); 7683d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (projection.length == 0) { 7693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is empty; "); 7703d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 7713d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < projection.length; ++i) { 7723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection["); 7733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 7743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 7753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(projection[i]); 7763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 7773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selection is "); 7803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selection); 7813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 7823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (selectionArgs == null) { 7833d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is null; "); 7843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (selectionArgs.length == 0) { 7853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is empty; "); 7863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 7873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < selectionArgs.length; ++i) { 7883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs["); 7893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 7903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 7913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selectionArgs[i]); 7923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 7933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 7953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("sort is "); 7963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(sort); 7973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("."); 7983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, sb.toString()); 7993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 8003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 8015224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private String getDownloadIdFromUri(final Uri uri) { 8025224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return uri.getPathSegments().get(1); 8035224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8045224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8055224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8065224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Insert request headers for a download into the DB. 8075224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8085224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void insertRequestHeaders(SQLiteDatabase db, long downloadId, ContentValues values) { 8095224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ContentValues rowValues = new ContentValues(); 8105224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID, downloadId); 8115224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 8125224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String key = entry.getKey(); 8135224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 8145224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String headerLine = entry.getValue().toString(); 8155224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (!headerLine.contains(":")) { 8165224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalArgumentException("Invalid HTTP header line: " + headerLine); 8175224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8185224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] parts = headerLine.split(":", 2); 8195224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_HEADER, parts[0].trim()); 8205224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_VALUE, parts[1].trim()); 8215224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.insert(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, null, rowValues); 8225224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8235224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Handle a query for the custom request headers registered for a download. 8285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private Cursor queryRequestHeaders(SQLiteDatabase db, Uri uri) { 8305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String where = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" 8315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + getDownloadIdFromUri(uri); 8325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl.RequestHeaders.COLUMN_HEADER, 8335224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE}; 8345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Cursor cursor = db.query(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, projection, where, 8355224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard null, null, null, null); 8365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return new ReadOnlyCursorWrapper(cursor); 8375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Delete request headers for downloads matching the given query. 8415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void deleteRequestHeaders(SQLiteDatabase db, String where, String[] whereArgs) { 8435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl._ID}; 844b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Cursor cursor = db.query(DB_TABLE, projection, where, whereArgs, null, null, null, null); 8455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 8465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 8475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard long id = cursor.getLong(0); 8485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String idWhere = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" + id; 8495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.delete(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, idWhere, null); 8505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } finally { 8525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard cursor.close(); 8535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 8565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 8573d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @return true if we should restrict the columns readable by this caller 8585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 8595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private boolean shouldRestrictVisibility() { 8605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard int callingUid = Binder.getCallingUid(); 8615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return Binder.getCallingPid() != Process.myPid() && 8625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard callingUid != mSystemUid && 8635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard callingUid != mDefContainerUid && 8645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Process.supportsProcesses(); 8655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 8665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 86757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 86857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates a row in the database 86957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 87057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 87157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public int update(final Uri uri, final ContentValues values, 87257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String where, final String[] whereArgs) { 8731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 8741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(where, sAppReadableColumnsSet); 8751fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 87657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 87757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 87857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 8791fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project boolean startService = false; 8801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 881e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori if (values.containsKey(Downloads.Impl.COLUMN_DELETED)) { 882e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori if (values.getAsInteger(Downloads.Impl.COLUMN_DELETED) == 1) { 883e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori // some rows are to be 'deleted'. need to start DownloadService. 884e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori startService = true; 885e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori } 886e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori } 887e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 8881fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues; 8891fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingPid() != Process.myPid()) { 8901fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = new ContentValues(); 8917dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 8927dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues); 8937dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL); 8941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 8957dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i); 8961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project startService = true; 8971fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 898e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 8997dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 9007dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues); 901e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori copyString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, values, filteredValues); 9027dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues); 903e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori copyInteger(Downloads.Impl.COLUMN_DELETED, values, filteredValues); 9041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 9051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = values; 906a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins String filename = values.getAsString(Downloads.Impl._DATA); 907a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins if (filename != null) { 908a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins Cursor c = query(uri, new String[] 909a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins { Downloads.Impl.COLUMN_TITLE }, null, null, null); 9103398db8f3b195959faa2a7cf09918f364432ac28Steve Howard if (!c.moveToFirst() || c.getString(0).isEmpty()) { 9113398db8f3b195959faa2a7cf09918f364432ac28Steve Howard values.put(Downloads.Impl.COLUMN_TITLE, new File(filename).getName()); 912a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 913a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins c.close(); 914a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 91571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 91671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Integer status = values.getAsInteger(Downloads.Impl.COLUMN_STATUS); 91771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isRestart = status != null && status == Downloads.Impl.STATUS_PENDING; 918d319729622da1893e895f2e35f41d01ecdca3705Steve Howard boolean isUserBypassingSizeLimit = 919d319729622da1893e895f2e35f41d01ecdca3705Steve Howard values.containsKey(Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT); 920d319729622da1893e895f2e35f41d01ecdca3705Steve Howard if (isRestart || isUserBypassingSizeLimit) { 92171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard startService = true; 92271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 92357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9243d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 92557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 92657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 9273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 9283d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 9293d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 9303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 931e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection selection = getWhereClause(uri, where, whereArgs, match); 9321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (filteredValues.size() > 0) { 933e610c0502c00689411624c00c3f81497df93b202Steve Howard count = db.update(DB_TABLE, filteredValues, selection.getSelection(), 934e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.getParameters()); 9351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 9361fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project count = 0; 9371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 93857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 9393d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9403d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 9413d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "updating unknown/invalid URI: " + uri); 94257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot update URI: " + uri); 94357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9443d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9453d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 9461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (startService) { 9471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Context context = getContext(); 9481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project context.startService(new Intent(context, DownloadService.class)); 9491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 95057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 95157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 95257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 9533d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** 9543d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * Notify of a change through both URIs (/my_downloads and /all_downloads) 9553d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uri either URI for the changed download(s) 9563d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uriMatch the match ID from {@link #sURIMatcher} 9573d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard */ 9583d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void notifyContentChanged(final Uri uri, int uriMatch) { 9593d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Long downloadId = null; 9603d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID) { 9613d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard downloadId = Long.parseLong(getDownloadIdFromUri(uri)); 9623d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9633d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (Uri uriToNotify : BASE_URIS) { 9643d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (downloadId != null) { 9653d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard uriToNotify = ContentUris.withAppendedId(uriToNotify, downloadId); 9663d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9673d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard getContext().getContentResolver().notifyChange(uriToNotify, null); 9683d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9703d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 971e610c0502c00689411624c00c3f81497df93b202Steve Howard private SqlSelection getWhereClause(final Uri uri, final String where, final String[] whereArgs, 972e610c0502c00689411624c00c3f81497df93b202Steve Howard int uriMatch) { 973e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection selection = new SqlSelection(); 974e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause(where, whereArgs); 9753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID) { 976e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause(Downloads.Impl._ID + " = ?", getDownloadIdFromUri(uri)); 977b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 978e1823c84698006aa26a8c5dcfa5c4034858dfbe3Kenny Root if ((uriMatch == MY_DOWNLOADS || uriMatch == MY_DOWNLOADS_ID) 979e1823c84698006aa26a8c5dcfa5c4034858dfbe3Kenny Root && getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ALL) 980e1823c84698006aa26a8c5dcfa5c4034858dfbe3Kenny Root != PackageManager.PERMISSION_GRANTED) { 981e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause( 982e610c0502c00689411624c00c3f81497df93b202Steve Howard Constants.UID + "= ? OR " + Downloads.Impl.COLUMN_OTHER_UID + "= ?", 983e610c0502c00689411624c00c3f81497df93b202Steve Howard Binder.getCallingUid(), Binder.getCallingPid()); 984b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 985e610c0502c00689411624c00c3f81497df93b202Steve Howard return selection; 986b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 987b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 98857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 98957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Deletes a row in the database 99057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 99157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 99257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public int delete(final Uri uri, final String where, 99357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String[] whereArgs) { 9941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 9951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Helpers.validateSelection(where, sAppReadableColumnsSet); 9961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 99757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 99857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 99957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 100057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 10013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 10023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 10033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 10043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 1005e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection selection = getWhereClause(uri, where, whereArgs, match); 1006e610c0502c00689411624c00c3f81497df93b202Steve Howard deleteRequestHeaders(db, selection.getSelection(), selection.getParameters()); 1007e610c0502c00689411624c00c3f81497df93b202Steve Howard count = db.delete(DB_TABLE, selection.getSelection(), selection.getParameters()); 100857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 10093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 10113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.d(Constants.TAG, "deleting unknown/invalid URI: " + uri); 101257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot delete URI: " + uri); 101357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 101557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 101657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 101771aab521efba9b28779541440c797220ec98ac97Steve Howard 101857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 101957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Remotely opens a file 102057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 102157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 10223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 102357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 10243d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseOpenFileInfo(uri, mode); 102557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Cursor cursor = query(uri, new String[] {"_data"}, null, null, null); 10283d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String path; 10293d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard try { 10303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int count = (cursor != null) ? cursor.getCount() : 0; 10313d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count != 1) { 10323d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // If there is not exactly one result, throw an appropriate exception. 10333d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count == 0) { 10343d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("No entry for " + uri); 10353d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10363d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("Multiple items at " + uri); 10371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10383d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10393d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.moveToFirst(); 10403d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard path = cursor.getString(0); 10413d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } finally { 10423d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor != null) { 10433d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 10441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 10471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (path == null) { 10481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("No filename found."); 10491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!Helpers.isFilenameValid(path)) { 10511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("Invalid filename."); 10521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (!"r".equals(mode)) { 10541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("Bad mode for " + uri + ": " + mode); 10551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 10563d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ParcelFileDescriptor ret = ParcelFileDescriptor.open(new File(path), 10581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 10591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 106057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (ret == null) { 10611fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Constants.LOGV) { 10621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Log.v(Constants.TAG, "couldn't open file"); 106357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 10641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("couldn't open file"); 106557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 106657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return ret; 106757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 106857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 10693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseOpenFileInfo(Uri uri, String mode) { 10703d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode 10713d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + ", uid: " + Binder.getCallingUid()); 10723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Cursor cursor = query(Downloads.Impl.CONTENT_URI, 10733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard new String[] { "_id" }, null, null, "_id"); 10743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 10753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "null cursor in openFile"); 10763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (!cursor.moveToFirst()) { 10783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "empty cursor in openFile"); 10793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10803d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard do { 10813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available"); 10823d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } while(cursor.moveToNext()); 10833d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10843d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 10853d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10863d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor = query(uri, new String[] { "_data" }, null, null, null); 10873d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 10883d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "null cursor in openFile"); 10893d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (!cursor.moveToFirst()) { 10913d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "empty cursor in openFile"); 10923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard String filename = cursor.getString(0); 10943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "filename in openFile: " + filename); 10953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (new java.io.File(filename).isFile()) { 10963d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Log.v(Constants.TAG, "file exists in openFile"); 10973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor.close(); 11003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 11023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 11031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyInteger(String key, ContentValues from, ContentValues to) { 11041fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Integer i = from.getAsInteger(key); 11051fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 11061fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, i); 11071fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11081fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11091fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11101fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyBoolean(String key, ContentValues from, ContentValues to) { 11111fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Boolean b = from.getAsBoolean(key); 11121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (b != null) { 11131fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, b); 11141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyString(String key, ContentValues from, ContentValues to) { 11181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project String s = from.getAsString(key); 11191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (s != null) { 11201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, s); 11211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11221fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1124a89321ea04ced76d06f60f5909be203cb654a830Steve Howard private static final void copyStringWithDefault(String key, ContentValues from, 1125a89321ea04ced76d06f60f5909be203cb654a830Steve Howard ContentValues to, String defaultValue) { 1126a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyString(key, from, to); 1127a89321ea04ced76d06f60f5909be203cb654a830Steve Howard if (!to.containsKey(key)) { 1128a89321ea04ced76d06f60f5909be203cb654a830Steve Howard to.put(key, defaultValue); 1129a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 1130a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 1131a89321ea04ced76d06f60f5909be203cb654a830Steve Howard 11321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private class ReadOnlyCursorWrapper extends CursorWrapper implements CrossProcessCursor { 11331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public ReadOnlyCursorWrapper(Cursor cursor) { 11341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project super(cursor); 11351fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project mCursor = (CrossProcessCursor) cursor; 11361fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11381fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public boolean deleteRow() { 11391fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new SecurityException("Download manager cursors are read-only"); 11401fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11421fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public boolean commitUpdates() { 11431fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new SecurityException("Download manager cursors are read-only"); 11441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public void fillWindow(int pos, CursorWindow window) { 11471fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project mCursor.fillWindow(pos, window); 11481fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11491fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11501fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public CursorWindow getWindow() { 11511fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project return mCursor.getWindow(); 11521fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11531fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11541fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public boolean onMove(int oldPosition, int newPosition) { 11551fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project return mCursor.onMove(oldPosition, newPosition); 11561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11571fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 11581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private CrossProcessCursor mCursor; 11591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 11601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 116157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project} 1162