summaryrefslogtreecommitdiffstats
path: root/src/com/android/bluetooth/opp
diff options
context:
space:
mode:
authorJake Hamby <jhamby@google.com>2012-07-27 14:38:32 -0700
committerJake Hamby <jhamby@google.com>2012-09-14 16:00:51 -0700
commitee52ddf33a0ce2cf89cc028136f60ae600c45de5 (patch)
treed12ece24296ebc70d613b0880475f47e9119a4d4 /src/com/android/bluetooth/opp
parentf46f032adaec19a0d0c11b921fb356cbcd7aedbd (diff)
downloadandroid_packages_apps_Bluetooth-ee52ddf33a0ce2cf89cc028136f60ae600c45de5.tar.gz
android_packages_apps_Bluetooth-ee52ddf33a0ce2cf89cc028136f60ae600c45de5.tar.bz2
android_packages_apps_Bluetooth-ee52ddf33a0ce2cf89cc028136f60ae600c45de5.zip
Enable Bluetooth sharing of downloaded files.
Change BT OPP to open the InputStreams of files to share in the BluetoothOppLauncherActivity (or BluetoothOppHandoverReceiver for NFC shares), while the process has grantUriPermission() on the URI's to share. InputStreams are saved inside the existing BluetoothOppSendFileInfo objects, which no longer include the mDestination field because this isn't known at the time the SendFileInfo object is now created (before the user has chosen the destination BT device). These objects are stored in a static ConcurrentHashMap in BluetoothOppUtility and are removed when the file is closed (on success or failure). If the user tries to share thousands of files in one batch, we may not be able to open InputStreams for all of the files in the batch. In this case, the open should fail gracefully. Bug: 6808783 Change-Id: I3f3f86d2dc1a78a837aeb6a888f90b26434ba499
Diffstat (limited to 'src/com/android/bluetooth/opp')
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppManager.java11
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java13
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java65
-rwxr-xr-xsrc/com/android/bluetooth/opp/BluetoothOppService.java37
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppShareInfo.java6
-rwxr-xr-xsrc/com/android/bluetooth/opp/BluetoothOppTransfer.java6
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppUtility.java26
7 files changed, 96 insertions, 68 deletions
diff --git a/src/com/android/bluetooth/opp/BluetoothOppManager.java b/src/com/android/bluetooth/opp/BluetoothOppManager.java
index c99669035..dd8efe01f 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppManager.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppManager.java
@@ -246,12 +246,15 @@ public class BluetoothOppManager {
if (V) Log.v(TAG, "Application data stored to SharedPreference! ");
}
- public void saveSendingFileInfo(String mimeType, String uri, boolean isHandover) {
+ public void saveSendingFileInfo(String mimeType, String uriString, boolean isHandover) {
synchronized (BluetoothOppManager.this) {
mMultipleFlag = false;
mMimeTypeOfSendingFile = mimeType;
- mUriOfSendingFile = uri;
+ mUriOfSendingFile = uriString;
mIsHandoverInitiated = isHandover;
+ Uri uri = Uri.parse(uriString);
+ BluetoothOppUtility.putSendFileInfo(uri,
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType));
storeApplicationData();
}
}
@@ -262,6 +265,10 @@ public class BluetoothOppManager {
mMimeTypeOfSendingFiles = mimeType;
mUrisOfSendingFiles = uris;
mIsHandoverInitiated = isHandover;
+ for (Uri uri : uris) {
+ BluetoothOppUtility.putSendFileInfo(uri,
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType));
+ }
storeApplicationData();
}
}
diff --git a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
index f234203ce..dce7fa3f3 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
@@ -305,8 +305,7 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
private BluetoothOppSendFileInfo processShareInfo() {
if (V) Log.v(TAG, "Client thread processShareInfo() " + mInfo.mId);
- BluetoothOppSendFileInfo fileInfo = BluetoothOppSendFileInfo.generateFileInfo(
- mContext1, mInfo.mUri, mInfo.mMimetype, mInfo.mDestination);
+ BluetoothOppSendFileInfo fileInfo = BluetoothOppUtility.getSendFileInfo(mInfo.mUri);
if (fileInfo.mFileName == null || fileInfo.mLength == 0) {
if (V) Log.v(TAG, "BluetoothOppSendFileInfo get invalid file");
Constants.updateShareStatus(mContext1, mInfo.mId, fileInfo.mStatus);
@@ -343,7 +342,7 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
request.setHeader(HeaderSet.NAME, fileInfo.mFileName);
request.setHeader(HeaderSet.TYPE, fileInfo.mMimetype);
- applyRemoteDeviceQuirks(request, fileInfo);
+ applyRemoteDeviceQuirks(request, mInfo.mDestination, fileInfo.mFileName);
Constants.updateShareStatus(mContext1, mInfo.mId, BluetoothShare.STATUS_RUNNING);
@@ -500,7 +499,8 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
handleSendException(e.toString());
} finally {
try {
- fileInfo.mInputStream.close();
+ // Close InputStream and remove SendFileInfo from map
+ BluetoothOppUtility.closeSendFileInfo(mInfo.mUri);
if (!error) {
responseCode = putOperation.getResponseCode();
if (responseCode != -1) {
@@ -566,8 +566,7 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
}
}
- public static void applyRemoteDeviceQuirks(HeaderSet request, BluetoothOppSendFileInfo info) {
- String address = info.mDestAddr;
+ public static void applyRemoteDeviceQuirks(HeaderSet request, String address, String filename) {
if (address == null) {
return;
}
@@ -576,8 +575,6 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession {
// Rejects filenames with more than one '.'. Rename to '_'.
// for example: 'a.b.jpg' -> 'a_b.jpg'
// 'abc.jpg' NOT CHANGED
- String filename = info.mFileName;
-
char[] c = filename.toCharArray();
boolean firstDot = true;
boolean modified = false;
diff --git a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
index ec879f05c..81c3c92cd 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
@@ -32,19 +32,18 @@
package com.android.bluetooth.opp;
-import java.io.File;
-import java.io.IOException;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-
-import android.util.Log;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
-import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
/**
* This class stores information about a single sending file It will only be
@@ -57,6 +56,10 @@ public class BluetoothOppSendFileInfo {
private static final boolean V = Constants.VERBOSE;
+ /** Reusable SendFileInfo for error status. */
+ static final BluetoothOppSendFileInfo SEND_FILE_INFO_ERROR = new BluetoothOppSendFileInfo(
+ null, null, 0, null, BluetoothShare.STATUS_FILE_ERROR);
+
/** readable media file name */
public final String mFileName;
@@ -72,46 +75,40 @@ public class BluetoothOppSendFileInfo {
public final long mLength;
- public final String mDestAddr;
-
/** for media file */
public BluetoothOppSendFileInfo(String fileName, String type, long length,
- FileInputStream inputStream, int status, String dest) {
+ FileInputStream inputStream, int status) {
mFileName = fileName;
mMimetype = type;
mLength = length;
mInputStream = inputStream;
mStatus = status;
- mDestAddr = dest;
mData = null;
}
/** for vCard, or later for vCal, vNote. Not used currently */
- public BluetoothOppSendFileInfo(String data, String type, long length, int status,
- String dest) {
+ public BluetoothOppSendFileInfo(String data, String type, long length, int status) {
mFileName = null;
mInputStream = null;
mData = data;
mMimetype = type;
mLength = length;
mStatus = status;
- mDestAddr = dest;
}
- public static BluetoothOppSendFileInfo generateFileInfo(Context context, String uri,
- String type, String dest) {
+ public static BluetoothOppSendFileInfo generateFileInfo(Context context, Uri uri,
+ String type) {
ContentResolver contentResolver = context.getContentResolver();
- Uri u = Uri.parse(uri);
- String scheme = u.getScheme();
+ String scheme = uri.getScheme();
String fileName = null;
- String contentType = null;
+ String contentType;
long length = 0;
// Support all Uri with "content" scheme
// This will allow more 3rd party applications to share files via
// bluetooth
- if (scheme.equals("content")) {
- contentType = contentResolver.getType(u);
- Cursor metadataCursor = contentResolver.query(u, new String[] {
+ if ("content".equals(scheme)) {
+ contentType = contentResolver.getType(uri);
+ Cursor metadataCursor = contentResolver.query(uri, new String[] {
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
}, null, null, null);
if (metadataCursor != null) {
@@ -125,25 +122,23 @@ public class BluetoothOppSendFileInfo {
metadataCursor.close();
}
}
- } else if (scheme.equals("file")) {
- fileName = u.getLastPathSegment();
+ } else if ("file".equals(scheme)) {
+ fileName = uri.getLastPathSegment();
contentType = type;
- File f = new File(u.getPath());
+ File f = new File(uri.getPath());
length = f.length();
} else {
// currently don't accept other scheme
- return new BluetoothOppSendFileInfo(null, null, 0, null,
- BluetoothShare.STATUS_FILE_ERROR, dest);
+ return SEND_FILE_INFO_ERROR;
}
FileInputStream is = null;
if (scheme.equals("content")) {
- AssetFileDescriptor fd = null;
try {
// We've found that content providers don't always have the
// right size in _OpenableColumns.SIZE
// As a second source of getting the correct file length,
// get a file descriptor and get the stat length
- fd = contentResolver.openAssetFileDescriptor(u, "r");
+ AssetFileDescriptor fd = contentResolver.openAssetFileDescriptor(uri, "r");
long statLength = fd.getLength();
if (length != statLength && statLength > 0) {
Log.e(TAG, "Content provider length is wrong (" + Long.toString(length) +
@@ -154,7 +149,7 @@ public class BluetoothOppSendFileInfo {
// This creates an auto-closing input-stream, so
// the file descriptor will be closed whenever the InputStream
// is closed.
- is = (FileInputStream)fd.createInputStream();
+ is = fd.createInputStream();
} catch (IOException e) {
try {
fd.close();
@@ -168,10 +163,9 @@ public class BluetoothOppSendFileInfo {
}
if (is == null) {
try {
- is = (FileInputStream)contentResolver.openInputStream(u);
+ is = (FileInputStream) contentResolver.openInputStream(uri);
} catch (FileNotFoundException e) {
- return new BluetoothOppSendFileInfo(null, null, 0, null,
- BluetoothShare.STATUS_FILE_ERROR, dest);
+ return SEND_FILE_INFO_ERROR;
}
}
// If we can not get file length from content provider, we can try to
@@ -182,11 +176,10 @@ public class BluetoothOppSendFileInfo {
if (V) Log.v(TAG, "file length is " + length);
} catch (IOException e) {
Log.e(TAG, "Read stream exception: ", e);
- return new BluetoothOppSendFileInfo(null, null, 0, null,
- BluetoothShare.STATUS_FILE_ERROR, dest);
+ return SEND_FILE_INFO_ERROR;
}
}
- return new BluetoothOppSendFileInfo(fileName, contentType, length, is, 0, dest);
+ return new BluetoothOppSendFileInfo(fileName, contentType, length, is, 0);
}
}
diff --git a/src/com/android/bluetooth/opp/BluetoothOppService.java b/src/com/android/bluetooth/opp/BluetoothOppService.java
index 5a304335c..902000614 100755
--- a/src/com/android/bluetooth/opp/BluetoothOppService.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppService.java
@@ -543,9 +543,18 @@ public class BluetoothOppService extends Service {
}
private void insertShare(Cursor cursor, int arrayPos) {
+ String uriString = cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.URI));
+ Uri uri;
+ if (uriString != null) {
+ uri = Uri.parse(uriString);
+ Log.d(TAG, "insertShare parsed URI: " + uri);
+ } else {
+ uri = null;
+ Log.e(TAG, "insertShare found null URI at cursor!");
+ }
BluetoothOppShareInfo info = new BluetoothOppShareInfo(
cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.URI)),
+ uri,
cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)),
cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare._DATA)),
cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.MIMETYPE)),
@@ -597,23 +606,12 @@ public class BluetoothOppService extends Service {
if (info.isReadyToStart()) {
if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
/* check if the file exists */
- InputStream i;
- try {
- i = getContentResolver().openInputStream(Uri.parse(info.mUri));
- } catch (FileNotFoundException e) {
+ BluetoothOppSendFileInfo sendFileInfo = BluetoothOppUtility.getSendFileInfo(
+ info.mUri);
+ if (sendFileInfo == null || sendFileInfo.mInputStream == null) {
Log.e(TAG, "Can't open file for OUTBOUND info " + info.mId);
Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_BAD_REQUEST);
- return;
- } catch (SecurityException e) {
- Log.e(TAG, "Exception:" + e.toString() + " for OUTBOUND info " + info.mId);
- Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_BAD_REQUEST);
- return;
- }
-
- try {
- i.close();
- } catch (IOException ex) {
- Log.e(TAG, "IO error when close file for OUTBOUND info " + info.mId);
+ BluetoothOppUtility.closeSendFileInfo(info.mUri);
return;
}
}
@@ -678,7 +676,12 @@ public class BluetoothOppService extends Service {
int statusColumn = cursor.getColumnIndexOrThrow(BluetoothShare.STATUS);
info.mId = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID));
- info.mUri = stringFromCursor(info.mUri, cursor, BluetoothShare.URI);
+ if (info.mUri != null) {
+ info.mUri = Uri.parse(stringFromCursor(info.mUri.toString(), cursor,
+ BluetoothShare.URI));
+ } else {
+ Log.d(TAG, "updateShare() called for ID " + info.mId + " with null URI");
+ }
info.mHint = stringFromCursor(info.mHint, cursor, BluetoothShare.FILENAME_HINT);
info.mFilename = stringFromCursor(info.mFilename, cursor, BluetoothShare._DATA);
info.mMimetype = stringFromCursor(info.mMimetype, cursor, BluetoothShare.MIMETYPE);
diff --git a/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java b/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java
index da57bd20e..32f6b3cb3 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java
@@ -32,6 +32,8 @@
package com.android.bluetooth.opp;
+import android.net.Uri;
+
/**
* This class stores information about a single OBEX share, e.g. one object
* send/receive to a destination address.
@@ -40,7 +42,7 @@ public class BluetoothOppShareInfo {
public int mId;
- public String mUri;
+ public Uri mUri;
public String mHint;
@@ -66,7 +68,7 @@ public class BluetoothOppShareInfo {
public boolean mMediaScanned;
- public BluetoothOppShareInfo(int id, String uri, String hint, String filename, String mimetype,
+ public BluetoothOppShareInfo(int id, Uri uri, String hint, String filename, String mimetype,
int direction, String destination, int visibility, int confirm, int status,
int totalBytes, int currentBytes, int timestamp, boolean mediaScanned) {
mId = id;
diff --git a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
index 44d9bb68e..2be679c04 100755
--- a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
@@ -315,9 +315,9 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
updateValues.put(BluetoothShare.STATUS, info.mStatus);
/* Update un-processed outbound transfer to show some info */
if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
- BluetoothOppSendFileInfo fileInfo = null;
- fileInfo = BluetoothOppSendFileInfo.generateFileInfo(mContext, info.mUri,
- info.mMimetype, info.mDestination);
+ BluetoothOppSendFileInfo fileInfo
+ = BluetoothOppUtility.getSendFileInfo(info.mUri);
+ BluetoothOppUtility.closeSendFileInfo(info.mUri);
if (fileInfo.mFileName != null) {
updateValues.put(BluetoothShare.FILENAME_HINT, fileInfo.mFileName);
updateValues.put(BluetoothShare.TOTAL_BYTES, fileInfo.mLength);
diff --git a/src/com/android/bluetooth/opp/BluetoothOppUtility.java b/src/com/android/bluetooth/opp/BluetoothOppUtility.java
index df26bd235..7e03281da 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppUtility.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppUtility.java
@@ -49,8 +49,10 @@ import android.database.Cursor;
import android.util.Log;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
/**
* This class has some utilities for Opp application;
@@ -60,6 +62,9 @@ public class BluetoothOppUtility {
private static final boolean D = Constants.DEBUG;
private static final boolean V = Constants.VERBOSE;
+ private static final ConcurrentHashMap<Uri, BluetoothOppSendFileInfo> sSendFileMap
+ = new ConcurrentHashMap<Uri, BluetoothOppSendFileInfo>();
+
public static BluetoothOppTransferInfo queryRecord(Context context, Uri uri) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothOppTransferInfo info = new BluetoothOppTransferInfo();
@@ -303,4 +308,25 @@ public class BluetoothOppUtility {
transInfo.mDeviceName);
}
+ static void putSendFileInfo(Uri uri, BluetoothOppSendFileInfo sendFileInfo) {
+ if (D) Log.d(TAG, "putSendFileInfo: uri=" + uri + " sendFileInfo=" + sendFileInfo);
+ sSendFileMap.put(uri, sendFileInfo);
+ }
+
+ static BluetoothOppSendFileInfo getSendFileInfo(Uri uri) {
+ if (D) Log.d(TAG, "getSendFileInfo: uri=" + uri);
+ BluetoothOppSendFileInfo info = sSendFileMap.get(uri);
+ return (info != null) ? info : BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR;
+ }
+
+ static void closeSendFileInfo(Uri uri) {
+ if (D) Log.d(TAG, "closeSendFileInfo: uri=" + uri);
+ BluetoothOppSendFileInfo info = sSendFileMap.remove(uri);
+ if (info != null) {
+ try {
+ info.mInputStream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
}