summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/nfc/DeviceHost.java20
-rw-r--r--src/com/android/nfc/FireflyRenderer.java1
-rw-r--r--src/com/android/nfc/NfcApplication.java24
-rw-r--r--src/com/android/nfc/NfcDispatcher.java42
-rw-r--r--src/com/android/nfc/NfcRootActivity.java4
-rwxr-xr-xsrc/com/android/nfc/NfcService.java401
-rwxr-xr-xsrc/com/android/nfc/P2pLinkManager.java18
-rw-r--r--src/com/android/nfc/RegisteredComponentCache.java31
-rw-r--r--src/com/android/nfc/SendUi.java20
-rw-r--r--src/com/android/nfc/handover/BluetoothHeadsetHandover.java231
-rw-r--r--src/com/android/nfc/handover/HandoverManager.java55
-rwxr-xr-xsrc/com/android/nfc/ndefpush/NdefPushServer.java67
-rw-r--r--src/com/android/nfc/snep/SnepClient.java24
-rw-r--r--src/com/android/nfc/snep/SnepServer.java22
14 files changed, 655 insertions, 305 deletions
diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java
index 047e3d5..e514bb6 100644
--- a/src/com/android/nfc/DeviceHost.java
+++ b/src/com/android/nfc/DeviceHost.java
@@ -49,6 +49,16 @@ public interface DeviceHost {
public void onRemoteFieldDeactivated();
+ /**
+ * Notifies that the SE has been activated in listen mode
+ */
+ public void onSeListenActivated();
+
+ /**
+ * Notifies that the SE has been deactivated
+ */
+ public void onSeListenDeactivated();
+
public void onSeApduReceived(byte[] apdu);
public void onSeEmvCardRemoval();
@@ -175,6 +185,8 @@ public interface DeviceHost {
public boolean deinitialize();
+ public String getName();
+
public void enableDiscovery();
public void disableDiscovery();
@@ -216,5 +228,13 @@ public interface DeviceHost {
boolean getExtendedLengthApdusSupported();
+ boolean enablePN544Quirks();
+
+ byte[][] getWipeApdus();
+
+ int getDefaultLlcpMiu();
+
+ int getDefaultLlcpRwSize();
+
String dump();
}
diff --git a/src/com/android/nfc/FireflyRenderer.java b/src/com/android/nfc/FireflyRenderer.java
index 4ce58b4..40c931d 100644
--- a/src/com/android/nfc/FireflyRenderer.java
+++ b/src/com/android/nfc/FireflyRenderer.java
@@ -200,6 +200,7 @@ public class FireflyRenderer {
for (int i = 0; i < 3; i++) {
// Call eglSwapBuffers 3 times - this will allocate the necessary
// buffers, and make sure the animation looks smooth from the start.
+ mGL.glClear(GL10.GL_COLOR_BUFFER_BIT);
if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
Log.e(LOG_TAG, "Could not swap buffers");
mFinished = true;
diff --git a/src/com/android/nfc/NfcApplication.java b/src/com/android/nfc/NfcApplication.java
new file mode 100644
index 0000000..867b8bb
--- /dev/null
+++ b/src/com/android/nfc/NfcApplication.java
@@ -0,0 +1,24 @@
+package com.android.nfc;
+
+import android.app.Application;
+import android.os.UserHandle;
+import android.util.Log;
+
+public class NfcApplication extends Application {
+
+ public static final String TAG = "NfcApplication";
+ NfcService mNfcService;
+
+ public NfcApplication() {
+
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ if (UserHandle.myUserId() == 0) {
+ mNfcService = new NfcService(this);
+ }
+ }
+}
diff --git a/src/com/android/nfc/NfcDispatcher.java b/src/com/android/nfc/NfcDispatcher.java
index b3ab97c..1721d1a 100644
--- a/src/com/android/nfc/NfcDispatcher.java
+++ b/src/com/android/nfc/NfcDispatcher.java
@@ -20,6 +20,7 @@ import com.android.nfc.RegisteredComponentCache.ComponentInfo;
import com.android.nfc.handover.HandoverManager;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.PendingIntent;
@@ -30,6 +31,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.nfc.NdefMessage;
@@ -38,6 +40,7 @@ import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.io.FileDescriptor;
@@ -58,7 +61,6 @@ public class NfcDispatcher {
final Context mContext;
final IActivityManager mIActivityManager;
final RegisteredComponentCache mTechListFilters;
- final PackageManager mPackageManager;
final ContentResolver mContentResolver;
final HandoverManager mHandoverManager;
@@ -72,7 +74,6 @@ public class NfcDispatcher {
mIActivityManager = ActivityManagerNative.getDefault();
mTechListFilters = new RegisteredComponentCache(mContext,
NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED);
- mPackageManager = context.getPackageManager();
mContentResolver = context.getContentResolver();
mHandoverManager = handoverManager;
}
@@ -157,19 +158,21 @@ public class NfcDispatcher {
// is not available on Context. Instead, we query the PackageManager beforehand
// to determine if there is an Activity to handle this intent, and base the
// result of off that.
- List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
+ List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(intent, 0,
+ ActivityManager.getCurrentUser());
if (activities.size() > 0) {
- context.startActivity(rootIntent);
+ context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
return true;
}
return false;
}
boolean tryStartActivity(Intent intentToStart) {
- List<ResolveInfo> activities = packageManager.queryIntentActivities(intentToStart, 0);
+ List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
+ intentToStart, 0, ActivityManager.getCurrentUser());
if (activities.size() > 0) {
rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intentToStart);
- context.startActivity(rootIntent);
+ context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
return true;
}
return false;
@@ -305,7 +308,10 @@ public class NfcDispatcher {
if (message == null) {
return false;
}
- dispatch.setNdefIntent();
+ Intent intent = dispatch.setNdefIntent();
+
+ // Bail out if the intent does not contain filterable NDEF data
+ if (intent == null) return false;
// Try to start AAR activity with matching filter
List<String> aarPackages = extractAarPackages(message);
@@ -320,7 +326,16 @@ public class NfcDispatcher {
// Try to perform regular launch of the first AAR
if (aarPackages.size() > 0) {
String firstPackage = aarPackages.get(0);
- Intent appLaunchIntent = mPackageManager.getLaunchIntentForPackage(firstPackage);
+ PackageManager pm;
+ try {
+ UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
+ pm = mContext.createPackageContextAsUser("android", 0,
+ currentUser).getPackageManager();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return false;
+ }
+ Intent appLaunchIntent = pm.getLaunchIntentForPackage(firstPackage);
if (appLaunchIntent != null && dispatch.tryStartActivity(appLaunchIntent)) {
if (DBG) Log.i(TAG, "matched AAR to application launch");
return true;
@@ -364,11 +379,20 @@ public class NfcDispatcher {
ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
List<ComponentInfo> registered = mTechListFilters.getComponents();
+ PackageManager pm;
+ try {
+ UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
+ pm = mContext.createPackageContextAsUser("android", 0,
+ currentUser).getPackageManager();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return false;
+ }
// Check each registered activity to see if it matches
for (ComponentInfo info : registered) {
// Don't allow wild card matching
if (filterMatch(tagTechs, info.techs) &&
- isComponentEnabled(mPackageManager, info.resolveInfo)) {
+ isComponentEnabled(pm, info.resolveInfo)) {
// Add the activity as a match if it's not already in the list
if (!matches.contains(info.resolveInfo)) {
matches.add(info.resolveInfo);
diff --git a/src/com/android/nfc/NfcRootActivity.java b/src/com/android/nfc/NfcRootActivity.java
index 1325ead..cc216f2 100644
--- a/src/com/android/nfc/NfcRootActivity.java
+++ b/src/com/android/nfc/NfcRootActivity.java
@@ -17,9 +17,11 @@
package com.android.nfc;
import android.app.Activity;
+import android.app.ActivityManager;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
+import android.os.UserHandle;
public class NfcRootActivity extends Activity {
@@ -33,7 +35,7 @@ public class NfcRootActivity extends Activity {
final Intent launchIntent = intent.getParcelableExtra(EXTRA_LAUNCH_INTENT);
if (launchIntent != null) {
try {
- startActivity(launchIntent);
+ startActivityAsUser(launchIntent, UserHandle.CURRENT);
} catch (ActivityNotFoundException e) {
}
}
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 3e7a6b5..d63f84f 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -63,6 +63,7 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -75,7 +76,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutionException;
-public class NfcService extends Application implements DeviceHostListener {
+public class NfcService implements DeviceHostListener {
private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
static final boolean DBG = false;
@@ -101,8 +102,6 @@ public class NfcService extends Application implements DeviceHostListener {
static final String PREF_FIRST_BOOT = "first_boot";
static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
- static final boolean PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE = true;
-
static final int MSG_NDEF_TAG = 0;
static final int MSG_CARD_EMULATION = 1;
static final int MSG_LLCP_LINK_ACTIVATION = 2;
@@ -114,6 +113,8 @@ public class NfcService extends Application implements DeviceHostListener {
static final int MSG_SE_APDU_RECEIVED = 10;
static final int MSG_SE_EMV_CARD_REMOVAL = 11;
static final int MSG_SE_MIFARE_ACCESS = 12;
+ static final int MSG_SE_LISTEN_ACTIVATED = 13;
+ static final int MSG_SE_LISTEN_DEACTIVATED = 14;
static final int TASK_ENABLE = 1;
static final int TASK_DISABLE = 2;
@@ -134,6 +135,15 @@ public class NfcService extends Application implements DeviceHostListener {
/** minimum screen state that enables NFC polling (discovery) */
static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
+ // Time to wait for NFC controller to initialize before watchdog
+ // goes off. This time is chosen large, because firmware download
+ // may be a part of initialization.
+ static final int INIT_WATCHDOG_MS = 90000;
+
+ // Time to wait for routing to be applied before watchdog
+ // goes off
+ static final int ROUTING_WATCHDOG_MS = 10000;
+
// for use with playSound()
public static final int SOUND_START = 0;
public static final int SOUND_END = 1;
@@ -160,18 +170,10 @@ public class NfcService extends Application implements DeviceHostListener {
public static final String EXTRA_MIFARE_BLOCK =
"com.android.nfc_extras.extra.MIFARE_BLOCK";
- //TODO: dont hardcode this
- private static final byte[][] EE_WIPE_APDUS = {
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
- (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
- {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
- (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
- {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
- };
+ public static final String ACTION_SE_LISTEN_ACTIVATED =
+ "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED";
+ public static final String ACTION_SE_LISTEN_DEACTIVATED =
+ "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED";
// NFC Execution Environment
// fields below are protected by this
@@ -184,6 +186,8 @@ public class NfcService extends Application implements DeviceHostListener {
// fields below are used in multiple threads and protected by synchronized(this)
final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
+ // mSePackages holds packages that accessed the SE, but only for the owner user,
+ // as SE access is not granted for non-owner users.
HashSet<String> mSePackages = new HashSet<String>();
int mScreenState;
boolean mIsNdefPushEnabled;
@@ -201,7 +205,9 @@ public class NfcService extends Application implements DeviceHostListener {
private DeviceHost mDeviceHost;
private SharedPreferences mPrefs;
private SharedPreferences.Editor mPrefsEditor;
- private PowerManager.WakeLock mWakeLock;
+ private PowerManager.WakeLock mRoutingWakeLock;
+ private PowerManager.WakeLock mEeWakeLock;
+
int mStartSound;
int mEndSound;
int mErrorSound;
@@ -233,6 +239,9 @@ public class NfcService extends Application implements DeviceHostListener {
throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
" denies NFCEE access to " + pkg);
}
+ if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+ throw new SecurityException("only the owner is allowed to call SE APIs");
+ }
}
public static NfcService getInstance() {
@@ -287,6 +296,17 @@ public class NfcService extends Application implements DeviceHostListener {
}
@Override
+ public void onSeListenActivated() {
+ sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null);
+ }
+
+ @Override
+ public void onSeListenDeactivated() {
+ sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null);
+ }
+
+
+ @Override
public void onSeApduReceived(byte[] apdu) {
sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
}
@@ -301,10 +321,7 @@ public class NfcService extends Application implements DeviceHostListener {
sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
}
- @Override
- public void onCreate() {
- super.onCreate();
-
+ public NfcService(Application nfcApplication) {
mNfcTagService = new TagService();
mNfcAdapter = new NfcAdapterService();
mExtrasService = new NfcAdapterExtrasService();
@@ -313,48 +330,60 @@ public class NfcService extends Application implements DeviceHostListener {
sService = this;
- mContext = this;
- mDeviceHost = new NativeNfcManager(this, this);
+ mContext = nfcApplication;
+ mDeviceHost = new NativeNfcManager(mContext, this);
HandoverManager handoverManager = new HandoverManager(mContext);
- mNfcDispatcher = new NfcDispatcher(this, handoverManager);
- mP2pLinkManager = new P2pLinkManager(mContext, handoverManager);
+ mNfcDispatcher = new NfcDispatcher(mContext, handoverManager);
+
+ mP2pLinkManager = new P2pLinkManager(mContext, handoverManager,
+ mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
mSecureElement = new NativeNfcSecureElement(mContext);
mEeRoutingState = ROUTE_OFF;
- mNfceeAccessControl = new NfceeAccessControl(this);
+ mNfceeAccessControl = new NfceeAccessControl(mContext);
- mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE);
+ mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
mPrefsEditor = mPrefs.edit();
mState = NfcAdapter.STATE_OFF;
mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
- mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+
+ mRoutingWakeLock = mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
+ mEeWakeLock = mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
- mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+ mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mScreenState = checkScreenState();
ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
+ // Intents only for owner
+ IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
+ ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
+
+ mContext.registerReceiver(mOwnerReceiver, ownerFilter);
+
+ ownerFilter = new IntentFilter();
+ ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ ownerFilter.addDataScheme("package");
+
+ mContext.registerReceiver(mOwnerReceiver, ownerFilter);
+
+ // Intents for all users
IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
filter.addAction(Intent.ACTION_USER_PRESENT);
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
registerForAirplaneMode(filter);
- registerReceiver(mReceiver, filter);
-
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
-
- registerReceiver(mReceiver, filter);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
updatePackageCache();
@@ -365,9 +394,9 @@ public class NfcService extends Application implements DeviceHostListener {
synchronized(this) {
if (mSoundPool == null) {
mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
- mStartSound = mSoundPool.load(this, R.raw.start, 1);
- mEndSound = mSoundPool.load(this, R.raw.end, 1);
- mErrorSound = mSoundPool.load(this, R.raw.error, 1);
+ mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
+ mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
+ mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
}
}
}
@@ -399,8 +428,8 @@ public class NfcService extends Application implements DeviceHostListener {
}
void updatePackageCache() {
- PackageManager pm = getPackageManager();
- List<PackageInfo> packages = pm.getInstalledPackages(0);
+ PackageManager pm = mContext.getPackageManager();
+ List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
synchronized (this) {
mInstalledPackages = packages;
}
@@ -416,6 +445,37 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
+ int doOpenSecureElementConnection() {
+ mEeWakeLock.acquire();
+ try {
+ return mSecureElement.doOpenSecureElementConnection();
+ } finally {
+ mEeWakeLock.release();
+ }
+ }
+
+ byte[] doTransceive(int handle, byte[] cmd) {
+ mEeWakeLock.acquire();
+ try {
+ return doTransceiveNoLock(handle, cmd);
+ } finally {
+ mEeWakeLock.release();
+ }
+ }
+
+ byte[] doTransceiveNoLock(int handle, byte[] cmd) {
+ return mSecureElement.doTransceive(handle, cmd);
+ }
+
+ void doDisconnect(int handle) {
+ mEeWakeLock.acquire();
+ try {
+ mSecureElement.doDisconnect(handle);
+ } finally {
+ mEeWakeLock.release();
+ }
+ }
+
/**
* Manages tasks that involve turning on/off the NFC controller.
*
@@ -512,11 +572,21 @@ public class NfcService extends Application implements DeviceHostListener {
Log.i(TAG, "Enabling NFC");
updateState(NfcAdapter.STATE_TURNING_ON);
-
- if (!mDeviceHost.initialize()) {
- Log.w(TAG, "Error enabling NFC");
- updateState(NfcAdapter.STATE_OFF);
- return false;
+ WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
+ watchDog.start();
+ try {
+ mRoutingWakeLock.acquire();
+ try {
+ if (!mDeviceHost.initialize()) {
+ Log.w(TAG, "Error enabling NFC");
+ updateState(NfcAdapter.STATE_OFF);
+ return false;
+ }
+ } finally {
+ mRoutingWakeLock.release();
+ }
+ } finally {
+ watchDog.cancel();
}
synchronized(NfcService.this) {
@@ -549,7 +619,7 @@ public class NfcService extends Application implements DeviceHostListener {
* Implemented with a new thread (instead of a Handler or AsyncTask),
* because the UI Thread and AsyncTask thread-pools can also get hung
* when the NFC controller stops responding */
- WatchDogThread watchDog = new WatchDogThread();
+ WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
watchDog.start();
mP2pLinkManager.enableDisable(false, false);
@@ -566,7 +636,6 @@ public class NfcService extends Application implements DeviceHostListener {
// A convenient way to stop the watchdog properly consists of
// disconnecting the tag. The polling loop shall be stopped before
// to avoid the tag being discovered again.
- applyRouting(true);
maybeDisconnectTarget();
mNfcDispatcher.setForegroundDispatch(null, null, null);
@@ -585,41 +654,64 @@ public class NfcService extends Application implements DeviceHostListener {
void executeEeWipe() {
// TODO: read SE reset list from /system/etc
- byte[][]apdus = EE_WIPE_APDUS;
+ byte[][]apdus = mDeviceHost.getWipeApdus();
+
+ if (apdus == null) {
+ Log.d(TAG, "No wipe APDUs found");
+ return;
+ }
boolean tempEnable = mState == NfcAdapter.STATE_OFF;
- if (tempEnable) {
- if (!enableInternal()) {
+ // Hold a wake-lock over the entire wipe procedure
+ mEeWakeLock.acquire();
+ try {
+ if (tempEnable && !enableInternal()) {
Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
return;
}
- }
- Log.i(TAG, "Executing SE wipe");
- int handle = mSecureElement.doOpenSecureElementConnection();
- if (handle == 0) {
- Log.w(TAG, "Could not open the secure element");
- if (tempEnable) {
- disableInternal();
- }
- return;
- }
-
- mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
+ try {
+ // NFC enabled
+ int handle = 0;
+ try {
+ Log.i(TAG, "Executing SE wipe");
+ handle = doOpenSecureElementConnection();
+ if (handle == 0) {
+ Log.w(TAG, "Could not open the secure element");
+ return;
+ }
+ // TODO: remove this hack
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
- for (byte[] cmd : apdus) {
- byte[] resp = mSecureElement.doTransceive(handle, cmd);
- if (resp == null) {
- Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
- break;
+ mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
+ try {
+ for (byte[] cmd : apdus) {
+ byte[] resp = doTransceiveNoLock(handle, cmd);
+ if (resp == null) {
+ Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
+ break;
+ }
+ }
+ } finally {
+ mDeviceHost.resetTimeouts();
+ }
+ } finally {
+ if (handle != 0) {
+ doDisconnect(handle);
+ }
+ }
+ } finally {
+ if (tempEnable) {
+ disableInternal();
+ }
}
+ } finally {
+ mEeWakeLock.release();
}
-
- mDeviceHost.resetTimeouts();
- mSecureElement.doDisconnect(handle);
-
- if (tempEnable) {
- disableInternal();
- }
+ Log.i(TAG, "SE wipe done");
}
void updateState(int newState) {
@@ -631,7 +723,7 @@ public class NfcService extends Application implements DeviceHostListener {
Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
}
}
}
@@ -663,12 +755,6 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
- @Override
- public void onTerminate() {
- super.onTerminate();
- // NFC application is persistent, it should not be destroyed by framework
- Log.wtf(TAG, "NFC service is under attack!");
- }
final class NfcAdapterService extends INfcAdapter.Stub {
@Override
@@ -870,10 +956,6 @@ public class NfcService extends Application implements DeviceHostListener {
return ErrorCodes.ERROR_DISCONNECT;
}
- if (technology == TagTechnology.NFC_B) {
- return ErrorCodes.ERROR_NOT_SUPPORTED;
- }
-
// Note that on most tags, all technologies are behind a single
// handle. This means that the connect at the lower levels
// will do nothing, as the tag is already connected to that handle.
@@ -1201,7 +1283,7 @@ public class NfcService extends Application implements DeviceHostListener {
binder.unlinkToDeath(mOpenEe, 0);
mDeviceHost.resetTimeouts();
- mSecureElement.doDisconnect(mOpenEe.handle);
+ doDisconnect(mOpenEe.handle);
mOpenEe = null;
applyRouting(true);
@@ -1244,11 +1326,11 @@ public class NfcService extends Application implements DeviceHostListener {
throw new IOException("NFC EE already open");
}
- int handle = mSecureElement.doOpenSecureElementConnection();
+ int handle = doOpenSecureElementConnection();
if (handle == 0) {
throw new IOException("NFC EE failed to open");
}
- mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
+ mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
try {
@@ -1259,7 +1341,7 @@ public class NfcService extends Application implements DeviceHostListener {
// Add the calling package to the list of packages that have accessed
// the secure element.
- for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
+ for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
mSePackages.add(packageName);
}
}
@@ -1308,7 +1390,7 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
- return mSecureElement.doTransceive(mOpenEe.handle, data);
+ return doTransceive(mOpenEe.handle, data);
}
@Override
@@ -1321,13 +1403,28 @@ public class NfcService extends Application implements DeviceHostListener {
public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
NfcService.this.enforceNfceeAdminPerm(pkg);
mEeRoutingState = route;
- applyRouting(true);
+ ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask();
+ applyRoutingTask.execute();
+ try {
+ // Block until route is set
+ applyRoutingTask.get();
+ } catch (ExecutionException e) {
+ Log.e(TAG, "failed to set card emulation mode");
+ } catch (InterruptedException e) {
+ Log.e(TAG, "failed to set card emulation mode");
+ }
}
@Override
public void authenticate(String pkg, byte[] token) throws RemoteException {
NfcService.this.enforceNfceeAdminPerm(pkg);
}
+
+ @Override
+ public String getDriverName(String pkg) throws RemoteException {
+ NfcService.this.enforceNfceeAdminPerm(pkg);
+ return mDeviceHost.getName();
+ }
}
/** resources kept while secure element is open */
@@ -1376,19 +1473,27 @@ public class NfcService extends Application implements DeviceHostListener {
class WatchDogThread extends Thread {
boolean mWatchDogCanceled = false;
+ final int mTimeout;
+
+ public WatchDogThread(String threadName, int timeout) {
+ super(threadName);
+ mTimeout = timeout;
+ }
+
@Override
public void run() {
boolean slept = false;
while (!slept) {
try {
- Thread.sleep(10000);
+ Thread.sleep(mTimeout);
slept = true;
} catch (InterruptedException e) { }
}
synchronized (this) {
if (!mWatchDogCanceled) {
// Trigger watch-dog
- Log.e(TAG, "Watch dog triggered");
+ Log.e(TAG, "Watchdog fired: name=" + getName() + " threadId=" +
+ getId() + " timeout=" + mTimeout);
mDeviceHost.doAbort();
}
}
@@ -1407,12 +1512,12 @@ public class NfcService extends Application implements DeviceHostListener {
// PN544 cannot be reconfigured while EE is open
return;
}
- WatchDogThread watchDog = new WatchDogThread();
+ WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
try {
watchDog.start();
- if (PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE && mScreenState == SCREEN_STATE_OFF) {
+ if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) {
/* TODO undo this after the LLCP stack is fixed.
* Use a different sequence when turning the screen off to
* workaround race conditions in pn544 libnfc. The race occurs
@@ -1704,6 +1809,22 @@ public class NfcService extends Application implements DeviceHostListener {
break;
}
+ case MSG_SE_LISTEN_ACTIVATED: {
+ if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED");
+ Intent listenModeActivated = new Intent();
+ listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED);
+ sendSeBroadcast(listenModeActivated);
+ break;
+ }
+
+ case MSG_SE_LISTEN_DEACTIVATED: {
+ if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED");
+ Intent listenModeDeactivated = new Intent();
+ listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED);
+ sendSeBroadcast(listenModeDeactivated);
+ break;
+ }
+
default:
Log.e(TAG, "Unknown message received");
break;
@@ -1808,52 +1929,22 @@ public class NfcService extends Application implements DeviceHostListener {
}
mScreenState = params[0].intValue();
- boolean needWakelock = mScreenState == SCREEN_STATE_OFF;
- if (needWakelock) {
- mWakeLock.acquire();
- }
- applyRouting(false);
- if (needWakelock) {
- mWakeLock.release();
+ mRoutingWakeLock.acquire();
+ try {
+ applyRouting(false);
+ } finally {
+ mRoutingWakeLock.release();
}
return null;
}
}
}
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(
- NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
- // Perform applyRouting() in AsyncTask to serialize blocking calls
- new ApplyRoutingTask().execute();
- } else if (action.equals(Intent.ACTION_SCREEN_ON)
- || action.equals(Intent.ACTION_SCREEN_OFF)
- || action.equals(Intent.ACTION_USER_PRESENT)) {
- // Perform applyRouting() in AsyncTask to serialize blocking calls
- int screenState = SCREEN_STATE_OFF;
- if (action.equals(Intent.ACTION_SCREEN_OFF)) {
- screenState = SCREEN_STATE_OFF;
- } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
- screenState = mKeyguard.isKeyguardLocked() ?
- SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
- } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
- screenState = SCREEN_STATE_ON_UNLOCKED;
- }
- new ApplyRoutingTask().execute(Integer.valueOf(screenState));
- } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
- EnableDisableTask eeWipeTask = new EnableDisableTask();
- eeWipeTask.execute(TASK_EE_WIPE);
- try {
- eeWipeTask.get(); // blocks until EE wipe is complete
- } catch (ExecutionException e) {
- Log.w(TAG, "failed to wipe NFC-EE");
- } catch (InterruptedException e) {
- Log.w(TAG, "failed to wipe NFC-EE");
- }
- } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
+ if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
action.equals(Intent.ACTION_PACKAGE_ADDED) ||
action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
@@ -1877,6 +1968,42 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
}
+ } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
+ EnableDisableTask eeWipeTask = new EnableDisableTask();
+ eeWipeTask.execute(TASK_EE_WIPE);
+ try {
+ eeWipeTask.get(); // blocks until EE wipe is complete
+ } catch (ExecutionException e) {
+ Log.w(TAG, "failed to wipe NFC-EE");
+ } catch (InterruptedException e) {
+ Log.w(TAG, "failed to wipe NFC-EE");
+ }
+ }
+ }
+ };
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(
+ NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
+ // Perform applyRouting() in AsyncTask to serialize blocking calls
+ new ApplyRoutingTask().execute();
+ } else if (action.equals(Intent.ACTION_SCREEN_ON)
+ || action.equals(Intent.ACTION_SCREEN_OFF)
+ || action.equals(Intent.ACTION_USER_PRESENT)) {
+ // Perform applyRouting() in AsyncTask to serialize blocking calls
+ int screenState = SCREEN_STATE_OFF;
+ if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+ screenState = SCREEN_STATE_OFF;
+ } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
+ screenState = mKeyguard.isKeyguardLocked() ?
+ SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
+ } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
+ screenState = SCREEN_STATE_ON_UNLOCKED;
+ }
+ new ApplyRoutingTask().execute(Integer.valueOf(screenState));
} else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
// Query the airplane mode from Settings.System just to make sure that
diff --git a/src/com/android/nfc/P2pLinkManager.java b/src/com/android/nfc/P2pLinkManager.java
index 253ddaf..9b23f65 100755
--- a/src/com/android/nfc/P2pLinkManager.java
+++ b/src/com/android/nfc/P2pLinkManager.java
@@ -167,6 +167,9 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
final Handler mHandler;
final HandoverManager mHandoverManager;
+ final int mDefaultMiu;
+ final int mDefaultRwSize;
+
// Locked on NdefP2pManager.this
int mLinkState;
int mSendState; // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE
@@ -179,9 +182,10 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
SharedPreferences mPrefs;
boolean mFirstBeam;
- public P2pLinkManager(Context context, HandoverManager handoverManager) {
+ public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu,
+ int defaultRwSize) {
mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);
- mDefaultSnepServer = new SnepServer(mDefaultSnepCallback);
+ mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);
mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback);
if (ECHOSERVER_ENABLED) {
@@ -201,6 +205,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE);
mFirstBeam = mPrefs.getBoolean(NfcService.PREF_FIRST_BEAM, true);
mHandoverManager = handoverManager;
+ mDefaultMiu = defaultMiu;
+ mDefaultRwSize = defaultRwSize;
}
/**
@@ -417,11 +423,11 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
long time = SystemClock.elapsedRealtime();
-
try {
if (DBG) Log.d(TAG, "Sending ndef via SNEP");
- int snepResult = doSnepProtocol(mHandoverManager, m, uris);
+ int snepResult = doSnepProtocol(mHandoverManager, m, uris,
+ mDefaultMiu, mDefaultRwSize);
switch (snepResult) {
case SNEP_HANDOVER_UNSUPPORTED:
@@ -461,8 +467,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
}
static int doSnepProtocol(HandoverManager handoverManager,
- NdefMessage msg, Uri[] uris) throws IOException {
- SnepClient snepClient = new SnepClient();
+ NdefMessage msg, Uri[] uris, int miu, int rwSize) throws IOException {
+ SnepClient snepClient = new SnepClient(miu, rwSize);
try {
snepClient.connect();
} catch (IOException e) {
diff --git a/src/com/android/nfc/RegisteredComponentCache.java b/src/com/android/nfc/RegisteredComponentCache.java
index 1bac283..5da2cd4 100644
--- a/src/com/android/nfc/RegisteredComponentCache.java
+++ b/src/com/android/nfc/RegisteredComponentCache.java
@@ -19,6 +19,7 @@ package com.android.nfc;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +30,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.os.UserHandle;
import android.util.Log;
import java.io.IOException;
@@ -69,12 +71,16 @@ public class RegisteredComponentCache {
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
- mContext.registerReceiver(receiver, intentFilter);
+ mContext.registerReceiverAsUser(receiver, UserHandle.ALL, intentFilter, null, null);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(receiver, sdFilter);
+ mContext.registerReceiverAsUser(receiver, UserHandle.ALL, sdFilter, null, null);
+ // Generate a new list upon switching users as well
+ IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiverAsUser(receiver, UserHandle.ALL, userFilter, null, null);
}
public static class ComponentInfo {
@@ -137,13 +143,21 @@ public class RegisteredComponentCache {
}
void generateComponentsList() {
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm;
+ try {
+ UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
+ pm = mContext.createPackageContextAsUser("android", 0,
+ currentUser).getPackageManager();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return;
+ }
ArrayList<ComponentInfo> components = new ArrayList<ComponentInfo>();
- List<ResolveInfo> resolveInfos = pm.queryIntentActivities(new Intent(mAction),
- PackageManager.GET_META_DATA);
+ List<ResolveInfo> resolveInfos = pm.queryIntentActivitiesAsUser(new Intent(mAction),
+ PackageManager.GET_META_DATA, ActivityManager.getCurrentUser());
for (ResolveInfo resolveInfo : resolveInfos) {
try {
- parseComponentInfo(resolveInfo, components);
+ parseComponentInfo(pm, resolveInfo, components);
} catch (XmlPullParserException e) {
Log.w(TAG, "Unable to load component info " + resolveInfo.toString(), e);
} catch (IOException e) {
@@ -158,10 +172,9 @@ public class RegisteredComponentCache {
}
}
- void parseComponentInfo(ResolveInfo info, ArrayList<ComponentInfo> components)
- throws XmlPullParserException, IOException {
+ void parseComponentInfo(PackageManager pm, ResolveInfo info,
+ ArrayList<ComponentInfo> components) throws XmlPullParserException, IOException {
ActivityInfo ai = info.activityInfo;
- PackageManager pm = mContext.getPackageManager();
XmlResourceParser parser = null;
try {
diff --git a/src/com/android/nfc/SendUi.java b/src/com/android/nfc/SendUi.java
index 23602c9..5b5c234 100644
--- a/src/com/android/nfc/SendUi.java
+++ b/src/com/android/nfc/SendUi.java
@@ -183,7 +183,7 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
// We're only allowed to use hardware acceleration if
// isHighEndGfx() returns true - otherwise, we're too limited
// on resources to do it.
- mHardwareAccelerated = ActivityManager.isHighEndGfx(mDisplay);
+ mHardwareAccelerated = ActivityManager.isHighEndGfx();
int hwAccelerationFlags = mHardwareAccelerated ?
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0;
@@ -194,6 +194,8 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
| hwAccelerationFlags
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.OPAQUE);
+ mWindowLayoutParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mWindowLayoutParams.token = new Binder();
mFrameCounterAnimator = new TimeAnimator();
@@ -443,6 +445,9 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
// Navbar has different sizes, depending on orientation
final int navBarHeight = hasNavBar ? mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height) : 0;
+ final int navBarHeightLandscape = hasNavBar ? mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height_landscape) : 0;
+
final int navBarWidth = hasNavBar ? mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_width) : 0;
@@ -483,13 +488,20 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
int newTop = statusBarHeight;
int newWidth = bitmap.getWidth();
int newHeight = bitmap.getHeight();
+ float smallestWidth = (float)Math.min(newWidth, newHeight);
+ float smallestWidthDp = smallestWidth / (mDisplayMetrics.densityDpi / 160f);
if (bitmap.getWidth() < bitmap.getHeight()) {
// Portrait mode: status bar is at the top, navbar bottom, width unchanged
newHeight = bitmap.getHeight() - statusBarHeight - navBarHeight;
} else {
- // Landscape mode: status bar is at the top, navbar right
- newHeight = bitmap.getHeight() - statusBarHeight;
- newWidth = bitmap.getWidth() - navBarWidth;
+ // Landscape mode: status bar is at the top
+ // Navbar: bottom on >599dp width devices, otherwise to the side
+ if (smallestWidthDp > 599) {
+ newHeight = bitmap.getHeight() - statusBarHeight - navBarHeightLandscape;
+ } else {
+ newHeight = bitmap.getHeight() - statusBarHeight;
+ newWidth = bitmap.getWidth() - navBarWidth;
+ }
}
bitmap = Bitmap.createBitmap(bitmap, newLeft, newTop, newWidth, newHeight);
diff --git a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java
index 7974dfa..1377160 100644
--- a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java
+++ b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java
@@ -16,6 +16,7 @@
package com.android.nfc.handover;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -28,6 +29,7 @@ import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
@@ -44,9 +46,8 @@ import com.android.nfc.R;
* designed to be re-used after the sequence has completed or timed out.
* Subsequent NFC interactions should use new objects.
*
- * TODO: UI review
*/
-public class BluetoothHeadsetHandover {
+public class BluetoothHeadsetHandover implements BluetoothProfile.ServiceListener {
static final String TAG = HandoverManager.TAG;
static final boolean DBG = HandoverManager.DBG;
@@ -57,28 +58,33 @@ public class BluetoothHeadsetHandover {
static final int STATE_INIT = 0;
static final int STATE_TURNING_ON = 1;
- static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 2;
- static final int STATE_BONDING = 3;
- static final int STATE_CONNECTING = 4;
- static final int STATE_DISCONNECTING = 5;
- static final int STATE_COMPLETE = 6;
+ static final int STATE_WAITING_FOR_PROXIES = 2;
+ static final int STATE_INIT_COMPLETE = 3;
+ static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 4;
+ static final int STATE_BONDING = 5;
+ static final int STATE_CONNECTING = 6;
+ static final int STATE_DISCONNECTING = 7;
+ static final int STATE_COMPLETE = 8;
static final int RESULT_PENDING = 0;
static final int RESULT_CONNECTED = 1;
static final int RESULT_DISCONNECTED = 2;
+ static final int ACTION_INIT = 0;
static final int ACTION_DISCONNECT = 1;
static final int ACTION_CONNECT = 2;
static final int MSG_TIMEOUT = 1;
+ static final int MSG_NEXT_STEP = 2;
final Context mContext;
final BluetoothDevice mDevice;
final String mName;
final HandoverPowerManager mHandoverPowerManager;
- final BluetoothA2dp mA2dp;
- final BluetoothHeadset mHeadset;
final Callback mCallback;
+ final BluetoothAdapter mBluetoothAdapter;
+
+ final Object mLock = new Object();
// only used on main thread
int mAction;
@@ -86,21 +92,24 @@ public class BluetoothHeadsetHandover {
int mHfpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING
int mA2dpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING
+ // protected by mLock
+ BluetoothA2dp mA2dp;
+ BluetoothHeadset mHeadset;
+
public interface Callback {
public void onBluetoothHeadsetHandoverComplete(boolean connected);
}
public BluetoothHeadsetHandover(Context context, BluetoothDevice device, String name,
- HandoverPowerManager powerManager, BluetoothA2dp a2dp, BluetoothHeadset headset,
- Callback callback) {
+ HandoverPowerManager powerManager, Callback callback) {
checkMainThread(); // mHandler must get get constructed on Main Thread for toasts to work
mContext = context;
mDevice = device;
mName = name;
mHandoverPowerManager = powerManager;
- mA2dp = a2dp;
- mHeadset = headset;
mCallback = callback;
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
mState = STATE_INIT;
}
@@ -111,6 +120,7 @@ public class BluetoothHeadsetHandover {
public void start() {
checkMainThread();
if (mState != STATE_INIT) return;
+ if (mBluetoothAdapter == null) return;
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -122,15 +132,8 @@ public class BluetoothHeadsetHandover {
mContext.registerReceiver(mReceiver, filter);
- if (mA2dp.getConnectedDevices().contains(mDevice) ||
- mHeadset.getConnectedDevices().contains(mDevice)) {
- Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName);
- mAction = ACTION_DISCONNECT;
- } else {
- Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName);
- mAction = ACTION_CONNECT;
- }
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
+ mAction = ACTION_INIT;
nextStep();
}
@@ -138,35 +141,83 @@ public class BluetoothHeadsetHandover {
* Called to execute next step in state machine
*/
void nextStep() {
- if (mAction == ACTION_CONNECT) {
+ if (mAction == ACTION_INIT) {
+ nextStepInit();
+ } else if (mAction == ACTION_CONNECT) {
nextStepConnect();
} else {
nextStepDisconnect();
}
}
- void nextStepDisconnect() {
+ /*
+ * Enables bluetooth and gets the profile proxies
+ */
+ void nextStepInit() {
switch (mState) {
case STATE_INIT:
- mState = STATE_DISCONNECTING;
- if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
- mHfpResult = RESULT_PENDING;
- mHeadset.disconnect(mDevice);
- } else {
- mHfpResult = RESULT_DISCONNECTED;
- }
- if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
- mA2dpResult = RESULT_PENDING;
- mA2dp.disconnect(mDevice);
- } else {
- mA2dpResult = RESULT_DISCONNECTED;
+ if (!mHandoverPowerManager.isBluetoothEnabled()) {
+ if (mHandoverPowerManager.enableBluetooth()) {
+ // Bluetooth is being enabled
+ mState = STATE_TURNING_ON;
+ } else {
+ toast(mContext.getString(R.string.failed_to_enable_bt));
+ complete(false);
+ }
+ break;
}
- if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
- toast(mContext.getString(R.string.disconnecting_headset ) + " " +
- mName + "...");
+ // fall-through
+ case STATE_TURNING_ON:
+ if (mA2dp == null || mHeadset == null) {
+ mState = STATE_WAITING_FOR_PROXIES;
+ if (!getProfileProxys()) {
+ complete(false);
+ }
break;
}
// fall-through
+ case STATE_WAITING_FOR_PROXIES:
+ mState = STATE_INIT_COMPLETE;
+ // Check connected devices and see if we need to disconnect
+ synchronized(mLock) {
+ if (mA2dp.getConnectedDevices().contains(mDevice) ||
+ mHeadset.getConnectedDevices().contains(mDevice)) {
+ Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName);
+ mAction = ACTION_DISCONNECT;
+ } else {
+ Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName);
+ mAction = ACTION_CONNECT;
+ }
+ }
+ nextStep();
+ }
+
+ }
+
+ void nextStepDisconnect() {
+ switch (mState) {
+ case STATE_INIT_COMPLETE:
+ mState = STATE_DISCONNECTING;
+ synchronized (mLock) {
+ if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
+ mHfpResult = RESULT_PENDING;
+ mHeadset.disconnect(mDevice);
+ } else {
+ mHfpResult = RESULT_DISCONNECTED;
+ }
+ if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
+ mA2dpResult = RESULT_PENDING;
+ mA2dp.disconnect(mDevice);
+ } else {
+ mA2dpResult = RESULT_DISCONNECTED;
+ }
+ if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
+ toast(mContext.getString(R.string.disconnecting_headset ) + " " +
+ mName + "...");
+ break;
+ }
+ }
+ // fall-through
case STATE_DISCONNECTING:
if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
// still disconnecting
@@ -178,26 +229,26 @@ public class BluetoothHeadsetHandover {
complete(false);
break;
}
+
+ }
+
+ boolean getProfileProxys() {
+ if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET))
+ return false;
+
+ if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP))
+ return false;
+
+ return true;
}
void nextStepConnect() {
switch (mState) {
- case STATE_INIT:
- if (!mHandoverPowerManager.isBluetoothEnabled()) {
- if (mHandoverPowerManager.enableBluetooth()) {
- // Bluetooth is being enabled
- mState = STATE_TURNING_ON;
- } else {
- toast(mContext.getString(R.string.failed_to_enable_bt));
- complete(false);
- }
- break;
- }
- // fall-through
- case STATE_TURNING_ON:
+ case STATE_INIT_COMPLETE:
if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
requestPairConfirmation();
mState = STATE_WAITING_FOR_BOND_CONFIRMATION;
+
break;
}
// fall-through
@@ -211,21 +262,23 @@ public class BluetoothHeadsetHandover {
// Bluetooth Profile service will correctly serialize
// HFP then A2DP connect
mState = STATE_CONNECTING;
- if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
- mHfpResult = RESULT_PENDING;
- mHeadset.connect(mDevice);
- } else {
- mHfpResult = RESULT_CONNECTED;
- }
- if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
- mA2dpResult = RESULT_PENDING;
- mA2dp.connect(mDevice);
- } else {
- mA2dpResult = RESULT_CONNECTED;
- }
- if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
- toast(mContext.getString(R.string.connecting_headset) + " " + mName + "...");
- break;
+ synchronized (mLock) {
+ if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
+ mHfpResult = RESULT_PENDING;
+ mHeadset.connect(mDevice);
+ } else {
+ mHfpResult = RESULT_CONNECTED;
+ }
+ if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
+ mA2dpResult = RESULT_PENDING;
+ mA2dp.connect(mDevice);
+ } else {
+ mA2dpResult = RESULT_CONNECTED;
+ }
+ if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
+ toast(mContext.getString(R.string.connecting_headset) + " " + mName + "...");
+ break;
+ }
}
// fall-through
case STATE_CONNECTING:
@@ -260,7 +313,7 @@ public class BluetoothHeadsetHandover {
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action) && mState == STATE_TURNING_ON) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_ON) {
- nextStepConnect();
+ nextStep();
} else if (state == BluetoothAdapter.STATE_OFF) {
toast(mContext.getString(R.string.failed_to_enable_bt));
complete(false);
@@ -313,6 +366,16 @@ public class BluetoothHeadsetHandover {
mState = STATE_COMPLETE;
mContext.unregisterReceiver(mReceiver);
mHandler.removeMessages(MSG_TIMEOUT);
+ synchronized (mLock) {
+ if (mA2dp != null) {
+ mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dp);
+ }
+ if (mHeadset != null) {
+ mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadset);
+ }
+ mA2dp = null;
+ mHeadset = null;
+ }
mCallback.onBluetoothHeadsetHandoverComplete(connected);
}
@@ -324,10 +387,10 @@ public class BluetoothHeadsetHandover {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_MEDIA_PLAY));
- mContext.sendOrderedBroadcast(intent, null);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, null, null, 0, null, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP,
KeyEvent.KEYCODE_MEDIA_PLAY));
- mContext.sendOrderedBroadcast(intent, null);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, null, null, 0, null, null);
}
void requestPairConfirmation() {
@@ -336,7 +399,7 @@ public class BluetoothHeadsetHandover {
dialogIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
- mContext.startActivity(dialogIntent);
+ mContext.startActivityAsUser(dialogIntent, new UserHandle(UserHandle.USER_CURRENT));
}
final Handler mHandler = new Handler() {
@@ -348,6 +411,9 @@ public class BluetoothHeadsetHandover {
Log.i(TAG, "Timeout completing BT handover");
complete(false);
break;
+ case MSG_NEXT_STEP:
+ nextStep();
+ break;
}
}
};
@@ -364,4 +430,29 @@ public class BluetoothHeadsetHandover {
throw new IllegalThreadStateException("must be called on main thread");
}
}
+
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ synchronized (mLock) {
+ switch (profile) {
+ case BluetoothProfile.HEADSET:
+ mHeadset = (BluetoothHeadset) proxy;
+ if (mA2dp != null) {
+ mHandler.sendEmptyMessage(MSG_NEXT_STEP);
+ }
+ break;
+ case BluetoothProfile.A2DP:
+ mA2dp = (BluetoothA2dp) proxy;
+ if (mHeadset != null) {
+ mHandler.sendEmptyMessage(MSG_NEXT_STEP);
+ }
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ // We can ignore these
+ }
}
diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java
index f77f780..e7e807d 100644
--- a/src/com/android/nfc/handover/HandoverManager.java
+++ b/src/com/android/nfc/handover/HandoverManager.java
@@ -33,11 +33,8 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Notification.Builder;
-import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -52,6 +49,7 @@ import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
@@ -62,8 +60,7 @@ import com.android.nfc.R;
/**
* Manages handover of NFC to other technologies.
*/
-public class HandoverManager implements BluetoothProfile.ServiceListener,
- BluetoothHeadsetHandover.Callback {
+public class HandoverManager implements BluetoothHeadsetHandover.Callback {
static final String TAG = "NfcHandover";
static final boolean DBG = true;
@@ -142,8 +139,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
// Variables below synchronized on HandoverManager.this
final HashMap<Pair<String, Boolean>, HandoverTransfer> mTransfers;
- BluetoothHeadset mBluetoothHeadset;
- BluetoothA2dp mBluetoothA2dp;
BluetoothHeadsetHandover mBluetoothHeadsetHandover;
boolean mBluetoothHeadsetConnected;
@@ -390,7 +385,8 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
notBuilder.setContentText(mContext.getString(R.string.beam_touch_to_view));
Intent viewIntent = buildViewIntent();
- PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, viewIntent, 0);
+ PendingIntent contentIntent = PendingIntent.getActivityAsUser(
+ mContext, 0, viewIntent, 0, null, UserHandle.CURRENT);
notBuilder.setContentIntent(contentIntent);
@@ -410,7 +406,8 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
return;
}
- mNotificationManager.notify(mNotificationId, notBuilder.build());
+ mNotificationManager.notifyAsUser(null, mNotificationId, notBuilder.build(),
+ UserHandle.CURRENT);
}
synchronized void updateStateAndNotification(int newState) {
@@ -537,7 +534,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
Uri uri = mediaUri != null ? mediaUri :
Uri.parse(ContentResolver.SCHEME_FILE + "://" + filePath);
viewIntent.setDataAndTypeAndNormalize(uri, mimeTypes.get(filePath));
-
+ viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return viewIntent;
}
@@ -612,10 +609,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
public HandoverManager(Context context) {
mContext = context;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if (mBluetoothAdapter != null) {
- mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET);
- mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP);
- }
mNotificationManager = (NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
@@ -792,9 +785,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
if (!handover.valid) return true;
synchronized (HandoverManager.this) {
- if (mBluetoothAdapter == null ||
- mBluetoothA2dp == null ||
- mBluetoothHeadset == null) {
+ if (mBluetoothAdapter == null) {
if (DBG) Log.d(TAG, "BT handover, but BT not available");
return true;
}
@@ -803,7 +794,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
return true;
}
mBluetoothHeadsetHandover = new BluetoothHeadsetHandover(mContext, handover.device,
- handover.name, mHandoverPowerManager, mBluetoothA2dp, mBluetoothHeadset, this);
+ handover.name, mHandoverPowerManager, this);
mBluetoothHeadsetHandover.start();
}
return true;
@@ -983,34 +974,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
}
@Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- synchronized (HandoverManager.this) {
- switch (profile) {
- case BluetoothProfile.HEADSET:
- mBluetoothHeadset = (BluetoothHeadset) proxy;
- break;
- case BluetoothProfile.A2DP:
- mBluetoothA2dp = (BluetoothA2dp) proxy;
- break;
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- synchronized (HandoverManager.this) {
- switch (profile) {
- case BluetoothProfile.HEADSET:
- mBluetoothHeadset = null;
- break;
- case BluetoothProfile.A2DP:
- mBluetoothA2dp = null;
- break;
- }
- }
- }
-
- @Override
public void onBluetoothHeadsetHandoverComplete(boolean connected) {
synchronized (HandoverManager.this) {
mBluetoothHeadsetHandover = null;
diff --git a/src/com/android/nfc/ndefpush/NdefPushServer.java b/src/com/android/nfc/ndefpush/NdefPushServer.java
index ca58a67..bf92c17 100755
--- a/src/com/android/nfc/ndefpush/NdefPushServer.java
+++ b/src/com/android/nfc/ndefpush/NdefPushServer.java
@@ -117,28 +117,49 @@ public class NdefPushServer {
/** Server class, used to listen for incoming connection request */
class ServerThread extends Thread {
+ // Variables below synchronized on NdefPushServer.this
boolean mRunning = true;
LlcpServerSocket mServerSocket;
@Override
public void run() {
- while (mRunning) {
+ boolean threadRunning;
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
+ while (threadRunning) {
if (DBG) Log.d(TAG, "about create LLCP service socket");
try {
- mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME,
- MIU, 1, 1024);
+ synchronized (NdefPushServer.this) {
+ mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME,
+ MIU, 1, 1024);
+ }
if (mServerSocket == null) {
if (DBG) Log.d(TAG, "failed to create LLCP service socket");
return;
}
if (DBG) Log.d(TAG, "created LLCP service socket");
- while (mRunning) {
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
+
+ while (threadRunning) {
+ LlcpServerSocket serverSocket;
+ synchronized (NdefPushServer.this) {
+ serverSocket = mServerSocket;
+ }
+ if (serverSocket == null) return;
+
if (DBG) Log.d(TAG, "about to accept");
- LlcpSocket communicationSocket = mServerSocket.accept();
+ LlcpSocket communicationSocket = serverSocket.accept();
if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
if (communicationSocket != null) {
new ConnectionThread(communicationSocket).start();
}
+
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
}
if (DBG) Log.d(TAG, "stop running");
} catch (LlcpException e) {
@@ -146,28 +167,36 @@ public class NdefPushServer {
} catch (IOException e) {
Log.e(TAG, "IO error", e);
} finally {
- if (mServerSocket != null) {
- if (DBG) Log.d(TAG, "about to close");
- try {
- mServerSocket.close();
- } catch (IOException e) {
- // ignore
+ synchronized (NdefPushServer.this) {
+ if (mServerSocket != null) {
+ if (DBG) Log.d(TAG, "about to close");
+ try {
+ mServerSocket.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ mServerSocket = null;
}
- mServerSocket = null;
}
}
+
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
}
}
public void shutdown() {
- mRunning = false;
- if (mServerSocket != null) {
- try {
- mServerSocket.close();
- } catch (IOException e) {
- // ignore
+ synchronized (NdefPushServer.this) {
+ mRunning = false;
+ if (mServerSocket != null) {
+ try {
+ mServerSocket.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ mServerSocket = null;
}
- mServerSocket = null;
}
}
}
diff --git a/src/com/android/nfc/snep/SnepClient.java b/src/com/android/nfc/snep/SnepClient.java
index 8dca6ae..fae8143 100644
--- a/src/com/android/nfc/snep/SnepClient.java
+++ b/src/com/android/nfc/snep/SnepClient.java
@@ -29,7 +29,8 @@ public final class SnepClient {
private static final String TAG = "SnepClient";
private static final boolean DBG = false;
private static final int DEFAULT_ACCEPTABLE_LENGTH = 100*1024;
- private static final int MIU = 128;
+ private static final int DEFAULT_MIU = 128;
+ private static final int DEFAULT_RWSIZE = 1;
SnepMessenger mMessenger = null;
private final Object mTransmissionLock = new Object();
@@ -38,6 +39,8 @@ public final class SnepClient {
private int mState = DISCONNECTED;
private final int mAcceptableLength;
private final int mFragmentLength;
+ private final int mMiu;
+ private final int mRwSize;
private static final int DISCONNECTED = 0;
private static final int CONNECTING = 1;
@@ -48,6 +51,8 @@ public final class SnepClient {
mPort = SnepServer.DEFAULT_PORT;
mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
}
public SnepClient(String serviceName) {
@@ -55,6 +60,17 @@ public final class SnepClient {
mPort = -1;
mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
+ }
+
+ public SnepClient(int miu, int rwSize) {
+ mServiceName = SnepServer.DEFAULT_SERVICE_NAME;
+ mPort = SnepServer.DEFAULT_PORT;
+ mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
+ mFragmentLength = -1;
+ mMiu = miu;
+ mRwSize = rwSize;
}
SnepClient(String serviceName, int fragmentLength) {
@@ -62,6 +78,8 @@ public final class SnepClient {
mPort = -1;
mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
mFragmentLength = fragmentLength;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
}
SnepClient(String serviceName, int acceptableLength, int fragmentLength) {
@@ -69,6 +87,8 @@ public final class SnepClient {
mPort = -1;
mAcceptableLength = acceptableLength;
mFragmentLength = fragmentLength;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
}
public void put(NdefMessage msg) throws IOException {
@@ -122,7 +142,7 @@ public final class SnepClient {
try {
if (DBG) Log.d(TAG, "about to create socket");
// Connect to the snep server on the remote side
- socket = NfcService.getInstance().createLlcpSocket(0, MIU, 1, 1024);
+ socket = NfcService.getInstance().createLlcpSocket(0, mMiu, mRwSize, 1024);
if (socket == null) {
throw new IOException("Could not connect to socket.");
}
diff --git a/src/com/android/nfc/snep/SnepServer.java b/src/com/android/nfc/snep/SnepServer.java
index 84bb673..aa7da48 100644
--- a/src/com/android/nfc/snep/SnepServer.java
+++ b/src/com/android/nfc/snep/SnepServer.java
@@ -34,9 +34,10 @@ import java.io.IOException;
public final class SnepServer {
private static final String TAG = "SnepServer";
private static final boolean DBG = false;
+ private static final int DEFAULT_MIU = 248;
+ private static final int DEFAULT_RW_SIZE = 1;
public static final int DEFAULT_PORT = 4;
- private static final int MIU = 248;
public static final String DEFAULT_SERVICE_NAME = "urn:nfc:sn:snep";
@@ -44,6 +45,8 @@ public final class SnepServer {
final String mServiceName;
final int mServiceSap;
final int mFragmentLength;
+ final int mMiu;
+ final int mRwSize;
/** Protected by 'this', null when stopped, non-null when running */
ServerThread mServerThread = null;
@@ -59,6 +62,8 @@ public final class SnepServer {
mServiceName = DEFAULT_SERVICE_NAME;
mServiceSap = DEFAULT_PORT;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RW_SIZE;
}
public SnepServer(String serviceName, int serviceSap, Callback callback) {
@@ -66,6 +71,17 @@ public final class SnepServer {
mServiceName = serviceName;
mServiceSap = serviceSap;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RW_SIZE;
+ }
+
+ public SnepServer(Callback callback, int miu, int rwSize) {
+ mCallback = callback;
+ mServiceName = DEFAULT_SERVICE_NAME;
+ mServiceSap = DEFAULT_PORT;
+ mFragmentLength = -1;
+ mMiu = miu;
+ mRwSize = rwSize;
}
SnepServer(String serviceName, int serviceSap, int fragmentLength, Callback callback) {
@@ -73,6 +89,8 @@ public final class SnepServer {
mServiceName = serviceName;
mServiceSap = serviceSap;
mFragmentLength = fragmentLength;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RW_SIZE;
}
/** Connection class, used to handle incoming connections */
@@ -168,7 +186,7 @@ public final class SnepServer {
try {
synchronized (SnepServer.this) {
mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap,
- mServiceName, MIU, 1, 1024);
+ mServiceName, mMiu, mRwSize, 1024);
}
if (mServerSocket == null) {
if (DBG) Log.d(TAG, "failed to create LLCP service socket");