BluetoothOppNotification.java revision 6769b59d715ea98bd72eafcfea9acd2714a887da
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 * @param ctx The context to use to obtain access to the Notification Service 98 */ 99 BluetoothOppNotification(Context ctx) { 100 mContext = ctx; 101 mNotificationMgr = (NotificationManager)mContext 102 .getSystemService(Context.NOTIFICATION_SERVICE); 103 mNotifications = new HashMap<String, NotificationItem>(); 104 } 105 106 /** 107 * Update the notification ui. 108 */ 109 public void updateNotification() { 110 updateActiveNotification(); 111 updateCompletedNotification(); 112 updateIncomingFileConfirmNotification(); 113 } 114 115 private void updateActiveNotification() { 116 // Active transfers 117 Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null, 118 WHERE_RUNNING, null, BluetoothShare._ID); 119 if (cursor == null) { 120 return; 121 } 122 123 // Collate the notifications 124 mNotifications.clear(); 125 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 126 int timeStamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); 127 int dir = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION)); 128 int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)); 129 int total = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)); 130 int current = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES)); 131 132 String fileName = cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare._DATA)); 133 if (fileName == null) { 134 fileName = cursor.getString(cursor 135 .getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)); 136 } 137 if (fileName == null) { 138 fileName = mContext.getString(R.string.unknown_file); 139 } 140 141 String batchID = Long.toString(timeStamp); 142 143 // sending objects in one batch has same timeStamp 144 if (mNotifications.containsKey(batchID)) { 145 // NOTE: currently no such case 146 // Batch sending case 147 } else { 148 NotificationItem item = new NotificationItem(); 149 item.id = id; 150 item.direction = dir; 151 if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) { 152 item.description = mContext.getString(R.string.notification_sending).replace( 153 "%s", fileName); 154 } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) { 155 item.description = mContext.getString(R.string.notification_receiving).replace( 156 "%s", fileName); 157 } else { 158 if (Constants.LOGVV) { 159 Log.v(TAG, "mDirection ERROR!"); 160 } 161 } 162 item.totalCurrent = current; 163 item.totalTotal = total; 164 165 mNotifications.put(batchID, item); 166 167 if (Constants.LOGVV) { 168 Log.v(TAG, "ID=" + item.id + "; batchID=" + batchID + "; totoalCurrent" 169 + item.totalCurrent + "; totalTotal=" + item.totalTotal); 170 } 171 } 172 } 173 cursor.close(); 174 175 // Add the notifications 176 for (NotificationItem item : mNotifications.values()) { 177 // Build the RemoteView object 178 RemoteViews expandedView = new RemoteViews(Constants.THIS_PACKAGE_NAME, 179 R.layout.status_bar_ongoing_event_progress_bar); 180 181 expandedView.setTextViewText(R.id.description, item.description); 182 183 expandedView.setProgressBar(R.id.progress_bar, item.totalTotal, item.totalCurrent, 184 item.totalTotal == -1); 185 186 expandedView.setTextViewText(R.id.progress_text, BluetoothOppUtility 187 .formatProgressText(item.totalTotal, item.totalCurrent)); 188 189 // Build the notification object 190 Notification n = new Notification(); 191 if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) { 192 n.icon = android.R.drawable.stat_sys_upload; 193 expandedView.setImageViewResource(R.id.appIcon, android.R.drawable.stat_sys_upload); 194 } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) { 195 n.icon = android.R.drawable.stat_sys_download; 196 expandedView.setImageViewResource(R.id.appIcon, 197 android.R.drawable.stat_sys_download); 198 } else { 199 if (Constants.LOGVV) { 200 Log.v(TAG, "mDirection ERROR!"); 201 } 202 } 203 204 n.flags |= Notification.FLAG_ONGOING_EVENT; 205 n.contentView = expandedView; 206 207 Intent intent = new Intent(Constants.ACTION_LIST); 208 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 209 intent.setData(Uri.parse(BluetoothShare.CONTENT_URI + "/" + item.id)); 210 211 n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 212 mNotificationMgr.notify(item.id, n); 213 } 214 } 215 216 private void updateCompletedNotification() { 217 Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null, 218 WHERE_COMPLETED, null, BluetoothShare._ID); 219 if (cursor == null) { 220 return; 221 } 222 223 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 224 // Add the notifications 225 int timeStamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); 226 int dir = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION)); 227 int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)); 228 int status = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.STATUS)); 229 230 String fileName = cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare._DATA)); 231 if (fileName == null) { 232 fileName = cursor.getString(cursor 233 .getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)); 234 } 235 if (fileName == null) { 236 fileName = mContext.getString(R.string.unknown_file); 237 } 238 239 String title; 240 String caption; 241 Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id); 242 243 Notification n = new Notification(); 244 if (BluetoothShare.isStatusError(status)) { 245 if (dir == BluetoothShare.DIRECTION_OUTBOUND) { 246 title = mContext.getString(R.string.notification_sent_fail).replace("%s", 247 fileName); 248 } else { 249 title = mContext.getString(R.string.notification_received_fail).replace("%s", 250 fileName); 251 } 252 caption = mContext.getString(R.string.download_fail_line3).replace("%s", 253 BluetoothOppUtility.getStatusDescription(mContext, status)); 254 n.icon = android.R.drawable.stat_notify_error; 255 } else { 256 if (dir == BluetoothShare.DIRECTION_OUTBOUND) { 257 title = mContext.getString(R.string.notification_sent).replace("%s", fileName); 258 n.icon = android.R.drawable.stat_sys_upload_done; 259 } else { 260 title = mContext.getString(R.string.notification_received).replace("%s", 261 fileName); 262 n.icon = android.R.drawable.stat_sys_download_done; 263 } 264 caption = mContext.getString(R.string.notification_sent_complete); 265 } 266 Intent intent = new Intent(Constants.ACTION_OPEN); 267 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 268 intent.setData(contentUri); 269 270 n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0, 271 intent, 0)); 272 273 intent = new Intent(Constants.ACTION_HIDE); 274 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 275 intent.setData(contentUri); 276 n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 277 278 n.when = timeStamp; 279 280 mNotificationMgr.notify(id, n); 281 } 282 cursor.close(); 283 } 284 285 private void updateIncomingFileConfirmNotification() { 286 Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null, 287 WHERE_CONFIRM_PENDING, null, BluetoothShare._ID); 288 289 if (cursor == null) { 290 return; 291 } 292 293 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 294 String title = mContext.getString(R.string.incoming_file_confirm_Notification_title); 295 String caption = mContext 296 .getString(R.string.incoming_file_confirm_Notification_caption); 297 int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)); 298 int timeStamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); 299 Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id); 300 301 Notification n = new Notification(); 302 n.icon = R.drawable.stat_sys_data_bt; 303 n.flags |= Notification.FLAG_ONLY_ALERT_ONCE; 304 n.defaults = Notification.DEFAULT_SOUND; 305 n.tickerText = title; 306 Intent intent = new Intent(Constants.ACTION_INCOMING_FILE_CONFIRM); 307 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 308 intent.setData(contentUri); 309 n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0, 310 intent, 0)); 311 312 intent = new Intent(Constants.ACTION_HIDE); 313 intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 314 intent.setData(contentUri); 315 n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 316 317 n.when = timeStamp; 318 mNotificationMgr.notify(id, n); 319 } 320 cursor.close(); 321 } 322} 323