BluetoothOppSendFileInfo.java revision fdc7bd89b00e40b459c706784fa003509a229096
1/* 2 * Copyright (c) 2008-2009, Motorola, Inc. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * - Neither the name of the Motorola, Inc. nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33package com.android.bluetooth.opp; 34 35import java.io.File; 36import java.io.IOException; 37import java.io.FileInputStream; 38import java.io.FileNotFoundException; 39 40import android.util.Log; 41import android.content.ContentResolver; 42import android.content.Context; 43import android.content.res.AssetFileDescriptor; 44import android.database.Cursor; 45import android.net.Uri; 46import android.os.ParcelFileDescriptor; 47import android.provider.OpenableColumns; 48 49/** 50 * This class stores information about a single sending file It will only be 51 * used for outbound share. 52 */ 53public class BluetoothOppSendFileInfo { 54 private static final String TAG = "BluetoothOppSendFileInfo"; 55 56 private static final boolean D = Constants.DEBUG; 57 58 private static final boolean V = Constants.VERBOSE; 59 60 /** readable media file name */ 61 public final String mFileName; 62 63 /** media file input stream */ 64 public final FileInputStream mInputStream; 65 66 /** vCard string data */ 67 public final String mData; 68 69 public final int mStatus; 70 71 public final String mMimetype; 72 73 public final long mLength; 74 75 public final String mDestAddr; 76 77 /** for media file */ 78 public BluetoothOppSendFileInfo(String fileName, String type, long length, 79 FileInputStream inputStream, int status, String dest) { 80 mFileName = fileName; 81 mMimetype = type; 82 mLength = length; 83 mInputStream = inputStream; 84 mStatus = status; 85 mDestAddr = dest; 86 mData = null; 87 } 88 89 /** for vCard, or later for vCal, vNote. Not used currently */ 90 public BluetoothOppSendFileInfo(String data, String type, long length, int status, 91 String dest) { 92 mFileName = null; 93 mInputStream = null; 94 mData = data; 95 mMimetype = type; 96 mLength = length; 97 mStatus = status; 98 mDestAddr = dest; 99 } 100 101 public static BluetoothOppSendFileInfo generateFileInfo(Context context, String uri, 102 String type, String dest) { 103 ContentResolver contentResolver = context.getContentResolver(); 104 Uri u = Uri.parse(uri); 105 String scheme = u.getScheme(); 106 String fileName = null; 107 String contentType = null; 108 long length = 0; 109 // Support all Uri with "content" scheme 110 // This will allow more 3rd party applications to share files via 111 // bluetooth 112 if (scheme.equals("content")) { 113 contentType = contentResolver.getType(u); 114 Cursor metadataCursor = contentResolver.query(u, new String[] { 115 OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE 116 }, null, null, null); 117 if (metadataCursor != null) { 118 try { 119 if (metadataCursor.moveToFirst()) { 120 fileName = metadataCursor.getString(0); 121 length = metadataCursor.getInt(1); 122 if (D) Log.d(TAG, "fileName = " + fileName + " length = " + length); 123 } 124 } finally { 125 metadataCursor.close(); 126 } 127 } 128 } else if (scheme.equals("file")) { 129 fileName = u.getLastPathSegment(); 130 contentType = type; 131 File f = new File(u.getPath()); 132 length = f.length(); 133 } else { 134 // currently don't accept other scheme 135 return new BluetoothOppSendFileInfo(null, null, 0, null, 136 BluetoothShare.STATUS_FILE_ERROR, dest); 137 } 138 FileInputStream is = null; 139 if (scheme.equals("content")) { 140 AssetFileDescriptor fd = null; 141 try { 142 // We've found that content providers don't always have the 143 // right size in _OpenableColumns.SIZE 144 // As a second source of getting the correct file length, 145 // get a file descriptor and get the stat length 146 fd = contentResolver.openAssetFileDescriptor(u, "r"); 147 long statLength = fd.getLength(); 148 if (length != statLength && statLength > 0) { 149 Log.e(TAG, "Content provider length is wrong (" + Long.toString(length) + 150 "), using stat length (" + Long.toString(statLength) + ")"); 151 length = statLength; 152 } 153 try { 154 // This creates an auto-closing input-stream, so 155 // the file descriptor will be closed whenever the InputStream 156 // is closed. 157 is = (FileInputStream)fd.createInputStream(); 158 } catch (IOException e) { 159 try { 160 fd.close(); 161 } catch (IOException e2) { 162 // Ignore 163 } 164 } 165 } catch (FileNotFoundException e) { 166 // Ignore 167 } 168 } 169 if (is == null) { 170 try { 171 is = (FileInputStream)contentResolver.openInputStream(u); 172 } catch (FileNotFoundException e) { 173 return new BluetoothOppSendFileInfo(null, null, 0, null, 174 BluetoothShare.STATUS_FILE_ERROR, dest); 175 } 176 } 177 // If we can not get file length from content provider, we can try to 178 // get the length via the opened stream. 179 if (length == 0) { 180 try { 181 length = is.available(); 182 if (V) Log.v(TAG, "file length is " + length); 183 } catch (IOException e) { 184 Log.e(TAG, "Read stream exception: ", e); 185 return new BluetoothOppSendFileInfo(null, null, 0, null, 186 BluetoothShare.STATUS_FILE_ERROR, dest); 187 } 188 } 189 190 return new BluetoothOppSendFileInfo(fileName, contentType, length, is, 0, dest); 191 } 192} 193