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 com.android.bluetooth.R; 36 37import java.io.File; 38import java.io.FileNotFoundException; 39import java.io.FileOutputStream; 40import java.io.IOException; 41import java.util.ArrayList; 42 43import android.app.Activity; 44import android.bluetooth.BluetoothDevice; 45import android.bluetooth.BluetoothDevicePicker; 46import android.content.Intent; 47import android.content.ContentResolver; 48import android.content.Context; 49import android.net.Uri; 50import android.os.Bundle; 51import android.util.Log; 52import android.provider.Settings; 53 54/** 55 * This class is designed to act as the entry point of handling the share intent 56 * via BT from other APPs. and also make "Bluetooth" available in sharing method 57 * selection dialog. 58 */ 59public class BluetoothOppLauncherActivity extends Activity { 60 private static final String TAG = "BluetoothLauncherActivity"; 61 private static final boolean D = Constants.DEBUG; 62 private static final boolean V = Constants.VERBOSE; 63 64 @Override 65 public void onCreate(Bundle savedInstanceState) { 66 super.onCreate(savedInstanceState); 67 68 Intent intent = getIntent(); 69 String action = intent.getAction(); 70 71 if (action.equals(Intent.ACTION_SEND) || action.equals(Intent.ACTION_SEND_MULTIPLE)) { 72 //Check if Bluetooth is available in the beginning instead of at the end 73 if (!isBluetoothAllowed()) { 74 Intent in = new Intent(this, BluetoothOppBtErrorActivity.class); 75 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 76 in.putExtra("title", this.getString(R.string.airplane_error_title)); 77 in.putExtra("content", this.getString(R.string.airplane_error_msg)); 78 startActivity(in); 79 finish(); 80 return; 81 } 82 83 /* 84 * Other application is trying to share a file via Bluetooth, 85 * probably Pictures, videos, or vCards. The Intent should contain 86 * an EXTRA_STREAM with the data to attach. 87 */ 88 if (action.equals(Intent.ACTION_SEND)) { 89 // TODO: handle type == null case 90 final String type = intent.getType(); 91 final Uri stream = (Uri)intent.getParcelableExtra(Intent.EXTRA_STREAM); 92 CharSequence extra_text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT); 93 // If we get ACTION_SEND intent with EXTRA_STREAM, we'll use the 94 // uri data; 95 // If we get ACTION_SEND intent without EXTRA_STREAM, but with 96 // EXTRA_TEXT, we will try send this TEXT out; Currently in 97 // Browser, share one link goes to this case; 98 if (stream != null && type != null) { 99 if (V) Log.v(TAG, "Get ACTION_SEND intent: Uri = " + stream + "; mimetype = " 100 + type); 101 // Save type/stream, will be used when adding transfer 102 // session to DB. 103 Thread t = new Thread(new Runnable() { 104 public void run() { 105 BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this) 106 .saveSendingFileInfo(type,stream.toString(), false); 107 //Done getting file info..Launch device picker and finish this activity 108 launchDevicePicker(); 109 finish(); 110 } 111 }); 112 t.start(); 113 return; 114 } else if (extra_text != null && type != null) { 115 if (V) Log.v(TAG, "Get ACTION_SEND intent with Extra_text = " 116 + extra_text.toString() + "; mimetype = " + type); 117 final Uri fileUri = creatFileForSharedContent(this, extra_text); 118 if (fileUri != null) { 119 Thread t = new Thread(new Runnable() { 120 public void run() { 121 BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this) 122 .saveSendingFileInfo(type,fileUri.toString(), false); 123 //Done getting file info..Launch device picker 124 //and finish this activity 125 launchDevicePicker(); 126 finish(); 127 } 128 }); 129 t.start(); 130 return; 131 } else { 132 Log.w(TAG,"Error trying to do set text...File not created!"); 133 finish(); 134 return; 135 } 136 } else { 137 Log.e(TAG, "type is null; or sending file URI is null"); 138 finish(); 139 return; 140 } 141 } else if (action.equals(Intent.ACTION_SEND_MULTIPLE)) { 142 final String mimeType = intent.getType(); 143 final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); 144 if (mimeType != null && uris != null) { 145 if (V) Log.v(TAG, "Get ACTION_SHARE_MULTIPLE intent: uris " + uris + "\n Type= " 146 + mimeType); 147 Thread t = new Thread(new Runnable() { 148 public void run() { 149 BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this) 150 .saveSendingFileInfo(mimeType,uris, false); 151 //Done getting file info..Launch device picker 152 //and finish this activity 153 launchDevicePicker(); 154 finish(); 155 } 156 }); 157 t.start(); 158 return; 159 } else { 160 Log.e(TAG, "type is null; or sending files URIs are null"); 161 finish(); 162 return; 163 } 164 } 165 } else if (action.equals(Constants.ACTION_OPEN)) { 166 Uri uri = getIntent().getData(); 167 if (V) Log.v(TAG, "Get ACTION_OPEN intent: Uri = " + uri); 168 169 Intent intent1 = new Intent(); 170 intent1.setAction(action); 171 intent1.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName()); 172 intent1.setDataAndNormalize(uri); 173 this.sendBroadcast(intent1); 174 finish(); 175 } else { 176 Log.w(TAG, "Unsupported action: " + action); 177 finish(); 178 } 179 } 180 181 /** 182 * Turns on Bluetooth if not already on, or launches device picker if Bluetooth is on 183 * @return 184 */ 185 private final void launchDevicePicker() { 186 // TODO: In the future, we may send intent to DevicePickerActivity 187 // directly, 188 // and let DevicePickerActivity to handle Bluetooth Enable. 189 if (!BluetoothOppManager.getInstance(this).isEnabled()) { 190 if (V) Log.v(TAG, "Prepare Enable BT!! "); 191 Intent in = new Intent(this, BluetoothOppBtEnableActivity.class); 192 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 193 startActivity(in); 194 } else { 195 if (V) Log.v(TAG, "BT already enabled!! "); 196 Intent in1 = new Intent(BluetoothDevicePicker.ACTION_LAUNCH); 197 in1.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 198 in1.putExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false); 199 in1.putExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE, 200 BluetoothDevicePicker.FILTER_TYPE_TRANSFER); 201 in1.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE, 202 Constants.THIS_PACKAGE_NAME); 203 in1.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS, 204 BluetoothOppReceiver.class.getName()); 205 if (V) {Log.d(TAG,"Launching " +BluetoothDevicePicker.ACTION_LAUNCH );} 206 startActivity(in1); 207 } 208 } 209 /* Returns true if Bluetooth is allowed given current airplane mode settings. */ 210 private final boolean isBluetoothAllowed() { 211 final ContentResolver resolver = this.getContentResolver(); 212 213 // Check if airplane mode is on 214 final boolean isAirplaneModeOn = Settings.System.getInt(resolver, 215 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 216 if (!isAirplaneModeOn) { 217 return true; 218 } 219 220 // Check if airplane mode matters 221 final String airplaneModeRadios = Settings.System.getString(resolver, 222 Settings.System.AIRPLANE_MODE_RADIOS); 223 final boolean isAirplaneSensitive = airplaneModeRadios == null ? true : 224 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 225 if (!isAirplaneSensitive) { 226 return true; 227 } 228 229 // Check if Bluetooth may be enabled in airplane mode 230 final String airplaneModeToggleableRadios = Settings.System.getString(resolver, 231 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 232 final boolean isAirplaneToggleable = airplaneModeToggleableRadios == null ? false : 233 airplaneModeToggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 234 if (isAirplaneToggleable) { 235 return true; 236 } 237 238 // If we get here we're not allowed to use Bluetooth right now 239 return false; 240 } 241 242 private Uri creatFileForSharedContent(Context context, CharSequence shareContent) { 243 if (shareContent == null) { 244 return null; 245 } 246 247 Uri fileUri = null; 248 FileOutputStream outStream = null; 249 try { 250 String fileName = getString(R.string.bluetooth_share_file_name) + ".html"; 251 context.deleteFile(fileName); 252 253 String uri = shareContent.toString(); 254 String content = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;" 255 + " charset=UTF-8\"/></head><body>" + "<a href=\"" + uri + "\">" + uri + "</a></p>" 256 + "</body></html>"; 257 byte[] byteBuff = content.getBytes(); 258 259 outStream = context.openFileOutput(fileName, Context.MODE_PRIVATE); 260 if (outStream != null) { 261 outStream.write(byteBuff, 0, byteBuff.length); 262 fileUri = Uri.fromFile(new File(context.getFilesDir(), fileName)); 263 if (fileUri != null) { 264 if (D) Log.d(TAG, "Created one file for shared content: " 265 + fileUri.toString()); 266 } 267 } 268 } catch (FileNotFoundException e) { 269 Log.e(TAG, "FileNotFoundException: " + e.toString()); 270 e.printStackTrace(); 271 } catch (IOException e) { 272 Log.e(TAG, "IOException: " + e.toString()); 273 } catch (Exception e) { 274 Log.e(TAG, "Exception: " + e.toString()); 275 } finally { 276 try { 277 if (outStream != null) { 278 outStream.close(); 279 } 280 } catch (IOException e) { 281 e.printStackTrace(); 282 } 283 } 284 return fileUri; 285 } 286} 287