blob: dfd5b4db4e43bce8c60a367a0e2ea98e4c80cf15 [file] [log] [blame]
/*
* Copyright (c) 2008-2009, Motorola, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Motorola, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.android.bluetooth.opp;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import java.io.UnsupportedEncodingException;
/**
* This class stores information about a single receiving file. It will only be
* used for inbounds share, e.g. receive a file to determine a correct save file
* name
*/
public class BluetoothOppReceiveFileInfo {
private static final boolean D = Constants.DEBUG;
private static final boolean V = Constants.VERBOSE;
private static String sDesiredStoragePath = null;
/* 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 */
public String mFileName;
public long mLength;
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) {
mFileName = filename;
mStatus = status;
mInsertUri = insertUri;
mLength = length;
}
public BluetoothOppReceiveFileInfo(int status) {
this(null, 0, null, status);
}
// public static final int BATCH_STATUS_CANCELED = 4;
public static BluetoothOppReceiveFileInfo generateFileInfo(Context context, int id) {
ContentResolver contentResolver = context.getContentResolver();
Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id);
String filename = null, hint = null, mimeType = null;
long length = 0;
Cursor metadataCursor = contentResolver.query(contentUri, new String[]{
BluetoothShare.FILENAME_HINT, BluetoothShare.TOTAL_BYTES, BluetoothShare.MIMETYPE
}, null, null, null);
if (metadataCursor != null) {
try {
if (metadataCursor.moveToFirst()) {
hint = metadataCursor.getString(0);
length = metadataCursor.getLong(1);
mimeType = metadataCursor.getString(2);
}
} finally {
metadataCursor.close();
}
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
if (D) {
Log.d(Constants.TAG, "Receive File aborted - no external storage");
}
return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_ERROR_NO_SDCARD);
}
filename = choosefilename(hint);
if (filename == null) {
// should not happen. It must be pre-rejected
return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
}
String extension = null;
int dotIndex = filename.lastIndexOf(".");
if (dotIndex < 0) {
if (mimeType == null) {
// should not happen. It must be pre-rejected
return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
} else {
extension = "";
}
} else {
extension = filename.substring(dotIndex);
filename = filename.substring(0, dotIndex);
}
if (D) {
Log.d(Constants.TAG, " File Name " + filename);
}
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.
*/
Log.i(Constants.TAG, " File Name Length :" + filename.length());
Log.i(Constants.TAG, " File Name Length in Bytes:" + filename.getBytes().length);
try {
byte[] oldfilename = filename.getBytes("UTF-8");
byte[] newfilename = new byte[OPP_LENGTH_OF_FILE_NAME];
System.arraycopy(oldfilename, 0, newfilename, 0, OPP_LENGTH_OF_FILE_NAME);
filename = new String(newfilename, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(Constants.TAG, "Exception: " + e);
}
if (D) {
Log.d(Constants.TAG, "File name is too long. Name is truncated as: " + filename);
}
}
String fullfilename = filename + extension;
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 (insertUri == null) {
if (D) {
Log.e(Constants.TAG, "Error when creating file " + fullfilename);
}
return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
}
Log.d(Constants.TAG, "file crated, insertUri:" + insertUri.toString());
return new BluetoothOppReceiveFileInfo(fullfilename, length, insertUri, 0);
}
private static String choosefilename(String hint) {
String filename = null;
// First, try to use the hint from the application, if there's one
if (filename == null && !(hint == null) && !hint.endsWith("/") && !hint.endsWith("\\")) {
// Prevent abuse of path backslashes by converting all backlashes '\\' chars
// to UNIX-style forward-slashes '/'
hint = hint.replace('\\', '/');
// Convert all whitespace characters to spaces.
hint = hint.replaceAll("\\s", " ");
// Replace illegal fat filesystem characters from the
// filename hint i.e. :"<>*?| with something safe.
hint = hint.replaceAll("[:\"<>*?|]", "_");
if (V) {
Log.v(Constants.TAG, "getting filename from hint");
}
int index = hint.lastIndexOf('/') + 1;
if (index > 0) {
filename = hint.substring(index);
} else {
filename = hint;
}
}
return filename;
}
}