diff options
Diffstat (limited to 'src')
22 files changed, 690 insertions, 1892 deletions
diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java index 022c804..bfd5d9c 100755 --- 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(); @@ -224,5 +236,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 06642f7..952b391 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -23,8 +23,8 @@ import com.android.nfc.DeviceHost.LlcpSocket; import com.android.nfc.DeviceHost.NfcDepEndpoint; import com.android.nfc.DeviceHost.TagEndpoint; import com.android.nfc.handover.HandoverManager; -import com.android.nfc.nxp.NativeNfcManager; -import com.android.nfc.nxp.NativeNfcSecureElement; +import com.android.nfc.dhimpl.NativeNfcManager; +import com.android.nfc.dhimpl.NativeNfcSecureElement; import android.app.Application; import android.app.KeyguardManager; @@ -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 @@ -903,10 +989,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. @@ -1234,7 +1316,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); @@ -1277,11 +1359,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 { @@ -1292,7 +1374,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); } } @@ -1341,7 +1423,7 @@ public class NfcService extends Application implements DeviceHostListener { } } - return mSecureElement.doTransceive(mOpenEe.handle, data); + return doTransceive(mOpenEe.handle, data); } @Override @@ -1354,13 +1436,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 */ @@ -1409,19 +1506,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(); } } @@ -1440,12 +1545,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 @@ -1737,6 +1842,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; @@ -1841,52 +1962,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)) { @@ -1910,6 +2001,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/P2pEventManager.java b/src/com/android/nfc/P2pEventManager.java index c024afc..68f479b 100644 --- a/src/com/android/nfc/P2pEventManager.java +++ b/src/com/android/nfc/P2pEventManager.java @@ -51,7 +51,16 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { Context.NOTIFICATION_SERVICE); mSending = false; - mSendUi = new SendUi(context, this); + final int uiModeType = mContext.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_TYPE_MASK; + if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) { + // "Appliances" don't intrinsically have a way of confirming this, so we + // don't use the UI and just autoconfirm where necessary. + // Don't instantiate SendUi or else we'll use memory and never reclaim it. + mSendUi = null; + } else { + mSendUi = new SendUi(context, this); + } } @Override @@ -61,19 +70,17 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { mNdefReceived = false; mVibrator.vibrate(VIBRATION_PATTERN, -1); - mSendUi.takeScreenshot(); + if (mSendUi != null) { + mSendUi.takeScreenshot(); + } } @Override public void onP2pSendConfirmationRequested() { - final int uiModeType = mContext.getResources().getConfiguration().uiMode - & Configuration.UI_MODE_TYPE_MASK; - if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) { - // "Appliances" don't intrinsically have a way of confirming this, so we - // will just auto-confirm. - mCallback.onP2pSendConfirmed(); - } else { + if (mSendUi != null) { mSendUi.showPreSend(); + } else { + mCallback.onP2pSendConfirmed(); } } @@ -81,7 +88,9 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { public void onP2pSendComplete() { mNfcService.playSound(NfcService.SOUND_END); mVibrator.vibrate(VIBRATION_PATTERN, -1); - mSendUi.finish(SendUi.FINISH_SEND_SUCCESS); + if (mSendUi != null) { + mSendUi.finish(SendUi.FINISH_SEND_SUCCESS); + } mSending = false; mNdefSent = true; } @@ -100,14 +109,16 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { public void onP2pReceiveComplete(boolean playSound) { mVibrator.vibrate(VIBRATION_PATTERN, -1); if (playSound) mNfcService.playSound(NfcService.SOUND_END); - // TODO we still don't have a nice receive solution - // The sanest solution right now is just to scale back up what we had - // and start the new activity. It is not perfect, but at least it is - // consistent behavior. All other variants involve making the old - // activity screenshot disappear, and then removing the animation - // window hoping the new activity has started by then. This just goes - // wrong too often and can look weird. - mSendUi.finish(SendUi.FINISH_SCALE_UP); + if (mSendUi != null) { + // TODO we still don't have a nice receive solution + // The sanest solution right now is just to scale back up what we had + // and start the new activity. It is not perfect, but at least it is + // consistent behavior. All other variants involve making the old + // activity screenshot disappear, and then removing the animation + // window hoping the new activity has started by then. This just goes + // wrong too often and can look weird. + mSendUi.finish(SendUi.FINISH_SCALE_UP); + } mNdefReceived = true; } @@ -117,7 +128,7 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { mNfcService.playSound(NfcService.SOUND_ERROR); mSending = false; } - if (!mNdefSent && !mNdefReceived) { + if (!mNdefSent && !mNdefReceived && mSendUi != null) { mSendUi.finish(SendUi.FINISH_SCALE_UP); } } @@ -125,7 +136,9 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { @Override public void onSendConfirmed() { if (!mSending) { - mSendUi.showStartSend(); + if (mSendUi != null) { + mSendUi.showStartSend(); + } mCallback.onP2pSendConfirmed(); } mSending = true; 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/nxp/NativeLlcpConnectionlessSocket.java b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java deleted file mode 100755 index c9d3b5d..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpPacket; - -import java.io.IOException; - -/** - * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used - * in a connectionless communication - */ -public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { - - private int mHandle; - private int mSap; - private int mLinkMiu; - - public NativeLlcpConnectionlessSocket() { } - - public native boolean doSendTo(int sap, byte[] data); - - public native LlcpPacket doReceiveFrom(int linkMiu); - - public native boolean doClose(); - - @Override - public int getLinkMiu(){ - return mLinkMiu; - } - - @Override - public int getSap(){ - return mSap; - } - - @Override - public void send(int sap, byte[] data) throws IOException { - if (!doSendTo(sap, data)) { - throw new IOException(); - } - } - - @Override - public LlcpPacket receive() throws IOException { - LlcpPacket packet = doReceiveFrom(mLinkMiu); - if (packet == null) { - throw new IOException(); - } - return packet; - } - - public int getHandle(){ - return mHandle; - } - - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java deleted file mode 100755 index 531afd8..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.DeviceHost.LlcpSocket; - -import java.io.IOException; - -/** - * LlcpServiceSocket represents a LLCP Service to be used in a - * Connection-oriented communication - */ -public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { - private int mHandle; - private int mLocalMiu; - private int mLocalRw; - private int mLocalLinearBufferLength; - private int mSap; - private String mServiceName; - - public NativeLlcpServiceSocket(){ } - - private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); - @Override - public LlcpSocket accept() throws IOException { - LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); - if (socket == null) throw new IOException(); - return socket; - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpSocket.java b/src/com/android/nfc/nxp/NativeLlcpSocket.java deleted file mode 100755 index a337d35..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; - -import java.io.IOException; - -/** - * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a - * connection-oriented communication - */ -public class NativeLlcpSocket implements DeviceHost.LlcpSocket { - private int mHandle; - private int mSap; - private int mLocalMiu; - private int mLocalRw; - - public NativeLlcpSocket(){ } - - private native boolean doConnect(int nSap); - @Override - public void connectToSap(int sap) throws IOException { - if (!doConnect(sap)) { - throw new IOException(); - } - } - - private native boolean doConnectBy(String sn); - @Override - public void connectToService(String serviceName) throws IOException { - if (!doConnectBy(serviceName)) { - throw new IOException(); - } - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } - - private native boolean doSend(byte[] data); - @Override - public void send(byte[] data) throws IOException { - if (!doSend(data)) { - throw new IOException(); - } - } - - private native int doReceive(byte[] recvBuff); - @Override - public int receive(byte[] recvBuff) throws IOException { - int receiveLength = doReceive(recvBuff); - if (receiveLength == -1) { - throw new IOException(); - } - return receiveLength; - } - - private native int doGetRemoteSocketMiu(); - @Override - public int getRemoteMiu() { return doGetRemoteSocketMiu(); } - - private native int doGetRemoteSocketRw(); - @Override - public int getRemoteRw() { return doGetRemoteSocketRw(); } - - @Override - public int getLocalSap(){ - return mSap; - } - - @Override - public int getLocalMiu(){ - return mLocalMiu; - } - - @Override - public int getLocalRw(){ - return mLocalRw; - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcManager.java b/src/com/android/nfc/nxp/NativeNfcManager.java deleted file mode 100755 index 832da7c..0000000 --- a/src/com/android/nfc/nxp/NativeNfcManager.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpException; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.content.SharedPreferences; -import android.nfc.ErrorCodes; -import android.nfc.tech.Ndef; -import android.nfc.tech.TagTechnology; -import android.util.Log; - -import java.io.File; - -/** - * Native interface to the NFC Manager functions - */ -public class NativeNfcManager implements DeviceHost { - private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; - - static { - System.loadLibrary("nfc_jni"); - } - - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; - - /* Native structure */ - private int mNative; - - private final DeviceHostListener mListener; - private final Context mContext; - - public NativeNfcManager(Context context, DeviceHostListener listener) { - mListener = listener; - initializeNativeStructure(); - mContext = context; - } - - public native boolean initializeNativeStructure(); - - private native boolean doDownload(); - - public native int doGetLastError(); - - @Override - public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } - } - - private native boolean doInitialize(); - - @Override - public boolean initialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { - try { - Thread.sleep (12000); - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - } catch (InterruptedException e) { } - } - - return doInitialize(); - } - - private native boolean doDeinitialize(); - - @Override - public boolean deinitialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - - return doDeinitialize(); - } - - @Override - public native void enableDiscovery(); - - @Override - public native void disableDiscovery(); - - @Override - public native void enableCE_A(); - - @Override - public native void disableCE_A(); - - @Override - public native void enableCE_B(); - - @Override - public native void disableCE_B(); - - - @Override - public native int[] doGetSecureElementList(); - - @Override - public native void doSelectSecureElement(); - - @Override - public native void doDeselectSecureElement(); - - - private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, - String sn); - - @Override - public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) - throws LlcpException { - LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength); - @Override - public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength) throws LlcpException { - LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, - int linearBufferLength); - @Override - public LlcpSocket createLlcpSocket(int sap, int miu, int rw, - int linearBufferLength) throws LlcpException { - LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - @Override - public native boolean doCheckLlcp(); - - @Override - public native boolean doActivateLlcp(); - - private native void doResetTimeouts(); - - @Override - public void resetTimeouts() { - doResetTimeouts(); - } - - @Override - public native void doAbort(); - - private native boolean doSetTimeout(int tech, int timeout); - @Override - public boolean setTimeout(int tech, int timeout) { - return doSetTimeout(tech, timeout); - } - - private native int doGetTimeout(int tech); - @Override - public int getTimeout(int tech) { - return doGetTimeout(tech); - } - - - @Override - public boolean canMakeReadOnly(int ndefType) { - return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || - ndefType == Ndef.TYPE_MIFARE_CLASSIC); - } - - @Override - public int getMaxTransceiveLength(int technology) { - switch (technology) { - case (TagTechnology.NFC_A): - case (TagTechnology.MIFARE_CLASSIC): - case (TagTechnology.MIFARE_ULTRALIGHT): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.NFC_B): - return 0; // PN544 does not support transceive of raw NfcB - case (TagTechnology.NFC_V): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.ISO_PCD_A): - case (TagTechnology.ISO_PCD_B): - case (TagTechnology.ISO_DEP): - /* The maximum length of a normal IsoDep frame consists of: - * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes - * such a frame is supported. Extended length frames however - * are not supported. - */ - return 261; // Will be automatically split in two frames on the RF layer - case (TagTechnology.NFC_F): - return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC - default: - return 0; - } - - } - - private native void doSetP2pInitiatorModes(int modes); - @Override - public void setP2pInitiatorModes(int modes) { - doSetP2pInitiatorModes(modes); - } - - private native void doSetP2pTargetModes(int modes); - @Override - public void setP2pTargetModes(int modes) { - doSetP2pTargetModes(modes); - } - - public boolean getExtendedLengthApdusSupported() { - // Not supported on the PN544 - return false; - } - - private native String doDump(); - @Override - public String dump() { - return doDump(); - } - - /** - * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) - */ - private void notifyNdefMessageListeners(NativeNfcTag tag) { - mListener.onRemoteEndpointDiscovered(tag); - } - - /** - * Notifies transaction - */ - private void notifyTargetDeselected() { - mListener.onCardEmulationDeselected(); - } - - /** - * Notifies transaction - */ - private void notifyTransactionListeners(byte[] aid) { - mListener.onCardEmulationAidSelected(aid); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkActivation(NativeP2pDevice device) { - mListener.onLlcpLinkActivated(device); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { - mListener.onLlcpLinkDeactivated(device); - } - - private void notifySeFieldActivated() { - mListener.onRemoteFieldActivated(); - } - - private void notifySeFieldDeactivated() { - mListener.onRemoteFieldDeactivated(); - } - - private void notifySeApduReceived(byte[] apdu) { - mListener.onSeApduReceived(apdu); - } - - private void notifySeEmvCardRemoval() { - mListener.onSeEmvCardRemoval(); - } - - private void notifySeMifareAccess(byte[] block) { - mListener.onSeMifareAccess(block); - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcSecureElement.java b/src/com/android/nfc/nxp/NativeNfcSecureElement.java deleted file mode 100755 index 88f9b9d..0000000 --- a/src/com/android/nfc/nxp/NativeNfcSecureElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import android.content.Context; -import android.content.SharedPreferences; - - -/** - * Native interface to the NFC Secure Element functions - * - * {@hide} - */ -public class NativeNfcSecureElement { - - static final String PREF_SE_WIRED = "se_wired"; - - private final Context mContext; - - SharedPreferences mPrefs; - SharedPreferences.Editor mPrefsEditor; - - public NativeNfcSecureElement(Context context) { - mContext = context; - - mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); - mPrefsEditor = mPrefs.edit(); - } - - private native int doNativeOpenSecureElementConnection(); - - public int doOpenSecureElementConnection() { - mPrefsEditor.putBoolean(PREF_SE_WIRED, true); - mPrefsEditor.apply(); - - return doNativeOpenSecureElementConnection(); - } - - private native boolean doNativeDisconnectSecureElementConnection(int handle); - - public boolean doDisconnect(int handle) { - mPrefsEditor.putBoolean(PREF_SE_WIRED, false); - mPrefsEditor.apply(); - - return doNativeDisconnectSecureElementConnection(handle); - } - - public native byte[] doTransceive(int handle, byte[] data); - - public native int[] doGetTechList(int handle); - - public native byte [] doGetUid(int handle); -} diff --git a/src/com/android/nfc/nxp/NativeNfcTag.java b/src/com/android/nfc/nxp/NativeNfcTag.java deleted file mode 100755 index 8996dfb..0000000 --- a/src/com/android/nfc/nxp/NativeNfcTag.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.TagEndpoint; - -import android.nfc.FormatException; -import android.nfc.NdefMessage; -import android.nfc.tech.IsoDep; -import android.nfc.tech.MifareClassic; -import android.nfc.tech.MifareUltralight; -import android.nfc.tech.Ndef; -import android.nfc.tech.NfcA; -import android.nfc.tech.NfcB; -import android.nfc.tech.NfcF; -import android.nfc.tech.NfcV; -import android.nfc.tech.TagTechnology; -import android.os.Bundle; -import android.util.Log; - -/** - * Native interface to the NFC tag functions - */ -public class NativeNfcTag implements TagEndpoint { - static final boolean DBG = false; - - static final int STATUS_CODE_TARGET_LOST = 146; - - private int[] mTechList; - private int[] mTechHandles; - private int[] mTechLibNfcTypes; - private Bundle[] mTechExtras; - private byte[][] mTechPollBytes; - private byte[][] mTechActBytes; - private byte[] mUid; - - // mConnectedHandle stores the *real* libnfc handle - // that we're connected to. - private int mConnectedHandle; - - // mConnectedTechIndex stores to which technology - // the upper layer stack is connected. Note that - // we may be connected to a libnfchandle without being - // connected to a technology - technology changes - // may occur runtime, whereas the underlying handle - // could stay present. Usually all technologies are on the - // same handle, with the exception of multi-protocol - // tags. - private int mConnectedTechIndex; // Index in mTechHandles - - private final String TAG = "NativeNfcTag"; - - private boolean mIsPresent; // Whether the tag is known to be still present - - private PresenceCheckWatchdog mWatchdog; - class PresenceCheckWatchdog extends Thread { - - private int watchdogTimeout = 125; - - private boolean isPresent = true; - private boolean isStopped = false; - private boolean isPaused = false; - private boolean doCheck = true; - - public synchronized void pause() { - isPaused = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void doResume() { - isPaused = false; - // We don't want to resume presence checking immediately, - // but go through at least one more wait period. - doCheck = false; - this.notifyAll(); - } - - public synchronized void end() { - isStopped = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void setTimeout(int timeout) { - watchdogTimeout = timeout; - doCheck = false; // Do it only after we have waited "timeout" ms again - this.notifyAll(); - } - - @Override - public synchronized void run() { - if (DBG) Log.d(TAG, "Starting background presence check"); - while (isPresent && !isStopped) { - try { - if (!isPaused) { - doCheck = true; - } - this.wait(watchdogTimeout); - if (doCheck) { - isPresent = doPresenceCheck(); - } else { - // 1) We are paused, waiting for unpause - // 2) We just unpaused, do pres check in next iteration - // (after watchdogTimeout ms sleep) - // 3) We just set the timeout, wait for this timeout - // to expire once first. - // 4) We just stopped, exit loop anyway - } - } catch (InterruptedException e) { - // Activity detected, loop - } - } - mIsPresent = false; - // Restart the polling loop - - Log.d(TAG, "Tag lost, restarting polling loop"); - doDisconnect(); - if (DBG) Log.d(TAG, "Stopping background presence check"); - } - } - - private native int doConnect(int handle); - public synchronized int connectWithStatus(int technology) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == technology) { - // Get the handle and connect, if not already connected - if (mConnectedHandle != mTechHandles[i]) { - // We're not yet connected to this handle, there are - // a few scenario's here: - // 1) We are not connected to anything yet - allow - // 2) We are connected to a technology which has - // a different handle (multi-protocol tag); we support - // switching to that. - if (mConnectedHandle == -1) { - // Not connected yet - status = doConnect(mTechHandles[i]); - } else { - // Connect to a tech with a different handle - status = reconnectWithStatus(mTechHandles[i]); - } - if (status == 0) { - mConnectedHandle = mTechHandles[i]; - mConnectedTechIndex = i; - } - } else { - // 1) We are connected to a technology which has the same - // handle; we do not support connecting at a different - // level (libnfc auto-activates to the max level on - // any handle). - // 2) We are connecting to the ndef technology - always - // allowed. - if ((technology == TagTechnology.NDEF) || - (technology == TagTechnology.NDEF_FORMATABLE)) { - status = 0; - } else { - if ((technology != TagTechnology.ISO_DEP) && - (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { - // Don't allow to connect a -4 tag at a different level - // than IsoDep, as this is not supported by - // libNFC. - status = -1; - } else { - status = 0; - } - } - if (status == 0) { - mConnectedTechIndex = i; - // Handle was already identical - } - } - break; - } - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean connect(int technology) { - return connectWithStatus(technology) == 0; - } - - @Override - public synchronized void startPresenceChecking() { - // Once we start presence checking, we allow the upper layers - // to know the tag is in the field. - mIsPresent = true; - if (mWatchdog == null) { - mWatchdog = new PresenceCheckWatchdog(); - mWatchdog.start(); - } - } - - @Override - public synchronized boolean isPresent() { - // Returns whether the tag is still in the field to the best - // of our knowledge. - return mIsPresent; - } - native boolean doDisconnect(); - @Override - public synchronized boolean disconnect() { - boolean result = false; - - mIsPresent = false; - if (mWatchdog != null) { - // Watchdog has already disconnected or will do it - mWatchdog.end(); - try { - mWatchdog.join(); - } catch (InterruptedException e) { - // Should never happen. - } - mWatchdog = null; - result = true; - } else { - result = doDisconnect(); - } - - mConnectedTechIndex = -1; - mConnectedHandle = -1; - return result; - } - - native int doReconnect(); - public synchronized int reconnectWithStatus() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doReconnect(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean reconnect() { - return reconnectWithStatus() == 0; - } - - native int doHandleReconnect(int handle); - public synchronized int reconnectWithStatus(int handle) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doHandleReconnect(handle); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - - private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); - @Override - public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doTransceive(data, raw, returnCode); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native int doCheckNdef(int[] ndefinfo); - private synchronized int checkNdefWithStatus(int[] ndefinfo) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doCheckNdef(ndefinfo); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean checkNdef(int[] ndefinfo) { - return checkNdefWithStatus(ndefinfo) == 0; - } - - private native byte[] doRead(); - @Override - public synchronized byte[] readNdef() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doRead(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native boolean doWrite(byte[] buf); - @Override - public synchronized boolean writeNdef(byte[] buf) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doWrite(buf); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doPresenceCheck(); - @Override - public synchronized boolean presenceCheck() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doPresenceCheck(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doNdefFormat(byte[] key); - @Override - public synchronized boolean formatNdef(byte[] key) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doNdefFormat(key); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doMakeReadonly(byte[] key); - @Override - public synchronized boolean makeReadOnly() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result; - if (hasTech(TagTechnology.MIFARE_CLASSIC)) { - result = doMakeReadonly(MifareClassic.KEY_DEFAULT); - } else { - // No key needed for other technologies - result = doMakeReadonly(new byte[] {}); - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); - @Override - public synchronized boolean isNdefFormatable() { - if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { - // These are always formatable - return true; - } - if (hasTech(TagTechnology.NFC_V)) { - // Currently libnfc only formats NXP NFC-V tags - if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { - return true; - } else { - return false; - } - } - // For ISO-DEP, call native code to determine at lower level if format - // is possible. It will need NFC-A poll/activation time bytes for this. - if (hasTech(TagTechnology.ISO_DEP)) { - int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); - if (nfcaTechIndex != -1) { - return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], - mTechActBytes[nfcaTechIndex]); - } else { - return false; - } - } else { - // Formatting not supported by libNFC - return false; - } - } - - @Override - public int getHandle() { - // This is just a handle for the clients; it can simply use the first - // technology handle we have. - if (mTechHandles.length > 0) { - return mTechHandles[0]; - } else { - return 0; - } - } - - @Override - public byte[] getUid() { - return mUid; - } - - @Override - public int[] getTechList() { - return mTechList; - } - - private int getConnectedHandle() { - return mConnectedHandle; - } - - private int getConnectedLibNfcType() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { - return mTechLibNfcTypes[mConnectedTechIndex]; - } else { - return 0; - } - } - - @Override - public int getConnectedTechnology() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { - return mTechList[mConnectedTechIndex]; - } else { - return 0; - } - } - native int doGetNdefType(int libnfctype, int javatype); - private int getNdefType(int libnfctype, int javatype) { - return doGetNdefType(libnfctype, javatype); - } - - private void addTechnology(int tech, int handle, int libnfctype) { - int[] mNewTechList = new int[mTechList.length + 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); - mNewTechList[mTechList.length] = tech; - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length + 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); - mNewHandleList[mTechHandles.length] = handle; - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); - mNewTypeList[mTechLibNfcTypes.length] = libnfctype; - mTechLibNfcTypes = mNewTypeList; - } - - @Override - public void removeTechnology(int tech) { - synchronized (this) { - int techIndex = getTechIndex(tech); - if (techIndex != -1) { - int[] mNewTechList = new int[mTechList.length - 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); - System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, - mTechList.length - techIndex - 1); - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length - 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); - System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, - mTechHandles.length - techIndex - 1); - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); - System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, - mTechLibNfcTypes.length - techIndex - 1); - mTechLibNfcTypes = mNewTypeList; - } - } - } - - public void addNdefFormatableTechnology(int handle, int libnfcType) { - synchronized (this) { - addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); - } - } - - // This method exists to "patch in" the ndef technologies, - // which is done inside Java instead of the native JNI code. - // To not create some nasty dependencies on the order on which things - // are called (most notably getTechExtras()), it needs some additional - // checking. - public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, - int javaType, int maxLength, int cardState) { - synchronized (this) { - addTechnology(TagTechnology.NDEF, handle, libnfcType); - - Bundle extras = new Bundle(); - extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); - extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); - extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); - extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); - - if (mTechExtras == null) { - // This will build the tech extra's for the first time, - // including a NULL ref for the NDEF tech we generated above. - Bundle[] builtTechExtras = getTechExtras(); - builtTechExtras[builtTechExtras.length - 1] = extras; - } - else { - // Tech extras were built before, patch the NDEF one in - Bundle[] oldTechExtras = getTechExtras(); - Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; - System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); - newTechExtras[oldTechExtras.length] = extras; - mTechExtras = newTechExtras; - } - - - } - } - - private int getTechIndex(int tech) { - int techIndex = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - techIndex = i; - break; - } - } - return techIndex; - } - - private boolean hasTech(int tech) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - hasTech = true; - break; - } - } - return hasTech; - } - - private boolean hasTechOnHandle(int tech, int handle) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech && mTechHandles[i] == handle) { - hasTech = true; - break; - } - } - return hasTech; - - } - - private boolean isUltralightC() { - /* Make a best-effort attempt at classifying ULTRALIGHT - * vs ULTRALIGHT-C (based on NXP's public AN1303). - * The memory layout is as follows: - * Page # BYTE1 BYTE2 BYTE3 BYTE4 - * 2 INT1 INT2 LOCK LOCK - * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) - * 4 DATA DATA DATA DATA (version info if factory-state) - * - * Read four blocks from page 2, which will get us both - * the lock page, the OTP page and the version info. - */ - boolean isUltralightC = false; - byte[] readCmd = { 0x30, 0x02 }; - int[] retCode = new int[2]; - byte[] respData = transceive(readCmd, false, retCode); - if (respData != null && respData.length == 16) { - // Check the lock bits (last 2 bytes in page2) - // and the OTP bytes (entire page 3) - if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && - respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { - // Very likely to be a blank card, look at version info - // in page 4. - if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { - // This is Ultralight-C - isUltralightC = true; - } else { - // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight - // as a fallback if it's anything else - isUltralightC = false; - } - } else { - // See if we can find the NDEF CC in the OTP page and if it's - // smaller than major version two - if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { - // OK, got NDEF. Technically we'd have to search for the - // NDEF TLV as well. However, this would add too much - // time for discovery and we can make already make a good guess - // with the data we have here. Byte 2 of the OTP page - // indicates the size of the tag - 0x06 is UL, anything - // above indicates UL-C. - if ((respData[6] & 0xff) > 0x06) { - isUltralightC = true; - } - } else { - // Fall back to ultralight - isUltralightC = false; - } - } - } - return isUltralightC; - } - - @Override - public Bundle[] getTechExtras() { - synchronized (this) { - if (mTechExtras != null) return mTechExtras; - mTechExtras = new Bundle[mTechList.length]; - for (int i = 0; i < mTechList.length; i++) { - Bundle extras = new Bundle(); - switch (mTechList[i]) { - case TagTechnology.NFC_A: { - byte[] actBytes = mTechActBytes[i]; - if ((actBytes != null) && (actBytes.length > 0)) { - extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); - } else { - // Unfortunately Jewel doesn't have act bytes, - // ignore this case. - } - extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); - break; - } - - case TagTechnology.NFC_B: { - // What's returned from the PN544 is actually: - // 4 bytes app data - // 3 bytes prot info - byte[] appData = new byte[4]; - byte[] protInfo = new byte[3]; - if (mTechPollBytes[i].length >= 7) { - System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); - System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); - - extras.putByteArray(NfcB.EXTRA_APPDATA, appData); - extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); - } - break; - } - - case TagTechnology.NFC_F: { - byte[] pmm = new byte[8]; - byte[] sc = new byte[2]; - if (mTechPollBytes[i].length >= 8) { - // At least pmm is present - System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); - extras.putByteArray(NfcF.EXTRA_PMM, pmm); - } - if (mTechPollBytes[i].length == 10) { - System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); - extras.putByteArray(NfcF.EXTRA_SC, sc); - } - break; - } - - case TagTechnology.ISO_DEP: { - if (hasTech(TagTechnology.NFC_A)) { - extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); - } - else { - extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); - } - break; - } - - case TagTechnology.NFC_V: { - // First byte response flags, second byte DSFID - if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { - extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); - extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); - } - break; - } - - case TagTechnology.MIFARE_ULTRALIGHT: { - boolean isUlc = isUltralightC(); - extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); - break; - } - - default: { - // Leave the entry in the array null - continue; - } - } - mTechExtras[i] = extras; - } - return mTechExtras; - } - } - - @Override - public NdefMessage findAndReadNdef() { - // Try to find NDEF on any of the technologies. - int[] technologies = getTechList(); - int[] handles = mTechHandles; - NdefMessage ndefMsg = null; - boolean foundFormattable = false; - int formattableHandle = 0; - int formattableLibNfcType = 0; - int status; - - for (int techIndex = 0; techIndex < technologies.length; techIndex++) { - // have we seen this handle before? - for (int i = 0; i < techIndex; i++) { - if (handles[i] == handles[techIndex]) { - continue; // don't check duplicate handles - } - } - - status = connectWithStatus(technologies[techIndex]); - if (status != 0) { - Log.d(TAG, "Connect Failed - status = "+ status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - // Check if this type is NDEF formatable - if (!foundFormattable) { - if (isNdefFormatable()) { - foundFormattable = true; - formattableHandle = getConnectedHandle(); - formattableLibNfcType = getConnectedLibNfcType(); - // We'll only add formattable tech if no ndef is - // found - this is because libNFC refuses to format - // an already NDEF formatted tag. - } - reconnect(); - } - - int[] ndefinfo = new int[2]; - status = checkNdefWithStatus(ndefinfo); - if (status != 0) { - Log.d(TAG, "Check NDEF Failed - status = " + status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - - // found our NDEF handle - boolean generateEmptyNdef = false; - - int supportedNdefLength = ndefinfo[0]; - int cardState = ndefinfo[1]; - byte[] buff = readNdef(); - if (buff != null) { - try { - ndefMsg = new NdefMessage(buff); - addNdefTechnology(ndefMsg, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } catch (FormatException e) { - // Create an intent anyway, without NDEF messages - generateEmptyNdef = true; - } - } else { - generateEmptyNdef = true; - } - - if (generateEmptyNdef) { - ndefMsg = null; - addNdefTechnology(null, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } - break; - } - - if (ndefMsg == null && foundFormattable) { - // Tag is not NDEF yet, and found a formattable target, - // so add formattable tech to tech list. - addNdefFormatableTechnology( - formattableHandle, - formattableLibNfcType); - } - - return ndefMsg; - } -} diff --git a/src/com/android/nfc/nxp/NativeP2pDevice.java b/src/com/android/nfc/nxp/NativeP2pDevice.java deleted file mode 100755 index 7c7db41..0000000 --- a/src/com/android/nfc/nxp/NativeP2pDevice.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.NfcDepEndpoint; - -/** - * Native interface to the P2P Initiator functions - */ -public class NativeP2pDevice implements NfcDepEndpoint { - - private int mHandle; - - private int mMode; - - private byte[] mGeneralBytes; - - private native byte[] doReceive(); - @Override - public byte[] receive() { - return doReceive(); - } - - private native boolean doSend(byte[] data); - @Override - public boolean send(byte[] data) { - return doSend(data); - } - - private native boolean doConnect(); - @Override - public boolean connect() { - return doConnect(); - } - - private native boolean doDisconnect(); - @Override - public boolean disconnect() { - return doDisconnect(); - } - - public native byte[] doTransceive(byte[] data); - @Override - public byte[] transceive(byte[] data) { - return doTransceive(data); - } - - @Override - public int getHandle() { - return mHandle; - } - - @Override - public int getMode() { - return mMode; - } - - @Override - public byte[] getGeneralBytes() { - return mGeneralBytes; - } - -} 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"); |