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