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 android.app.NotificationManager; 36 import android.bluetooth.BluetoothDevice; 37 import android.bluetooth.BluetoothDevicePicker; 38 import android.bluetooth.BluetoothProfile; 39 import android.bluetooth.BluetoothProtoEnums; 40 import android.bluetooth.BluetoothUtils; 41 import android.content.BroadcastReceiver; 42 import android.content.ContentValues; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.database.Cursor; 46 import android.net.Uri; 47 import android.util.Log; 48 import android.widget.Toast; 49 50 import com.android.bluetooth.BluetoothMethodProxy; 51 import com.android.bluetooth.BluetoothStatsLog; 52 import com.android.bluetooth.R; 53 import com.android.bluetooth.Utils; 54 import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; 55 import com.android.bluetooth.flags.Flags; 56 57 /** 58 * Receives and handles: system broadcasts; Intents from other applications; Intents from 59 * OppService; Intents from modules in Opp application layer. 60 */ 61 // Next tag value for ContentProfileErrorReportUtils.report(): 2 62 public class BluetoothOppReceiver extends BroadcastReceiver { 63 private static final String TAG = "BluetoothOppReceiver"; 64 65 @Override onReceive(Context context, Intent intent)66 public void onReceive(Context context, Intent intent) { 67 String action = intent.getAction(); 68 Log.d(TAG, " action :" + action); 69 if (action == null) return; 70 if (action.equals(BluetoothDevicePicker.ACTION_DEVICE_SELECTED)) { 71 BluetoothOppManager mOppManager = BluetoothOppManager.getInstance(context); 72 73 BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 74 75 if (remoteDevice == null) { 76 mOppManager.cleanUpSendingFileInfo(); 77 return; 78 } 79 80 Log.d( 81 TAG, 82 "Received BT device selected intent, bt device: " 83 + BluetoothUtils.toAnonymizedAddress( 84 Flags.identityAddressNullIfUnknown() 85 ? Utils.getBrEdrAddress(remoteDevice) 86 : remoteDevice.getIdentityAddress())); 87 88 // Insert transfer session record to database 89 mOppManager.startTransfer(remoteDevice); 90 91 // Display toast message 92 String deviceName = mOppManager.getDeviceName(remoteDevice); 93 String toastMsg; 94 int batchSize = mOppManager.getBatchSize(); 95 if (mOppManager.mMultipleFlag) { 96 toastMsg = 97 context.getString( 98 R.string.bt_toast_5, Integer.toString(batchSize), deviceName); 99 } else { 100 toastMsg = context.getString(R.string.bt_toast_4, deviceName); 101 } 102 Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show(); 103 } else if (action.equals(Constants.ACTION_INCOMING_FILE_CONFIRM) 104 && !Flags.oppStartActivityDirectlyFromNotification()) { 105 Log.v(TAG, "Receiver ACTION_INCOMING_FILE_CONFIRM"); 106 107 Uri uri = intent.getData(); 108 Intent in = new Intent(context, BluetoothOppIncomingFileConfirmActivity.class); 109 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 110 in.setDataAndNormalize(uri); 111 context.startActivity(in); 112 } else if (action.equals(Constants.ACTION_DECLINE)) { 113 Log.v(TAG, "Receiver ACTION_DECLINE"); 114 115 Uri uri = intent.getData(); 116 ContentValues values = new ContentValues(); 117 values.put(BluetoothShare.USER_CONFIRMATION, BluetoothShare.USER_CONFIRMATION_DENIED); 118 BluetoothMethodProxy.getInstance() 119 .contentResolverUpdate(context.getContentResolver(), uri, values, null, null); 120 cancelNotification(context, BluetoothOppNotification.NOTIFICATION_ID_PROGRESS); 121 122 } else if (action.equals(Constants.ACTION_ACCEPT)) { 123 Log.v(TAG, "Receiver ACTION_ACCEPT"); 124 125 Uri uri = intent.getData(); 126 ContentValues values = new ContentValues(); 127 values.put( 128 BluetoothShare.USER_CONFIRMATION, BluetoothShare.USER_CONFIRMATION_CONFIRMED); 129 BluetoothMethodProxy.getInstance() 130 .contentResolverUpdate(context.getContentResolver(), uri, values, null, null); 131 } else if (action.equals(Constants.ACTION_OPEN) || action.equals(Constants.ACTION_LIST)) { 132 if (action.equals(Constants.ACTION_OPEN)) { 133 Log.v(TAG, "Receiver open for " + intent.getData()); 134 } else { 135 Log.v(TAG, "Receiver list for " + intent.getData()); 136 } 137 138 Uri uri = intent.getData(); 139 BluetoothOppTransferInfo transInfo = BluetoothOppUtility.queryRecord(context, uri); 140 if (transInfo == null) { 141 Log.e(TAG, "Error: Can not get data from db"); 142 ContentProfileErrorReportUtils.report( 143 BluetoothProfile.OPP, 144 BluetoothProtoEnums.BLUETOOTH_OPP_RECEIVER, 145 BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_ERROR, 146 0); 147 return; 148 } 149 150 if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND 151 && BluetoothShare.isStatusSuccess(transInfo.mStatus)) { 152 // if received file successfully, open this file 153 BluetoothOppUtility.openReceivedFile( 154 context, 155 transInfo.mFileName, 156 transInfo.mFileType, 157 transInfo.mTimeStamp, 158 uri); 159 BluetoothOppUtility.updateVisibilityToHidden(context, uri); 160 } else { 161 Intent in = new Intent(context, BluetoothOppTransferActivity.class); 162 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 163 in.setDataAndNormalize(uri); 164 context.startActivity(in); 165 } 166 167 } else if (action.equals(Constants.ACTION_OPEN_OUTBOUND_TRANSFER) 168 && !Flags.oppStartActivityDirectlyFromNotification()) { 169 Log.v(TAG, "Received ACTION_OPEN_OUTBOUND_TRANSFER."); 170 171 Intent in = new Intent(context, BluetoothOppTransferHistory.class); 172 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 173 in.putExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_OUTBOUND); 174 context.startActivity(in); 175 } else if (action.equals(Constants.ACTION_OPEN_INBOUND_TRANSFER) 176 && !Flags.oppStartActivityDirectlyFromNotification()) { 177 Log.v(TAG, "Received ACTION_OPEN_INBOUND_TRANSFER."); 178 179 Intent in = new Intent(context, BluetoothOppTransferHistory.class); 180 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 181 in.putExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_INBOUND); 182 context.startActivity(in); 183 } else if (action.equals(Constants.ACTION_HIDE)) { 184 Log.v(TAG, "Receiver hide for " + intent.getData()); 185 Cursor cursor = 186 BluetoothMethodProxy.getInstance() 187 .contentResolverQuery( 188 context.getContentResolver(), 189 intent.getData(), 190 null, 191 null, 192 null, 193 null); 194 if (cursor != null) { 195 if (cursor.moveToFirst()) { 196 int visibilityColumn = cursor.getColumnIndexOrThrow(BluetoothShare.VISIBILITY); 197 int visibility = cursor.getInt(visibilityColumn); 198 int userConfirmationColumn = 199 cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION); 200 int userConfirmation = cursor.getInt(userConfirmationColumn); 201 if (((userConfirmation == BluetoothShare.USER_CONFIRMATION_PENDING)) 202 && visibility == BluetoothShare.VISIBILITY_VISIBLE) { 203 ContentValues values = new ContentValues(); 204 values.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN); 205 BluetoothMethodProxy.getInstance() 206 .contentResolverUpdate( 207 context.getContentResolver(), 208 intent.getData(), 209 values, 210 null, 211 null); 212 Log.v(TAG, "Action_hide received and db updated"); 213 } 214 } 215 cursor.close(); 216 } 217 } else if (action.equals(Constants.ACTION_COMPLETE_HIDE) 218 && !Flags.oppFixMultipleNotificationsIssues()) { 219 Log.v(TAG, "Receiver ACTION_COMPLETE_HIDE"); 220 ContentValues updateValues = new ContentValues(); 221 updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN); 222 BluetoothMethodProxy.getInstance() 223 .contentResolverUpdate( 224 context.getContentResolver(), 225 BluetoothShare.CONTENT_URI, 226 updateValues, 227 BluetoothOppNotification.WHERE_COMPLETED, 228 null); 229 } else if (action.equals(Constants.ACTION_HIDE_COMPLETED_INBOUND_TRANSFER) 230 && Flags.oppFixMultipleNotificationsIssues()) { 231 Log.v(TAG, "Received ACTION_HIDE_COMPLETED_INBOUND_TRANSFER"); 232 ContentValues updateValues = new ContentValues(); 233 updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN); 234 BluetoothMethodProxy.getInstance() 235 .contentResolverUpdate( 236 context.getContentResolver(), 237 BluetoothShare.CONTENT_URI, 238 updateValues, 239 BluetoothOppNotification.WHERE_COMPLETED_INBOUND, 240 null); 241 } else if (action.equals(Constants.ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER) 242 && Flags.oppFixMultipleNotificationsIssues()) { 243 Log.v(TAG, "Received ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER"); 244 ContentValues updateValues = new ContentValues(); 245 updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN); 246 BluetoothMethodProxy.getInstance() 247 .contentResolverUpdate( 248 context.getContentResolver(), 249 BluetoothShare.CONTENT_URI, 250 updateValues, 251 BluetoothOppNotification.WHERE_COMPLETED_OUTBOUND, 252 null); 253 } else if (action.equals(BluetoothShare.TRANSFER_COMPLETED_ACTION)) { 254 Log.v(TAG, "Receiver Transfer Complete Intent for " + intent.getData()); 255 256 String toastMsg = null; 257 BluetoothOppTransferInfo transInfo = 258 BluetoothOppUtility.queryRecord(context, intent.getData()); 259 if (transInfo == null) { 260 Log.e(TAG, "Error: Can not get data from db"); 261 ContentProfileErrorReportUtils.report( 262 BluetoothProfile.OPP, 263 BluetoothProtoEnums.BLUETOOTH_OPP_RECEIVER, 264 BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_ERROR, 265 1); 266 return; 267 } 268 269 if (transInfo.mHandoverInitiated) { 270 // Deal with handover-initiated transfers separately 271 Intent handoverIntent = new Intent(Constants.ACTION_BT_OPP_TRANSFER_DONE); 272 if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND) { 273 handoverIntent.putExtra( 274 Constants.EXTRA_BT_OPP_TRANSFER_DIRECTION, 275 Constants.DIRECTION_BLUETOOTH_INCOMING); 276 } else { 277 handoverIntent.putExtra( 278 Constants.EXTRA_BT_OPP_TRANSFER_DIRECTION, 279 Constants.DIRECTION_BLUETOOTH_OUTGOING); 280 } 281 handoverIntent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_ID, transInfo.mID); 282 handoverIntent.putExtra(Constants.EXTRA_BT_OPP_ADDRESS, transInfo.mDestAddr); 283 284 if (BluetoothShare.isStatusSuccess(transInfo.mStatus)) { 285 handoverIntent.putExtra( 286 Constants.EXTRA_BT_OPP_TRANSFER_STATUS, 287 Constants.HANDOVER_TRANSFER_STATUS_SUCCESS); 288 handoverIntent.putExtra( 289 Constants.EXTRA_BT_OPP_TRANSFER_URI, transInfo.mFileName); 290 handoverIntent.putExtra( 291 Constants.EXTRA_BT_OPP_TRANSFER_MIMETYPE, transInfo.mFileType); 292 } else { 293 handoverIntent.putExtra( 294 Constants.EXTRA_BT_OPP_TRANSFER_STATUS, 295 Constants.HANDOVER_TRANSFER_STATUS_FAILURE); 296 } 297 context.sendBroadcast( 298 handoverIntent, 299 Constants.HANDOVER_STATUS_PERMISSION, 300 Utils.getTempBroadcastOptions().toBundle()); 301 return; 302 } 303 304 if (BluetoothShare.isStatusSuccess(transInfo.mStatus)) { 305 if (transInfo.mDirection == BluetoothShare.DIRECTION_OUTBOUND) { 306 toastMsg = context.getString(R.string.notification_sent, transInfo.mFileName); 307 } else if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND) { 308 toastMsg = 309 context.getString(R.string.notification_received, transInfo.mFileName); 310 } 311 312 } else if (BluetoothShare.isStatusError(transInfo.mStatus)) { 313 if (transInfo.mDirection == BluetoothShare.DIRECTION_OUTBOUND) { 314 toastMsg = 315 context.getString(R.string.notification_sent_fail, transInfo.mFileName); 316 } else if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND) { 317 toastMsg = context.getString(R.string.download_fail_line1); 318 } 319 } 320 Log.v(TAG, "Toast msg == " + toastMsg); 321 if (toastMsg != null) { 322 Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show(); 323 } 324 } 325 } 326 cancelNotification(Context context, int id)327 private void cancelNotification(Context context, int id) { 328 NotificationManager notMgr = context.getSystemService(NotificationManager.class); 329 if (notMgr == null) { 330 return; 331 } 332 notMgr.cancel(id); 333 Log.v(TAG, "notMgr.cancel called"); 334 } 335 } 336