13b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen/* 23b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * Copyright (C) 2012 The Android Open Source Project 33b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * 43b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License"); 53b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * you may not use this file except in compliance with the License. 63b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * You may obtain a copy of the License at 73b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * 83b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * http://www.apache.org/licenses/LICENSE-2.0 93b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * 103b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * Unless required by applicable law or agreed to in writing, software 113b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS, 123b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * See the License for the specific language governing permissions and 143b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * limitations under the License. 153b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen */ 163b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen 17b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralespackage com.android.nfc.beam; 18b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 19b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.R; 20be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 21be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.Notification; 223cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoiimport android.app.NotificationChannel; 23be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.NotificationManager; 24be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.PendingIntent; 25be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.Notification.Builder; 26be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.bluetooth.BluetoothDevice; 27be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.content.ContentResolver; 28be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.content.Context; 29be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.content.Intent; 30be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.media.MediaScannerConnection; 31be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.net.Uri; 32be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Environment; 33be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Handler; 34be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Looper; 35be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Message; 36be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.SystemClock; 37be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.UserHandle; 38be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.util.Log; 39be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 40be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.io.File; 41be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.text.SimpleDateFormat; 42be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.util.ArrayList; 43b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport java.util.Arrays; 44be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.util.Date; 45be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.util.HashMap; 46116dfa0107cdc7ab098ed95828280542bf6b0a1eThe Android Open Source Projectimport java.util.Locale; 47be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 48d5567fc2ff2d4e462932b40450f536b7e1a3bf3bJohan Redestigimport android.support.v4.content.FileProvider; 49d5567fc2ff2d4e462932b40450f536b7e1a3bf3bJohan Redestig 50be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project/** 51b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales * A BeamTransferManager object represents a set of files 52be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * that were received through NFC connection handover 53be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * from the same source address. 54be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * 55b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales * It manages starting, stopping, and processing the transfer, as well 56b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales * as the user visible notification. 57b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales * 58be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * For Bluetooth, files are received through OPP, and 59be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * we have no knowledge how many files will be transferred 60be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * as part of a single transaction. 61be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * Hence, a transfer has a notion of being "alive": if 62be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * the last update to a transfer was within WAIT_FOR_NEXT_TRANSFER_MS 63be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * milliseconds, we consider a new file transfer from the 64be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * same source address as part of the same transfer. 65be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * The corresponding URIs will be grouped in a single folder. 66be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * 67b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales * @hide 68be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project */ 69be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 70b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralespublic class BeamTransferManager implements Handler.Callback, 71b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales MediaScannerConnection.OnScanCompletedListener { 72be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project interface Callback { 733ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales 74b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales void onTransferComplete(BeamTransferManager transfer, boolean success); 75be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project }; 76b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final String TAG = "BeamTransferManager"; 77be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 78be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final Boolean DBG = true; 79be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 80be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // In the states below we still accept new file transfer 81be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int STATE_NEW = 0; 82be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int STATE_IN_PROGRESS = 1; 83be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int STATE_W4_NEXT_TRANSFER = 2; 84be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // In the states below no new files are accepted. 85be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int STATE_W4_MEDIA_SCANNER = 3; 86be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int STATE_FAILED = 4; 87be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int STATE_SUCCESS = 5; 88be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int STATE_CANCELLED = 6; 893ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales static final int STATE_CANCELLING = 7; 90be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int MSG_NEXT_TRANSFER_TIMER = 0; 91fbd59bd47482eb0784077ee3faf498d531497304Andres Morales 92be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int MSG_TRANSFER_TIMEOUT = 1; 93b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final int DATA_LINK_TYPE_BLUETOOTH = 1; 94be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 95be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // We need to receive an update within this time period 96be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // to still consider this transfer to be "alive" (ie 97be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // a reason to keep the handover transport enabled). 98be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int ALIVE_CHECK_MS = 20000; 99be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 100be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // The amount of time to wait for a new transfer 101be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // once the current one completes. 102be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final int WAIT_FOR_NEXT_TRANSFER_MS = 4000; 103be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 104be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project static final String BEAM_DIR = "beam"; 105be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 1063cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi static final String BEAM_NOTIFICATION_CHANNEL = "beam_notification_channel"; 1073cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi 108b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final String ACTION_WHITELIST_DEVICE = 109b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales "android.btopp.intent.action.WHITELIST_DEVICE"; 110b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 111b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final String ACTION_STOP_BLUETOOTH_TRANSFER = 112b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales "android.btopp.intent.action.STOP_HANDOVER_TRANSFER"; 113b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 114be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final boolean mIncoming; // whether this is an incoming transfer 115fbd59bd47482eb0784077ee3faf498d531497304Andres Morales 116be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final int mTransferId; // Unique ID of this transfer used for notifications 1173ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales int mBluetoothTransferId; // ID of this transfer in Bluetooth namespace 118fbd59bd47482eb0784077ee3faf498d531497304Andres Morales 119be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final PendingIntent mCancelIntent; 120be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final Context mContext; 121be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final Handler mHandler; 122be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final NotificationManager mNotificationManager; 123be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final BluetoothDevice mRemoteDevice; 124be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project final Callback mCallback; 125b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales final boolean mRemoteActivating; 126be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 127be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // Variables below are only accessed on the main thread 128be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project int mState; 129d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen int mCurrentCount; 130d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen int mSuccessCount; 131d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen int mTotalCount; 132b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales int mDataLinkType; 133be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project boolean mCalledBack; 134be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Long mLastUpdate; // Last time an event occurred for this transfer 135be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project float mProgress; // Progress in range [0..1] 136fbd59bd47482eb0784077ee3faf498d531497304Andres Morales ArrayList<Uri> mUris; // Received uris from transport 137fbd59bd47482eb0784077ee3faf498d531497304Andres Morales ArrayList<String> mTransferMimeTypes; // Mime-types received from transport 138b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Uri[] mOutgoingUris; // URIs to send 139be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project ArrayList<String> mPaths; // Raw paths on the filesystem for Beam-stored files 140be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project HashMap<String, String> mMimeTypes; // Mime-types associated with each path 141be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project HashMap<String, Uri> mMediaUris; // URIs found by the media scanner for each path 142be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project int mUrisScanned; 143b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Long mStartTime; 144be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 145b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales public BeamTransferManager(Context context, Callback callback, 146b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales BeamTransferRecord pendingTransfer, boolean incoming) { 147be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mContext = context; 148be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mCallback = callback; 149be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mRemoteDevice = pendingTransfer.remoteDevice; 150b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mIncoming = incoming; 151be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mTransferId = pendingTransfer.id; 1523ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales mBluetoothTransferId = -1; 153b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mDataLinkType = pendingTransfer.dataLinkType; 154b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mRemoteActivating = pendingTransfer.remoteActivating; 155b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mStartTime = 0L; 156d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen // For incoming transfers, count can be set later 157d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mTotalCount = (pendingTransfer.uris != null) ? pendingTransfer.uris.length : 0; 158be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mLastUpdate = SystemClock.elapsedRealtime(); 159be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mProgress = 0.0f; 160be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mState = STATE_NEW; 161b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mUris = pendingTransfer.uris == null 162b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales ? new ArrayList<Uri>() 163b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales : new ArrayList<Uri>(Arrays.asList(pendingTransfer.uris)); 164fbd59bd47482eb0784077ee3faf498d531497304Andres Morales mTransferMimeTypes = new ArrayList<String>(); 165be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mMimeTypes = new HashMap<String, String>(); 166fbd59bd47482eb0784077ee3faf498d531497304Andres Morales mPaths = new ArrayList<String>(); 167be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mMediaUris = new HashMap<String, Uri>(); 168b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mCancelIntent = buildCancelIntent(); 169be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mUrisScanned = 0; 170d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mCurrentCount = 0; 171d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mSuccessCount = 0; 172fbd59bd47482eb0784077ee3faf498d531497304Andres Morales mOutgoingUris = pendingTransfer.uris; 173be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mHandler = new Handler(Looper.getMainLooper(), this); 174be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mHandler.sendEmptyMessageDelayed(MSG_TRANSFER_TIMEOUT, ALIVE_CHECK_MS); 175be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mNotificationManager = (NotificationManager) mContext.getSystemService( 176be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Context.NOTIFICATION_SERVICE); 1773cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi NotificationChannel notificationChannel = new NotificationChannel( 1783cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi BEAM_NOTIFICATION_CHANNEL, mContext.getString(R.string.app_name), 1793cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi NotificationManager.IMPORTANCE_HIGH); 1803cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi mNotificationManager.createNotificationChannel(notificationChannel); 181be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 182be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 183be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project void whitelistOppDevice(BluetoothDevice device) { 184be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP"); 185b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Intent intent = new Intent(ACTION_WHITELIST_DEVICE); 186073f0981e3920c085a57ff46f7f41bf329071c89Akinobu Nakashima intent.setPackage(mContext.getString(R.string.bluetooth_package)); 187be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 188be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); 189be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 190be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 191b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales public void start() { 192b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (mStartTime > 0) { 193b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales // already started 194b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales return; 195b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 196b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 197b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mStartTime = System.currentTimeMillis(); 198b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 199b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (!mIncoming) { 200b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) { 201b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales new BluetoothOppHandover(mContext, mRemoteDevice, mUris, mRemoteActivating).start(); 202b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 203b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 204b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 205b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 206be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project public void updateFileProgress(float progress) { 207be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (!isRunning()) return; // Ignore when we're no longer running 208be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 209be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mHandler.removeMessages(MSG_NEXT_TRANSFER_TIMER); 210be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 211be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project this.mProgress = progress; 212be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 213be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // We're still receiving data from this device - keep it in 214be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // the whitelist for a while longer 215fbd59bd47482eb0784077ee3faf498d531497304Andres Morales if (mIncoming && mRemoteDevice != null) whitelistOppDevice(mRemoteDevice); 216be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 217be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateStateAndNotification(STATE_IN_PROGRESS); 218be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 219be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 2203ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales public synchronized void setBluetoothTransferId(int id) { 2213ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales if (mBluetoothTransferId == -1 && id != -1) { 2223ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales mBluetoothTransferId = id; 2233ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales if (mState == STATE_CANCELLING) { 2243ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales sendBluetoothCancelIntentAndUpdateState(); 2253ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales } 2263ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales } 2273ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales } 2283ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales 229be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project public void finishTransfer(boolean success, Uri uri, String mimeType) { 230be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (!isRunning()) return; // Ignore when we're no longer running 231be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 232d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mCurrentCount++; 233be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (success && uri != null) { 234d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mSuccessCount++; 235be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (DBG) Log.d(TAG, "Transfer success, uri " + uri + " mimeType " + mimeType); 236d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mProgress = 0.0f; 237be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (mimeType == null) { 238fbd59bd47482eb0784077ee3faf498d531497304Andres Morales mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, uri); 239be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 240be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (mimeType != null) { 241fbd59bd47482eb0784077ee3faf498d531497304Andres Morales mUris.add(uri); 242fbd59bd47482eb0784077ee3faf498d531497304Andres Morales mTransferMimeTypes.add(mimeType); 243be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 244be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (DBG) Log.d(TAG, "Could not get mimeType for file."); 245be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 246be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 247be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Log.e(TAG, "Handover transfer failed"); 248be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // Do wait to see if there's another file coming. 249be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 250be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mHandler.removeMessages(MSG_NEXT_TRANSFER_TIMER); 251d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen if (mCurrentCount == mTotalCount) { 252d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen if (mIncoming) { 253d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen processFiles(); 254d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } else { 255d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen updateStateAndNotification(mSuccessCount > 0 ? STATE_SUCCESS : STATE_FAILED); 256d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } 257d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } else { 258d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mHandler.sendEmptyMessageDelayed(MSG_NEXT_TRANSFER_TIMER, WAIT_FOR_NEXT_TRANSFER_MS); 259d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen updateStateAndNotification(STATE_W4_NEXT_TRANSFER); 260d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } 261be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 262be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 263be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project public boolean isRunning() { 2641c517e0f7d2162ec6bfbda964adf45ca69faa694george.kg_chang if (mState != STATE_NEW && mState != STATE_IN_PROGRESS && mState != STATE_W4_NEXT_TRANSFER 2651c517e0f7d2162ec6bfbda964adf45ca69faa694george.kg_chang && mState != STATE_CANCELLING) { 266be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return false; 267be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 268be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return true; 269be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 270be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 271be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 272d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen public void setObjectCount(int objectCount) { 273d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mTotalCount = objectCount; 274d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } 275d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen 276be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project void cancel() { 277be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (!isRunning()) return; 278be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 279be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // Delete all files received so far 280fbd59bd47482eb0784077ee3faf498d531497304Andres Morales for (Uri uri : mUris) { 281be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project File file = new File(uri.getPath()); 282be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (file.exists()) file.delete(); 283be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 284be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 2853ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales if (mBluetoothTransferId != -1) { 2863ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales // we know the ID, we can cancel immediately 2873ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales sendBluetoothCancelIntentAndUpdateState(); 2883ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales } else { 2893ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales updateStateAndNotification(STATE_CANCELLING); 2903ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales } 2913ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales 2923ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales } 2933ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales 2943ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales private void sendBluetoothCancelIntentAndUpdateState() { 295b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Intent cancelIntent = new Intent(ACTION_STOP_BLUETOOTH_TRANSFER); 296073f0981e3920c085a57ff46f7f41bf329071c89Akinobu Nakashima cancelIntent.setPackage(mContext.getString(R.string.bluetooth_package)); 297b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales cancelIntent.putExtra(BeamStatusReceiver.EXTRA_TRANSFER_ID, mBluetoothTransferId); 2983ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales mContext.sendBroadcast(cancelIntent); 299be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateStateAndNotification(STATE_CANCELLED); 300be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 301be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 302be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project void updateNotification() { 3033cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi Builder notBuilder = new Notification.Builder(mContext, BEAM_NOTIFICATION_CHANNEL); 304524777046191da324fc08881a103d0567cf91519Selim Cinek notBuilder.setColor(mContext.getResources().getColor( 305524777046191da324fc08881a103d0567cf91519Selim Cinek com.android.internal.R.color.system_notification_accent_color)); 3061a0e18c0ba2236275fdc53a01adcf8d09b185c19Martijn Coenen notBuilder.setWhen(mStartTime); 30797c433e213ed7ccdbac300da7577fbb9dd6cd1fcAndres Morales notBuilder.setVisibility(Notification.VISIBILITY_PUBLIC); 3083cdb596c8e3a19515545eb060696fa2a335b9db0Ruchi Kandoi notBuilder.setOnlyAlertOnce(true); 309d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen String beamString; 310d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen if (mIncoming) { 311d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen beamString = mContext.getString(R.string.beam_progress); 312d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } else { 313d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen beamString = mContext.getString(R.string.beam_outgoing); 314d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } 315be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (mState == STATE_NEW || mState == STATE_IN_PROGRESS || 316be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mState == STATE_W4_NEXT_TRANSFER || mState == STATE_W4_MEDIA_SCANNER) { 317be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setAutoCancel(false); 31870fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download : 31970fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen android.R.drawable.stat_sys_upload); 320d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen notBuilder.setTicker(beamString); 321d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen notBuilder.setContentTitle(beamString); 322be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.addAction(R.drawable.ic_menu_cancel_holo_dark, 323be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mContext.getString(R.string.cancel), mCancelIntent); 324d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen float progress = 0; 325d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen if (mTotalCount > 0) { 326d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen float progressUnit = 1.0f / mTotalCount; 327d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen progress = (float) mCurrentCount * progressUnit + mProgress * progressUnit; 328d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } 329d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen if (mTotalCount > 0 && progress > 0) { 330d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen notBuilder.setProgress(100, (int) (100 * progress), false); 331d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } else { 332d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen notBuilder.setProgress(100, 0, true); 333d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } 334be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else if (mState == STATE_SUCCESS) { 335be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setAutoCancel(true); 33670fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download_done : 33770fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen android.R.drawable.stat_sys_upload_done); 338be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setTicker(mContext.getString(R.string.beam_complete)); 339be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setContentTitle(mContext.getString(R.string.beam_complete)); 340be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 341d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen if (mIncoming) { 342b2e735d7e1de4fda8b4d34096b8dce275fe52844Martijn Coenen notBuilder.setContentText(mContext.getString(R.string.beam_tap_to_view)); 343d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen Intent viewIntent = buildViewIntent(); 344d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen PendingIntent contentIntent = PendingIntent.getActivity( 345d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen mContext, mTransferId, viewIntent, 0, null); 346be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 347d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen notBuilder.setContentIntent(contentIntent); 348d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen } 349be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else if (mState == STATE_FAILED) { 350be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setAutoCancel(false); 35170fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download_done : 35270fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen android.R.drawable.stat_sys_upload_done); 353be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setTicker(mContext.getString(R.string.beam_failed)); 354be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setContentTitle(mContext.getString(R.string.beam_failed)); 3553ee12128efdf8f96d7921429b4b9e20b55943eb6Andres Morales } else if (mState == STATE_CANCELLED || mState == STATE_CANCELLING) { 356be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setAutoCancel(false); 35770fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download_done : 35870fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen android.R.drawable.stat_sys_upload_done); 359be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setTicker(mContext.getString(R.string.beam_canceled)); 360be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project notBuilder.setContentTitle(mContext.getString(R.string.beam_canceled)); 361be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 362be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return; 363be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 364be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 365be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mNotificationManager.notify(null, mTransferId, notBuilder.build()); 366be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 367be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 368be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project void updateStateAndNotification(int newState) { 369be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project this.mState = newState; 370be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project this.mLastUpdate = SystemClock.elapsedRealtime(); 371be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 372f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen mHandler.removeMessages(MSG_TRANSFER_TIMEOUT); 373f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen if (isRunning()) { 374f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen // Update timeout timer if we're still running 375be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mHandler.sendEmptyMessageDelayed(MSG_TRANSFER_TIMEOUT, ALIVE_CHECK_MS); 376be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 377be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 378be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateNotification(); 379be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 380be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if ((mState == STATE_SUCCESS || mState == STATE_FAILED || mState == STATE_CANCELLED) 381be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project && !mCalledBack) { 382be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mCalledBack = true; 383be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // Notify that we're done with this transfer 384be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mCallback.onTransferComplete(this, mState == STATE_SUCCESS); 385be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 386be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 387be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 388be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project void processFiles() { 389be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // Check the amount of files we received in this transfer; 390be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // If more than one, create a separate directory for it. 391be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String extRoot = Environment.getExternalStorageDirectory().getPath(); 392be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project File beamPath = new File(extRoot + "/" + BEAM_DIR); 393be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 394fbd59bd47482eb0784077ee3faf498d531497304Andres Morales if (!checkMediaStorage(beamPath) || mUris.size() == 0) { 395be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Log.e(TAG, "Media storage not valid or no uris received."); 396be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateStateAndNotification(STATE_FAILED); 397be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return; 398be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 399be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 400fbd59bd47482eb0784077ee3faf498d531497304Andres Morales if (mUris.size() > 1) { 401be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project beamPath = generateMultiplePath(extRoot + "/" + BEAM_DIR + "/"); 402be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (!beamPath.isDirectory() && !beamPath.mkdir()) { 403be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Log.e(TAG, "Failed to create multiple path " + beamPath.toString()); 404be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateStateAndNotification(STATE_FAILED); 405be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return; 406be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 407be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 408be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 409fbd59bd47482eb0784077ee3faf498d531497304Andres Morales for (int i = 0; i < mUris.size(); i++) { 410fbd59bd47482eb0784077ee3faf498d531497304Andres Morales Uri uri = mUris.get(i); 411fbd59bd47482eb0784077ee3faf498d531497304Andres Morales String mimeType = mTransferMimeTypes.get(i); 412be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 413be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project File srcFile = new File(uri.getPath()); 414be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 415be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project File dstFile = generateUniqueDestination(beamPath.getAbsolutePath(), 416be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project uri.getLastPathSegment()); 417fbd59bd47482eb0784077ee3faf498d531497304Andres Morales Log.d(TAG, "Renaming from " + srcFile); 418be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (!srcFile.renameTo(dstFile)) { 419be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (DBG) Log.d(TAG, "Failed to rename from " + srcFile + " to " + dstFile); 420be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project srcFile.delete(); 421be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return; 422be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 423be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mPaths.add(dstFile.getAbsolutePath()); 424be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mMimeTypes.put(dstFile.getAbsolutePath(), mimeType); 425be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (DBG) Log.d(TAG, "Did successful rename from " + srcFile + " to " + dstFile); 426be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 427be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 428be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 429be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // We can either add files to the media provider, or provide an ACTION_VIEW 430be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // intent to the file directly. We base this decision on the mime type 431be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // of the first file; if it's media the platform can deal with, 432be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // use the media provider, if it's something else, just launch an ACTION_VIEW 433be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // on the file. 434be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String mimeType = mMimeTypes.get(mPaths.get(0)); 435be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (mimeType.startsWith("image/") || mimeType.startsWith("video/") || 436be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mimeType.startsWith("audio/")) { 437be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String[] arrayPaths = new String[mPaths.size()]; 438be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project MediaScannerConnection.scanFile(mContext, mPaths.toArray(arrayPaths), null, this); 439be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateStateAndNotification(STATE_W4_MEDIA_SCANNER); 440be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 441be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // We're done. 442be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateStateAndNotification(STATE_SUCCESS); 443be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 444be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 445be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 446be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 447be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project public boolean handleMessage(Message msg) { 448be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (msg.what == MSG_NEXT_TRANSFER_TIMER) { 449be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // We didn't receive a new transfer in time, finalize this one 450be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (mIncoming) { 451be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project processFiles(); 452be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 453d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen updateStateAndNotification(mSuccessCount > 0 ? STATE_SUCCESS : STATE_FAILED); 454be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 455be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return true; 456be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else if (msg.what == MSG_TRANSFER_TIMEOUT) { 457f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen // No update on this transfer for a while, fail it. 458f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen if (DBG) Log.d(TAG, "Transfer timed out for id: " + Integer.toString(mTransferId)); 459f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen updateStateAndNotification(STATE_FAILED); 460be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 461be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return false; 462be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 463be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 464be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project public synchronized void onScanCompleted(String path, Uri uri) { 465be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (DBG) Log.d(TAG, "Scan completed, path " + path + " uri " + uri); 466be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (uri != null) { 467be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mMediaUris.put(path, uri); 468be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 469be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project mUrisScanned++; 470be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (mUrisScanned == mPaths.size()) { 471be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // We're done 472be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project updateStateAndNotification(STATE_SUCCESS); 473be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 474be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 475be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 476be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 477be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Intent buildViewIntent() { 478be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (mPaths.size() == 0) return null; 479be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 480be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Intent viewIntent = new Intent(Intent.ACTION_VIEW); 481be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 482be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String filePath = mPaths.get(0); 483be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Uri mediaUri = mMediaUris.get(filePath); 484be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Uri uri = mediaUri != null ? mediaUri : 485d5567fc2ff2d4e462932b40450f536b7e1a3bf3bJohan Redestig FileProvider.getUriForFile(mContext, "com.google.android.nfc.fileprovider", 486d5567fc2ff2d4e462932b40450f536b7e1a3bf3bJohan Redestig new File(filePath)); 487be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project viewIntent.setDataAndTypeAndNormalize(uri, mMimeTypes.get(filePath)); 488d5567fc2ff2d4e462932b40450f536b7e1a3bf3bJohan Redestig viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | 489d5567fc2ff2d4e462932b40450f536b7e1a3bf3bJohan Redestig Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 490be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return viewIntent; 491be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 492be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 493b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales PendingIntent buildCancelIntent() { 494b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Intent intent = new Intent(BeamStatusReceiver.ACTION_CANCEL_HANDOVER_TRANSFER); 495b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(BeamStatusReceiver.EXTRA_ADDRESS, mRemoteDevice.getAddress()); 496b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(BeamStatusReceiver.EXTRA_INCOMING, mIncoming ? 497b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales BeamStatusReceiver.DIRECTION_INCOMING : BeamStatusReceiver.DIRECTION_OUTGOING); 498d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen PendingIntent pi = PendingIntent.getBroadcast(mContext, mTransferId, intent, 499d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen PendingIntent.FLAG_ONE_SHOT); 500be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 501be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return pi; 502be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 503be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 504b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static boolean checkMediaStorage(File path) { 505b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 506b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (!path.isDirectory() && !path.mkdir()) { 507b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Log.e(TAG, "Not dir or not mkdir " + path.getAbsolutePath()); 508b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales return false; 509b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 510b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales return true; 511b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } else { 512b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Log.e(TAG, "External storage not mounted, can't store file."); 513b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales return false; 514b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 515b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 516b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 517b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static File generateUniqueDestination(String path, String fileName) { 518be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project int dotIndex = fileName.lastIndexOf("."); 519be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String extension = null; 520be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String fileNameWithoutExtension = null; 521be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project if (dotIndex < 0) { 522be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project extension = ""; 523be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project fileNameWithoutExtension = fileName; 524be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } else { 525be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project extension = fileName.substring(dotIndex); 526be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project fileNameWithoutExtension = fileName.substring(0, dotIndex); 527be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 528be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project File dstFile = new File(path + File.separator + fileName); 529be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project int count = 0; 530be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project while (dstFile.exists()) { 531be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project dstFile = new File(path + File.separator + fileNameWithoutExtension + "-" + 532be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Integer.toString(count) + extension); 533be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project count++; 534be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 535be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return dstFile; 536be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 537be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 538b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static File generateMultiplePath(String beamRoot) { 539be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // Generate a unique directory with the date 540be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String format = "yyyy-MM-dd"; 541116dfa0107cdc7ab098ed95828280542bf6b0a1eThe Android Open Source Project SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US); 542be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project String newPath = beamRoot + "beam-" + sdf.format(new Date()); 543be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project File newFile = new File(newPath); 544be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project int count = 0; 545be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project while (newFile.exists()) { 546be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project newPath = beamRoot + "beam-" + sdf.format(new Date()) + "-" + 547be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project Integer.toString(count); 548be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project newFile = new File(newPath); 549be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project count++; 550be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 551be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project return newFile; 552be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project } 553be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project} 554be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project 555