blob: 26ad992ea2d8844f77374380faf15efdb9122f2b [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.providers.downloads;
import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.provider.Downloads;
import android.util.Log;
import com.google.common.annotations.VisibleForTesting;
import java.io.File;
/**
* Receives system broadcasts (boot, network connectivity)
*/
public class DownloadReceiver extends BroadcastReceiver {
@VisibleForTesting
SystemFacade mSystemFacade = null;
@Override
public void onReceive(Context context, Intent intent) {
if (mSystemFacade == null) {
mSystemFacade = new RealSystemFacade(context);
}
String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "Received broadcast intent for " +
Intent.ACTION_BOOT_COMPLETED);
}
startService(context);
} else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "Received broadcast intent for " +
Intent.ACTION_MEDIA_MOUNTED);
}
startService(context);
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
final ConnectivityManager connManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo info = connManager.getActiveNetworkInfo();
if (info != null && info.isConnected()) {
startService(context);
}
} else if (action.equals(Constants.ACTION_RETRY)) {
startService(context);
} else if (action.equals(Constants.ACTION_OPEN)
|| action.equals(Constants.ACTION_LIST)
|| action.equals(Constants.ACTION_HIDE)) {
handleNotificationBroadcast(context, intent);
}
}
/**
* Handle any broadcast related to a system notification.
*/
private void handleNotificationBroadcast(Context context, Intent intent) {
Uri uri = intent.getData();
String action = intent.getAction();
if (Constants.LOGVV) {
if (action.equals(Constants.ACTION_OPEN)) {
Log.v(Constants.TAG, "Receiver open for " + uri);
} else if (action.equals(Constants.ACTION_LIST)) {
Log.v(Constants.TAG, "Receiver list for " + uri);
} else { // ACTION_HIDE
Log.v(Constants.TAG, "Receiver hide for " + uri);
}
}
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor == null) {
return;
}
try {
if (!cursor.moveToFirst()) {
return;
}
if (action.equals(Constants.ACTION_OPEN)) {
openDownload(context, cursor);
hideNotification(context, uri, cursor);
} else if (action.equals(Constants.ACTION_LIST)) {
sendNotificationClickedIntent(intent, cursor);
} else { // ACTION_HIDE
hideNotification(context, uri, cursor);
}
} finally {
cursor.close();
}
}
/**
* Hide a system notification for a download.
* @param uri URI to update the download
* @param cursor Cursor for reading the download's fields
*/
private void hideNotification(Context context, Uri uri, Cursor cursor) {
mSystemFacade.cancelNotification(ContentUris.parseId(uri));
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS);
int status = cursor.getInt(statusColumn);
int visibilityColumn =
cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_VISIBILITY);
int visibility = cursor.getInt(visibilityColumn);
if (Downloads.Impl.isStatusCompleted(status)
&& visibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
ContentValues values = new ContentValues();
values.put(Downloads.Impl.COLUMN_VISIBILITY,
Downloads.Impl.VISIBILITY_VISIBLE);
context.getContentResolver().update(uri, values, null, null);
}
}
/**
* Open the download that cursor is currently pointing to, since it's completed notification
* has been clicked.
*/
private void openDownload(Context context, Cursor cursor) {
String filename = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl._DATA));
String mimetype =
cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_MIME_TYPE));
Uri path = Uri.parse(filename);
// If there is no scheme, then it must be a file
if (path.getScheme() == null) {
path = Uri.fromFile(new File(filename));
}
Intent activityIntent = new Intent(Intent.ACTION_VIEW);
mimetype = DownloadDrmHelper.getOriginalMimeType(context, filename, mimetype);
activityIntent.setDataAndType(path, mimetype);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(activityIntent);
} catch (ActivityNotFoundException ex) {
Log.d(Constants.TAG, "no activity for " + mimetype, ex);
}
}
/**
* Notify the owner of a running download that its notification was clicked.
* @param intent the broadcast intent sent by the notification manager
* @param cursor Cursor for reading the download's fields
*/
private void sendNotificationClickedIntent(Intent intent, Cursor cursor) {
String pckg = cursor.getString(
cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE));
if (pckg == null) {
return;
}
String clazz = cursor.getString(
cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_NOTIFICATION_CLASS));
boolean isPublicApi =
cursor.getInt(cursor.getColumnIndex(Downloads.Impl.COLUMN_IS_PUBLIC_API)) != 0;
Intent appIntent = null;
if (isPublicApi) {
appIntent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED);
appIntent.setPackage(pckg);
// send id of the items clicked on.
if (intent.getBooleanExtra("multiple", false)) {
// broadcast received saying click occurred on a notification with multiple titles.
// don't include any ids at all - let the caller query all downloads belonging to it
// TODO modify the broadcast to include ids of those multiple notifications.
} else {
appIntent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS,
new long[] {
cursor.getLong(cursor.getColumnIndexOrThrow(Downloads.Impl._ID))});
}
} else { // legacy behavior
if (clazz == null) {
return;
}
appIntent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED);
appIntent.setClassName(pckg, clazz);
if (intent.getBooleanExtra("multiple", true)) {
appIntent.setData(Downloads.Impl.CONTENT_URI);
} else {
long downloadId = cursor.getLong(cursor.getColumnIndexOrThrow(Downloads.Impl._ID));
appIntent.setData(
ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, downloadId));
}
}
mSystemFacade.sendBroadcast(appIntent);
}
private void startService(Context context) {
context.startService(new Intent(context, DownloadService.class));
}
}