安卓12 蓝牙接收文件默认保存到downloads目录
修改为bluetooth
主要修改BluetoothOppObexServerSession.java
BluetoothOppReceiveFileInfo.java
.../opp/BluetoothOppObexServerSession.java | 37 ++--
.../opp/BluetoothOppReceiveFileInfo.java | 165 ++++++++++++++----
2 files changed, 149 insertions(+), 53 deletions(-)
mode change 100644 => 100755 vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
mode change 100644 => 100755 vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java
diff --git a/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java b/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
old mode 100644
new mode 100755
index 6a8013dd59..a74789cc7f
--- a/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
+++ b/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
@@ -48,10 +48,10 @@ import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.BluetoothObexTransport;
import com.android.bluetooth.btservice.MetricsLogger;
-import java.io.FileNotFoundException;
+import java.io.BufferedOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.util.Arrays;
import javax.obex.HeaderSet;
@@ -109,7 +109,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
private String destination;
public BluetoothOppObexServerSession(Context context, ObexTransport transport,
- BluetoothOppService service) {
+ BluetoothOppService service) {
mContext = context;
mTransport = transport;
mBluetoothOppService = service;
@@ -368,16 +368,14 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
}
- if (mFileInfo.mFileName != null && mFileInfo.mInsertUri != null) {
+ if (mFileInfo.mFileName != null) {
ContentValues updateValues = new ContentValues();
contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId);
updateValues.put(BluetoothShare._DATA, mFileInfo.mFileName);
updateValues.put(BluetoothShare.STATUS, BluetoothShare.STATUS_RUNNING);
- updateValues.put(BluetoothShare.URI, mFileInfo.mInsertUri.toString());
mContext.getContentResolver().update(contentUri, updateValues, null, null);
- mInfo.mUri = mFileInfo.mInsertUri;
status = receiveFile(mFileInfo, op);
/*
* TODO map status to obex response code
@@ -414,8 +412,13 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
*/
Log.i(TAG, "Rejected incoming request");
- if (mFileInfo.mInsertUri != null) {
- mContext.getContentResolver().delete(mFileInfo.mInsertUri, null, null);
+ if (mFileInfo.mFileName != null) {
+ try {
+ mFileInfo.mOutputStream.close();
+ } catch (IOException e) {
+ Log.e(TAG, "error close file stream");
+ }
+ new File(mFileInfo.mFileName).delete();
}
// set status as local cancel
status = BluetoothShare.STATUS_CANCELED;
@@ -437,7 +440,8 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
*/
long beginTime = 0;
int status = -1;
- OutputStream os = null;
+ BufferedOutputStream bos = null;
+
InputStream is = null;
boolean error = false;
try {
@@ -461,12 +465,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
long prevPercent = 0;
if (!error) {
- try {
- os = mContext.getContentResolver().openOutputStream(fileInfo.mInsertUri);
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Error when openOutputStream");
- error = true;
- }
+ bos = new BufferedOutputStream(fileInfo.mOutputStream, 0x10000);
}
if (!error) {
@@ -493,7 +492,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
break;
}
- os.write(b, 0, readLength);
+ bos.write(b, 0, readLength);
position += readLength;
percent = position * 100 / fileInfo.mLength;
currentTime = SystemClock.elapsedRealtime();
@@ -555,10 +554,9 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
}
}
- if (os != null) {
+ if (bos != null) {
try {
- os.flush();
- os.close();
+ bos.close();
} catch (IOException e) {
Log.e(TAG, "Error when closing stream after send");
}
@@ -669,3 +667,4 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
}
}
}
+
diff --git a/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java b/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java
old mode 100644
new mode 100755
index 1589988db4..c53fceeb9b
--- a/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java
+++ b/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java
@@ -38,13 +38,15 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
-import android.provider.MediaStore;
+import android.os.StatFs;
+import android.os.SystemClock;
import android.util.Log;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
+import java.util.Random;
/**
* This class stores information about a single receiving file. It will only be
@@ -56,8 +58,8 @@ public class BluetoothOppReceiveFileInfo {
private static final boolean V = Constants.VERBOSE;
private static String sDesiredStoragePath = null;
- /* To truncate the name of the received file if the length exceeds 237 */
- private static final int OPP_LENGTH_OF_FILE_NAME = 237;
+ /* To truncate the name of the received file if the length exceeds 245 */
+ private static final int OPP_LENGTH_OF_FILE_NAME = 244;
/** absolute store file name */
@@ -65,22 +67,23 @@ public class BluetoothOppReceiveFileInfo {
public long mLength;
+ public FileOutputStream mOutputStream;
+
public int mStatus;
public String mData;
- public Uri mInsertUri;
-
public BluetoothOppReceiveFileInfo(String data, long length, int status) {
mData = data;
mStatus = status;
mLength = length;
}
- public BluetoothOppReceiveFileInfo(String filename, long length, Uri insertUri, int status) {
+ public BluetoothOppReceiveFileInfo(String filename, long length, FileOutputStream outputStream,
+ int status) {
mFileName = filename;
+ mOutputStream = outputStream;
mStatus = status;
- mInsertUri = insertUri;
mLength = length;
}
@@ -110,13 +113,39 @@ public class BluetoothOppReceiveFileInfo {
}
}
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ File base = null;
+ StatFs stat = null;
+
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ String root = Environment.getExternalStorageDirectory().getPath();
+ base = new File(root + Constants.DEFAULT_STORE_SUBDIR);
+ if (!base.isDirectory() && !base.mkdir()) {
+ if (D) {
+ Log.d(Constants.TAG,
+ "Receive File aborted - can't create base directory " + base.getPath());
+ }
+ return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
+ }
+ stat = new StatFs(base.getPath());
+ } else {
if (D) {
Log.d(Constants.TAG, "Receive File aborted - no external storage");
}
return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_ERROR_NO_SDCARD);
}
+ /*
+ * Check whether there's enough space on the target filesystem to save
+ * the file. Put a bit of margin (in case creating the file grows the
+ * system by a few blocks).
+ */
+ if (stat.getBlockSizeLong() * (stat.getAvailableBlocksLong() - 4) < length) {
+ if (D) {
+ Log.d(Constants.TAG, "Receive File aborted - not enough free space");
+ }
+ return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_ERROR_SDCARD_FULL);
+ }
+
filename = choosefilename(hint);
if (filename == null) {
// should not happen. It must be pre-rejected
@@ -140,13 +169,13 @@ public class BluetoothOppReceiveFileInfo {
}
if (filename.getBytes().length > OPP_LENGTH_OF_FILE_NAME) {
- /* Including extn of the file, Linux supports 255 character as a maximum length of the
- * file name to be created. Hence, Instead of sending OBEX_HTTP_INTERNAL_ERROR,
- * as a response, truncate the length of the file name and save it. This check majorly
- * helps in the case of vcard, where Phone book app supports contact name to be saved
- * more than 255 characters, But the server rejects the card just because the length of
- * vcf file name received exceeds 255 Characters.
- */
+ /* Including extn of the file, Linux supports 255 character as a maximum length of the
+ * file name to be created. Hence, Instead of sending OBEX_HTTP_INTERNAL_ERROR,
+ * as a response, truncate the length of the file name and save it. This check majorly
+ * helps in the case of vcard, where Phone book app supports contact name to be saved
+ * more than 255 characters, But the server rejects the card just because the length of
+ * vcf file name received exceeds 255 Characters.
+ */
Log.i(Constants.TAG, " File Name Length :" + filename.length());
Log.i(Constants.TAG, " File Name Length in Bytes:" + filename.getBytes().length);
@@ -163,33 +192,100 @@ public class BluetoothOppReceiveFileInfo {
}
}
- DateFormat dateFormat = new SimpleDateFormat("_hhmmss");
- String currentTime = dateFormat.format(Calendar.getInstance().getTime());
- String fullfilename = filename + currentTime + extension;
+ filename = base.getPath() + File.separator + filename;
+ // Generate a unique filename, create the file, return it.
+ String fullfilename = chooseUniquefilename(filename, extension);
+ if (!safeCanonicalPath(fullfilename)) {
+ // If this second check fails, then we better reject the transfer
+ return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
+ }
if (V) {
Log.v(Constants.TAG, "Generated received filename " + fullfilename);
}
- Uri insertUri = null;
- ContentValues mediaContentValues = new ContentValues();
- mediaContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fullfilename);
- mediaContentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
- mediaContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,
- Environment.DIRECTORY_DOWNLOADS);
- insertUri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI,
- mediaContentValues);
+ if (fullfilename != null) {
+ try {
+ new FileOutputStream(fullfilename).close();
+ int index = fullfilename.lastIndexOf('/') + 1;
+ // update display name
+ if (index > 0) {
+ String displayName = fullfilename.substring(index);
+ if (V) {
+ Log.v(Constants.TAG, "New display name " + displayName);
+ }
+ ContentValues updateValues = new ContentValues();
+ updateValues.put(BluetoothShare.FILENAME_HINT, displayName);
+ context.getContentResolver().update(contentUri, updateValues, null, null);
- if (insertUri == null) {
- if (D) {
- Log.e(Constants.TAG, "Error when creating file " + fullfilename);
+ }
+ return new BluetoothOppReceiveFileInfo(fullfilename, length,
+ new FileOutputStream(fullfilename), 0);
+ } catch (IOException e) {
+ if (D) {
+ Log.e(Constants.TAG, "Error when creating file " + fullfilename);
+ }
+ return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
}
+ } else {
return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
}
- Log.d(Constants.TAG, "file crated, insertUri:" + insertUri.toString());
+ }
+
+ private static boolean safeCanonicalPath(String uniqueFileName) {
+ try {
+ File receiveFile = new File(uniqueFileName);
+ if (sDesiredStoragePath == null) {
+ sDesiredStoragePath = Environment.getExternalStorageDirectory().getPath()
+ + Constants.DEFAULT_STORE_SUBDIR;
+ }
+ String canonicalPath = receiveFile.getCanonicalPath();
+
+ // Check if canonical path is complete - case sensitive-wise
+ if (!canonicalPath.startsWith(sDesiredStoragePath)) {
+ return false;
+ }
+
+ return true;
+ } catch (IOException ioe) {
+ // If an exception is thrown, there might be something wrong with the file.
+ return false;
+ }
+ }
- return new BluetoothOppReceiveFileInfo(fullfilename, length, insertUri, 0);
+ private static String chooseUniquefilename(String filename, String extension) {
+ String fullfilename = filename + extension;
+ if (!new File(fullfilename).exists()) {
+ return fullfilename;
+ }
+ filename = filename + Constants.FILENAME_SEQUENCE_SEPARATOR;
+ /*
+ * This number is used to generate partially randomized filenames to
+ * avoid collisions. It starts at 1. The next 9 iterations increment it
+ * by 1 at a time (up to 10). The next 9 iterations increment it by 1 to
+ * 10 (random) at a time. The next 9 iterations increment it by 1 to 100
+ * (random) at a time. ... Up to the point where it increases by
+ * 100000000 at a time. (the maximum value that can be reached is
+ * 1000000000) As soon as a number is reached that generates a filename
+ * that doesn't exist, that filename is used. If the filename coming in
+ * is [base].[ext], the generated filenames are [base]-[sequence].[ext].
+ */
+ Random rnd = new Random(SystemClock.uptimeMillis());
+ int sequence = 1;
+ for (int magnitude = 1; magnitude < 1000000000; magnitude *= 10) {
+ for (int iteration = 0; iteration < 9; ++iteration) {
+ fullfilename = filename + sequence + extension;
+ if (!new File(fullfilename).exists()) {
+ return fullfilename;
+ }
+ if (V) {
+ Log.v(Constants.TAG, "file with sequence number " + sequence + " exists");
+ }
+ sequence += rnd.nextInt(magnitude) + 1;
+ }
+ }
+ return null;
}
private static String choosefilename(String hint) {
@@ -218,3 +314,4 @@ public class BluetoothOppReceiveFileInfo {
return filename;
}
}
+
--
2.29.0