diff options
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/nfc/DeviceHost.java | 20 | ||||
-rw-r--r-- | src/com/android/nfc/FireflyRenderer.java | 1 | ||||
-rw-r--r-- | src/com/android/nfc/NfcApplication.java | 24 | ||||
-rw-r--r-- | src/com/android/nfc/NfcDispatcher.java | 42 | ||||
-rw-r--r-- | src/com/android/nfc/NfcRootActivity.java | 4 | ||||
-rwxr-xr-x | src/com/android/nfc/NfcService.java | 401 | ||||
-rwxr-xr-x | src/com/android/nfc/P2pLinkManager.java | 18 | ||||
-rw-r--r-- | src/com/android/nfc/RegisteredComponentCache.java | 31 | ||||
-rw-r--r-- | src/com/android/nfc/SendUi.java | 20 | ||||
-rw-r--r-- | src/com/android/nfc/handover/BluetoothHeadsetHandover.java | 231 | ||||
-rw-r--r-- | src/com/android/nfc/handover/HandoverManager.java | 55 | ||||
-rwxr-xr-x | src/com/android/nfc/ndefpush/NdefPushServer.java | 67 | ||||
-rw-r--r-- | src/com/android/nfc/snep/SnepClient.java | 24 | ||||
-rw-r--r-- | src/com/android/nfc/snep/SnepServer.java | 22 |
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"); |