BluetoothOppNotification.java revision 464d9d216ab1a6cf192e3e526596073c7e35e4a7
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 33package com.android.bluetooth.opp; 34 35import com.android.bluetooth.R; 36 37import android.content.Context; 38import android.app.Notification; 39import android.app.NotificationManager; 40import android.app.PendingIntent; 41import android.content.Intent; 42import android.database.Cursor; 43import android.net.Uri; 44import android.util.Log; 45import android.widget.RemoteViews; 46import android.widget.Toast; 47import java.util.HashMap; 48 49/** 50 * This class handles the updating of the Notification Manager for the cases 51 * where there is an ongoing transfer, incoming transfer need confirm and 52 * complete (successful or failed) transfer. 53 */ 54class BluetoothOppNotification { 55 private static final String TAG = "BluetoothOppNotification"; 56 57 Context mContext; 58 59 public NotificationManager mNotificationMgr; 60 61 HashMap<String, NotificationItem> mNotifications; 62 63 static final String status = "(" + BluetoothShare.STATUS + " == '192'" + ")"; 64 65 static final String visible = "(" + BluetoothShare.VISIBILITY + " IS NULL OR " 66 + BluetoothShare.VISIBILITY + " == '" + BluetoothShare.VISIBILITY_VISIBLE + "'" + ")"; 67 68 static final String confirm = "(" + BluetoothShare.USER_CONFIRMATION + " == '" 69 + BluetoothShare.USER_CONFIRMATION_CONFIRMED + "' OR " 70 + BluetoothShare.USER_CONFIRMATION + " == '" 71 + BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED + "'" + ")"; 72 73 static final String WHERE_RUNNING = status + " AND " + visible + " AND " + confirm; 74 75 static final String WHERE_COMPLETED = BluetoothShare.STATUS + " >= '200' AND " + visible; 76 77 static final String WHERE_CONFIRM_PENDING = BluetoothShare.USER_CONFIRMATION + " == '" 78 + BluetoothShare.USER_CONFIRMATION_PENDING + "'" + " AND " + visible; 79 80 /** 81 * This inner class is used to describe some properties for one transfer. 82 */ 83 static class NotificationItem { 84 int id; // This first field _id in db; 85 86 int direction; // to indicate sending or receiving 87 88 int totalCurrent = 0; // current transfer bytes 89 90 int totalTotal = 0; // total bytes for current transfer 91 92 String description; // the text above progress bar 93 } 94 95 /** 96 * Constructor 97 * 98 * @param ctx The context to use to obtain access to the Notification 99 * Service 100 */ 101 BluetoothOppNotification(Context ctx) { 102 mContext = ctx; 103 mNotificationMgr = (NotificationManager)mContext 104 .getSystemService(Context.NOTIFICATION_SERVICE); 105 mNotifications = new HashMap<String, NotificationItem>(); 106 } 107 108 /** 109 * Update the notification ui. 110 */ 111 public void updateNotification() { 112 updateActiveNotification(); 113 updateCompletedNotification(); 114 updateIncomingFileConfirmNotification(); 115 } 116 117 private void updateActiveNotification() { 118 // Active transfers 119 Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null, 120 WHERE_RUNNING, null, BluetoothShare._ID); 121 if (cursor == null) { 122 return; 123 } 124 125 // Collate the notifications 126 mNotifications.clear(); 127 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 128 int timeStamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); 129 int dir = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION)); 130 int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)); 131 int total = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)); 132 int current = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES)); 133 134 String fileName = cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare._DATA)); 135 if (fileName == null) { 136 fileName = cursor.getString(cursor 137 .getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)); 138 } 139 if (fileName == null) { 140 fileName = mContext.getString(R.string.unknown_file); 141 } 142 143 String batchID = Long.toString(timeStamp); 144 145 // sending objects in one batch has same timeStamp 146 if (mNotifications.containsKey(batchID)) { 147 // NOTE: currently no such case 148 // Batch sending case 149 } else { 150 NotificationItem item = new NotificationItem(); 151 item.id = id; 152 item.direction = dir; 153 if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) { 154 item.description = mContext.getString(R.string.notification_sending, fileName); 155 } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) { 156 item.description = mContext 157 .getString(R.string.notification_receiving, fileName); 158 } else { 159 if (Constants.LOGVV) { 160 Log.v(TAG, "mDirection ERROR!"); 161 } 162 } 163 item.totalCurrent = current; 164 item.totalTotal = total; 165 166 mNotifications.put(batchID, item); 167 168 if (Constants.LOGVV) { 169 Log.v(TAG, "ID=" + item.id + "; batchID=" + batchID + "; totoalCurrent" 170 + item.totalCurrent + "; totalTotal=" + item.totalTotal); 171 } 172 } 173 } 174 cursor.close(); 175 176 // Add the notifications 177 for (NotificationItem item : mNotifications.values()) { 178 // Build the RemoteView object 179 RemoteViews expandedView = new RemoteViews(Constants.THIS_PACKAGE_NAME, 180 R.layout.status_bar_ongoing_event_progress_bar); 181 182 expandedView.setTextViewText(R.id.description, item.description); 183 184 expandedView.setProgressBar(R.id.progress_bar, item.totalTotal, item.totalCurrent, 185 item.totalTotal == -1); 186 187 expandedView.setTextViewText(R.id.progress_text, BluetoothOppUtility 188 .formatProgressText(item.totalTotal, item.totalCurrent)); 189 190 // Build the notification object 191 Notification n = new Notification(); 192 if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) { 193 n.icon = android.R.drawable.stat_sys_upload; 194 expandedView.setImageViewResource(R.id.appIcon, android.R.drawable.stat_sys_upload); 195 } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) { 196 n.icon = android.R.drawable.stat_sys_download; 197 expandedView.setImageViewResource(R.id.appIcon, 198 android.R.drawable.stat_sys_download); 199 } else { 200 if (Constants.LOGVV) { 201 Log.v(TAG, "mDirection ERROR!"); 202 } 203 } 204 205 n.flags |= Notification.FLAG_ONGOING_EVENT; 206 n.contentView = expandedView; 207 208 Intent intent = new Intent(Constants.ACTION_LIST); 209 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 210 intent.setData(Uri.parse(BluetoothShare.CONTENT_URI + "/" + item.id)); 211 212 n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 213 mNotificationMgr.notify(item.id, n); 214 } 215 } 216 217 private void updateCompletedNotification() { 218 Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null, 219 WHERE_COMPLETED, null, BluetoothShare._ID); 220 if (cursor == null) { 221 return; 222 } 223 224 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 225 // Add the notifications 226 int timeStamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); 227 int dir = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION)); 228 int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)); 229 int status = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.STATUS)); 230 231 String fileName = cursor.getString(cursor 232 .getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)); 233 if (fileName == null) { 234 fileName = mContext.getString(R.string.unknown_file); 235 } 236 237 String title; 238 String caption; 239 Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id); 240 241 Notification n = new Notification(); 242 if (BluetoothShare.isStatusError(status)) { 243 if (dir == BluetoothShare.DIRECTION_OUTBOUND) { 244 title = mContext.getString(R.string.notification_sent_fail, fileName); 245 } else { 246 title = mContext.getString(R.string.notification_received_fail, fileName); 247 } 248 caption = mContext.getString(R.string.download_fail_line3, BluetoothOppUtility 249 .getStatusDescription(mContext, status)); 250 n.icon = android.R.drawable.stat_notify_error; 251 } else { 252 if (dir == BluetoothShare.DIRECTION_OUTBOUND) { 253 title = mContext.getString(R.string.notification_sent, fileName); 254 n.icon = android.R.drawable.stat_sys_upload_done; 255 } else { 256 title = mContext.getString(R.string.notification_received, fileName); 257 n.icon = android.R.drawable.stat_sys_download_done; 258 } 259 caption = mContext.getString(R.string.notification_sent_complete); 260 } 261 Intent intent = new Intent(Constants.ACTION_OPEN); 262 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 263 intent.setData(contentUri); 264 265 n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0, 266 intent, 0)); 267 268 intent = new Intent(Constants.ACTION_HIDE); 269 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 270 intent.setData(contentUri); 271 n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 272 273 n.when = timeStamp; 274 275 mNotificationMgr.notify(id, n); 276 } 277 cursor.close(); 278 } 279 280 private void updateIncomingFileConfirmNotification() { 281 Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null, 282 WHERE_CONFIRM_PENDING, null, BluetoothShare._ID); 283 284 if (cursor == null) { 285 return; 286 } 287 288 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 289 String title = mContext.getString(R.string.incoming_file_confirm_Notification_title); 290 String caption = mContext 291 .getString(R.string.incoming_file_confirm_Notification_caption); 292 int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)); 293 int timeStamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); 294 Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id); 295 296 Notification n = new Notification(); 297 n.icon = R.drawable.bt_incomming_file_notification; 298 n.flags |= Notification.FLAG_ONLY_ALERT_ONCE; 299 n.defaults = Notification.DEFAULT_SOUND; 300 n.tickerText = title; 301 Intent intent = new Intent(Constants.ACTION_INCOMING_FILE_CONFIRM); 302 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 303 intent.setData(contentUri); 304 n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0, 305 intent, 0)); 306 307 intent = new Intent(Constants.ACTION_HIDE); 308 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 309 intent.setData(contentUri); 310 n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 311 312 n.when = timeStamp; 313 mNotificationMgr.notify(id, n); 314 } 315 cursor.close(); 316 } 317} 318