Move notification tests to LittleMock.
[android/platform/packages/providers/DownloadProvider.git] / src / com / android / providers / downloads / DownloadReceiver.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.providers.downloads;
18
19 import android.app.DownloadManager;
20 import android.app.NotificationManager;
21 import android.content.ActivityNotFoundException;
22 import android.content.BroadcastReceiver;
23 import android.content.ContentUris;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.database.Cursor;
28 import android.net.ConnectivityManager;
29 import android.net.NetworkInfo;
30 import android.net.Uri;
31 import android.provider.Downloads;
32 import android.util.Log;
33
34 import com.google.common.annotations.VisibleForTesting;
35
36 import java.io.File;
37
38 /**
39  * Receives system broadcasts (boot, network connectivity)
40  */
41 public class DownloadReceiver extends BroadcastReceiver {
42     @VisibleForTesting
43     SystemFacade mSystemFacade = null;
44
45     @Override
46     public void onReceive(Context context, Intent intent) {
47         if (mSystemFacade == null) {
48             mSystemFacade = new RealSystemFacade(context);
49         }
50
51         String action = intent.getAction();
52         if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
53             if (Constants.LOGVV) {
54                 Log.v(Constants.TAG, "Received broadcast intent for " +
55                         Intent.ACTION_BOOT_COMPLETED);
56             }
57             startService(context);
58         } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
59             if (Constants.LOGVV) {
60                 Log.v(Constants.TAG, "Received broadcast intent for " +
61                         Intent.ACTION_MEDIA_MOUNTED);
62             }
63             startService(context);
64         } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
65             final ConnectivityManager connManager = (ConnectivityManager) context
66                     .getSystemService(Context.CONNECTIVITY_SERVICE);
67             final NetworkInfo info = connManager.getActiveNetworkInfo();
68             if (info != null && info.isConnected()) {
69                 startService(context);
70             }
71         } else if (action.equals(Constants.ACTION_RETRY)) {
72             startService(context);
73         } else if (action.equals(Constants.ACTION_OPEN)
74                 || action.equals(Constants.ACTION_LIST)
75                 || action.equals(Constants.ACTION_HIDE)) {
76             handleNotificationBroadcast(context, intent);
77         }
78     }
79
80     /**
81      * Handle any broadcast related to a system notification.
82      */
83     private void handleNotificationBroadcast(Context context, Intent intent) {
84         Uri uri = intent.getData();
85         String action = intent.getAction();
86         if (Constants.LOGVV) {
87             if (action.equals(Constants.ACTION_OPEN)) {
88                 Log.v(Constants.TAG, "Receiver open for " + uri);
89             } else if (action.equals(Constants.ACTION_LIST)) {
90                 Log.v(Constants.TAG, "Receiver list for " + uri);
91             } else { // ACTION_HIDE
92                 Log.v(Constants.TAG, "Receiver hide for " + uri);
93             }
94         }
95
96         Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
97         if (cursor == null) {
98             return;
99         }
100         try {
101             if (!cursor.moveToFirst()) {
102                 return;
103             }
104
105             if (action.equals(Constants.ACTION_OPEN)) {
106                 openDownload(context, cursor);
107                 hideNotification(context, uri, cursor);
108             } else if (action.equals(Constants.ACTION_LIST)) {
109                 sendNotificationClickedIntent(intent, cursor);
110             } else { // ACTION_HIDE
111                 hideNotification(context, uri, cursor);
112             }
113         } finally {
114             cursor.close();
115         }
116     }
117
118     /**
119      * Hide a system notification for a download.
120      * @param uri URI to update the download
121      * @param cursor Cursor for reading the download's fields
122      */
123     private void hideNotification(Context context, Uri uri, Cursor cursor) {
124         final NotificationManager notifManager = (NotificationManager) context.getSystemService(
125                 Context.NOTIFICATION_SERVICE);
126         notifManager.cancel((int) ContentUris.parseId(uri));
127
128         int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS);
129         int status = cursor.getInt(statusColumn);
130         int visibilityColumn =
131                 cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_VISIBILITY);
132         int visibility = cursor.getInt(visibilityColumn);
133         if (Downloads.Impl.isStatusCompleted(status)
134                 && visibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
135             ContentValues values = new ContentValues();
136             values.put(Downloads.Impl.COLUMN_VISIBILITY,
137                     Downloads.Impl.VISIBILITY_VISIBLE);
138             context.getContentResolver().update(uri, values, null, null);
139         }
140     }
141
142     /**
143      * Open the download that cursor is currently pointing to, since it's completed notification
144      * has been clicked.
145      */
146     private void openDownload(Context context, Cursor cursor) {
147         String filename = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl._DATA));
148         String mimetype =
149             cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_MIME_TYPE));
150         Uri path = Uri.parse(filename);
151         // If there is no scheme, then it must be a file
152         if (path.getScheme() == null) {
153             path = Uri.fromFile(new File(filename));
154         }
155
156         Intent activityIntent = new Intent(Intent.ACTION_VIEW);
157         mimetype = DownloadDrmHelper.getOriginalMimeType(context, filename, mimetype);
158         activityIntent.setDataAndType(path, mimetype);
159         activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
160         try {
161             context.startActivity(activityIntent);
162         } catch (ActivityNotFoundException ex) {
163             Log.d(Constants.TAG, "no activity for " + mimetype, ex);
164         }
165     }
166
167     /**
168      * Notify the owner of a running download that its notification was clicked.
169      * @param intent the broadcast intent sent by the notification manager
170      * @param cursor Cursor for reading the download's fields
171      */
172     private void sendNotificationClickedIntent(Intent intent, Cursor cursor) {
173         String pckg = cursor.getString(
174                 cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE));
175         if (pckg == null) {
176             return;
177         }
178
179         String clazz = cursor.getString(
180                 cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_NOTIFICATION_CLASS));
181         boolean isPublicApi =
182                 cursor.getInt(cursor.getColumnIndex(Downloads.Impl.COLUMN_IS_PUBLIC_API)) != 0;
183
184         Intent appIntent = null;
185         if (isPublicApi) {
186             appIntent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED);
187             appIntent.setPackage(pckg);
188             // send id of the items clicked on.
189             if (intent.getBooleanExtra("multiple", false)) {
190                 // broadcast received saying click occurred on a notification with multiple titles.
191                 // don't include any ids at all - let the caller query all downloads belonging to it
192                 // TODO modify the broadcast to include ids of those multiple notifications.
193             } else {
194                 appIntent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS,
195                         new long[] {
196                                 cursor.getLong(cursor.getColumnIndexOrThrow(Downloads.Impl._ID))});
197             }
198         } else { // legacy behavior
199             if (clazz == null) {
200                 return;
201             }
202             appIntent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED);
203             appIntent.setClassName(pckg, clazz);
204             if (intent.getBooleanExtra("multiple", true)) {
205                 appIntent.setData(Downloads.Impl.CONTENT_URI);
206             } else {
207                 long downloadId = cursor.getLong(cursor.getColumnIndexOrThrow(Downloads.Impl._ID));
208                 appIntent.setData(
209                         ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, downloadId));
210             }
211         }
212
213         mSystemFacade.sendBroadcast(appIntent);
214     }
215
216     private void startService(Context context) {
217         context.startService(new Intent(context, DownloadService.class));
218     }
219 }