Merge "Improve NDEF push API"
This commit is contained in:
@@ -107,6 +107,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/R/com/android/systemui/R.
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IAudioService.P)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IAudioService.P)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/)
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
||||
@@ -12413,13 +12413,15 @@ package android.nfc {
|
||||
|
||||
public final class NfcAdapter {
|
||||
method public void disableForegroundDispatch(android.app.Activity);
|
||||
method public void disableForegroundNdefPush(android.app.Activity);
|
||||
method public deprecated void disableForegroundNdefPush(android.app.Activity);
|
||||
method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][]);
|
||||
method public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
|
||||
method public void enableForegroundNdefPush(android.app.Activity, android.nfc.NfcAdapter.NdefPushCallback);
|
||||
method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
|
||||
method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
|
||||
method public static deprecated android.nfc.NfcAdapter getDefaultAdapter();
|
||||
method public boolean isEnabled();
|
||||
method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity...);
|
||||
method public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity...);
|
||||
method public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity...);
|
||||
field public static final java.lang.String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
|
||||
field public static final java.lang.String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
|
||||
field public static final java.lang.String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
|
||||
@@ -12428,9 +12430,16 @@ package android.nfc {
|
||||
field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
|
||||
}
|
||||
|
||||
public static abstract interface NfcAdapter.NdefPushCallback {
|
||||
method public abstract android.nfc.NdefMessage createMessage();
|
||||
method public abstract void onMessagePushed();
|
||||
public static abstract interface NfcAdapter.CreateNdefMessageCallback {
|
||||
method public abstract android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
|
||||
}
|
||||
|
||||
public static abstract interface NfcAdapter.OnNdefPushCompleteCallback {
|
||||
method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
|
||||
}
|
||||
|
||||
public final class NfcEvent {
|
||||
field public final android.nfc.NfcAdapter nfcAdapter;
|
||||
}
|
||||
|
||||
public final class NfcManager {
|
||||
|
||||
@@ -23,6 +23,6 @@ import android.nfc.NdefMessage;
|
||||
*/
|
||||
interface INdefPushCallback
|
||||
{
|
||||
NdefMessage onConnect();
|
||||
void onMessagePushed();
|
||||
NdefMessage createMessage();
|
||||
void onNdefPushComplete();
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import android.nfc.NdefMessage;
|
||||
import android.nfc.Tag;
|
||||
import android.nfc.TechListParcel;
|
||||
import android.nfc.INdefPushCallback;
|
||||
import android.nfc.INfcTag;
|
||||
import android.nfc.INfcAdapterExtras;
|
||||
import android.nfc.INfcTag;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -34,19 +34,14 @@ interface INfcAdapter
|
||||
INfcTag getNfcTagInterface();
|
||||
INfcAdapterExtras getNfcAdapterExtrasInterface();
|
||||
|
||||
// NfcAdapter-class related methods
|
||||
int getState();
|
||||
void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
|
||||
in IntentFilter[] filters, in TechListParcel techLists);
|
||||
void disableForegroundDispatch(in ComponentName activity);
|
||||
void enableForegroundNdefPush(in ComponentName activity, in NdefMessage msg);
|
||||
void enableForegroundNdefPushWithCallback(in ComponentName activity, in INdefPushCallback callback);
|
||||
void disableForegroundNdefPush(in ComponentName activity);
|
||||
|
||||
// Non-public methods
|
||||
boolean disable();
|
||||
boolean enable();
|
||||
boolean enableZeroClick();
|
||||
boolean disableZeroClick();
|
||||
boolean isZeroClickEnabled();
|
||||
boolean enableNdefPush();
|
||||
boolean disableNdefPush();
|
||||
boolean isNdefPushEnabled();
|
||||
|
||||
void setForegroundDispatch(in PendingIntent intent,
|
||||
in IntentFilter[] filters, in TechListParcel techLists);
|
||||
void setForegroundNdefPush(in NdefMessage msg, in INdefPushCallback callback);
|
||||
}
|
||||
|
||||
217
core/java/android/nfc/NfcActivityManager.java
Normal file
217
core/java/android/nfc/NfcActivityManager.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.nfc;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Manages NFC API's that are coupled to the life-cycle of an Activity.
|
||||
*
|
||||
* <p>Uses a fragment to hook into onPause() and onResume() of the host
|
||||
* activities.
|
||||
*
|
||||
* <p>Ideally all of this management would be done in the NFC Service,
|
||||
* but right now it is much easier to do it in the application process.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class NfcActivityManager extends INdefPushCallback.Stub {
|
||||
static final String TAG = NfcAdapter.TAG;
|
||||
static final Boolean DBG = false;
|
||||
|
||||
final NfcAdapter mAdapter;
|
||||
final HashMap<Activity, NfcActivityState> mNfcState; // contents protected by this
|
||||
final NfcEvent mDefaultEvent; // can re-use one NfcEvent because it just contains adapter
|
||||
|
||||
/**
|
||||
* NFC state associated with an {@link Activity}
|
||||
*/
|
||||
class NfcActivityState {
|
||||
boolean resumed = false; // is the activity resumed
|
||||
NdefMessage ndefMessage;
|
||||
NfcAdapter.CreateNdefMessageCallback ndefMessageCallback;
|
||||
NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback;
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder("[").append(resumed).append(" ");
|
||||
s.append(ndefMessage).append(" ").append(ndefMessageCallback).append(" ");
|
||||
s.append(onNdefPushCompleteCallback).append("]");
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public NfcActivityManager(NfcAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
mNfcState = new HashMap<Activity, NfcActivityState>();
|
||||
mDefaultEvent = new NfcEvent(mAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* onResume hook from fragment attached to activity
|
||||
*/
|
||||
public synchronized void onResume(Activity activity) {
|
||||
NfcActivityState state = mNfcState.get(activity);
|
||||
if (DBG) Log.d(TAG, "onResume() for " + activity + " " + state);
|
||||
if (state != null) {
|
||||
state.resumed = true;
|
||||
updateNfcService(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* onPause hook from fragment attached to activity
|
||||
*/
|
||||
public synchronized void onPause(Activity activity) {
|
||||
NfcActivityState state = mNfcState.get(activity);
|
||||
if (DBG) Log.d(TAG, "onPause() for " + activity + " " + state);
|
||||
if (state != null) {
|
||||
state.resumed = false;
|
||||
updateNfcService(state);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setNdefPushMessage(Activity activity, NdefMessage message) {
|
||||
NfcActivityState state = getOrCreateState(activity, message != null);
|
||||
if (state == null || state.ndefMessage == message) {
|
||||
return; // nothing more to do;
|
||||
}
|
||||
state.ndefMessage = message;
|
||||
if (message == null) {
|
||||
maybeRemoveState(activity, state);
|
||||
}
|
||||
if (state.resumed) {
|
||||
updateNfcService(state);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setNdefPushMessageCallback(Activity activity,
|
||||
NfcAdapter.CreateNdefMessageCallback callback) {
|
||||
NfcActivityState state = getOrCreateState(activity, callback != null);
|
||||
if (state == null || state.ndefMessageCallback == callback) {
|
||||
return; // nothing more to do;
|
||||
}
|
||||
state.ndefMessageCallback = callback;
|
||||
if (callback == null) {
|
||||
maybeRemoveState(activity, state);
|
||||
}
|
||||
if (state.resumed) {
|
||||
updateNfcService(state);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setOnNdefPushCompleteCallback(Activity activity,
|
||||
NfcAdapter.OnNdefPushCompleteCallback callback) {
|
||||
NfcActivityState state = getOrCreateState(activity, callback != null);
|
||||
if (state == null || state.onNdefPushCompleteCallback == callback) {
|
||||
return; // nothing more to do;
|
||||
}
|
||||
state.onNdefPushCompleteCallback = callback;
|
||||
if (callback == null) {
|
||||
maybeRemoveState(activity, state);
|
||||
}
|
||||
if (state.resumed) {
|
||||
updateNfcService(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the NfcActivityState for the specified Activity.
|
||||
* If create is true, then create it if it doesn't already exist,
|
||||
* and ensure the NFC fragment is attached to the activity.
|
||||
*/
|
||||
synchronized NfcActivityState getOrCreateState(Activity activity, boolean create) {
|
||||
if (DBG) Log.d(TAG, "getOrCreateState " + activity + " " + create);
|
||||
NfcActivityState state = mNfcState.get(activity);
|
||||
if (state == null && create) {
|
||||
state = new NfcActivityState();
|
||||
mNfcState.put(activity, state);
|
||||
NfcFragment.attach(activity);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the NfcActivityState is empty then remove it, and
|
||||
* detach it from the Activity.
|
||||
*/
|
||||
synchronized void maybeRemoveState(Activity activity, NfcActivityState state) {
|
||||
if (state.ndefMessage == null && state.ndefMessageCallback == null &&
|
||||
state.onNdefPushCompleteCallback == null) {
|
||||
mNfcState.remove(activity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register NfcActivityState with the NFC service.
|
||||
*/
|
||||
synchronized void updateNfcService(NfcActivityState state) {
|
||||
boolean serviceCallbackNeeded = state.ndefMessageCallback != null ||
|
||||
state.onNdefPushCompleteCallback != null;
|
||||
|
||||
try {
|
||||
NfcAdapter.sService.setForegroundNdefPush(state.resumed ? state.ndefMessage : null,
|
||||
state.resumed && serviceCallbackNeeded ? this : null);
|
||||
} catch (RemoteException e) {
|
||||
mAdapter.attemptDeadServiceRecovery(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from NFC service
|
||||
*/
|
||||
@Override
|
||||
public NdefMessage createMessage() {
|
||||
NfcAdapter.CreateNdefMessageCallback callback = null;
|
||||
synchronized (NfcActivityManager.this) {
|
||||
for (NfcActivityState state : mNfcState.values()) {
|
||||
if (state.resumed) {
|
||||
callback = state.ndefMessageCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drop lock before making callback
|
||||
if (callback != null) {
|
||||
return callback.createNdefMessage(mDefaultEvent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from NFC service
|
||||
*/
|
||||
@Override
|
||||
public void onNdefPushComplete() {
|
||||
NfcAdapter.OnNdefPushCompleteCallback callback = null;
|
||||
synchronized (NfcActivityManager.this) {
|
||||
for (NfcActivityState state : mNfcState.values()) {
|
||||
if (state.resumed) {
|
||||
callback = state.onNdefPushCompleteCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drop lock before making callback
|
||||
if (callback != null) {
|
||||
callback.onNdefPushComplete(mDefaultEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ import android.util.Log;
|
||||
* adapter for this Android device.
|
||||
*/
|
||||
public final class NfcAdapter {
|
||||
private static final String TAG = "NFC";
|
||||
static final String TAG = "NFC";
|
||||
|
||||
/**
|
||||
* Intent to start an activity when a tag with NDEF payload is discovered.
|
||||
@@ -187,106 +187,67 @@ public final class NfcAdapter {
|
||||
/** @hide */
|
||||
public static final int STATE_TURNING_OFF = 4;
|
||||
|
||||
/**
|
||||
* LLCP link status: The LLCP link is activated.
|
||||
* @hide
|
||||
*/
|
||||
public static final int LLCP_LINK_STATE_ACTIVATED = 0;
|
||||
|
||||
/**
|
||||
* LLCP link status: The LLCP link is deactivated.
|
||||
* @hide
|
||||
*/
|
||||
public static final int LLCP_LINK_STATE_DEACTIVATED = 1;
|
||||
|
||||
/**
|
||||
* Broadcast Action: the LLCP link state changed.
|
||||
* <p>
|
||||
* Always contains the extra field
|
||||
* {@link android.nfc.NfcAdapter#EXTRA_LLCP_LINK_STATE_CHANGED}.
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_LLCP_LINK_STATE_CHANGED =
|
||||
"android.nfc.action.LLCP_LINK_STATE_CHANGED";
|
||||
|
||||
/**
|
||||
* Used as int extra field in
|
||||
* {@link android.nfc.NfcAdapter#ACTION_LLCP_LINK_STATE_CHANGED}.
|
||||
* <p>
|
||||
* It contains the new state of the LLCP link.
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_LLCP_LINK_STATE_CHANGED = "android.nfc.extra.LLCP_LINK_STATE";
|
||||
|
||||
/**
|
||||
* Tag Reader Discovery mode
|
||||
* @hide
|
||||
*/
|
||||
private static final int DISCOVERY_MODE_TAG_READER = 0;
|
||||
|
||||
/**
|
||||
* NFC-IP1 Peer-to-Peer mode Enables the manager to act as a peer in an
|
||||
* NFC-IP1 communication. Implementations should not assume that the
|
||||
* controller will end up behaving as an NFC-IP1 target or initiator and
|
||||
* should handle both cases, depending on the type of the remote peer type.
|
||||
* @hide
|
||||
*/
|
||||
private static final int DISCOVERY_MODE_NFCIP1 = 1;
|
||||
|
||||
/**
|
||||
* Card Emulation mode Enables the manager to act as an NFC tag. Provided
|
||||
* that a Secure Element (an UICC for instance) is connected to the NFC
|
||||
* controller through its SWP interface, it can be exposed to the outside
|
||||
* NFC world and be addressed by external readers the same way they would
|
||||
* with a tag.
|
||||
* <p>
|
||||
* Which Secure Element is exposed is implementation-dependent.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private static final int DISCOVERY_MODE_CARD_EMULATION = 2;
|
||||
|
||||
/**
|
||||
* Callback passed into {@link #enableForegroundNdefPush(Activity,NdefPushCallback)}. This
|
||||
*/
|
||||
public interface NdefPushCallback {
|
||||
/**
|
||||
* Called when a P2P connection is created.
|
||||
*/
|
||||
NdefMessage createMessage();
|
||||
/**
|
||||
* Called when the message is pushed.
|
||||
*/
|
||||
void onMessagePushed();
|
||||
}
|
||||
|
||||
private static class NdefPushCallbackWrapper extends INdefPushCallback.Stub {
|
||||
private NdefPushCallback mCallback;
|
||||
|
||||
public NdefPushCallbackWrapper(NdefPushCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NdefMessage onConnect() {
|
||||
return mCallback.createMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessagePushed() {
|
||||
mCallback.onMessagePushed();
|
||||
}
|
||||
}
|
||||
|
||||
// Guarded by NfcAdapter.class
|
||||
private static boolean sIsInitialized = false;
|
||||
static boolean sIsInitialized = false;
|
||||
|
||||
// Final after first constructor, except for
|
||||
// attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
|
||||
// recovery
|
||||
private static INfcAdapter sService;
|
||||
private static INfcTag sTagService;
|
||||
static INfcAdapter sService;
|
||||
static INfcTag sTagService;
|
||||
|
||||
/**
|
||||
* NfcAdapter is currently a singleton, and does not require a context.
|
||||
* However all the public API's are future-proofed to require a context.
|
||||
* If we start using that then we'll need to keep a HashMap of
|
||||
* Context.getApplicationContext() -> NfcAdapter, such that NfcAdapter
|
||||
* is a singleton within each application context.
|
||||
*/
|
||||
static NfcAdapter sSingleton; // protected by NfcAdapter.class
|
||||
|
||||
final NfcActivityManager mNfcActivityManager;
|
||||
|
||||
/**
|
||||
* @see {@link #setNdefPushMessageCallback}
|
||||
*/
|
||||
public interface OnNdefPushCompleteCallback {
|
||||
/**
|
||||
* Called on successful NDEF push.
|
||||
*
|
||||
* <p>This callback is usually made on a binder thread (not the UI thread).
|
||||
*
|
||||
* @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
|
||||
* @see {@link #setNdefPushMessageCallback}
|
||||
*/
|
||||
public void onNdefPushComplete(NfcEvent event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link #setCeateNdefMessageCallback}
|
||||
*/
|
||||
public interface CreateNdefMessageCallback {
|
||||
/**
|
||||
* Called to provide a {@link NdefMessage} to push.
|
||||
*
|
||||
* <p>This callback is usually made on a binder thread (not the UI thread).
|
||||
*
|
||||
* <p>Called when this device is in range of another device
|
||||
* that might support NDEF push. It allows the application to
|
||||
* create the NDEF message only when it is required.
|
||||
*
|
||||
* <p>NDEF push cannot occur until this method returns, so do not
|
||||
* block for too long.
|
||||
*
|
||||
* <p>The Android operating system will usually show a system UI
|
||||
* on top of your activity during this time, so do not try to request
|
||||
* input from the user to complete the callback, or provide custom NDEF
|
||||
* push UI. The user probably will not see it.
|
||||
*
|
||||
* @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
|
||||
* @return NDEF message to push, or null to not provide a message
|
||||
*/
|
||||
public NdefMessage createNdefMessage(NfcEvent event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to check if this device has FEATURE_NFC, but without using
|
||||
@@ -308,29 +269,36 @@ public final class NfcAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized INfcAdapter setupService() {
|
||||
/**
|
||||
* Returns the singleton, or throws if NFC is not available.
|
||||
*/
|
||||
static synchronized NfcAdapter getSingleton() {
|
||||
if (!sIsInitialized) {
|
||||
sIsInitialized = true;
|
||||
|
||||
/* is this device meant to have NFC */
|
||||
if (!hasNfcFeature()) {
|
||||
Log.v(TAG, "this device does not have NFC support");
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
sService = getServiceInterface();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "could not retrieve NFC service");
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
try {
|
||||
sTagService = sService.getNfcTagInterface();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "could not retrieve NFC Tag service");
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
sSingleton = new NfcAdapter();
|
||||
}
|
||||
return sService;
|
||||
if (sSingleton == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
/** get handle to NFC service interface */
|
||||
@@ -376,13 +344,14 @@ public final class NfcAdapter {
|
||||
public static NfcAdapter getDefaultAdapter() {
|
||||
Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
|
||||
"NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
|
||||
return new NfcAdapter(null);
|
||||
return getSingleton();
|
||||
}
|
||||
|
||||
/*package*/ NfcAdapter(Context context) {
|
||||
if (setupService() == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
/**
|
||||
* Does not currently need a context.
|
||||
*/
|
||||
NfcAdapter() {
|
||||
mNfcActivityManager = new NfcActivityManager(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,6 +492,87 @@ public final class NfcAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link NdefMessage} to push over NFC during the specified activities.
|
||||
*
|
||||
* <p>This method may be called at any time, but the NDEF message is
|
||||
* only made available for NDEF push when one of the specified activities
|
||||
* is in resumed (foreground) state.
|
||||
*
|
||||
* <p>Only one NDEF message can be pushed by the currently resumed activity.
|
||||
* If both {@link #setNdefPushMessage} and
|
||||
* {@link #setNdefPushMessageCallback} are set then
|
||||
* the callback will take priority.
|
||||
*
|
||||
* <p>Pass a null NDEF message to disable foreground NDEF push in the
|
||||
* specified activities.
|
||||
*
|
||||
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
|
||||
*
|
||||
* @param message NDEF message to push over NFC, or null to disable
|
||||
* @param activities one or more {@link Activity} to enable for NDEF push
|
||||
*/
|
||||
public void setNdefPushMessage(NdefMessage message, Activity ... activities) {
|
||||
if (activities.length == 0) {
|
||||
throw new NullPointerException("Must specificy one or more activities");
|
||||
}
|
||||
for (Activity a : activities) {
|
||||
mNfcActivityManager.setNdefPushMessage(a, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the callback to create a {@link NdefMessage} to push over NFC.
|
||||
*
|
||||
* <p>This method may be called at any time, but this callback is
|
||||
* only made if one of the specified activities
|
||||
* is in resumed (foreground) state.
|
||||
*
|
||||
* <p>Only one NDEF message can be pushed by the currently resumed activity.
|
||||
* If both {@link #setNdefPushMessage} and
|
||||
* {@link #setNdefPushMessageCallback} are set then
|
||||
* the callback will take priority.
|
||||
*
|
||||
* <p>Pass a null callback to disable the callback in the
|
||||
* specified activities.
|
||||
*
|
||||
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
|
||||
*
|
||||
* @param callback callback, or null to disable
|
||||
* @param activities one or more {@link Activity} to enable for NDEF push
|
||||
*/
|
||||
public void setNdefPushMessageCallback(CreateNdefMessageCallback callback,
|
||||
Activity ... activities) {
|
||||
if (activities.length == 0) {
|
||||
throw new NullPointerException("Must specificy one or more activities");
|
||||
}
|
||||
for (Activity a : activities) {
|
||||
mNfcActivityManager.setNdefPushMessageCallback(a, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the callback on a successful NDEF push over NFC.
|
||||
*
|
||||
* <p>This method may be called at any time, but NDEF push and this callback
|
||||
* can only occur when one of the specified activities is in resumed
|
||||
* (foreground) state.
|
||||
*
|
||||
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
|
||||
*
|
||||
* @param callback callback, or null to disable
|
||||
* @param activities one or more {@link Activity} to enable the callback
|
||||
*/
|
||||
public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
|
||||
Activity ... activities) {
|
||||
if (activities.length == 0) {
|
||||
throw new NullPointerException("Must specificy one or more activities");
|
||||
}
|
||||
for (Activity a : activities) {
|
||||
mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable foreground dispatch to the given Activity.
|
||||
*
|
||||
@@ -562,7 +612,7 @@ public final class NfcAdapter {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (!activity.isResumed()) {
|
||||
throw new IllegalStateException("Foregorund dispatching can only be enabled " +
|
||||
throw new IllegalStateException("Foreground dispatch can only be enabled " +
|
||||
"when your activity is resumed");
|
||||
}
|
||||
try {
|
||||
@@ -572,8 +622,7 @@ public final class NfcAdapter {
|
||||
}
|
||||
ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
|
||||
mForegroundDispatchListener);
|
||||
sService.enableForegroundDispatch(activity.getComponentName(), intent, filters,
|
||||
parcel);
|
||||
sService.setForegroundDispatch(intent, filters, parcel);
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
}
|
||||
@@ -608,9 +657,9 @@ public final class NfcAdapter {
|
||||
|
||||
void disableForegroundDispatchInternal(Activity activity, boolean force) {
|
||||
try {
|
||||
sService.disableForegroundDispatch(activity.getComponentName());
|
||||
sService.setForegroundDispatch(null, null, null);
|
||||
if (!force && !activity.isResumed()) {
|
||||
throw new IllegalStateException("You must disable forgeground dispatching " +
|
||||
throw new IllegalStateException("You must disable foreground dispatching " +
|
||||
"while your activity is still resumed");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
@@ -619,78 +668,38 @@ public final class NfcAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable NDEF message push over P2P while this Activity is in the foreground.
|
||||
* Enable NDEF message push over NFC while this Activity is in the foreground.
|
||||
*
|
||||
* <p>For this to function properly the other NFC device being scanned must
|
||||
* support the "com.android.npp" NDEF push protocol. Support for this
|
||||
* protocol is currently optional for Android NFC devices.
|
||||
* <p>You must explicitly call this method every time the activity is
|
||||
* resumed, and you must call {@link #disableForegroundNdefPush} before
|
||||
* your activity completes {@link Activity#onPause}.
|
||||
*
|
||||
* <p>Strongly recommend to use the new {@link #setNdefPushMessage}
|
||||
* instead: it automatically hooks into your activity life-cycle,
|
||||
* so you do not need to call enable/disable in your onResume/onPause.
|
||||
*
|
||||
* <p>For NDEF push to function properly the other NFC device must
|
||||
* support either NFC Forum's SNEP (Simple Ndef Exchange Protocol), or
|
||||
* Android's "com.android.npp" (Ndef Push Protocol). This was optional
|
||||
* on Gingerbread level Android NFC devices, but SNEP is mandatory on
|
||||
* Ice-Cream-Sandwich and beyond.
|
||||
*
|
||||
* <p>This method must be called from the main thread.
|
||||
*
|
||||
* <p class="note"><em>NOTE:</em> While foreground NDEF push is active standard tag dispatch is disabled.
|
||||
* Only the foreground activity may receive tag discovered dispatches via
|
||||
* {@link #enableForegroundDispatch}.
|
||||
*
|
||||
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
|
||||
*
|
||||
* @param activity the foreground Activity
|
||||
* @param msg a NDEF Message to push over P2P
|
||||
* @throws IllegalStateException if the Activity is not currently in the foreground
|
||||
* @throws OperationNotSupportedException if this Android device does not support NDEF push
|
||||
* @param activity foreground activity
|
||||
* @param message a NDEF Message to push over NFC
|
||||
* @throws IllegalStateException if the activity is not currently in the foreground
|
||||
* @deprecated use {@link #setNdefPushMessage} instead
|
||||
*/
|
||||
public void enableForegroundNdefPush(Activity activity, NdefMessage msg) {
|
||||
if (activity == null || msg == null) {
|
||||
@Deprecated
|
||||
public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
|
||||
if (activity == null || message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (!activity.isResumed()) {
|
||||
throw new IllegalStateException("Foregorund NDEF push can only be enabled " +
|
||||
"when your activity is resumed");
|
||||
}
|
||||
try {
|
||||
ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
|
||||
mForegroundNdefPushListener);
|
||||
sService.enableForegroundNdefPush(activity.getComponentName(), msg);
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable NDEF message push over P2P while this Activity is in the foreground.
|
||||
*
|
||||
* <p>For this to function properly the other NFC device being scanned must
|
||||
* support the "com.android.npp" NDEF push protocol. Support for this
|
||||
* protocol is currently optional for Android NFC devices.
|
||||
*
|
||||
* <p>This method must be called from the main thread.
|
||||
*
|
||||
* <p class="note"><em>NOTE:</em> While foreground NDEF push is active standard tag dispatch is disabled.
|
||||
* Only the foreground activity may receive tag discovered dispatches via
|
||||
* {@link #enableForegroundDispatch}.
|
||||
*
|
||||
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
|
||||
*
|
||||
* @param activity the foreground Activity
|
||||
* @param callback is called on when the P2P connection is established
|
||||
* @throws IllegalStateException if the Activity is not currently in the foreground
|
||||
* @throws OperationNotSupportedException if this Android device does not support NDEF push
|
||||
*/
|
||||
public void enableForegroundNdefPush(Activity activity, NdefPushCallback callback) {
|
||||
if (activity == null || callback == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (!activity.isResumed()) {
|
||||
throw new IllegalStateException("Foregorund NDEF push can only be enabled " +
|
||||
"when your activity is resumed");
|
||||
}
|
||||
try {
|
||||
ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
|
||||
mForegroundNdefPushListener);
|
||||
sService.enableForegroundNdefPushWithCallback(activity.getComponentName(),
|
||||
new NdefPushCallbackWrapper(callback));
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
}
|
||||
enforceResumed(activity);
|
||||
mNfcActivityManager.setNdefPushMessage(activity, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -700,47 +709,91 @@ public final class NfcAdapter {
|
||||
* must call this method before its {@link Activity#onPause} callback
|
||||
* completes.
|
||||
*
|
||||
* <p>Strongly recommend to use the new {@link #setNdefPushMessage}
|
||||
* instead: it automatically hooks into your activity life-cycle,
|
||||
* so you do not need to call enable/disable in your onResume/onPause.
|
||||
*
|
||||
* <p>This method must be called from the main thread.
|
||||
*
|
||||
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
|
||||
*
|
||||
* @param activity the Foreground activity
|
||||
* @throws IllegalStateException if the Activity has already been paused
|
||||
* @throws OperationNotSupportedException if this Android device does not support NDEF push
|
||||
* @deprecated use {@link #setNdefPushMessage} instead
|
||||
*/
|
||||
public void disableForegroundNdefPush(Activity activity) {
|
||||
ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
|
||||
mForegroundNdefPushListener);
|
||||
disableForegroundNdefPushInternal(activity, false);
|
||||
if (activity == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
enforceResumed(activity);
|
||||
mNfcActivityManager.setNdefPushMessage(activity, null);
|
||||
mNfcActivityManager.setNdefPushMessageCallback(activity, null);
|
||||
mNfcActivityManager.setOnNdefPushCompleteCallback(activity, null);
|
||||
}
|
||||
|
||||
OnActivityPausedListener mForegroundNdefPushListener = new OnActivityPausedListener() {
|
||||
/**
|
||||
* TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
|
||||
* @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback}
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
public interface NdefPushCallback {
|
||||
/**
|
||||
* @deprecated use {@link CreateNdefMessageCallback} instead
|
||||
*/
|
||||
@Deprecated
|
||||
NdefMessage createMessage();
|
||||
/**
|
||||
* @deprecated use{@link OnNdefPushCompleteCallback} instead
|
||||
*/
|
||||
@Deprecated
|
||||
void onMessagePushed();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Remove this
|
||||
* Converts new callbacks to old callbacks.
|
||||
*/
|
||||
static final class LegacyCallbackWrapper implements CreateNdefMessageCallback,
|
||||
OnNdefPushCompleteCallback {
|
||||
final NdefPushCallback mLegacyCallback;
|
||||
LegacyCallbackWrapper(NdefPushCallback legacyCallback) {
|
||||
mLegacyCallback = legacyCallback;
|
||||
}
|
||||
@Override
|
||||
public void onPaused(Activity activity) {
|
||||
disableForegroundNdefPushInternal(activity, true);
|
||||
public void onNdefPushComplete(NfcEvent event) {
|
||||
mLegacyCallback.onMessagePushed();
|
||||
}
|
||||
};
|
||||
|
||||
void disableForegroundNdefPushInternal(Activity activity, boolean force) {
|
||||
try {
|
||||
sService.disableForegroundNdefPush(activity.getComponentName());
|
||||
if (!force && !activity.isResumed()) {
|
||||
throw new IllegalStateException("You must disable forgeground NDEF push " +
|
||||
"while your activity is still resumed");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
@Override
|
||||
public NdefMessage createNdefMessage(NfcEvent event) {
|
||||
return mLegacyCallback.createMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable zero-click sharing.
|
||||
*
|
||||
* TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
|
||||
* @deprecated use {@link #setNdefPushMessageCallback} instead
|
||||
* @hide
|
||||
*/
|
||||
public boolean enableZeroClick() {
|
||||
@Deprecated
|
||||
public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) {
|
||||
if (activity == null || callback == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
enforceResumed(activity);
|
||||
LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback);
|
||||
mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper);
|
||||
mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable NDEF Push feature.
|
||||
* <p>This API is for the Settings application.
|
||||
* @hide
|
||||
*/
|
||||
public boolean enableNdefPush() {
|
||||
try {
|
||||
return sService.enableZeroClick();
|
||||
return sService.enableNdefPush();
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
return false;
|
||||
@@ -748,13 +801,13 @@ public final class NfcAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable zero-click sharing.
|
||||
*
|
||||
* Disable NDEF Push feature.
|
||||
* <p>This API is for the Settings application.
|
||||
* @hide
|
||||
*/
|
||||
public boolean disableZeroClick() {
|
||||
public boolean disableNdefPush() {
|
||||
try {
|
||||
return sService.disableZeroClick();
|
||||
return sService.disableNdefPush();
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
return false;
|
||||
@@ -762,20 +815,20 @@ public final class NfcAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if zero-click sharing feature is enabled.
|
||||
* Return true if NDEF Push feature is enabled.
|
||||
* <p>This function can return true even if NFC is currently turned-off.
|
||||
* This indicates that zero-click is not currently active, but it has
|
||||
* This indicates that NDEF Push is not currently active, but it has
|
||||
* been requested by the user and will be active as soon as NFC is turned
|
||||
* on.
|
||||
* <p>If you want to check if zero-click sharing is currently active, use
|
||||
* <code>{@link #isEnabled()} && {@link #isZeroClickEnabled()}</code>
|
||||
* <p>If you want to check if NDEF PUsh sharing is currently active, use
|
||||
* <code>{@link #isEnabled()} && {@link #isNdefPushEnabled()}</code>
|
||||
*
|
||||
* @return true if zero-click sharing is enabled
|
||||
* @return true if NDEF Push feature is enabled
|
||||
* @hide
|
||||
*/
|
||||
public boolean isZeroClickEnabled() {
|
||||
public boolean isNdefPushEnabled() {
|
||||
try {
|
||||
return sService.isZeroClickEnabled();
|
||||
return sService.isNdefPushEnabled();
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
return false;
|
||||
@@ -793,4 +846,10 @@ public final class NfcAdapter {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void enforceResumed(Activity activity) {
|
||||
if (!activity.isResumed()) {
|
||||
throw new IllegalStateException("API cannot be called while activity is paused");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
44
core/java/android/nfc/NfcEvent.java
Normal file
44
core/java/android/nfc/NfcEvent.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.nfc;
|
||||
|
||||
/**
|
||||
* Wraps information associated with any NFC event.
|
||||
*
|
||||
* <p>Immutable object, with direct access to the (final) fields.
|
||||
*
|
||||
* <p>An {@link NfcEvent} object is usually included in callbacks from
|
||||
* {@link NfcAdapter}. Check the documentation of the callback to see
|
||||
* which fields may be set.
|
||||
*
|
||||
* <p>This wrapper object is used (instead of parameters
|
||||
* in the callback) because it allows new fields to be added without breaking
|
||||
* API compatibility.
|
||||
*
|
||||
* @see {@link NfcAdapter.OnNdefPushCompleteCallback#onNdefPushComplete}
|
||||
* @see {@link NfcAdapter.CreateNdefMessageCallback#createNdefMessage}
|
||||
*/
|
||||
public final class NfcEvent {
|
||||
/**
|
||||
* The {@link NfcAdapter} associated with the NFC event.
|
||||
*/
|
||||
public final NfcAdapter nfcAdapter;
|
||||
|
||||
NfcEvent(NfcAdapter nfcAdapter) {
|
||||
this.nfcAdapter = nfcAdapter;
|
||||
}
|
||||
}
|
||||
83
core/java/android/nfc/NfcFragment.java
Normal file
83
core/java/android/nfc/NfcFragment.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.nfc;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
|
||||
/**
|
||||
* Used by {@link NfcActivityManager} to attach to activity life-cycle.
|
||||
* @hide
|
||||
*/
|
||||
public final class NfcFragment extends Fragment {
|
||||
static final String FRAGMENT_TAG = "android.nfc.NfcFragment";
|
||||
|
||||
// only used on UI thread
|
||||
static boolean sIsInitialized = false;
|
||||
static NfcActivityManager sNfcActivityManager;
|
||||
|
||||
/**
|
||||
* Attach NfcFragment to an activity (if not already attached).
|
||||
*/
|
||||
public static void attach(Activity activity) {
|
||||
FragmentManager manager = activity.getFragmentManager();
|
||||
if (manager.findFragmentByTag(FRAGMENT_TAG) == null) {
|
||||
manager.beginTransaction().add(new NfcFragment(), FRAGMENT_TAG).commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove NfcFragment from activity.
|
||||
*/
|
||||
public static void remove(Activity activity) {
|
||||
FragmentManager manager = activity.getFragmentManager();
|
||||
Fragment fragment = manager.findFragmentByTag(FRAGMENT_TAG);
|
||||
if (fragment != null) {
|
||||
manager.beginTransaction().remove(fragment).commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
if (!sIsInitialized) {
|
||||
sIsInitialized = true;
|
||||
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(
|
||||
activity.getApplicationContext());
|
||||
if (adapter != null) {
|
||||
sNfcActivityManager = adapter.mNfcActivityManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (sNfcActivityManager != null) {
|
||||
sNfcActivityManager.onResume(getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (sNfcActivityManager != null) {
|
||||
sNfcActivityManager.onPause(getActivity());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public final class NfcManager {
|
||||
public NfcManager(Context context) {
|
||||
NfcAdapter adapter;
|
||||
try {
|
||||
adapter = new NfcAdapter(context);
|
||||
adapter = NfcAdapter.getSingleton();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
adapter = null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user