• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2008-2009, Motorola, Inc.
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * - Neither the name of the Motorola, Inc. nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.android.bluetooth.opp;
34 
35 import com.android.bluetooth.R;
36 
37 import android.content.Context;
38 import android.app.Notification;
39 import android.app.NotificationManager;
40 import android.app.PendingIntent;
41 import android.content.Intent;
42 import android.database.Cursor;
43 import android.net.Uri;
44 import android.util.Log;
45 import android.os.Handler;
46 import android.os.Message;
47 import android.os.Process;
48 import java.util.HashMap;
49 
50 /**
51  * This class handles the updating of the Notification Manager for the cases
52  * where there is an ongoing transfer, incoming transfer need confirm and
53  * complete (successful or failed) transfer.
54  */
55 class BluetoothOppNotification {
56     private static final String TAG = "BluetoothOppNotification";
57     private static final boolean V = Constants.VERBOSE;
58 
59     static final String status = "(" + BluetoothShare.STATUS + " == '192'" + ")";
60 
61     static final String visible = "(" + BluetoothShare.VISIBILITY + " IS NULL OR "
62             + BluetoothShare.VISIBILITY + " == '" + BluetoothShare.VISIBILITY_VISIBLE + "'" + ")";
63 
64     static final String confirm = "(" + BluetoothShare.USER_CONFIRMATION + " == '"
65             + BluetoothShare.USER_CONFIRMATION_CONFIRMED + "' OR "
66             + BluetoothShare.USER_CONFIRMATION + " == '"
67             + BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED  + "' OR "
68             + BluetoothShare.USER_CONFIRMATION + " == '"
69             + BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED + "'" + ")";
70 
71     static final String not_through_handover = "(" + BluetoothShare.USER_CONFIRMATION + " != '"
72             + BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED + "'" + ")";
73 
74     static final String WHERE_RUNNING = status + " AND " + visible + " AND " + confirm;
75 
76     static final String WHERE_COMPLETED = BluetoothShare.STATUS + " >= '200' AND " + visible +
77             " AND " + not_through_handover; // Don't show handover-initiated transfers
78 
79     private static final String WHERE_COMPLETED_OUTBOUND = WHERE_COMPLETED + " AND " + "("
80             + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_OUTBOUND + ")";
81 
82     private static final String WHERE_COMPLETED_INBOUND = WHERE_COMPLETED + " AND " + "("
83             + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_INBOUND + ")";
84 
85     static final String WHERE_CONFIRM_PENDING = BluetoothShare.USER_CONFIRMATION + " == '"
86             + BluetoothShare.USER_CONFIRMATION_PENDING + "'" + " AND " + visible;
87 
88     public NotificationManager mNotificationMgr;
89 
90     private Context mContext;
91 
92     private HashMap<String, NotificationItem> mNotifications;
93 
94     private NotificationUpdateThread mUpdateNotificationThread;
95 
96     private int mPendingUpdate = 0;
97 
98     private static final int NOTIFICATION_ID_OUTBOUND = -1000005;
99 
100     private static final int NOTIFICATION_ID_INBOUND = -1000006;
101 
102     private boolean mUpdateCompleteNotification = true;
103 
104     private int mActiveNotificationId = 0;
105 
106     /**
107      * This inner class is used to describe some properties for one transfer.
108      */
109     static class NotificationItem {
110         int id; // This first field _id in db;
111 
112         int direction; // to indicate sending or receiving
113 
114         long totalCurrent = 0; // current transfer bytes
115 
116         long totalTotal = 0; // total bytes for current transfer
117 
118         long timeStamp = 0; // Database time stamp. Used for sorting ongoing transfers.
119 
120         String description; // the text above progress bar
121 
122         boolean handoverInitiated = false; // transfer initiated by connection handover (eg NFC)
123 
124         String destination; // destination associated with this transfer
125     }
126 
127     /**
128      * Constructor
129      *
130      * @param ctx The context to use to obtain access to the Notification
131      *            Service
132      */
BluetoothOppNotification(Context ctx)133     BluetoothOppNotification(Context ctx) {
134         mContext = ctx;
135         mNotificationMgr = (NotificationManager)mContext
136                 .getSystemService(Context.NOTIFICATION_SERVICE);
137         mNotifications = new HashMap<String, NotificationItem>();
138     }
139 
140     /**
141      * Update the notification ui.
142      */
updateNotification()143     public void updateNotification() {
144         synchronized (BluetoothOppNotification.this) {
145             mPendingUpdate++;
146             if (mPendingUpdate > 1) {
147                 if (V) Log.v(TAG, "update too frequent, put in queue");
148                 return;
149             }
150             if (!mHandler.hasMessages(NOTIFY)) {
151                 if (V) Log.v(TAG, "send message");
152                 mHandler.sendMessage(mHandler.obtainMessage(NOTIFY));
153             }
154         }
155     }
156 
157     private static final int NOTIFY = 0;
158     // Use 1 second timer to limit notification frequency.
159     // 1. On the first notification, create the update thread.
160     //    Buffer other updates.
161     // 2. Update thread will clear mPendingUpdate.
162     // 3. Handler sends a delayed message to self
163     // 4. Handler checks if there are any more updates after 1 second.
164     // 5. If there is an update, update it else stop.
165     private Handler mHandler = new Handler() {
166         public void handleMessage(Message msg) {
167             switch (msg.what) {
168                 case NOTIFY:
169                     synchronized (BluetoothOppNotification.this) {
170                         if (mPendingUpdate > 0 && mUpdateNotificationThread == null) {
171                             if (V) Log.v(TAG, "new notify threadi!");
172                             mUpdateNotificationThread = new NotificationUpdateThread();
173                             mUpdateNotificationThread.start();
174                             if (V) Log.v(TAG, "send delay message");
175                             mHandler.sendMessageDelayed(mHandler.obtainMessage(NOTIFY), 1000);
176                         } else if (mPendingUpdate > 0) {
177                             if (V) Log.v(TAG, "previous thread is not finished yet");
178                             mHandler.sendMessageDelayed(mHandler.obtainMessage(NOTIFY), 1000);
179                         }
180                         break;
181                     }
182               }
183          }
184     };
185 
186     private class NotificationUpdateThread extends Thread {
187 
NotificationUpdateThread()188         public NotificationUpdateThread() {
189             super("Notification Update Thread");
190         }
191 
192         @Override
run()193         public void run() {
194             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
195             synchronized (BluetoothOppNotification.this) {
196                 if (mUpdateNotificationThread != this) {
197                     throw new IllegalStateException(
198                             "multiple UpdateThreads in BluetoothOppNotification");
199                 }
200                 mPendingUpdate = 0;
201             }
202             updateActiveNotification();
203             updateCompletedNotification();
204             updateIncomingFileConfirmNotification();
205             synchronized (BluetoothOppNotification.this) {
206                 mUpdateNotificationThread = null;
207             }
208         }
209     }
210 
updateActiveNotification()211     private void updateActiveNotification() {
212         // Active transfers
213         Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
214                 WHERE_RUNNING, null, BluetoothShare._ID);
215         if (cursor == null) {
216             return;
217         }
218 
219         // If there is active transfers, then no need to update completed transfer
220         // notifications
221         if (cursor.getCount() > 0) {
222             mUpdateCompleteNotification = false;
223         } else {
224             mUpdateCompleteNotification = true;
225         }
226         if (V) Log.v(TAG, "mUpdateCompleteNotification = " + mUpdateCompleteNotification);
227 
228         // Collate the notifications
229         final int timestampIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP);
230         final int directionIndex = cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION);
231         final int idIndex = cursor.getColumnIndexOrThrow(BluetoothShare._ID);
232         final int totalBytesIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES);
233         final int currentBytesIndex = cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES);
234         final int dataIndex = cursor.getColumnIndexOrThrow(BluetoothShare._DATA);
235         final int filenameHintIndex = cursor.getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT);
236         final int confirmIndex = cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION);
237         final int destinationIndex = cursor.getColumnIndexOrThrow(BluetoothShare.DESTINATION);
238 
239         mNotifications.clear();
240         for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
241             long timeStamp = cursor.getLong(timestampIndex);
242             int dir = cursor.getInt(directionIndex);
243             int id = cursor.getInt(idIndex);
244             long total = cursor.getLong(totalBytesIndex);
245             long current = cursor.getLong(currentBytesIndex);
246             int confirmation = cursor.getInt(confirmIndex);
247 
248             String destination = cursor.getString(destinationIndex);
249             String fileName = cursor.getString(dataIndex);
250             if (fileName == null) {
251                 fileName = cursor.getString(filenameHintIndex);
252             }
253             if (fileName == null) {
254                 fileName = mContext.getString(R.string.unknown_file);
255             }
256 
257             String batchID = Long.toString(timeStamp);
258 
259             // sending objects in one batch has same timeStamp
260             if (mNotifications.containsKey(batchID)) {
261                 // NOTE: currently no such case
262                 // Batch sending case
263             } else {
264                 NotificationItem item = new NotificationItem();
265                 item.timeStamp = timeStamp;
266                 item.id = id;
267                 item.direction = dir;
268                 if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) {
269                     item.description = mContext.getString(R.string.notification_sending, fileName);
270                 } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) {
271                     item.description = mContext
272                             .getString(R.string.notification_receiving, fileName);
273                 } else {
274                     if (V) Log.v(TAG, "mDirection ERROR!");
275                 }
276                 item.totalCurrent = current;
277                 item.totalTotal = total;
278                 item.handoverInitiated =
279                         confirmation == BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED;
280                 item.destination = destination;
281                 mNotifications.put(batchID, item);
282 
283                 if (V) Log.v(TAG, "ID=" + item.id + "; batchID=" + batchID + "; totoalCurrent"
284                             + item.totalCurrent + "; totalTotal=" + item.totalTotal);
285             }
286         }
287         cursor.close();
288 
289         // Add the notifications
290         for (NotificationItem item : mNotifications.values()) {
291             if (item.handoverInitiated) {
292                 float progress = 0;
293                 if (item.totalTotal == -1) {
294                     progress = -1;
295                 } else {
296                     progress = (float)item.totalCurrent / item.totalTotal;
297                 }
298 
299                 // Let NFC service deal with notifications for this transfer
300                 Intent intent = new Intent(Constants.ACTION_BT_OPP_TRANSFER_PROGRESS);
301                 if (item.direction == BluetoothShare.DIRECTION_INBOUND) {
302                     intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_DIRECTION,
303                             Constants.DIRECTION_BLUETOOTH_INCOMING);
304                 } else {
305                     intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_DIRECTION,
306                             Constants.DIRECTION_BLUETOOTH_OUTGOING);
307                 }
308                 intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_ID, item.id);
309                 intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_PROGRESS, progress);
310                 intent.putExtra(Constants.EXTRA_BT_OPP_ADDRESS, item.destination);
311                 mContext.sendBroadcast(intent, Constants.HANDOVER_STATUS_PERMISSION);
312                 continue;
313             }
314             // Build the notification object
315             // TODO: split description into two rows with filename in second row
316             Notification.Builder b = new Notification.Builder(mContext);
317             b.setColor(mContext.getResources().getColor(
318                     com.android.internal.R.color.system_notification_accent_color));
319             b.setContentTitle(item.description);
320             b.setContentInfo(
321                 BluetoothOppUtility.formatProgressText(item.totalTotal, item.totalCurrent));
322             if (item.totalTotal != 0) {
323                 if (V) Log.v(TAG, "mCurrentBytes: " + item.totalCurrent +
324                     " mTotalBytes: " + item.totalTotal + " (" +
325                     (int)((item.totalCurrent * 100) / item.totalTotal) + " %)");
326                 b.setProgress(100, (int)((item.totalCurrent * 100) / item.totalTotal),
327                     item.totalTotal == -1);
328             } else {
329                 b.setProgress(100, 100, item.totalTotal == -1);
330             }
331             b.setWhen(item.timeStamp);
332             if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) {
333                 b.setSmallIcon(android.R.drawable.stat_sys_upload);
334             } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) {
335                 b.setSmallIcon(android.R.drawable.stat_sys_download);
336             } else {
337                 if (V) Log.v(TAG, "mDirection ERROR!");
338             }
339             b.setOngoing(true);
340 
341             Intent intent = new Intent(Constants.ACTION_LIST);
342             intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
343             intent.setDataAndNormalize(Uri.parse(BluetoothShare.CONTENT_URI + "/" + item.id));
344 
345             b.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0));
346             mNotificationMgr.notify(item.id, b.getNotification());
347 
348             mActiveNotificationId = item.id;
349         }
350     }
351 
updateCompletedNotification()352     private void updateCompletedNotification() {
353         String title;
354         String unsuccess_caption;
355         String caption;
356         long timeStamp = 0;
357         int outboundSuccNumber = 0;
358         int outboundFailNumber = 0;
359         int outboundNum;
360         int inboundNum;
361         int inboundSuccNumber = 0;
362         int inboundFailNumber = 0;
363         Intent intent;
364 
365         // If there is active transfer, no need to update complete transfer
366         // notification
367         if (!mUpdateCompleteNotification) {
368             if (V) Log.v(TAG, "No need to update complete notification");
369             return;
370         }
371 
372         // After merge complete notifications to 2 notifications, there is no
373         // chance to update the active notifications to complete notifications
374         // as before. So need cancel the active notification after the active
375         // transfer becomes complete.
376         if (mNotificationMgr != null && mActiveNotificationId != 0) {
377             mNotificationMgr.cancel(mActiveNotificationId);
378             if (V) Log.v(TAG, "ongoing transfer notification was removed");
379         }
380 
381         // Creating outbound notification
382         Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
383                 WHERE_COMPLETED_OUTBOUND, null, BluetoothShare.TIMESTAMP + " DESC");
384         if (cursor == null) {
385             return;
386         }
387 
388         final int timestampIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP);
389         final int statusIndex = cursor.getColumnIndexOrThrow(BluetoothShare.STATUS);
390 
391         for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
392             if (cursor.isFirst()) {
393                 // Display the time for the latest transfer
394                 timeStamp = cursor.getLong(timestampIndex);
395             }
396             int status = cursor.getInt(statusIndex);
397 
398             if (BluetoothShare.isStatusError(status)) {
399                 outboundFailNumber++;
400             } else {
401                 outboundSuccNumber++;
402             }
403         }
404         if (V) Log.v(TAG, "outbound: succ-" + outboundSuccNumber + "  fail-" + outboundFailNumber);
405         cursor.close();
406 
407         outboundNum = outboundSuccNumber + outboundFailNumber;
408         // create the outbound notification
409         if (outboundNum > 0) {
410             Notification outNoti = new Notification();
411             outNoti.icon = android.R.drawable.stat_sys_upload_done;
412             title = mContext.getString(R.string.outbound_noti_title);
413             unsuccess_caption = mContext.getResources().getQuantityString(
414                     R.plurals.noti_caption_unsuccessful, outboundFailNumber, outboundFailNumber);
415             caption = mContext.getResources().getQuantityString(
416                     R.plurals.noti_caption_success, outboundSuccNumber, outboundSuccNumber,
417                     unsuccess_caption);
418             intent = new Intent(Constants.ACTION_OPEN_OUTBOUND_TRANSFER);
419             intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
420             outNoti.color = mContext.getResources().getColor(
421                     com.android.internal.R.color.system_notification_accent_color);
422             outNoti.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(
423                     mContext, 0, intent, 0));
424             intent = new Intent(Constants.ACTION_COMPLETE_HIDE);
425             intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
426             outNoti.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
427             outNoti.when = timeStamp;
428             mNotificationMgr.notify(NOTIFICATION_ID_OUTBOUND, outNoti);
429         } else {
430             if (mNotificationMgr != null) {
431                 mNotificationMgr.cancel(NOTIFICATION_ID_OUTBOUND);
432                 if (V) Log.v(TAG, "outbound notification was removed.");
433             }
434         }
435 
436         // Creating inbound notification
437         cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
438                 WHERE_COMPLETED_INBOUND, null, BluetoothShare.TIMESTAMP + " DESC");
439         if (cursor == null) {
440             return;
441         }
442 
443         for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
444             if (cursor.isFirst()) {
445                 // Display the time for the latest transfer
446                 timeStamp = cursor.getLong(timestampIndex);
447             }
448             int status = cursor.getInt(statusIndex);
449 
450             if (BluetoothShare.isStatusError(status)) {
451                 inboundFailNumber++;
452             } else {
453                 inboundSuccNumber++;
454             }
455         }
456         if (V) Log.v(TAG, "inbound: succ-" + inboundSuccNumber + "  fail-" + inboundFailNumber);
457         cursor.close();
458 
459         inboundNum = inboundSuccNumber + inboundFailNumber;
460         // create the inbound notification
461         if (inboundNum > 0) {
462             Notification inNoti = new Notification();
463             inNoti.icon = android.R.drawable.stat_sys_download_done;
464             title = mContext.getString(R.string.inbound_noti_title);
465             unsuccess_caption = mContext.getResources().getQuantityString(
466                     R.plurals.noti_caption_unsuccessful, inboundFailNumber, inboundFailNumber);
467             caption = mContext.getResources().getQuantityString(
468                     R.plurals.noti_caption_success, inboundSuccNumber, inboundSuccNumber,
469                     unsuccess_caption);
470             intent = new Intent(Constants.ACTION_OPEN_INBOUND_TRANSFER);
471             intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
472             inNoti.color = mContext.getResources().getColor(
473                     com.android.internal.R.color.system_notification_accent_color);
474             inNoti.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(
475                     mContext, 0, intent, 0));
476             intent = new Intent(Constants.ACTION_COMPLETE_HIDE);
477             intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
478             inNoti.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
479             inNoti.when = timeStamp;
480             mNotificationMgr.notify(NOTIFICATION_ID_INBOUND, inNoti);
481         } else {
482             if (mNotificationMgr != null) {
483                 mNotificationMgr.cancel(NOTIFICATION_ID_INBOUND);
484                 if (V) Log.v(TAG, "inbound notification was removed.");
485             }
486         }
487     }
488 
updateIncomingFileConfirmNotification()489     private void updateIncomingFileConfirmNotification() {
490         Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
491                 WHERE_CONFIRM_PENDING, null, BluetoothShare._ID);
492 
493         if (cursor == null) {
494             return;
495         }
496 
497         for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
498             CharSequence title =
499                     mContext.getText(R.string.incoming_file_confirm_Notification_title);
500             CharSequence caption = mContext
501                     .getText(R.string.incoming_file_confirm_Notification_caption);
502             int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID));
503             long timeStamp = cursor.getLong(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP));
504             Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id);
505 
506             Notification n = new Notification();
507             n.icon = R.drawable.bt_incomming_file_notification;
508             n.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
509             n.flags |= Notification.FLAG_ONGOING_EVENT;
510             n.defaults = Notification.DEFAULT_SOUND;
511             n.tickerText = title;
512 
513             Intent intent = new Intent(Constants.ACTION_INCOMING_FILE_CONFIRM);
514             intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
515             intent.setDataAndNormalize(contentUri);
516 
517             n.when = timeStamp;
518             n.color = mContext.getResources().getColor(
519                     com.android.internal.R.color.system_notification_accent_color);
520             n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0,
521                     intent, 0));
522 
523             intent = new Intent(Constants.ACTION_HIDE);
524             intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
525             intent.setDataAndNormalize(contentUri);
526             n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
527 
528             mNotificationMgr.notify(id, n);
529         }
530         cursor.close();
531     }
532 }
533