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