summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndres Morales <anmorales@google.com>2014-11-17 21:54:16 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-11-17 21:54:17 +0000
commit2ca2ced60d0cebbe8041c4318cff9975d3bff2c4 (patch)
tree78bc0fabe42dc0dd4eb59c2d41b3768af560b2c2
parent8172b1eaa4a1aa57f38b66a57dd1109ad887cd96 (diff)
parentb82d80d891077ccd74729e4143925a66eb89eef2 (diff)
downloadandroid_packages_apps_Nfc-2ca2ced60d0cebbe8041c4318cff9975d3bff2c4.tar.gz
android_packages_apps_Nfc-2ca2ced60d0cebbe8041c4318cff9975d3bff2c4.tar.bz2
android_packages_apps_Nfc-2ca2ced60d0cebbe8041c4318cff9975d3bff2c4.zip
Merge "Refactor Beam to work with managed profiles" into lmp-mr1-dev
-rwxr-xr-xAndroidManifest.xml10
-rw-r--r--src/com/android/nfc/BeamShareActivity.java8
-rw-r--r--src/com/android/nfc/NfcDispatcher.java35
-rwxr-xr-xsrc/com/android/nfc/NfcService.java11
-rw-r--r--src/com/android/nfc/P2pEventManager.java2
-rwxr-xr-xsrc/com/android/nfc/P2pLinkManager.java47
-rw-r--r--src/com/android/nfc/beam/BeamManager.java133
-rw-r--r--src/com/android/nfc/beam/BeamReceiveService.java175
-rw-r--r--src/com/android/nfc/beam/BeamSendService.java206
-rw-r--r--src/com/android/nfc/beam/BeamStatusReceiver.java155
-rw-r--r--src/com/android/nfc/beam/BeamTransferManager.java (renamed from src/com/android/nfc/handover/HandoverTransfer.java)126
-rw-r--r--src/com/android/nfc/beam/BeamTransferRecord.aidl19
-rw-r--r--src/com/android/nfc/beam/BeamTransferRecord.java98
-rw-r--r--src/com/android/nfc/beam/BluetoothOppHandover.java (renamed from src/com/android/nfc/handover/BluetoothOppHandover.java)22
-rw-r--r--src/com/android/nfc/beam/FireflyRenderer.java (renamed from src/com/android/nfc/FireflyRenderer.java)2
-rw-r--r--src/com/android/nfc/beam/MimeTypeUtil.java (renamed from src/com/android/nfc/handover/MimeTypeUtil.java)4
-rw-r--r--src/com/android/nfc/beam/SendUi.java (renamed from src/com/android/nfc/SendUi.java)10
-rw-r--r--src/com/android/nfc/handover/HandoverDataParser.java (renamed from src/com/android/nfc/handover/HandoverManager.java)337
-rw-r--r--src/com/android/nfc/handover/HandoverServer.java50
-rw-r--r--src/com/android/nfc/handover/HandoverService.java568
-rw-r--r--src/com/android/nfc/handover/PendingHandoverTransfer.java122
-rw-r--r--src/com/android/nfc/handover/PeripheralHandoverService.java250
22 files changed, 1274 insertions, 1116 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 56ef3d41..690a4f59 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -125,8 +125,14 @@
android:noHistory="true"
/>
- <service android:name=".handover.HandoverService"
- android:process=":handover"
+ <service android:name=".beam.BeamSendService"
+ android:process=":beam"
+ />
+ <service android:name=".beam.BeamReceiveService"
+ android:process=":beam"
+ />
+
+ <service android:name=".handover.PeripheralHandoverService"
/>
</application>
</manifest>
diff --git a/src/com/android/nfc/BeamShareActivity.java b/src/com/android/nfc/BeamShareActivity.java
index c22c184f..10f6632c 100644
--- a/src/com/android/nfc/BeamShareActivity.java
+++ b/src/com/android/nfc/BeamShareActivity.java
@@ -205,18 +205,18 @@ public class BeamShareActivity extends Activity {
}
}
if (numValidUris > 0) {
- shareData = new BeamShareData(null, uriArray, 0);
+ shareData = new BeamShareData(null, uriArray, UserHandle.CURRENT, 0);
} else {
// No uris left
- shareData = new BeamShareData(null, null, 0);
+ shareData = new BeamShareData(null, null, UserHandle.CURRENT, 0);
}
} else if (mNdefMessage != null) {
- shareData = new BeamShareData(mNdefMessage, null, 0);
+ shareData = new BeamShareData(mNdefMessage, null, UserHandle.CURRENT, 0);
if (DBG) Log.d(TAG, "Created NDEF message:" + mNdefMessage.toString());
} else {
if (DBG) Log.d(TAG, "Could not find any data to parse.");
// Activity may have set something to share over NFC, so pass on anyway
- shareData = new BeamShareData(null, null, 0);
+ shareData = new BeamShareData(null, null, UserHandle.CURRENT, 0);
}
mNfcAdapter.invokeBeam(shareData);
finish();
diff --git a/src/com/android/nfc/NfcDispatcher.java b/src/com/android/nfc/NfcDispatcher.java
index 90261c40..9fd30a60 100644
--- a/src/com/android/nfc/NfcDispatcher.java
+++ b/src/com/android/nfc/NfcDispatcher.java
@@ -16,9 +16,11 @@
package com.android.nfc;
-import android.nfc.INfcUnlockHandler;
+import android.bluetooth.BluetoothAdapter;
+
import com.android.nfc.RegisteredComponentCache.ComponentInfo;
-import com.android.nfc.handover.HandoverManager;
+import com.android.nfc.handover.HandoverDataParser;
+import com.android.nfc.handover.PeripheralHandoverService;
import android.app.Activity;
import android.app.ActivityManager;
@@ -50,7 +52,6 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -69,10 +70,11 @@ class NfcDispatcher {
private final IActivityManager mIActivityManager;
private final RegisteredComponentCache mTechListFilters;
private final ContentResolver mContentResolver;
- private final HandoverManager mHandoverManager;
+ private final HandoverDataParser mHandoverDataParser;
private final String[] mProvisioningMimes;
private final ScreenStateHelper mScreenStateHelper;
private final NfcUnlockManager mNfcUnlockManager;
+ private final boolean mDeviceSupportsBluetooth;
// Locked on this
private PendingIntent mOverrideIntent;
@@ -81,16 +83,17 @@ class NfcDispatcher {
private boolean mProvisioningOnly;
NfcDispatcher(Context context,
- HandoverManager handoverManager,
+ HandoverDataParser handoverDataParser,
boolean provisionOnly) {
mContext = context;
mIActivityManager = ActivityManagerNative.getDefault();
mTechListFilters = new RegisteredComponentCache(mContext,
NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED);
mContentResolver = context.getContentResolver();
- mHandoverManager = handoverManager;
+ mHandoverDataParser = handoverDataParser;
mScreenStateHelper = new ScreenStateHelper(context);
mNfcUnlockManager = NfcUnlockManager.getInstance();
+ mDeviceSupportsBluetooth = BluetoothAdapter.getDefaultAdapter() != null;
synchronized (this) {
mProvisioningOnly = provisionOnly;
@@ -259,7 +262,7 @@ class NfcDispatcher {
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
}
- if (mHandoverManager.tryHandover(message)) {
+ if (tryPeripheralHandover(message)) {
if (DBG) Log.i(TAG, "matched BT HANDOVER");
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
}
@@ -505,6 +508,24 @@ class NfcDispatcher {
return false;
}
+ public boolean tryPeripheralHandover(NdefMessage m) {
+ if (m == null || !mDeviceSupportsBluetooth) return false;
+
+ if (DBG) Log.d(TAG, "tryHandover(): " + m.toString());
+
+ HandoverDataParser.BluetoothHandoverData handover = mHandoverDataParser.parseBluetooth(m);
+ if (handover == null || !handover.valid) return false;
+
+ Intent intent = new Intent(mContext, PeripheralHandoverService.class);
+ intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
+ intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
+ intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport);
+ mContext.startServiceAsUser(intent, UserHandle.CURRENT);
+
+ return true;
+ }
+
+
/**
* Tells the ActivityManager to resume allowing app switches.
*
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 86531bdf..46697717 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -75,7 +75,7 @@ import com.android.nfc.DeviceHost.NfcDepEndpoint;
import com.android.nfc.DeviceHost.TagEndpoint;
import com.android.nfc.cardemulation.CardEmulationManager;
import com.android.nfc.dhimpl.NativeNfcManager;
-import com.android.nfc.handover.HandoverManager;
+import com.android.nfc.handover.HandoverDataParser;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -216,7 +216,7 @@ public class NfcService implements DeviceHostListener {
private NfcDispatcher mNfcDispatcher;
private PowerManager mPowerManager;
private KeyguardManager mKeyguard;
- private HandoverManager mHandoverManager;
+ private HandoverDataParser mHandoverDataParser;
private ContentResolver mContentResolver;
private CardEmulationManager mCardEmulationManager;
@@ -314,7 +314,7 @@ public class NfcService implements DeviceHostListener {
mNfcUnlockManager = NfcUnlockManager.getInstance();
- mHandoverManager = new HandoverManager(mContext);
+ mHandoverDataParser = new HandoverDataParser();
boolean isNfcProvisioningEnabled = false;
try {
isNfcProvisioningEnabled = mContext.getResources().getBoolean(
@@ -329,8 +329,8 @@ public class NfcService implements DeviceHostListener {
mInProvisionMode = false;
}
- mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
- mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
+ mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode);
+ mP2pLinkManager = new P2pLinkManager(mContext, mHandoverDataParser,
mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
@@ -1445,7 +1445,6 @@ public class NfcService implements DeviceHostListener {
// Notify dispatcher it's fine to dispatch to any package now
// and allow handover transfers.
mNfcDispatcher.disableProvisioningMode();
- mHandoverManager.setEnabled(true);
}
}
// Special case: if we're transitioning to unlocked state while
diff --git a/src/com/android/nfc/P2pEventManager.java b/src/com/android/nfc/P2pEventManager.java
index f5db5443..468aeaff 100644
--- a/src/com/android/nfc/P2pEventManager.java
+++ b/src/com/android/nfc/P2pEventManager.java
@@ -16,6 +16,8 @@
package com.android.nfc;
+import com.android.nfc.beam.SendUi;
+
import android.app.NotificationManager;
import android.content.Context;
import android.content.res.Configuration;
diff --git a/src/com/android/nfc/P2pLinkManager.java b/src/com/android/nfc/P2pLinkManager.java
index 480d1d10..0effe4e3 100755
--- a/src/com/android/nfc/P2pLinkManager.java
+++ b/src/com/android/nfc/P2pLinkManager.java
@@ -16,11 +16,17 @@
package com.android.nfc;
+import android.content.Intent;
import android.content.pm.UserInfo;
+
+import com.android.nfc.beam.BeamManager;
+import com.android.nfc.beam.BeamSendService;
+import com.android.nfc.beam.BeamTransferRecord;
+
import android.os.UserManager;
import com.android.nfc.echoserver.EchoServer;
import com.android.nfc.handover.HandoverClient;
-import com.android.nfc.handover.HandoverManager;
+import com.android.nfc.handover.HandoverDataParser;
import com.android.nfc.handover.HandoverServer;
import com.android.nfc.ndefpush.NdefPushClient;
import com.android.nfc.ndefpush.NdefPushServer;
@@ -204,7 +210,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
final Context mContext;
final P2pEventListener mEventListener;
final Handler mHandler;
- final HandoverManager mHandoverManager;
+ final HandoverDataParser mHandoverDataParser;
final ForegroundUtils mForegroundUtils;
final int mDefaultMiu;
@@ -218,6 +224,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
boolean mIsReceiveEnabled;
NdefMessage mMessageToSend; // not valid in SEND_STATE_NOTHING_TO_SEND
Uri[] mUrisToSend; // not valid in SEND_STATE_NOTHING_TO_SEND
+ UserHandle mUserHandle; // not valid in SEND_STATE_NOTHING_TO_SEND
int mSendFlags; // not valid in SEND_STATE_NOTHING_TO_SEND
IAppCallback mCallbackNdef;
int mNdefCallbackUid;
@@ -231,11 +238,11 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
boolean mLlcpConnectDelayed;
long mLastLlcpActivationTime;
- public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu,
+ public P2pLinkManager(Context context, HandoverDataParser handoverDataParser, int defaultMiu,
int defaultRwSize) {
mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);
mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);
- mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback);
+ mHandoverServer = new HandoverServer(context, HANDOVER_SAP, handoverDataParser, mHandoverCallback);
if (ECHOSERVER_ENABLED) {
mEchoServer = new EchoServer();
@@ -251,7 +258,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
mIsSendEnabled = false;
mIsReceiveEnabled = false;
mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE);
- mHandoverManager = handoverManager;
+ mHandoverDataParser = handoverDataParser;
mDefaultMiu = defaultMiu;
mDefaultRwSize = defaultRwSize;
mLlcpServicesConnected = false;
@@ -330,7 +337,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
}
}
if (mMessageToSend != null ||
- (mUrisToSend != null && mHandoverManager.isHandoverSupported())) {
+ (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) {
mSendState = SEND_STATE_PENDING;
mEventListener.onP2pNfcTapRequested();
scheduleTimeoutLocked(MSG_WAIT_FOR_LINK_TIMEOUT, WAIT_FOR_LINK_TIMEOUT_MS);
@@ -364,7 +371,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
mSendState = SEND_STATE_NOTHING_TO_SEND;
prepareMessageToSend(true);
if (mMessageToSend != null ||
- (mUrisToSend != null && mHandoverManager.isHandoverSupported())) {
+ (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) {
// Ideally we would delay showing the Beam animation until
// we know for certain the other side has SNEP/handover.
// Unfortunately, the NXP LLCP implementation has a bug that
@@ -466,6 +473,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
BeamShareData shareData = mCallbackNdef.createBeamShareData();
mMessageToSend = shareData.ndefMessage;
mUrisToSend = shareData.uris;
+ mUserHandle = shareData.userHandle;
mSendFlags = shareData.flags;
return;
} catch (Exception e) {
@@ -747,9 +755,15 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
SnepClient snepClient;
HandoverClient handoverClient;
- int doHandover(Uri[] uris) throws IOException {
+ int doHandover(Uri[] uris, UserHandle userHandle) throws IOException {
NdefMessage response = null;
- NdefMessage request = mHandoverManager.createHandoverRequestMessage();
+ BeamManager beamManager = BeamManager.getInstance();
+
+ if (beamManager.isBeamInProgress()) {
+ return HANDOVER_FAILURE;
+ }
+
+ NdefMessage request = mHandoverDataParser.createHandoverRequestMessage();
if (request != null) {
if (handoverClient != null) {
response = handoverClient.sendHandoverRequest(request);
@@ -767,8 +781,13 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
} else {
return HANDOVER_UNSUPPORTED;
}
- mHandoverManager.doHandoverUri(uris, response);
- return HANDOVER_SUCCESS;
+
+ if (beamManager.startBeamSend(mContext,
+ mHandoverDataParser.getOutgoingHandoverData(response), uris, userHandle)) {
+ return HANDOVER_SUCCESS;
+ }
+
+ return HANDOVER_FAILURE;
}
int doSnepProtocol(NdefMessage msg) throws IOException {
@@ -784,6 +803,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
public Void doInBackground(Void... args) {
NdefMessage m;
Uri[] uris;
+ UserHandle userHandle;
boolean result = false;
synchronized (P2pLinkManager.this) {
@@ -792,6 +812,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
}
m = mMessageToSend;
uris = mUrisToSend;
+ userHandle = mUserHandle;
snepClient = mSnepClient;
handoverClient = mHandoverClient;
nppClient = mNdefPushClient;
@@ -802,7 +823,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
if (uris != null) {
if (DBG) Log.d(TAG, "Trying handover request");
try {
- int handoverResult = doHandover(uris);
+ int handoverResult = doHandover(uris, userHandle);
switch (handoverResult) {
case HANDOVER_SUCCESS:
result = true;
@@ -882,7 +903,7 @@ class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
// since Android 4.1 used the NFC Forum default server to
// implement connection handover, we will support this
// until we can deprecate it.
- NdefMessage response = mHandoverManager.tryHandoverRequest(msg);
+ NdefMessage response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect;
if (response != null) {
onReceiveHandover();
return SnepMessage.getSuccessResponse(response);
diff --git a/src/com/android/nfc/beam/BeamManager.java b/src/com/android/nfc/beam/BeamManager.java
new file mode 100644
index 00000000..ba16aa5e
--- /dev/null
+++ b/src/com/android/nfc/beam/BeamManager.java
@@ -0,0 +1,133 @@
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.android.nfc.beam;
+
+import com.android.nfc.handover.HandoverDataParser;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * Manager for starting and stopping Beam transfers. Prevents more than one transfer from
+ * happening at a time.
+ */
+public class BeamManager implements Handler.Callback {
+ private static final String TAG = "BeamManager";
+ private static final boolean DBG = false;
+
+ private static final String ACTION_WHITELIST_DEVICE =
+ "android.btopp.intent.action.WHITELIST_DEVICE";
+ public static final int MSG_BEAM_COMPLETE = 0;
+
+ private final Object mLock;
+
+ private boolean mBeamInProgress;
+ private final Handler mCallback;
+
+ private static final class Singleton {
+ public static final BeamManager INSTANCE = new BeamManager();
+ }
+
+ private BeamManager() {
+ mLock = new Object();
+ mBeamInProgress = false;
+ mCallback = new Handler(Looper.getMainLooper(), this);
+ }
+
+ public static BeamManager getInstance() {
+ return Singleton.INSTANCE;
+ }
+
+ public boolean isBeamInProgress() {
+ synchronized (mLock) {
+ return mBeamInProgress;
+ }
+ }
+
+ public boolean startBeamReceive(Context context,
+ HandoverDataParser.BluetoothHandoverData handoverData) {
+ synchronized (mLock) {
+ if (mBeamInProgress) {
+ return false;
+ } else {
+ mBeamInProgress = true;
+ }
+ }
+
+ BeamTransferRecord transferRecord =
+ BeamTransferRecord.forBluetoothDevice(
+ handoverData.device, handoverData.carrierActivating, null);
+
+ Intent receiveIntent = new Intent(context.getApplicationContext(),
+ BeamReceiveService.class);
+ receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
+ receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_COMPLETE_CALLBACK,
+ new Messenger(mCallback));
+ whitelistOppDevice(context, handoverData.device);
+ context.startServiceAsUser(receiveIntent, UserHandle.CURRENT);
+ return true;
+ }
+
+ public boolean startBeamSend(Context context,
+ HandoverDataParser.BluetoothHandoverData outgoingHandoverData,
+ Uri[] uris, UserHandle userHandle) {
+ synchronized (mLock) {
+ if (mBeamInProgress) {
+ return false;
+ } else {
+ mBeamInProgress = true;
+ }
+ }
+
+ BeamTransferRecord transferRecord = BeamTransferRecord.forBluetoothDevice(
+ outgoingHandoverData.device, outgoingHandoverData.carrierActivating,
+ uris);
+ Intent sendIntent = new Intent(context.getApplicationContext(),
+ BeamSendService.class);
+ sendIntent.putExtra(BeamSendService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
+ sendIntent.putExtra(BeamSendService.EXTRA_BEAM_COMPLETE_CALLBACK,
+ new Messenger(mCallback));
+ context.startServiceAsUser(sendIntent, userHandle);
+ return true;
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ if (msg.what == MSG_BEAM_COMPLETE) {
+ synchronized (mLock) {
+ mBeamInProgress = false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void whitelistOppDevice(Context context, BluetoothDevice device) {
+ if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP");
+ Intent intent = new Intent(ACTION_WHITELIST_DEVICE);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ context.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ }
+
+}
diff --git a/src/com/android/nfc/beam/BeamReceiveService.java b/src/com/android/nfc/beam/BeamReceiveService.java
new file mode 100644
index 00000000..7deb0148
--- /dev/null
+++ b/src/com/android/nfc/beam/BeamReceiveService.java
@@ -0,0 +1,175 @@
+package com.android.nfc.beam;
+
+import com.android.nfc.R;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.media.SoundPool;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+
+/**
+ * @hide
+ */
+public class BeamReceiveService extends Service implements BeamTransferManager.Callback {
+ private static String TAG = "BeamReceiveService";
+ private static boolean DBG = true;
+
+ public static final String EXTRA_BEAM_TRANSFER_RECORD
+ = "com.android.nfc.beam.EXTRA_BEAM_TRANSFER_RECORD";
+ public static final String EXTRA_BEAM_COMPLETE_CALLBACK
+ = "com.android.nfc.beam.TRANSFER_COMPLETE_CALLBACK";
+
+ private BeamStatusReceiver mBeamStatusReceiver;
+ private boolean mBluetoothEnabledByNfc;
+ private int mStartId;
+ private SoundPool mSoundPool;
+ private int mSuccessSound;
+ private BeamTransferManager mTransferManager;
+ private Messenger mCompleteCallback;
+
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ if (state == BluetoothAdapter.STATE_OFF) {
+ mBluetoothEnabledByNfc = false;
+ }
+ }
+ }
+ };
+
+ public BeamReceiveService() {
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ mStartId = startId;
+
+ BeamTransferRecord transferRecord;
+ if (intent == null ||
+ (transferRecord = intent.getParcelableExtra(EXTRA_BEAM_TRANSFER_RECORD)) == null) {
+ if (DBG) Log.e(TAG, "No transfer record provided. Stopping.");
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+
+ mCompleteCallback = intent.getParcelableExtra(EXTRA_BEAM_COMPLETE_CALLBACK);
+
+ if (prepareToReceive(transferRecord)) {
+ if (DBG) Log.i(TAG, "Ready for incoming Beam transfer");
+ return START_STICKY;
+ } else {
+ invokeCompleteCallback();
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+ }
+
+ // TODO: figure out a way to not duplicate this code
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
+ mSuccessSound = mSoundPool.load(this, R.raw.end, 1);
+
+ // register BT state receiver
+ IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ registerReceiver(mBluetoothStateReceiver, filter);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mSoundPool != null) {
+ mSoundPool.release();
+ }
+
+ if (mBeamStatusReceiver != null) {
+ unregisterReceiver(mBeamStatusReceiver);
+ }
+ unregisterReceiver(mBluetoothStateReceiver);
+ }
+
+ boolean prepareToReceive(BeamTransferRecord transferRecord) {
+ if (mTransferManager != null) {
+ return false;
+ }
+
+ if (transferRecord.dataLinkType != BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
+ // only support BT
+ return false;
+ }
+
+ if (!mBluetoothAdapter.isEnabled()) {
+ if (!mBluetoothAdapter.enableNoAutoConnect()) {
+ Log.e(TAG, "Error enabling Bluetooth.");
+ return false;
+ }
+ mBluetoothEnabledByNfc = true;
+ if (DBG) Log.d(TAG, "Queueing out transfer "
+ + Integer.toString(transferRecord.id));
+ }
+
+ mTransferManager = new BeamTransferManager(this, this, transferRecord, true);
+
+ // register Beam status receiver
+ mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager);
+ registerReceiver(mBeamStatusReceiver, mBeamStatusReceiver.getIntentFilter(),
+ BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler());
+
+ mTransferManager.start();
+ mTransferManager.updateNotification();
+ return true;
+ }
+
+ private void invokeCompleteCallback() {
+ if (mCompleteCallback != null) {
+ try {
+ mCompleteCallback.send(Message.obtain(null, BeamManager.MSG_BEAM_COMPLETE));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to invoke Beam complete callback", e);
+ }
+ }
+ }
+
+ @Override
+ public void onTransferComplete(BeamTransferManager transfer, boolean success) {
+ // Play success sound
+ if (success) {
+ mSoundPool.play(mSuccessSound, 1.0f, 1.0f, 0, 0, 1.0f);
+ } else {
+ if (DBG) Log.d(TAG, "Transfer failed, final state: " +
+ Integer.toString(transfer.mState));
+ }
+
+ if (mBluetoothEnabledByNfc) {
+ mBluetoothEnabledByNfc = false;
+ mBluetoothAdapter.disable();
+ }
+
+ invokeCompleteCallback();
+ stopSelf(mStartId);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/src/com/android/nfc/beam/BeamSendService.java b/src/com/android/nfc/beam/BeamSendService.java
new file mode 100644
index 00000000..59019d53
--- /dev/null
+++ b/src/com/android/nfc/beam/BeamSendService.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.beam;
+
+import com.android.nfc.R;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.media.SoundPool;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+public class BeamSendService extends Service implements BeamTransferManager.Callback {
+ private static String TAG = "BeamSendService";
+ private static boolean DBG = true;
+
+ public static String EXTRA_BEAM_TRANSFER_RECORD
+ = "com.android.nfc.beam.EXTRA_BEAM_TRANSFER_RECORD";
+ public static final String EXTRA_BEAM_COMPLETE_CALLBACK
+ = "com.android.nfc.beam.TRANSFER_COMPLETE_CALLBACK";
+
+ private BeamTransferManager mTransferManager;
+ private BeamStatusReceiver mBeamStatusReceiver;
+ private boolean mBluetoothEnabledByNfc;
+ private Messenger mCompleteCallback;
+ private int mStartId;
+ SoundPool mSoundPool;
+ int mSuccessSound;
+
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+ handleBluetoothStateChanged(intent);
+ }
+ }
+ };
+
+ public BeamSendService() {
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
+ mSuccessSound = mSoundPool.load(this, R.raw.end, 1);
+
+ // register BT state receiver
+ IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ registerReceiver(mBluetoothStateReceiver, filter);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mSoundPool != null) {
+ mSoundPool.release();
+ }
+
+ if (mBeamStatusReceiver != null) {
+ unregisterReceiver(mBeamStatusReceiver);
+ }
+ unregisterReceiver(mBluetoothStateReceiver);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ mStartId = startId;
+
+ BeamTransferRecord transferRecord;
+ if (intent == null ||
+ (transferRecord = intent.getParcelableExtra(EXTRA_BEAM_TRANSFER_RECORD)) == null) {
+ if (DBG) Log.e(TAG, "No transfer record provided. Stopping.");
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+
+ mCompleteCallback = intent.getParcelableExtra(EXTRA_BEAM_COMPLETE_CALLBACK);
+
+ if (doTransfer(transferRecord)) {
+ if (DBG) Log.i(TAG, "Starting outgoing Beam transfer");
+ return START_STICKY;
+ } else {
+ invokeCompleteCallback();
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+ }
+
+ boolean doTransfer(BeamTransferRecord transferRecord) {
+ if (createBeamTransferManager(transferRecord)) {
+ // register Beam status receiver
+ mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager);
+ registerReceiver(mBeamStatusReceiver, mBeamStatusReceiver.getIntentFilter(),
+ BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler());
+
+ if (transferRecord.dataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
+ if (mBluetoothAdapter.isEnabled()) {
+ // Start the transfer
+ mTransferManager.start();
+ } else {
+ if (!mBluetoothAdapter.enableNoAutoConnect()) {
+ Log.e(TAG, "Error enabling Bluetooth.");
+ mTransferManager = null;
+ return false;
+ }
+ mBluetoothEnabledByNfc = true;
+ if (DBG) Log.d(TAG, "Queueing out transfer "
+ + Integer.toString(transferRecord.id));
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ boolean createBeamTransferManager(BeamTransferRecord transferRecord) {
+ if (mTransferManager != null) {
+ return false;
+ }
+
+ if (transferRecord.dataLinkType != BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
+ // only support BT
+ return false;
+ }
+
+ mTransferManager = new BeamTransferManager(this, this, transferRecord, false);
+ mTransferManager.updateNotification();
+ return true;
+ }
+
+ private void handleBluetoothStateChanged(Intent intent) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ if (state == BluetoothAdapter.STATE_ON) {
+ if (mTransferManager != null &&
+ mTransferManager.mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
+ mTransferManager.start();
+ }
+ } else if (state == BluetoothAdapter.STATE_OFF) {
+ mBluetoothEnabledByNfc = false;
+ }
+ }
+
+ private void invokeCompleteCallback() {
+ if (mCompleteCallback != null) {
+ try {
+ mCompleteCallback.send(Message.obtain(null, BeamManager.MSG_BEAM_COMPLETE));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to invoke Beam complete callback", e);
+ }
+ }
+ }
+
+ @Override
+ public void onTransferComplete(BeamTransferManager transfer, boolean success) {
+ // Play success sound
+ if (success) {
+ mSoundPool.play(mSuccessSound, 1.0f, 1.0f, 0, 0, 1.0f);
+ } else {
+ if (DBG) Log.d(TAG, "Transfer failed, final state: " +
+ Integer.toString(transfer.mState));
+ }
+
+ if (mBluetoothEnabledByNfc) {
+ mBluetoothEnabledByNfc = false;
+ mBluetoothAdapter.disable();
+ }
+
+ invokeCompleteCallback();
+ stopSelf(mStartId);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/src/com/android/nfc/beam/BeamStatusReceiver.java b/src/com/android/nfc/beam/BeamStatusReceiver.java
new file mode 100644
index 00000000..67b5b82a
--- /dev/null
+++ b/src/com/android/nfc/beam/BeamStatusReceiver.java
@@ -0,0 +1,155 @@
+package com.android.nfc.beam;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.util.Log;
+
+import java.io.File;
+
+/**
+ * @hide
+ */
+public class BeamStatusReceiver extends BroadcastReceiver {
+ private static final boolean DBG = true;
+ private static final String TAG = "BeamStatusReceiver";
+
+ private static final String ACTION_HANDOVER_STARTED =
+ "android.nfc.handover.intent.action.HANDOVER_STARTED";
+
+ private static final String ACTION_TRANSFER_PROGRESS =
+ "android.nfc.handover.intent.action.TRANSFER_PROGRESS";
+
+ private static final String ACTION_TRANSFER_DONE =
+ "android.nfc.handover.intent.action.TRANSFER_DONE";
+
+ private static final String EXTRA_HANDOVER_DATA_LINK_TYPE =
+ "android.nfc.handover.intent.extra.HANDOVER_DATA_LINK_TYPE";
+
+
+ private static final String EXTRA_TRANSFER_PROGRESS =
+ "android.nfc.handover.intent.extra.TRANSFER_PROGRESS";
+
+ private static final String EXTRA_TRANSFER_URI =
+ "android.nfc.handover.intent.extra.TRANSFER_URI";
+
+ private static final String EXTRA_OBJECT_COUNT =
+ "android.nfc.handover.intent.extra.OBJECT_COUNT";
+
+ private static final String EXTRA_TRANSFER_STATUS =
+ "android.nfc.handover.intent.extra.TRANSFER_STATUS";
+
+ private static final String EXTRA_TRANSFER_MIMETYPE =
+ "android.nfc.handover.intent.extra.TRANSFER_MIME_TYPE";
+
+ private static final String ACTION_STOP_BLUETOOTH_TRANSFER =
+ "android.btopp.intent.action.STOP_HANDOVER_TRANSFER";
+
+ // FIXME: Needs to stay in sync with com.android.bluetooth.opp.Constants
+ private static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
+ private static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
+
+ // permission needed to be able to receive handover status requests
+ public static final String BEAM_STATUS_PERMISSION =
+ "android.permission.NFC_HANDOVER_STATUS";
+
+ // Needed to build cancel intent in Beam notification
+ public static final String EXTRA_INCOMING =
+ "com.android.nfc.handover.extra.INCOMING";
+
+ public static final String EXTRA_TRANSFER_ID =
+ "android.nfc.handover.intent.extra.TRANSFER_ID";
+
+ public static final String EXTRA_ADDRESS =
+ "android.nfc.handover.intent.extra.ADDRESS";
+
+ public static final String ACTION_CANCEL_HANDOVER_TRANSFER =
+ "com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER";
+
+ public static final int DIRECTION_INCOMING = 0;
+ public static final int DIRECTION_OUTGOING = 1;
+
+ private final Context mContext;
+ private final BeamTransferManager mTransferManager;
+
+ BeamStatusReceiver(Context context, BeamTransferManager transferManager) {
+ mContext = context;
+ mTransferManager = transferManager;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ int dataLinkType = intent.getIntExtra(EXTRA_HANDOVER_DATA_LINK_TYPE,
+ BeamTransferManager.DATA_LINK_TYPE_BLUETOOTH);
+
+ if (ACTION_CANCEL_HANDOVER_TRANSFER.equals(action)) {
+ if (mTransferManager != null) {
+ mTransferManager.cancel();
+ }
+ } else if (ACTION_TRANSFER_PROGRESS.equals(action) ||
+ ACTION_TRANSFER_DONE.equals(action) ||
+ ACTION_HANDOVER_STARTED.equals(action)) {
+ handleTransferEvent(intent, dataLinkType);
+ }
+ }
+
+ public IntentFilter getIntentFilter() {
+ IntentFilter filter = new IntentFilter(ACTION_TRANSFER_DONE);
+ filter.addAction(ACTION_TRANSFER_PROGRESS);
+ filter.addAction(ACTION_CANCEL_HANDOVER_TRANSFER);
+ filter.addAction(ACTION_HANDOVER_STARTED);
+ return filter;
+ }
+
+ private void handleTransferEvent(Intent intent, int deviceType) {
+ String action = intent.getAction();
+ int id = intent.getIntExtra(EXTRA_TRANSFER_ID, -1);
+
+ String sourceAddress = intent.getStringExtra(EXTRA_ADDRESS);
+
+ if (sourceAddress == null) return;
+
+ if (mTransferManager == null) {
+ // There is no transfer running for this source address; most likely
+ // the transfer was cancelled. We need to tell BT OPP to stop transferring.
+ if (id != -1) {
+ if (deviceType == BeamTransferManager.DATA_LINK_TYPE_BLUETOOTH) {
+ if (DBG) Log.d(TAG, "Didn't find transfer, stopping");
+ Intent cancelIntent = new Intent(ACTION_STOP_BLUETOOTH_TRANSFER);
+ cancelIntent.putExtra(EXTRA_TRANSFER_ID, id);
+ mContext.sendBroadcast(cancelIntent);
+ }
+ }
+ return;
+ }
+
+ mTransferManager.setBluetoothTransferId(id);
+
+ if (action.equals(ACTION_TRANSFER_DONE)) {
+ int handoverStatus = intent.getIntExtra(EXTRA_TRANSFER_STATUS,
+ HANDOVER_TRANSFER_STATUS_FAILURE);
+ if (handoverStatus == HANDOVER_TRANSFER_STATUS_SUCCESS) {
+ String uriString = intent.getStringExtra(EXTRA_TRANSFER_URI);
+ String mimeType = intent.getStringExtra(EXTRA_TRANSFER_MIMETYPE);
+ Uri uri = Uri.parse(uriString);
+ if (uri != null && uri.getScheme() == null) {
+ uri = Uri.fromFile(new File(uri.getPath()));
+ }
+ mTransferManager.finishTransfer(true, uri, mimeType);
+ } else {
+ mTransferManager.finishTransfer(false, null, null);
+ }
+ } else if (action.equals(ACTION_TRANSFER_PROGRESS)) {
+ float progress = intent.getFloatExtra(EXTRA_TRANSFER_PROGRESS, 0.0f);
+ mTransferManager.updateFileProgress(progress);
+ } else if (action.equals(ACTION_HANDOVER_STARTED)) {
+ int count = intent.getIntExtra(EXTRA_OBJECT_COUNT, 0);
+ if (count > 0) {
+ mTransferManager.setObjectCount(count);
+ }
+ }
+ }
+}
diff --git a/src/com/android/nfc/handover/HandoverTransfer.java b/src/com/android/nfc/beam/BeamTransferManager.java
index b0baf182..b6785010 100644
--- a/src/com/android/nfc/handover/HandoverTransfer.java
+++ b/src/com/android/nfc/beam/BeamTransferManager.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.nfc.handover;
+package com.android.nfc.beam;
+
+import com.android.nfc.R;
import android.app.Notification;
import android.app.NotificationManager;
@@ -34,20 +36,22 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
-import com.android.nfc.R;
-
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
/**
- * A HandoverTransfer object represents a set of files
+ * A BeamTransferManager object represents a set of files
* that were received through NFC connection handover
* from the same source address.
*
+ * It manages starting, stopping, and processing the transfer, as well
+ * as the user visible notification.
+ *
* For Bluetooth, files are received through OPP, and
* we have no knowledge how many files will be transferred
* as part of a single transaction.
@@ -57,21 +61,21 @@ import java.util.Locale;
* same source address as part of the same transfer.
* The corresponding URIs will be grouped in a single folder.
*
+ * @hide
*/
-public class HandoverTransfer implements Handler.Callback,
- MediaScannerConnection.OnScanCompletedListener {
+public class BeamTransferManager implements Handler.Callback,
+ MediaScannerConnection.OnScanCompletedListener {
interface Callback {
- void onTransferComplete(HandoverTransfer transfer, boolean success);
+ void onTransferComplete(BeamTransferManager transfer, boolean success);
};
- static final String TAG = "HandoverTransfer";
+ static final String TAG = "BeamTransferManager";
static final Boolean DBG = true;
// In the states below we still accept new file transfer
static final int STATE_NEW = 0;
-
static final int STATE_IN_PROGRESS = 1;
static final int STATE_W4_NEXT_TRANSFER = 2;
// In the states below no new files are accepted.
@@ -83,9 +87,8 @@ public class HandoverTransfer implements Handler.Callback,
static final int MSG_NEXT_TRANSFER_TIMER = 0;
static final int MSG_TRANSFER_TIMEOUT = 1;
- static final int DEVICE_TYPE_BLUETOOTH = 1;
+ static final int DATA_LINK_TYPE_BLUETOOTH = 1;
- public static final int DEVICE_TYPE_WIFI = 2;
// We need to receive an update within this time period
// to still consider this transfer to be "alive" (ie
// a reason to keep the handover transport enabled).
@@ -97,6 +100,12 @@ public class HandoverTransfer implements Handler.Callback,
static final String BEAM_DIR = "beam";
+ static final String ACTION_WHITELIST_DEVICE =
+ "android.btopp.intent.action.WHITELIST_DEVICE";
+
+ static final String ACTION_STOP_BLUETOOTH_TRANSFER =
+ "android.btopp.intent.action.STOP_HANDOVER_TRANSFER";
+
final boolean mIncoming; // whether this is an incoming transfer
final int mTransferId; // Unique ID of this transfer used for notifications
@@ -107,49 +116,51 @@ public class HandoverTransfer implements Handler.Callback,
final Handler mHandler;
final NotificationManager mNotificationManager;
final BluetoothDevice mRemoteDevice;
- final String mRemoteMac;
final Callback mCallback;
- final Long mStartTime;
+ final boolean mRemoteActivating;
// Variables below are only accessed on the main thread
int mState;
int mCurrentCount;
int mSuccessCount;
int mTotalCount;
- int mDeviceType;
+ int mDataLinkType;
boolean mCalledBack;
Long mLastUpdate; // Last time an event occurred for this transfer
float mProgress; // Progress in range [0..1]
ArrayList<Uri> mUris; // Received uris from transport
ArrayList<String> mTransferMimeTypes; // Mime-types received from transport
- Uri[] mOutgoingUris; // URIs to send via Wifi Direct
-
+ Uri[] mOutgoingUris; // URIs to send
ArrayList<String> mPaths; // Raw paths on the filesystem for Beam-stored files
HashMap<String, String> mMimeTypes; // Mime-types associated with each path
HashMap<String, Uri> mMediaUris; // URIs found by the media scanner for each path
int mUrisScanned;
+ Long mStartTime;
- public HandoverTransfer(Context context, Callback callback,
- PendingHandoverTransfer pendingTransfer) {
+ public BeamTransferManager(Context context, Callback callback,
+ BeamTransferRecord pendingTransfer, boolean incoming) {
mContext = context;
mCallback = callback;
mRemoteDevice = pendingTransfer.remoteDevice;
- mRemoteMac = pendingTransfer.remoteMacAddress;
- mIncoming = pendingTransfer.incoming;
+ mIncoming = incoming;
mTransferId = pendingTransfer.id;
mBluetoothTransferId = -1;
- mDeviceType = pendingTransfer.deviceType;
+ mDataLinkType = pendingTransfer.dataLinkType;
+ mRemoteActivating = pendingTransfer.remoteActivating;
+ mStartTime = 0L;
// For incoming transfers, count can be set later
mTotalCount = (pendingTransfer.uris != null) ? pendingTransfer.uris.length : 0;
mLastUpdate = SystemClock.elapsedRealtime();
mProgress = 0.0f;
mState = STATE_NEW;
- mUris = new ArrayList<Uri>();
+ mUris = pendingTransfer.uris == null
+ ? new ArrayList<Uri>()
+ : new ArrayList<Uri>(Arrays.asList(pendingTransfer.uris));
mTransferMimeTypes = new ArrayList<String>();
mMimeTypes = new HashMap<String, String>();
mPaths = new ArrayList<String>();
mMediaUris = new HashMap<String, Uri>();
- mCancelIntent = buildCancelIntent(mIncoming);
+ mCancelIntent = buildCancelIntent();
mUrisScanned = 0;
mCurrentCount = 0;
mSuccessCount = 0;
@@ -158,17 +169,30 @@ public class HandoverTransfer implements Handler.Callback,
mHandler.sendEmptyMessageDelayed(MSG_TRANSFER_TIMEOUT, ALIVE_CHECK_MS);
mNotificationManager = (NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
-
- mStartTime = System.currentTimeMillis();
}
void whitelistOppDevice(BluetoothDevice device) {
if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP");
- Intent intent = new Intent(HandoverManager.ACTION_WHITELIST_DEVICE);
+ Intent intent = new Intent(ACTION_WHITELIST_DEVICE);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
}
+ public void start() {
+ if (mStartTime > 0) {
+ // already started
+ return;
+ }
+
+ mStartTime = System.currentTimeMillis();
+
+ if (!mIncoming) {
+ if (mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
+ new BluetoothOppHandover(mContext, mRemoteDevice, mUris, mRemoteActivating).start();
+ }
+ }
+ }
+
public void updateFileProgress(float progress) {
if (!isRunning()) return; // Ignore when we're no longer running
@@ -218,7 +242,6 @@ public class HandoverTransfer implements Handler.Callback,
if (mIncoming) {
processFiles();
} else {
- Log.i(TAG, "Updating state!");
updateStateAndNotification(mSuccessCount > 0 ? STATE_SUCCESS : STATE_FAILED);
}
} else {
@@ -258,9 +281,8 @@ public class HandoverTransfer implements Handler.Callback,
}
private void sendBluetoothCancelIntentAndUpdateState() {
- Intent cancelIntent = new Intent(
- "android.btopp.intent.action.STOP_HANDOVER_TRANSFER");
- cancelIntent.putExtra(HandoverService.EXTRA_TRANSFER_ID, mBluetoothTransferId);
+ Intent cancelIntent = new Intent(ACTION_STOP_BLUETOOTH_TRANSFER);
+ cancelIntent.putExtra(BeamStatusReceiver.EXTRA_TRANSFER_ID, mBluetoothTransferId);
mContext.sendBroadcast(cancelIntent);
updateStateAndNotification(STATE_CANCELLED);
}
@@ -409,10 +431,6 @@ public class HandoverTransfer implements Handler.Callback,
}
- public int getTransferId() {
- return mTransferId;
- }
-
public boolean handleMessage(Message msg) {
if (msg.what == MSG_NEXT_TRANSFER_TIMER) {
// We didn't receive a new transfer in time, finalize this one
@@ -442,18 +460,6 @@ public class HandoverTransfer implements Handler.Callback,
}
}
- boolean checkMediaStorage(File path) {
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- if (!path.isDirectory() && !path.mkdir()) {
- Log.e(TAG, "Not dir or not mkdir " + path.getAbsolutePath());
- return false;
- }
- return true;
- } else {
- Log.e(TAG, "External storage not mounted, can't store file.");
- return false;
- }
- }
Intent buildViewIntent() {
if (mPaths.size() == 0) return null;
@@ -469,19 +475,31 @@ public class HandoverTransfer implements Handler.Callback,
return viewIntent;
}
- PendingIntent buildCancelIntent(boolean incoming) {
- Intent intent = new Intent(HandoverService.ACTION_CANCEL_HANDOVER_TRANSFER);
- intent.putExtra(HandoverService.EXTRA_ADDRESS, mDeviceType == DEVICE_TYPE_BLUETOOTH
- ? mRemoteDevice.getAddress() : mRemoteMac);
- intent.putExtra(HandoverService.EXTRA_INCOMING, incoming ?
- HandoverService.DIRECTION_INCOMING : HandoverService.DIRECTION_OUTGOING);
+ PendingIntent buildCancelIntent() {
+ Intent intent = new Intent(BeamStatusReceiver.ACTION_CANCEL_HANDOVER_TRANSFER);
+ intent.putExtra(BeamStatusReceiver.EXTRA_ADDRESS, mRemoteDevice.getAddress());
+ intent.putExtra(BeamStatusReceiver.EXTRA_INCOMING, mIncoming ?
+ BeamStatusReceiver.DIRECTION_INCOMING : BeamStatusReceiver.DIRECTION_OUTGOING);
PendingIntent pi = PendingIntent.getBroadcast(mContext, mTransferId, intent,
PendingIntent.FLAG_ONE_SHOT);
return pi;
}
- File generateUniqueDestination(String path, String fileName) {
+ static boolean checkMediaStorage(File path) {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ if (!path.isDirectory() && !path.mkdir()) {
+ Log.e(TAG, "Not dir or not mkdir " + path.getAbsolutePath());
+ return false;
+ }
+ return true;
+ } else {
+ Log.e(TAG, "External storage not mounted, can't store file.");
+ return false;
+ }
+ }
+
+ static File generateUniqueDestination(String path, String fileName) {
int dotIndex = fileName.lastIndexOf(".");
String extension = null;
String fileNameWithoutExtension = null;
@@ -502,7 +520,7 @@ public class HandoverTransfer implements Handler.Callback,
return dstFile;
}
- File generateMultiplePath(String beamRoot) {
+ static File generateMultiplePath(String beamRoot) {
// Generate a unique directory with the date
String format = "yyyy-MM-dd";
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
diff --git a/src/com/android/nfc/beam/BeamTransferRecord.aidl b/src/com/android/nfc/beam/BeamTransferRecord.aidl
new file mode 100644
index 00000000..93af205d
--- /dev/null
+++ b/src/com/android/nfc/beam/BeamTransferRecord.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.beam;
+
+parcelable BeamTransferRecord;
diff --git a/src/com/android/nfc/beam/BeamTransferRecord.java b/src/com/android/nfc/beam/BeamTransferRecord.java
new file mode 100644
index 00000000..d8f86689
--- /dev/null
+++ b/src/com/android/nfc/beam/BeamTransferRecord.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.beam;
+
+import android.bluetooth.BluetoothDevice;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class BeamTransferRecord implements Parcelable {
+
+ public static int DATA_LINK_TYPE_BLUETOOTH = 0;
+
+ public int id;
+ public boolean remoteActivating;
+ public Uri[] uris;
+ public int dataLinkType;
+
+ // Data link specific fields
+ public BluetoothDevice remoteDevice;
+
+
+ private BeamTransferRecord(BluetoothDevice remoteDevice,
+ boolean remoteActivating, Uri[] uris) {
+ this.id = 0;
+ this.remoteDevice = remoteDevice;
+ this.remoteActivating = remoteActivating;
+ this.uris = uris;
+
+ this.dataLinkType = DATA_LINK_TYPE_BLUETOOTH;
+ }
+
+ public static final BeamTransferRecord forBluetoothDevice(
+ BluetoothDevice remoteDevice, boolean remoteActivating,
+ Uri[] uris) {
+ return new BeamTransferRecord(remoteDevice, remoteActivating, uris);
+ }
+
+ public static final Parcelable.Creator<BeamTransferRecord> CREATOR
+ = new Parcelable.Creator<BeamTransferRecord>() {
+ public BeamTransferRecord createFromParcel(Parcel in) {
+ int deviceType = in.readInt();
+
+ if (deviceType != DATA_LINK_TYPE_BLUETOOTH) {
+ // only support BLUETOOTH
+ return null;
+ }
+
+ BluetoothDevice remoteDevice = in.readParcelable(getClass().getClassLoader());
+ boolean remoteActivating = (in.readInt() == 1);
+ int numUris = in.readInt();
+ Uri[] uris = null;
+ if (numUris > 0) {
+ uris = new Uri[numUris];
+ in.readTypedArray(uris, Uri.CREATOR);
+ }
+
+ return new BeamTransferRecord(remoteDevice,
+ remoteActivating, uris);
+
+ }
+
+ @Override
+ public BeamTransferRecord[] newArray(int size) {
+ return new BeamTransferRecord[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(dataLinkType);
+ dest.writeParcelable(remoteDevice, 0);
+ dest.writeInt(remoteActivating ? 1 : 0);
+ dest.writeInt(uris != null ? uris.length : 0);
+ if (uris != null && uris.length > 0) {
+ dest.writeTypedArray(uris, 0);
+ }
+ }
+}
diff --git a/src/com/android/nfc/handover/BluetoothOppHandover.java b/src/com/android/nfc/beam/BluetoothOppHandover.java
index 85e7f133..84d3c209 100644
--- a/src/com/android/nfc/handover/BluetoothOppHandover.java
+++ b/src/com/android/nfc/beam/BluetoothOppHandover.java
@@ -14,21 +14,18 @@
* limitations under the License.
*/
-package com.android.nfc.handover;
+package com.android.nfc.beam;
import android.bluetooth.BluetoothDevice;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.Log;
-import android.webkit.MimeTypeMap;
+
import java.util.ArrayList;
-import java.util.Arrays;
public class BluetoothOppHandover implements Handler.Callback {
static final String TAG = "BluetoothOppHandover";
@@ -52,14 +49,14 @@ public class BluetoothOppHandover implements Handler.Callback {
final Context mContext;
final BluetoothDevice mDevice;
- final Uri[] mUris;
+ final ArrayList<Uri> mUris;
final boolean mRemoteActivating;
final Handler mHandler;
final Long mCreateTime;
int mState;
- public BluetoothOppHandover(Context context, BluetoothDevice device, Uri[] uris,
+ public BluetoothOppHandover(Context context, BluetoothDevice device, ArrayList<Uri> uris,
boolean remoteActivating) {
mContext = context;
mDevice = device;
@@ -67,7 +64,7 @@ public class BluetoothOppHandover implements Handler.Callback {
mRemoteActivating = remoteActivating;
mCreateTime = SystemClock.elapsedRealtime();
- mHandler = new Handler(context.getMainLooper(),this);
+ mHandler = new Handler(context.getMainLooper(), this);
mState = STATE_INIT;
}
@@ -99,7 +96,7 @@ public class BluetoothOppHandover implements Handler.Callback {
void sendIntent() {
Intent intent = new Intent();
intent.setPackage("com.android.bluetooth");
- String mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, mUris[0]);
+ String mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, mUris.get(0));
intent.setType(mimeType);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
for (Uri uri : mUris) {
@@ -113,13 +110,12 @@ public class BluetoothOppHandover implements Handler.Callback {
Log.e(TAG, "Failed to transfer permission to Bluetooth process.");
}
}
- if (mUris.length == 1) {
+ if (mUris.size() == 1) {
intent.setAction(ACTION_HANDOVER_SEND);
- intent.putExtra(Intent.EXTRA_STREAM, mUris[0]);
+ intent.putExtra(Intent.EXTRA_STREAM, mUris.get(0));
} else {
- ArrayList<Uri> uris = new ArrayList<Uri>(Arrays.asList(mUris));
intent.setAction(ACTION_HANDOVER_SEND_MULTIPLE);
- intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+ intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, mUris);
}
if (DBG) Log.d(TAG, "Handing off outging transfer to BT");
mContext.sendBroadcast(intent);
diff --git a/src/com/android/nfc/FireflyRenderer.java b/src/com/android/nfc/beam/FireflyRenderer.java
index 40c931d1..d87a5d97 100644
--- a/src/com/android/nfc/FireflyRenderer.java
+++ b/src/com/android/nfc/beam/FireflyRenderer.java
@@ -15,7 +15,7 @@
*/
-package com.android.nfc;
+package com.android.nfc.beam;
import android.content.Context;
import android.graphics.Bitmap;
diff --git a/src/com/android/nfc/handover/MimeTypeUtil.java b/src/com/android/nfc/beam/MimeTypeUtil.java
index 7a0556d9..73d7fd6e 100644
--- a/src/com/android/nfc/handover/MimeTypeUtil.java
+++ b/src/com/android/nfc/beam/MimeTypeUtil.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.nfc.handover;
+package com.android.nfc.beam;
import android.content.ContentResolver;
import android.content.Context;
@@ -46,4 +46,4 @@ public final class MimeTypeUtil {
return null;
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/nfc/SendUi.java b/src/com/android/nfc/beam/SendUi.java
index 58a38888..0761ba52 100644
--- a/src/com/android/nfc/SendUi.java
+++ b/src/com/android/nfc/beam/SendUi.java
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-package com.android.nfc;
+package com.android.nfc.beam;
import com.android.internal.policy.PolicyManager;
+import com.android.nfc.R;
+import com.android.nfc.beam.FireflyRenderer;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -110,8 +112,8 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
static final int TEXT_HINT_ALPHA_DURATION_MS = 500;
static final int TEXT_HINT_ALPHA_START_DELAY_MS = 300;
- static final int FINISH_SCALE_UP = 0;
- static final int FINISH_SEND_SUCCESS = 1;
+ public static final int FINISH_SCALE_UP = 0;
+ public static final int FINISH_SEND_SUCCESS = 1;
static final int STATE_IDLE = 0;
static final int STATE_W4_SCREENSHOT = 1;
@@ -185,7 +187,7 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
int mSurfaceWidth;
int mSurfaceHeight;
- interface Callback {
+ public interface Callback {
public void onSendConfirmed();
public void onCanceled();
}
diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverDataParser.java
index d48b4904..71e06ad1 100644
--- a/src/com/android/nfc/handover/HandoverManager.java
+++ b/src/com/android/nfc/handover/HandoverDataParser.java
@@ -19,36 +19,23 @@ package com.android.nfc.handover;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Random;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.net.Uri;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
/**
* Manages handover of NFC to other technologies.
*/
-public class HandoverManager {
+public class HandoverDataParser {
private static final String TAG = "NfcHandover";
private static final boolean DBG = false;
@@ -72,33 +59,14 @@ public class HandoverManager {
private static final int BT_HANDOVER_TYPE_SHORT_LOCAL_NAME = 0x08;
public static final int BT_HANDOVER_LE_ROLE_CENTRAL_ONLY = 0x01;
- static final String ACTION_WHITELIST_DEVICE =
- "android.btopp.intent.action.WHITELIST_DEVICE";
-
- static final int MSG_HANDOVER_COMPLETE = 0;
- static final int MSG_HEADSET_CONNECTED = 1;
- static final int MSG_HEADSET_NOT_CONNECTED = 2;
-
- private final Context mContext;
private final BluetoothAdapter mBluetoothAdapter;
- private final MessageHandler mHandler = new MessageHandler();
- private final Messenger mMessenger = new Messenger(mHandler);
private final Object mLock = new Object();
// Variables below synchronized on mLock
- /* package as optimization */ HashMap<Integer, PendingHandoverTransfer> mPendingTransfers;
- private ArrayList<Message> mPendingServiceMessages;
- /* package as optimization */ boolean mBluetoothHeadsetPending;
- /* package as optimization */ boolean mBluetoothHeadsetConnected;
- protected boolean mBluetoothEnabledByNfc;
- private int mHandoverTransferId;
- private Messenger mService = null;
- private boolean mBinding = false;
- private boolean mBound;
+
private String mLocalBluetoothAddress;
- private boolean mEnabled;
- static class BluetoothHandoverData {
+ public static class BluetoothHandoverData {
public boolean valid = false;
public BluetoothDevice device;
public String name;
@@ -106,141 +74,19 @@ public class HandoverManager {
public int transport = BluetoothDevice.TRANSPORT_AUTO;
}
- class MessageHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- synchronized (mLock) {
- switch (msg.what) {
- case MSG_HANDOVER_COMPLETE:
- int transferId = msg.arg1;
- Log.d(TAG, "Completed transfer id: " + Integer.toString(transferId));
- if (mPendingTransfers.containsKey(transferId)) {
- mPendingTransfers.remove(transferId);
- } else {
- Log.e(TAG, "Could not find completed transfer id: " +
- Integer.toString(transferId));
- }
- break;
- case MSG_HEADSET_CONNECTED:
- mBluetoothEnabledByNfc = msg.arg1 != 0;
- mBluetoothHeadsetConnected = true;
- mBluetoothHeadsetPending = false;
- break;
- case MSG_HEADSET_NOT_CONNECTED:
- mBluetoothEnabledByNfc = false; // No need to maintain this state any longer
- mBluetoothHeadsetConnected = false;
- mBluetoothHeadsetPending = false;
- break;
- default:
- break;
- }
- unbindServiceIfNeededLocked(false);
- }
- }
- };
-
- private ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- mService = new Messenger(service);
- mBinding = false;
- mBound = true;
- // Register this client and transfer last known service state
- Message msg = Message.obtain(null, HandoverService.MSG_REGISTER_CLIENT);
- msg.arg1 = mBluetoothEnabledByNfc ? 1 : 0;
- msg.arg2 = mBluetoothHeadsetConnected ? 1 : 0;
- msg.replyTo = mMessenger;
- try {
- mService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register client");
- }
- // Send all queued messages
- while (!mPendingServiceMessages.isEmpty()) {
- msg = mPendingServiceMessages.remove(0);
- try {
- mService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send queued message to service");
- }
- }
- }
- }
+ public static class IncomingHandoverData {
+ public final NdefMessage handoverSelect;
+ public final BluetoothHandoverData handoverData;
- @Override
- public void onServiceDisconnected(ComponentName name) {
- synchronized (mLock) {
- Log.d(TAG, "Service disconnected");
- if (mService != null) {
- try {
- Message msg = Message.obtain(null, HandoverService.MSG_DEREGISTER_CLIENT);
- msg.replyTo = mMessenger;
- mService.send(msg);
- } catch (RemoteException e) {
- // Service may have crashed - ignore
- }
- }
- mService = null;
- mBound = false;
- mBluetoothHeadsetPending = false;
- mPendingTransfers.clear();
- mPendingServiceMessages.clear();
- }
- }
- };
-
- public HandoverManager(Context context) {
- mContext = context;
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mPendingTransfers = new HashMap<Integer, PendingHandoverTransfer>();
- mPendingServiceMessages = new ArrayList<Message>();
-
- IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiver(mReceiver, filter, null, null);
- mEnabled = true;
- mBluetoothEnabledByNfc = false;
- }
-
- final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_USER_SWITCHED)) {
- // Just force unbind the service.
- unbindServiceIfNeededLocked(true);
- }
- }
- };
-
- /**
- * @return whether the service was bound to successfully
- */
- boolean bindServiceIfNeededLocked() {
- if (!mBinding) {
- Log.d(TAG, "Binding to handover service");
- boolean bindSuccess = mContext.bindServiceAsUser(new Intent(mContext,
- HandoverService.class), mConnection, Context.BIND_AUTO_CREATE,
- UserHandle.CURRENT);
- mBinding = bindSuccess;
- return bindSuccess;
- } else {
- // A previous bind is pending
- return true;
+ public IncomingHandoverData(NdefMessage handoverSelect,
+ BluetoothHandoverData handoverData) {
+ this.handoverSelect = handoverSelect;
+ this.handoverData = handoverData;
}
}
- void unbindServiceIfNeededLocked(boolean force) {
- // If no service operation is pending, unbind
- if (mBound && (force || (!mBluetoothHeadsetPending && mPendingTransfers.isEmpty()))) {
- Log.d(TAG, "Unbinding from service.");
- mContext.unbindService(mConnection);
- mBound = false;
- mPendingServiceMessages.clear();
- mBluetoothHeadsetPending = false;
- mPendingTransfers.clear();
- }
- return;
+ public HandoverDataParser() {
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
static NdefRecord createCollisionRecord() {
@@ -256,7 +102,8 @@ public class HandoverManager {
payload[1] = 1; // length of carrier data reference
payload[2] = 'b'; // carrier data reference: ID for Bluetooth OOB data record
payload[3] = 0; // Auxiliary data reference count
- return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_ALTERNATIVE_CARRIER, null, payload);
+ return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_ALTERNATIVE_CARRIER, null,
+ payload);
}
NdefRecord createBluetoothOobDataRecord() {
@@ -280,12 +127,6 @@ public class HandoverManager {
return new NdefRecord(NdefRecord.TNF_MIME_MEDIA, TYPE_BT_OOB, new byte[]{'b'}, payload);
}
- public void setEnabled(boolean enabled) {
- synchronized (mLock) {
- mEnabled = enabled;
- }
- }
-
public boolean isHandoverSupported() {
return (mBluetoothAdapter != null);
}
@@ -345,16 +186,16 @@ public class HandoverManager {
}
/**
- * Return null if message is not a Handover Request,
- * return the Handover Select response if it is.
+ * Returns null if message is not a Handover Request,
+ * returns the IncomingHandoverData (Hs + parsed data) if it is.
*/
- public NdefMessage tryHandoverRequest(NdefMessage m) {
- if (m == null) return null;
+ public IncomingHandoverData getIncomingHandoverData(NdefMessage handoverRequest) {
+ if (handoverRequest == null) return null;
if (mBluetoothAdapter == null) return null;
- if (DBG) Log.d(TAG, "tryHandoverRequest():" + m.toString());
+ if (DBG) Log.d(TAG, "getIncomingHandoverData():" + handoverRequest.toString());
- NdefRecord handoverRequestRecord = m.getRecords()[0];
+ NdefRecord handoverRequestRecord = handoverRequest.getRecords()[0];
if (handoverRequestRecord.getTnf() != NdefRecord.TNF_WELL_KNOWN) {
return null;
}
@@ -365,7 +206,7 @@ public class HandoverManager {
// we have a handover request, look for BT OOB record
BluetoothHandoverData bluetoothData = null;
- for (NdefRecord dataRecord : m.getRecords()) {
+ for (NdefRecord dataRecord : handoverRequest.getRecords()) {
if (dataRecord.getTnf() == NdefRecord.TNF_MIME_MEDIA) {
if (Arrays.equals(dataRecord.getType(), TYPE_BT_OOB)) {
bluetoothData = parseBtOob(ByteBuffer.wrap(dataRecord.getPayload()));
@@ -373,13 +214,21 @@ public class HandoverManager {
}
}
- return tryBluetoothHandoverRequest(bluetoothData);
+ NdefMessage hs = tryBluetoothHandoverRequest(bluetoothData);
+ if (hs != null) {
+ return new IncomingHandoverData(hs, bluetoothData);
+ }
+
+ return null;
+ }
+
+ public BluetoothHandoverData getOutgoingHandoverData(NdefMessage handoverSelect) {
+ return parseBluetooth(handoverSelect);
}
private NdefMessage tryBluetoothHandoverRequest(BluetoothHandoverData bluetoothData) {
NdefMessage selectMessage = null;
if (bluetoothData != null) {
-
// Note: there could be a race where we conclude
// that Bluetooth is already enabled, and shortly
// after the user turns it off. That will cause
@@ -388,23 +237,6 @@ public class HandoverManager {
// be common for the user to be changing BT settings
// while waiting to receive a picture.
boolean bluetoothActivating = !mBluetoothAdapter.isEnabled();
- synchronized (mLock) {
- if (!mEnabled) return null;
-
- Message msg = Message.obtain(null, HandoverService.MSG_START_INCOMING_TRANSFER);
- PendingHandoverTransfer transfer
- = registerBluetoothInTransferLocked(bluetoothData.device);
- Bundle transferData = new Bundle();
- transferData.putParcelable(HandoverService.BUNDLE_TRANSFER, transfer);
- msg.setData(transferData);
-
- if (!sendOrQueueMessageLocked(msg)) {
- removeTransferLocked(transfer.id);
- return null;
- }
- }
- // BT OOB found, whitelist it for incoming OPP data
- whitelistOppDevice(bluetoothData.device);
// return BT OOB record so they can perform handover
selectMessage = (createBluetoothHandoverSelectMessage(bluetoothActivating));
@@ -415,101 +247,7 @@ public class HandoverManager {
return selectMessage;
}
- public boolean sendOrQueueMessageLocked(Message msg) {
- if (!mBound || mService == null) {
- // Need to start service, let us know if we can queue the message
- if (!bindServiceIfNeededLocked()) {
- Log.e(TAG, "Could not start service");
- return false;
- }
- // Queue the message to send when the service is bound
- mPendingServiceMessages.add(msg);
- } else {
- try {
- mService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not connect to handover service");
- return false;
- }
- }
- return true;
- }
-
- public boolean tryHandover(NdefMessage m) {
- if (m == null) return false;
- if (mBluetoothAdapter == null) return false;
-
- if (DBG) Log.d(TAG, "tryHandover(): " + m.toString());
-
- BluetoothHandoverData handover = parseBluetooth(m);
- if (handover == null) return false;
- if (!handover.valid) return true;
-
- synchronized (mLock) {
- if (!mEnabled) return false;
-
- if (mBluetoothAdapter == null) {
- if (DBG) Log.d(TAG, "BT handover, but BT not available");
- return true;
- }
-
- Message msg = Message.obtain(null, HandoverService.MSG_PERIPHERAL_HANDOVER, 0, 0);
- Bundle headsetData = new Bundle();
- headsetData.putParcelable(HandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
- headsetData.putString(HandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
- headsetData.putInt(HandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport);
- msg.setData(headsetData);
- return sendOrQueueMessageLocked(msg);
- }
- }
-
- // This starts sending an Uri over BT
- public void doHandoverUri(Uri[] uris,
- NdefMessage handoverResponse) {
- if (mBluetoothAdapter == null) return;
-
- BluetoothHandoverData data = parseBluetooth(handoverResponse);
- if (data != null && data.valid) {
- // Register a new handover transfer object
- synchronized (mLock) {
- Message msg = Message.obtain(null, HandoverService.MSG_START_OUTGOING_TRANSFER, 0, 0);
- PendingHandoverTransfer transfer = registerBluetoothOutTransferLocked(data, uris);
- Bundle transferData = new Bundle();
- transferData.putParcelable(HandoverService.BUNDLE_TRANSFER, transfer);
- msg.setData(transferData);
- if (DBG) Log.d(TAG, "Initiating outgoing bluetooth transfer, [" +
- mLocalBluetoothAddress + "]->[" + data.device.getAddress() + "]");
- sendOrQueueMessageLocked(msg);
- }
- }
- }
-
- PendingHandoverTransfer registerBluetoothInTransferLocked(BluetoothDevice remoteDevice) {
- PendingHandoverTransfer transfer = PendingHandoverTransfer.forBluetoothDevice(
- mHandoverTransferId++, true, remoteDevice, false, null);
- mPendingTransfers.put(transfer.id, transfer);
-
- return transfer;
- }
-
- PendingHandoverTransfer registerBluetoothOutTransferLocked(BluetoothHandoverData data,
- Uri[] uris) {
- PendingHandoverTransfer transfer = PendingHandoverTransfer.forBluetoothDevice(
- mHandoverTransferId++, false, data.device, data.carrierActivating, uris);
- mPendingTransfers.put(transfer.id, transfer);
- return transfer;
- }
- void removeTransferLocked(int id) {
- mPendingTransfers.remove(id);
- }
-
- void whitelistOppDevice(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP");
- Intent intent = new Intent(ACTION_WHITELIST_DEVICE);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
- }
boolean isCarrierActivating(NdefRecord handoverRec, byte[] carrierId) {
byte[] payload = handoverRec.getPayload();
@@ -567,7 +305,7 @@ public class HandoverManager {
return null;
}
- BluetoothHandoverData parseBluetooth(NdefMessage m) {
+ public BluetoothHandoverData parseBluetooth(NdefMessage m) {
NdefRecord r = m.getRecords()[0];
short tnf = r.getTnf();
byte[] type = r.getType();
@@ -729,16 +467,5 @@ public class HandoverManager {
return result;
}
-
- final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
- private static String byteArrayToHexString(byte[] bytes) {
- char[] hexChars = new char[bytes.length * 2];
- for ( int j = 0; j < bytes.length; j++ ) {
- int v = bytes[j] & 0xFF;
- hexChars[j * 2] = hexArray[v >>> 4];
- hexChars[j * 2 + 1] = hexArray[v & 0x0F];
- }
- return new String(hexChars);
- }
}
diff --git a/src/com/android/nfc/handover/HandoverServer.java b/src/com/android/nfc/handover/HandoverServer.java
index 093d1dd5..56036d82 100644
--- a/src/com/android/nfc/handover/HandoverServer.java
+++ b/src/com/android/nfc/handover/HandoverServer.java
@@ -15,29 +15,37 @@
*/
package com.android.nfc.handover;
+import com.android.nfc.DeviceHost.LlcpServerSocket;
+import com.android.nfc.DeviceHost.LlcpSocket;
+import com.android.nfc.LlcpException;
+import com.android.nfc.NfcService;
+import com.android.nfc.beam.BeamManager;
+import com.android.nfc.beam.BeamReceiveService;
+import com.android.nfc.beam.BeamTransferRecord;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.Intent;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
+import android.os.UserHandle;
import android.util.Log;
-import com.android.nfc.LlcpException;
-import com.android.nfc.NfcService;
-import com.android.nfc.DeviceHost.LlcpServerSocket;
-import com.android.nfc.DeviceHost.LlcpSocket;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
public final class HandoverServer {
- public static final String HANDOVER_SERVICE_NAME = "urn:nfc:sn:handover";
- public static final String TAG = "HandoverServer";
- public static final Boolean DBG = false;
+ static final String HANDOVER_SERVICE_NAME = "urn:nfc:sn:handover";
+ static final String TAG = "HandoverServer";
+ static final Boolean DBG = false;
- public static final int MIU = 128;
+ static final int MIU = 128;
- final HandoverManager mHandoverManager;
+ final HandoverDataParser mHandoverDataParser;
final int mSap;
final Callback mCallback;
+ private final Context mContext;
ServerThread mServerThread = null;
boolean mServerRunning = false;
@@ -46,9 +54,10 @@ public final class HandoverServer {
void onHandoverRequestReceived();
}
- public HandoverServer(int sap, HandoverManager manager, Callback callback) {
+ public HandoverServer(Context context, int sap, HandoverDataParser manager, Callback callback) {
+ mContext = context;
mSap = sap;
- mHandoverManager = manager;
+ mHandoverDataParser = manager;
mCallback = callback;
}
@@ -191,16 +200,23 @@ public final class HandoverServer {
}
if (handoverRequestMsg != null) {
+ BeamManager beamManager = BeamManager.getInstance();
+
+ if (beamManager.isBeamInProgress()) {
+ break;
+ }
+
// 2) convert to handover response
- NdefMessage resp = mHandoverManager.tryHandoverRequest(handoverRequestMsg);
- if (resp == null) {
+ HandoverDataParser.IncomingHandoverData handoverData
+ = mHandoverDataParser.getIncomingHandoverData(handoverRequestMsg);
+ if (handoverData == null) {
Log.e(TAG, "Failed to create handover response");
break;
}
// 3) send handover response
int offset = 0;
- byte[] buffer = resp.toByteArray();
+ byte[] buffer = handoverData.handoverSelect.toByteArray();
int remoteMiu = mSock.getRemoteMiu();
while (offset < buffer.length) {
int length = Math.min(buffer.length - offset, remoteMiu);
@@ -210,6 +226,9 @@ public final class HandoverServer {
}
// We're done
mCallback.onHandoverRequestReceived();
+ if (!beamManager.startBeamReceive(mContext, handoverData.handoverData)) {
+ break;
+ }
// We can process another handover transfer
byteStream = new ByteArrayOutputStream();
}
@@ -238,3 +257,4 @@ public final class HandoverServer {
}
}
}
+
diff --git a/src/com/android/nfc/handover/HandoverService.java b/src/com/android/nfc/handover/HandoverService.java
deleted file mode 100644
index b2c7814e..00000000
--- a/src/com/android/nfc/handover/HandoverService.java
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.nfc.handover;
-
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.media.SoundPool;
-import android.net.Uri;
-import android.nfc.NfcAdapter;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.nfc.R;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Queue;
-
-public class HandoverService extends Service implements HandoverTransfer.Callback,
- BluetoothPeripheralHandover.Callback {
-
- static final String TAG = "HandoverService";
- static final boolean DBG = true;
-
- static final int MSG_REGISTER_CLIENT = 0;
- static final int MSG_DEREGISTER_CLIENT = 1;
- static final int MSG_START_INCOMING_TRANSFER = 2;
- static final int MSG_START_OUTGOING_TRANSFER = 3;
- static final int MSG_PERIPHERAL_HANDOVER = 4;
- static final int MSG_PAUSE_POLLING = 5;
-
-
- static final String BUNDLE_TRANSFER = "transfer";
-
- static final String EXTRA_PERIPHERAL_DEVICE = "device";
- static final String EXTRA_PERIPHERAL_NAME = "headsetname";
- static final String EXTRA_PERIPHERAL_TRANSPORT = "transporttype";
-
- public static final String ACTION_CANCEL_HANDOVER_TRANSFER =
- "com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER";
-
- public static final String EXTRA_INCOMING =
- "com.android.nfc.handover.extra.INCOMING";
-
- public static final String ACTION_HANDOVER_STARTED =
- "android.nfc.handover.intent.action.HANDOVER_STARTED";
-
- public static final String ACTION_TRANSFER_PROGRESS =
- "android.nfc.handover.intent.action.TRANSFER_PROGRESS";
-
- public static final String ACTION_TRANSFER_DONE =
- "android.nfc.handover.intent.action.TRANSFER_DONE";
-
- public static final String EXTRA_TRANSFER_STATUS =
- "android.nfc.handover.intent.extra.TRANSFER_STATUS";
-
- public static final String EXTRA_TRANSFER_MIMETYPE =
- "android.nfc.handover.intent.extra.TRANSFER_MIME_TYPE";
-
- public static final String EXTRA_ADDRESS =
- "android.nfc.handover.intent.extra.ADDRESS";
-
- public static final String EXTRA_TRANSFER_DIRECTION =
- "android.nfc.handover.intent.extra.TRANSFER_DIRECTION";
-
- public static final String EXTRA_TRANSFER_ID =
- "android.nfc.handover.intent.extra.TRANSFER_ID";
-
- public static final String EXTRA_TRANSFER_PROGRESS =
- "android.nfc.handover.intent.extra.TRANSFER_PROGRESS";
-
- public static final String EXTRA_TRANSFER_URI =
- "android.nfc.handover.intent.extra.TRANSFER_URI";
-
- public static final String EXTRA_OBJECT_COUNT =
- "android.nfc.handover.intent.extra.OBJECT_COUNT";
-
- public static final String EXTRA_HANDOVER_DEVICE_TYPE =
- "android.nfc.handover.intent.extra.HANDOVER_DEVICE_TYPE";
-
- public static final int DIRECTION_INCOMING = 0;
- public static final int DIRECTION_OUTGOING = 1;
-
- public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
- public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
-
- // permission needed to be able to receive handover status requests
- public static final String HANDOVER_STATUS_PERMISSION =
- "android.permission.NFC_HANDOVER_STATUS";
-
- // Amount of time to pause polling when connecting to peripherals
- private static final int PAUSE_POLLING_TIMEOUT_MS = 35000;
- public static final int PAUSE_DELAY_MILLIS = 300;
-
- // Variables below only accessed on main thread
- final Queue<BluetoothOppHandover> mPendingOutTransfers;
- final HashMap<Pair<String, Boolean>, HandoverTransfer> mBluetoothTransfers;
- final Messenger mMessenger;
-
- SoundPool mSoundPool;
- int mSuccessSound;
-
- BluetoothAdapter mBluetoothAdapter;
- NfcAdapter mNfcAdapter;
- Messenger mClient;
- Handler mHandler;
- BluetoothPeripheralHandover mBluetoothPeripheralHandover;
- boolean mBluetoothHeadsetConnected;
- boolean mBluetoothEnabledByNfc;
-
- private HandoverTransfer mWifiTransfer;
-
- class MessageHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_REGISTER_CLIENT:
- mClient = msg.replyTo;
- // Restore state from previous instance
- mBluetoothEnabledByNfc = msg.arg1 != 0;
- mBluetoothHeadsetConnected = msg.arg2 != 0;
- break;
- case MSG_DEREGISTER_CLIENT:
- mClient = null;
- break;
- case MSG_START_INCOMING_TRANSFER:
- doIncomingTransfer(msg);
- break;
- case MSG_START_OUTGOING_TRANSFER:
- doOutgoingTransfer(msg);
- break;
- case MSG_PERIPHERAL_HANDOVER:
- doPeripheralHandover(msg);
- break;
- case MSG_PAUSE_POLLING:
- mNfcAdapter.pausePolling(PAUSE_POLLING_TIMEOUT_MS);
- break;
- }
- }
-
- }
-
- final BroadcastReceiver mHandoverStatusReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- int deviceType = intent.getIntExtra(EXTRA_HANDOVER_DEVICE_TYPE,
- HandoverTransfer.DEVICE_TYPE_BLUETOOTH);
-
- if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
- handleBluetoothStateChanged(intent);
- } else if (action.equals(ACTION_CANCEL_HANDOVER_TRANSFER)) {
- handleCancelTransfer(intent, deviceType);
- } else if (action.equals(ACTION_TRANSFER_PROGRESS) ||
- action.equals(ACTION_TRANSFER_DONE) ||
- action.equals(ACTION_HANDOVER_STARTED)) {
- handleTransferEvent(intent, deviceType);
- }
- }
- };
-
- public HandoverService() {
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mPendingOutTransfers = new LinkedList<BluetoothOppHandover>();
- mBluetoothTransfers = new HashMap<Pair<String, Boolean>, HandoverTransfer>();
- mHandler = new MessageHandler();
- mMessenger = new Messenger(mHandler);
- mBluetoothHeadsetConnected = false;
- mBluetoothEnabledByNfc = false;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
- mSuccessSound = mSoundPool.load(this, R.raw.end, 1);
- mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
-
- IntentFilter filter = new IntentFilter(ACTION_TRANSFER_DONE);
- filter.addAction(ACTION_TRANSFER_PROGRESS);
- filter.addAction(ACTION_CANCEL_HANDOVER_TRANSFER);
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- filter.addAction(ACTION_HANDOVER_STARTED);
- registerReceiver(mHandoverStatusReceiver, filter, HANDOVER_STATUS_PERMISSION, mHandler);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (mSoundPool != null) {
- mSoundPool.release();
- }
- unregisterReceiver(mHandoverStatusReceiver);
- }
-
- void doOutgoingTransfer(Message msg) {
- Bundle msgData = msg.getData();
-
- msgData.setClassLoader(getClassLoader());
- PendingHandoverTransfer pendingTransfer = msgData.getParcelable(BUNDLE_TRANSFER);
- createHandoverTransfer(pendingTransfer);
-
- if (pendingTransfer.deviceType == HandoverTransfer.DEVICE_TYPE_BLUETOOTH) {
- // Create the actual bluetooth transfer
-
- BluetoothOppHandover handover = new BluetoothOppHandover(HandoverService.this,
- pendingTransfer.remoteDevice, pendingTransfer.uris,
- pendingTransfer.remoteActivating);
- if (mBluetoothAdapter.isEnabled()) {
- // Start the transfer
- handover.start();
- } else {
- if (!enableBluetooth()) {
- Log.e(TAG, "Error enabling Bluetooth.");
- notifyClientTransferComplete(pendingTransfer.id);
- return;
- }
- if (DBG) Log.d(TAG, "Queueing out transfer " + Integer.toString(pendingTransfer.id));
- mPendingOutTransfers.add(handover);
- // Queue the transfer and enable Bluetooth - when it is enabled
- // the transfer will be started.
- }
- }
- }
-
- void doIncomingTransfer(Message msg) {
- Bundle msgData = msg.getData();
-
- msgData.setClassLoader(getClassLoader());
- PendingHandoverTransfer pendingTransfer = msgData.getParcelable(BUNDLE_TRANSFER);
- if (pendingTransfer.deviceType == HandoverTransfer.DEVICE_TYPE_BLUETOOTH &&
- !mBluetoothAdapter.isEnabled() && !enableBluetooth()) {
- Log.e(TAG, "Error enabling Bluetooth.");
- notifyClientTransferComplete(pendingTransfer.id);
- return;
- }
- createHandoverTransfer(pendingTransfer);
- // Remote device will connect and finish the transfer
- }
-
- void doPeripheralHandover(Message msg) {
- Bundle msgData = msg.getData();
- BluetoothDevice device = msgData.getParcelable(EXTRA_PERIPHERAL_DEVICE);
- String name = msgData.getString(EXTRA_PERIPHERAL_NAME);
- int transport = msgData.getInt(EXTRA_PERIPHERAL_TRANSPORT);
- if (mBluetoothPeripheralHandover != null) {
- Log.d(TAG, "Ignoring pairing request, existing handover in progress.");
- return;
- }
- mBluetoothPeripheralHandover = new BluetoothPeripheralHandover(HandoverService.this,
- device, name, transport, HandoverService.this);
- // TODO: figure out a way to disable polling without deactivating current target
- if (transport == BluetoothDevice.TRANSPORT_LE) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_PAUSE_POLLING), PAUSE_DELAY_MILLIS);
- }
- if (mBluetoothAdapter.isEnabled()) {
- if (!mBluetoothPeripheralHandover.start()) {
- mNfcAdapter.resumePolling();
- }
- } else {
- // Once BT is enabled, the headset pairing will be started
-
- if (!enableBluetooth()) {
- Log.e(TAG, "Error enabling Bluetooth.");
- mBluetoothPeripheralHandover = null;
- }
- }
- }
-
- void startPendingTransfers() {
- while (!mPendingOutTransfers.isEmpty()) {
- BluetoothOppHandover handover = mPendingOutTransfers.remove();
- handover.start();
- }
- }
-
- boolean enableBluetooth() {
- if (!mBluetoothAdapter.isEnabled()) {
- mBluetoothEnabledByNfc = true;
- return mBluetoothAdapter.enableNoAutoConnect();
- }
- return true;
- }
-
- void disableBluetoothIfNeeded() {
- if (!mBluetoothEnabledByNfc) return;
-
- if (mBluetoothTransfers.size() == 0 && !mBluetoothHeadsetConnected) {
- mBluetoothAdapter.disable();
- mBluetoothEnabledByNfc = false;
- }
- }
-
- void createHandoverTransfer(PendingHandoverTransfer pendingTransfer) {
- HandoverTransfer transfer;
- String macAddress;
-
- if (pendingTransfer.deviceType == HandoverTransfer.DEVICE_TYPE_BLUETOOTH) {
- macAddress = pendingTransfer.remoteDevice.getAddress();
- transfer = maybeCreateHandoverTransfer(macAddress,
- pendingTransfer.incoming, pendingTransfer);
- } else {
- Log.e(TAG, "Invalid device type [" + pendingTransfer.deviceType + "] received.");
- return;
- }
-
- if (transfer != null) {
- transfer.updateNotification();
- }
- }
-
- HandoverTransfer maybeCreateHandoverTransfer(String address, boolean incoming,
- PendingHandoverTransfer pendingTransfer) {
- HandoverTransfer transfer;
- Pair<String, Boolean> key = new Pair<String, Boolean>(address, incoming);
-
- if (mBluetoothTransfers.containsKey(key)) {
- transfer = mBluetoothTransfers.get(key);
- if (!transfer.isRunning()) {
- mBluetoothTransfers.remove(key); // new one created below
- } else {
- // There is already a transfer running to this
- // device - it will automatically get combined
- // with the existing transfer.
- notifyClientTransferComplete(pendingTransfer.id);
- return null;
- }
- } else {
- transfer = new HandoverTransfer(this, this, pendingTransfer);
- }
-
- mBluetoothTransfers.put(key, transfer);
- return transfer;
- }
-
-
- HandoverTransfer findHandoverTransfer(String macAddress, boolean incoming) {
- Pair<String, Boolean> key = new Pair<String, Boolean>(macAddress, incoming);
- if (mBluetoothTransfers.containsKey(key)) {
- HandoverTransfer transfer = mBluetoothTransfers.get(key);
- if (transfer.isRunning()) {
- return transfer;
- }
- }
-
- return null;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mMessenger.getBinder();
- }
-
- private void handleTransferEvent(Intent intent, int deviceType) {
- String action = intent.getAction();
- int direction = intent.getIntExtra(EXTRA_TRANSFER_DIRECTION, -1);
- int id = intent.getIntExtra(EXTRA_TRANSFER_ID, -1);
- if (action.equals(ACTION_HANDOVER_STARTED)) {
- // This is always for incoming transfers
- direction = DIRECTION_INCOMING;
- }
- String sourceAddress = intent.getStringExtra(EXTRA_ADDRESS);
-
- if (direction == -1 || sourceAddress == null) return;
- boolean incoming = (direction == DIRECTION_INCOMING);
-
- HandoverTransfer transfer =
- findHandoverTransfer(sourceAddress, incoming);
- if (transfer == null) {
- // There is no transfer running for this source address; most likely
- // the transfer was cancelled. We need to tell BT OPP to stop transferring.
- if (id != -1) {
- if (deviceType == HandoverTransfer.DEVICE_TYPE_BLUETOOTH) {
- if (DBG) Log.d(TAG, "Didn't find transfer, stopping");
- Intent cancelIntent = new Intent(
- "android.btopp.intent.action.STOP_HANDOVER_TRANSFER");
- cancelIntent.putExtra(EXTRA_TRANSFER_ID, id);
- sendBroadcast(cancelIntent);
- }
- }
- return;
- }
-
- transfer.setBluetoothTransferId(id);
-
- if (action.equals(ACTION_TRANSFER_DONE)) {
- int handoverStatus = intent.getIntExtra(EXTRA_TRANSFER_STATUS,
- HANDOVER_TRANSFER_STATUS_FAILURE);
- if (handoverStatus == HANDOVER_TRANSFER_STATUS_SUCCESS) {
- String uriString = intent.getStringExtra(EXTRA_TRANSFER_URI);
- String mimeType = intent.getStringExtra(EXTRA_TRANSFER_MIMETYPE);
- Uri uri = Uri.parse(uriString);
- if (uri != null && uri.getScheme() == null) {
- uri = Uri.fromFile(new File(uri.getPath()));
- }
- transfer.finishTransfer(true, uri, mimeType);
- } else {
- transfer.finishTransfer(false, null, null);
- }
- } else if (action.equals(ACTION_TRANSFER_PROGRESS)) {
- float progress = intent.getFloatExtra(EXTRA_TRANSFER_PROGRESS, 0.0f);
- transfer.updateFileProgress(progress);
- } else if (action.equals(ACTION_HANDOVER_STARTED)) {
- int count = intent.getIntExtra(EXTRA_OBJECT_COUNT, 0);
- if (count > 0) {
- transfer.setObjectCount(count);
- }
- }
- }
-
- private void handleCancelTransfer(Intent intent, int deviceType) {
- String sourceAddress = intent.getStringExtra(EXTRA_ADDRESS);
- int direction = intent.getIntExtra(EXTRA_INCOMING, -1);
-
- if (direction == -1) {
- return;
- }
-
- boolean incoming = direction == DIRECTION_INCOMING;
- HandoverTransfer transfer = findHandoverTransfer(sourceAddress, incoming);
-
- if (transfer != null) {
- if (DBG) Log.d(TAG, "Cancelling transfer " + Integer.toString(transfer.mTransferId));
- transfer.cancel();
- }
- }
-
- private void handleBluetoothStateChanged(Intent intent) {
- int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- BluetoothAdapter.ERROR);
- if (state == BluetoothAdapter.STATE_ON) {
- // If there is a pending device pairing, start it
- if (mBluetoothPeripheralHandover != null &&
- !mBluetoothPeripheralHandover.hasStarted()) {
- if (!mBluetoothPeripheralHandover.start()) {
- mNfcAdapter.resumePolling();
- }
- }
-
- // Start any pending file transfers
- startPendingTransfers();
- } else if (state == BluetoothAdapter.STATE_OFF) {
- mBluetoothEnabledByNfc = false;
- mBluetoothHeadsetConnected = false;
- }
- }
-
- void notifyClientTransferComplete(int transferId) {
- if (mClient != null) {
- Message msg = Message.obtain(null, HandoverManager.MSG_HANDOVER_COMPLETE);
- msg.arg1 = transferId;
- try {
- mClient.send(msg);
- } catch (RemoteException e) {
- // Ignore
- }
- }
- }
-
- @Override
- public boolean onUnbind(Intent intent) {
- // prevent any future callbacks to the client, no rebind call needed.
- mClient = null;
- return false;
- }
-
- @Override
- public void onTransferComplete(HandoverTransfer transfer, boolean success) {
- // Called on the main thread
-
- // First, remove the transfer from our list
- synchronized (this) {
- if (mWifiTransfer == transfer) {
- mWifiTransfer = null;
- }
- }
-
- if (mWifiTransfer == null) {
- Iterator it = mBluetoothTransfers.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry hashPair = (Map.Entry)it.next();
- HandoverTransfer transferEntry = (HandoverTransfer) hashPair.getValue();
- if (transferEntry == transfer) {
- it.remove();
- }
- }
- }
-
- // Notify any clients of the service
- notifyClientTransferComplete(transfer.getTransferId());
-
- // Play success sound
- if (success) {
- mSoundPool.play(mSuccessSound, 1.0f, 1.0f, 0, 0, 1.0f);
- } else {
- if (DBG) Log.d(TAG, "Transfer failed, final state: " +
- Integer.toString(transfer.mState));
- }
- disableBluetoothIfNeeded();
- }
-
- @Override
- public void onBluetoothPeripheralHandoverComplete(boolean connected) {
- // Called on the main thread
- int transport = mBluetoothPeripheralHandover.mTransport;
- mBluetoothPeripheralHandover = null;
- mBluetoothHeadsetConnected = connected;
-
- // <hack> resume polling immediately if the connection failed,
- // otherwise just wait for polling to come back up after the timeout
- // This ensures we don't disconnect if the user left the volantis
- // on the tag after pairing completed, which results in automatic
- // disconnection </hack>
- if (transport == BluetoothDevice.TRANSPORT_LE && !connected) {
- if (mHandler.hasMessages(MSG_PAUSE_POLLING)) {
- mHandler.removeMessages(MSG_PAUSE_POLLING);
- }
-
- // do this unconditionally as the polling could have been paused as we were removing
- // the message in the handler. It's a no-op if polling is already enabled.
- mNfcAdapter.resumePolling();
- }
-
- if (mClient != null) {
- Message msg = Message.obtain(null,
- connected ? HandoverManager.MSG_HEADSET_CONNECTED
- : HandoverManager.MSG_HEADSET_NOT_CONNECTED);
- msg.arg1 = mBluetoothEnabledByNfc ? 1 : 0;
- try {
- mClient.send(msg);
- } catch (RemoteException e) {
- // Ignore
- }
- }
- disableBluetoothIfNeeded();
- }
-}
diff --git a/src/com/android/nfc/handover/PendingHandoverTransfer.java b/src/com/android/nfc/handover/PendingHandoverTransfer.java
deleted file mode 100644
index 568b3ecd..00000000
--- a/src/com/android/nfc/handover/PendingHandoverTransfer.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.nfc.handover;
-
-import android.bluetooth.BluetoothDevice;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class PendingHandoverTransfer implements Parcelable {
-
- public String remoteMacAddress; // For type WIFI only
- public BluetoothDevice remoteDevice; // For type BLUETOOTH only
- public int id;
- public boolean incoming;
- public boolean remoteActivating;
- public Uri[] uris;
- public int deviceType;
-
- private PendingHandoverTransfer(int id, boolean incoming, BluetoothDevice remoteDevice,
- boolean remoteActivating, Uri[] uris) {
- this.id = id;
- this.incoming = incoming;
- this.remoteDevice = remoteDevice;
- this.remoteActivating = remoteActivating;
- this.uris = uris;
-
- this.deviceType = HandoverTransfer.DEVICE_TYPE_BLUETOOTH;
- }
-
- private PendingHandoverTransfer(int id, boolean incoming, String remoteMacAddress,
- boolean remoteActivating, Uri[] uris) {
- this.id = id;
- this.incoming = incoming;
- this.remoteMacAddress = remoteMacAddress;
- this.remoteActivating = remoteActivating;
- this.uris = uris;
-
- this.deviceType = HandoverTransfer.DEVICE_TYPE_WIFI;
- }
-
- public static final PendingHandoverTransfer forBluetoothDevice(
- int id, boolean incoming, BluetoothDevice remoteDevice, boolean remoteActivating,
- Uri[] uris) {
- return new PendingHandoverTransfer(id, incoming, remoteDevice, remoteActivating, uris);
- }
-
- public static final PendingHandoverTransfer forWifiDevice(
- int id, boolean incoming, String macAddress, boolean remoteActivating, Uri[] uris) {
- return new PendingHandoverTransfer(id, incoming, macAddress, remoteActivating, uris);
- }
-
- public static final Parcelable.Creator<PendingHandoverTransfer> CREATOR
- = new Parcelable.Creator<PendingHandoverTransfer>() {
- public PendingHandoverTransfer createFromParcel(Parcel in) {
- int id = in.readInt();
- boolean incoming = (in.readInt() == 1) ? true : false;
- int deviceType = in.readInt();
- BluetoothDevice remoteDevice = null;
- String remoteMac = null;
- if (deviceType == HandoverTransfer.DEVICE_TYPE_BLUETOOTH) {
- remoteDevice = in.readParcelable(getClass().getClassLoader());
- } else {
- remoteMac = in.readString();
- }
- boolean remoteActivating = (in.readInt() == 1) ? true : false;
- int numUris = in.readInt();
- Uri[] uris = null;
- if (numUris > 0) {
- uris = new Uri[numUris];
- in.readTypedArray(uris, Uri.CREATOR);
- }
- if (deviceType == HandoverTransfer.DEVICE_TYPE_BLUETOOTH) {
- return new PendingHandoverTransfer(id, incoming, remoteDevice,
- remoteActivating, uris);
- } else {
- return new PendingHandoverTransfer(id, incoming, remoteMac, remoteActivating, uris);
- }
- }
-
- @Override
- public PendingHandoverTransfer[] newArray(int size) {
- return new PendingHandoverTransfer[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(id);
- dest.writeInt(incoming ? 1 : 0);
- dest.writeInt(deviceType);
- if (deviceType == HandoverTransfer.DEVICE_TYPE_BLUETOOTH) {
- dest.writeParcelable(remoteDevice, 0);
- } else {
- dest.writeString(remoteMacAddress);
- }
- dest.writeInt(remoteActivating ? 1 : 0);
- dest.writeInt(uris != null ? uris.length : 0);
- if (uris != null && uris.length > 0) {
- dest.writeTypedArray(uris, 0);
- }
- }
-}
diff --git a/src/com/android/nfc/handover/PeripheralHandoverService.java b/src/com/android/nfc/handover/PeripheralHandoverService.java
new file mode 100644
index 00000000..3e0f2448
--- /dev/null
+++ b/src/com/android/nfc/handover/PeripheralHandoverService.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.handover;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.media.SoundPool;
+import android.nfc.NfcAdapter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.nfc.R;
+
+public class PeripheralHandoverService extends Service implements BluetoothPeripheralHandover.Callback {
+ static final String TAG = "PeripheralHandoverService";
+ static final boolean DBG = true;
+
+ static final int MSG_PAUSE_POLLING = 0;
+
+ public static final String BUNDLE_TRANSFER = "transfer";
+ public static final String EXTRA_PERIPHERAL_DEVICE = "device";
+ public static final String EXTRA_PERIPHERAL_NAME = "headsetname";
+ public static final String EXTRA_PERIPHERAL_TRANSPORT = "transporttype";
+
+ // Amount of time to pause polling when connecting to peripherals
+ private static final int PAUSE_POLLING_TIMEOUT_MS = 35000;
+ private static final int PAUSE_DELAY_MILLIS = 300;
+
+ // Variables below only accessed on main thread
+ final Messenger mMessenger;
+
+ SoundPool mSoundPool;
+ int mSuccessSound;
+ int mStartId;
+
+ BluetoothAdapter mBluetoothAdapter;
+ NfcAdapter mNfcAdapter;
+ Handler mHandler;
+ BluetoothPeripheralHandover mBluetoothPeripheralHandover;
+ boolean mBluetoothHeadsetConnected;
+ boolean mBluetoothEnabledByNfc;
+
+ class MessageHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PAUSE_POLLING:
+ mNfcAdapter.pausePolling(PAUSE_POLLING_TIMEOUT_MS);
+ break;
+ }
+ }
+ }
+
+ final BroadcastReceiver mBluetoothStatusReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+ handleBluetoothStateChanged(intent);
+ }
+ }
+ };
+
+ public PeripheralHandoverService() {
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mHandler = new MessageHandler();
+ mMessenger = new Messenger(mHandler);
+ mBluetoothHeadsetConnected = false;
+ mBluetoothEnabledByNfc = false;
+ mStartId = 0;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (mStartId != 0) {
+ // already running
+ return START_STICKY;
+ }
+
+ mStartId = startId;
+
+ if (intent == null) {
+ if (DBG) Log.e(TAG, "Intent is null, can't do peripheral handover.");
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+
+ if (doPeripheralHandover(intent.getExtras())) {
+ return START_STICKY;
+ } else {
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
+ mSuccessSound = mSoundPool.load(this, R.raw.end, 1);
+ mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
+
+ IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ registerReceiver(mBluetoothStatusReceiver, filter);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mSoundPool != null) {
+ mSoundPool.release();
+ }
+ unregisterReceiver(mBluetoothStatusReceiver);
+ }
+
+ boolean doPeripheralHandover(Bundle msgData) {
+ if (mBluetoothPeripheralHandover != null) {
+ Log.d(TAG, "Ignoring pairing request, existing handover in progress.");
+ return true;
+ }
+
+ if (msgData == null) {
+ return false;
+ }
+
+ BluetoothDevice device = msgData.getParcelable(EXTRA_PERIPHERAL_DEVICE);
+ String name = msgData.getString(EXTRA_PERIPHERAL_NAME);
+ int transport = msgData.getInt(EXTRA_PERIPHERAL_TRANSPORT);
+
+ mBluetoothPeripheralHandover = new BluetoothPeripheralHandover(
+ this, device, name, transport, this);
+
+ if (transport == BluetoothDevice.TRANSPORT_LE) {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_PAUSE_POLLING), PAUSE_DELAY_MILLIS);
+ }
+ if (mBluetoothAdapter.isEnabled()) {
+ if (!mBluetoothPeripheralHandover.start()) {
+ mHandler.removeMessages(MSG_PAUSE_POLLING);
+ mNfcAdapter.resumePolling();
+ }
+ } else {
+ // Once BT is enabled, the headset pairing will be started
+ if (!enableBluetooth()) {
+ Log.e(TAG, "Error enabling Bluetooth.");
+ mBluetoothPeripheralHandover = null;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void handleBluetoothStateChanged(Intent intent) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ if (state == BluetoothAdapter.STATE_ON) {
+ // If there is a pending device pairing, start it
+ if (mBluetoothPeripheralHandover != null &&
+ !mBluetoothPeripheralHandover.hasStarted()) {
+ if (!mBluetoothPeripheralHandover.start()) {
+ mNfcAdapter.resumePolling();
+ }
+ }
+ } else if (state == BluetoothAdapter.STATE_OFF) {
+ mBluetoothEnabledByNfc = false;
+ mBluetoothHeadsetConnected = false;
+ }
+ }
+
+ @Override
+ public void onBluetoothPeripheralHandoverComplete(boolean connected) {
+ // Called on the main thread
+ int transport = mBluetoothPeripheralHandover.mTransport;
+ mBluetoothPeripheralHandover = null;
+ mBluetoothHeadsetConnected = connected;
+
+ // <hack> resume polling immediately if the connection failed,
+ // otherwise just wait for polling to come back up after the timeout
+ // This ensures we don't disconnect if the user left the volantis
+ // on the tag after pairing completed, which results in automatic
+ // disconnection </hack>
+ if (transport == BluetoothDevice.TRANSPORT_LE && !connected) {
+ if (mHandler.hasMessages(MSG_PAUSE_POLLING)) {
+ mHandler.removeMessages(MSG_PAUSE_POLLING);
+ }
+
+ // do this unconditionally as the polling could have been paused as we were removing
+ // the message in the handler. It's a no-op if polling is already enabled.
+ mNfcAdapter.resumePolling();
+ }
+ disableBluetoothIfNeeded();
+ stopSelf(mStartId);
+ }
+
+
+ boolean enableBluetooth() {
+ if (!mBluetoothAdapter.isEnabled()) {
+ mBluetoothEnabledByNfc = true;
+ return mBluetoothAdapter.enableNoAutoConnect();
+ }
+ return true;
+ }
+
+ void disableBluetoothIfNeeded() {
+ if (!mBluetoothEnabledByNfc) return;
+
+ if (!mBluetoothHeadsetConnected) {
+ mBluetoothAdapter.disable();
+ mBluetoothEnabledByNfc = false;
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ // prevent any future callbacks to the client, no rebind call needed.
+ return false;
+ }
+}