merge in jb-release history after reset to jb-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1883ba9..735fabf 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -67,6 +67,16 @@
                 <action android:name="android.btopp.intent.action.WHITELIST_DEVICE" />
                 <action android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.btopp.intent.action.HANDOVER_SEND" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.btopp.intent.action.HANDOVER_SEND_MULTIPLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
         </receiver>
         <activity android:name=".opp.BluetoothOppLauncherActivity"
             android:process="@string/process"
diff --git a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
index 336487c..c2cd172 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
@@ -23,6 +23,8 @@
 import android.net.Uri;
 import android.util.Log;
 
+import java.util.ArrayList;
+
 public class BluetoothOppHandoverReceiver extends BroadcastReceiver {
     public static final String TAG ="BluetoothOppHandoverReceiver";
     private static final boolean D = Constants.DEBUG;
@@ -31,7 +33,42 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();
-        if (action.equals(Constants.ACTION_WHITELIST_DEVICE)) {
+
+        if (action.equals(Constants.ACTION_HANDOVER_SEND) ||
+               action.equals(Constants.ACTION_HANDOVER_SEND_MULTIPLE)) {
+
+            BluetoothDevice device =
+                    (BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+            if (device == null) {
+                if (D) Log.d(TAG, "No device attached to handover intent.");
+                return;
+            }
+            if (action.equals(Constants.ACTION_HANDOVER_SEND)) {
+                String type = intent.getType();
+                Uri stream = (Uri)intent.getParcelableExtra(Intent.EXTRA_STREAM);
+                if (stream != null && type != null) {
+                    // Save type/stream, will be used when adding transfer
+                    // session to DB.
+                    BluetoothOppManager.getInstance(context).saveSendingFileInfo(type,
+                            stream.toString(), true);
+                } else {
+                    if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
+                }
+            } else if (action.equals(Constants.ACTION_HANDOVER_SEND_MULTIPLE)) {
+                ArrayList<Uri> uris = new ArrayList<Uri>();
+                String mimeType = intent.getType();
+                uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+                if (mimeType != null && uris != null) {
+                    BluetoothOppManager.getInstance(context).saveSendingFileInfo(mimeType,
+                            uris, true);
+                } else {
+                    if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
+                    return;
+                }
+            }
+            // we already know where to send to
+            BluetoothOppManager.getInstance(context).startTransfer(device);
+        } else if (action.equals(Constants.ACTION_WHITELIST_DEVICE)) {
             BluetoothDevice device =
                     (BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             if (D) Log.d(TAG, "Adding " + device + " to whitelist");
diff --git a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java
index 55ba463..8f2b910 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java
@@ -67,8 +67,6 @@
 
         Intent intent = getIntent();
         String action = intent.getAction();
-        BluetoothDevice device = null;
-        boolean isHandover = true;
 
         if (action.equals(Intent.ACTION_SEND) || action.equals(Intent.ACTION_SEND_MULTIPLE)) {
             /*
@@ -76,10 +74,6 @@
              * probably Pictures, videos, or vCards. The Intent should contain
              * an EXTRA_STREAM with the data to attach.
              */
-            if (intent.getBooleanExtra(Constants.EXTRA_CONNECTION_HANDOVER, false)) {
-                device = (BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-                isHandover = true;
-            }
             if (action.equals(Intent.ACTION_SEND)) {
                 // TODO: handle type == null case
                 String type = intent.getType();
@@ -96,7 +90,7 @@
                     // Save type/stream, will be used when adding transfer
                     // session to DB.
                     BluetoothOppManager.getInstance(this).saveSendingFileInfo(type,
-                            stream.toString(), isHandover);
+                            stream.toString(), false);
                 } else if (extra_text != null && type != null) {
                     if (V) Log.v(TAG, "Get ACTION_SEND intent with Extra_text = "
                                 + extra_text.toString() + "; mimetype = " + type);
@@ -104,7 +98,7 @@
 
                     if (fileUri != null) {
                         BluetoothOppManager.getInstance(this).saveSendingFileInfo(type,
-                                fileUri.toString(), isHandover);
+                                fileUri.toString(), false);
                     }
                 } else {
                     Log.e(TAG, "type is null; or sending file URI is null");
@@ -119,7 +113,7 @@
                     if (V) Log.v(TAG, "Get ACTION_SHARE_MULTIPLE intent: uris " + uris + "\n Type= "
                                 + mimeType);
                     BluetoothOppManager.getInstance(this).saveSendingFileInfo(mimeType,
-                            uris, isHandover);
+                            uris, false);
                 } else {
                     Log.e(TAG, "type is null; or sending files URIs are null");
                     finish();
@@ -146,7 +140,7 @@
                 Intent in = new Intent(this, BluetoothOppBtEnableActivity.class);
                 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 this.startActivity(in);
-            } else if (device == null) {
+            } else {
                 if (V) Log.v(TAG, "BT already enabled!! ");
                 Intent in1 = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
                 in1.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -159,9 +153,6 @@
                         BluetoothOppReceiver.class.getName());
 
                 this.startActivity(in1);
-            } else {
-                // we already know where to send to
-                BluetoothOppManager.getInstance(this).startTransfer(device);
             }
         } else if (action.equals(Constants.ACTION_OPEN)) {
             Uri uri = getIntent().getData();
diff --git a/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java b/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
index 8fd2c1e..3512fad 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
@@ -180,8 +180,18 @@
             return ResponseCodes.OBEX_HTTP_FORBIDDEN;
         }
 
+        String destination;
+        if (mTransport instanceof BluetoothOppRfcommTransport) {
+            destination = ((BluetoothOppRfcommTransport)mTransport).getRemoteAddress();
+        } else {
+            destination = "FF:FF:FF:00:00:00";
+        }
+        boolean isWhitelisted = BluetoothOppManager.getInstance(mContext).
+                isWhitelisted(destination);
+
         try {
             boolean pre_reject = false;
+
             request = op.getReceivedHeader();
             if (V) Constants.logHeader(request);
             name = (String)request.getHeader(HeaderSet.NAME);
@@ -204,8 +214,9 @@
                 /* first we look for Mimetype in Android map */
                 String extension, type;
                 int dotIndex = name.lastIndexOf(".");
-                if (dotIndex < 0) {
-                    if (D) Log.w(TAG, "There is no file extension, reject the transfer");
+                if (dotIndex < 0 && mimeType == null) {
+                    if (D) Log.w(TAG, "There is no file extension or mime type," +
+                            "reject the transfer");
                     pre_reject = true;
                     obexResponse = ResponseCodes.OBEX_HTTP_BAD_REQUEST;
                 } else {
@@ -233,8 +244,8 @@
             // MIME Types. Also reject everything in the "black list".
             if (!pre_reject
                     && (mimeType == null
-                            || !Constants.mimeTypeMatches(mimeType,
-                                    Constants.ACCEPTABLE_SHARE_INBOUND_TYPES)
+                            || (!isWhitelisted && !Constants.mimeTypeMatches(mimeType,
+                                    Constants.ACCEPTABLE_SHARE_INBOUND_TYPES))
                             || Constants.mimeTypeMatches(mimeType,
                                     Constants.UNACCEPTABLE_SHARE_INBOUND_TYPES))) {
                 if (D) Log.w(TAG, "mimeType is null or in unacceptable list, reject the transfer");
@@ -258,12 +269,6 @@
         values.put(BluetoothShare.TOTAL_BYTES, length.intValue());
         values.put(BluetoothShare.MIMETYPE, mimeType);
 
-        String destination;
-        if (mTransport instanceof BluetoothOppRfcommTransport) {
-            destination = ((BluetoothOppRfcommTransport)mTransport).getRemoteAddress();
-        } else {
-            destination = "FF:FF:FF:00:00:00";
-        }
         values.put(BluetoothShare.DESTINATION, destination);
 
         values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_INBOUND);
@@ -277,7 +282,7 @@
             needConfirm = false;
         }
 
-        if (BluetoothOppManager.getInstance(mContext).isWhitelisted(destination)) {
+        if (isWhitelisted) {
             values.put(BluetoothShare.USER_CONFIRMATION,
                     BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED);
             needConfirm = false;
diff --git a/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java b/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java
index 913e28c..c6f5bd8 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java
@@ -91,7 +91,7 @@
 
         ContentResolver contentResolver = context.getContentResolver();
         Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id);
-        String filename = null, hint = null;
+        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
@@ -101,6 +101,7 @@
                 if (metadataCursor.moveToFirst()) {
                     hint = metadataCursor.getString(0);
                     length = metadataCursor.getInt(1);
+                    mimeType = metadataCursor.getString(2);
                 }
             } finally {
                 metadataCursor.close();
@@ -142,8 +143,12 @@
         String extension = null;
         int dotIndex = filename.lastIndexOf(".");
         if (dotIndex < 0) {
-            // should not happen. It must be pre-rejected
-            return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR);
+            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);
diff --git a/src/com/android/bluetooth/opp/Constants.java b/src/com/android/bluetooth/opp/Constants.java
index 77c448a..8bb3312 100644
--- a/src/com/android/bluetooth/opp/Constants.java
+++ b/src/com/android/bluetooth/opp/Constants.java
@@ -80,6 +80,14 @@
     /** the intent that gets sent when clicking an incomplete/failed transfer */
     public static final String ACTION_LIST = "android.btopp.intent.action.LIST";
 
+    /** the intent that is used for initiating a handover transfer */
+    public static final String ACTION_HANDOVER_SEND =
+            "android.btopp.intent.action.HANDOVER_SEND";
+
+    /** the intent that is used for initiating a multi-uri handover transfer */
+    public static final String ACTION_HANDOVER_SEND_MULTIPLE =
+            "android.btopp.intent.action.HANDOVER_SEND_MULTIPLE";
+
     /** intent action used to indicate the progress of a handover transfer */
     public static final String ACTION_BT_OPP_TRANSFER_PROGRESS =
             "android.btopp.intent.action.BT_OPP_TRANSFER_PROGRESS";