Merge "Use Application#registerLifecycleEvents() instead of a Fragment for Beam."

This commit is contained in:
Nick Pelly
2012-03-29 09:58:42 -07:00
committed by Android (Google) Code Review
4 changed files with 420 additions and 294 deletions

View File

@@ -42,7 +42,7 @@ interface INfcAdapter
void setForegroundDispatch(in PendingIntent intent,
in IntentFilter[] filters, in TechListParcel techLists);
void setForegroundNdefPush(in NdefMessage msg, in INdefPushCallback callback);
void setNdefPushCallback(in INdefPushCallback callback);
void dispatch(in Tag tag);

View File

@@ -17,210 +17,303 @@
package android.nfc;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import java.util.WeakHashMap;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* 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.
* <p>Uses {@link Application#registerActivityLifecycleCallbacks} to hook
* into activity life-cycle events such as onPause() and onResume().
*
* @hide
*/
public final class NfcActivityManager extends INdefPushCallback.Stub {
public final class NfcActivityManager extends INdefPushCallback.Stub
implements Application.ActivityLifecycleCallbacks {
static final String TAG = NfcAdapter.TAG;
static final Boolean DBG = false;
final NfcAdapter mAdapter;
final WeakHashMap<Activity, NfcActivityState> mNfcState; // contents protected by this
final NfcEvent mDefaultEvent; // can re-use one NfcEvent because it just contains adapter
final NfcEvent mDefaultEvent; // cached NfcEvent (its currently always the same)
// All objects in the lists are protected by this
final List<NfcApplicationState> mApps; // Application(s) that have NFC state. Usually one
final List<NfcActivityState> mActivities; // Activities that have NFC state
/**
* NFC State associated with an {@link Application}.
*/
class NfcApplicationState {
int refCount = 0;
final Application app;
public NfcApplicationState(Application app) {
this.app = app;
}
public void register() {
refCount++;
if (refCount == 1) {
this.app.registerActivityLifecycleCallbacks(NfcActivityManager.this);
}
}
public void unregister() {
refCount--;
if (refCount == 0) {
this.app.unregisterActivityLifecycleCallbacks(NfcActivityManager.this);
} else if (refCount < 0) {
Log.e(TAG, "-ve refcount for " + app);
}
}
}
NfcApplicationState findAppState(Application app) {
for (NfcApplicationState appState : mApps) {
if (appState.app == app) {
return appState;
}
}
return null;
}
void registerApplication(Application app) {
NfcApplicationState appState = findAppState(app);
if (appState == null) {
appState = new NfcApplicationState(app);
mApps.add(appState);
}
appState.register();
}
void unregisterApplication(Application app) {
NfcApplicationState appState = findAppState(app);
if (appState == null) {
Log.e(TAG, "app was not registered " + app);
return;
}
appState.unregister();
}
/**
* NFC state associated with an {@link Activity}
*/
class NfcActivityState {
boolean resumed = false; // is the activity resumed
NdefMessage ndefMessage;
NfcAdapter.CreateNdefMessageCallback ndefMessageCallback;
NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback;
boolean resumed = false;
Activity activity;
NdefMessage ndefMessage = null; // static NDEF message
NfcAdapter.CreateNdefMessageCallback ndefMessageCallback = null;
NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback = null;
public NfcActivityState(Activity activity) {
if (activity.getWindow().isDestroyed()) {
throw new IllegalStateException("activity is already destroyed");
}
this.activity = activity;
registerApplication(activity.getApplication());
}
public void destroy() {
unregisterApplication(activity.getApplication());
resumed = false;
activity = null;
ndefMessage = null;
ndefMessageCallback = null;
onNdefPushCompleteCallback = null;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder("[").append(resumed).append(" ");
StringBuilder s = new StringBuilder("[").append(" ");
s.append(ndefMessage).append(" ").append(ndefMessageCallback).append(" ");
s.append(onNdefPushCompleteCallback).append("]");
return s.toString();
}
}
public NfcActivityManager(NfcAdapter adapter) {
mAdapter = adapter;
mNfcState = new WeakHashMap<Activity, NfcActivityState>();
mDefaultEvent = new NfcEvent(mAdapter);
/** find activity state from mActivities */
synchronized NfcActivityState findActivityState(Activity activity) {
for (NfcActivityState state : mActivities) {
if (state.activity == activity) {
return state;
}
}
return null;
}
/**
* 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);
}
}
/**
* onDestroy hook from fragment attached to activity
*/
public void onDestroy(Activity activity) {
mNfcState.remove(activity);
}
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);
/** find or create activity state from mActivities */
synchronized NfcActivityState getActivityState(Activity activity) {
NfcActivityState state = findActivityState(activity);
if (state == null) {
state = new NfcActivityState(activity);
mActivities.add(state);
}
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) {
NfcFragment.remove(activity);
mNfcState.remove(activity);
synchronized NfcActivityState findResumedActivityState() {
for (NfcActivityState state : mActivities) {
if (state.resumed) {
return state;
}
}
return null;
}
synchronized void destroyActivityState(Activity activity) {
NfcActivityState activityState = findActivityState(activity);
if (activityState != null) {
activityState.destroy();
mActivities.remove(activityState);
}
}
public NfcActivityManager(NfcAdapter adapter) {
mAdapter = adapter;
mActivities = new LinkedList<NfcActivityState>();
mApps = new ArrayList<NfcApplicationState>(1); // Android VM usually has 1 app
mDefaultEvent = new NfcEvent(mAdapter);
}
public void setNdefPushMessage(Activity activity, NdefMessage message) {
boolean isResumed;
synchronized (NfcActivityManager.this) {
NfcActivityState state = getActivityState(activity);
state.ndefMessage = message;
isResumed = state.resumed;
}
if (isResumed) {
requestNfcServiceCallback(true);
}
}
public void setNdefPushMessageCallback(Activity activity,
NfcAdapter.CreateNdefMessageCallback callback) {
boolean isResumed;
synchronized (NfcActivityManager.this) {
NfcActivityState state = getActivityState(activity);
state.ndefMessageCallback = callback;
isResumed = state.resumed;
}
if (isResumed) {
requestNfcServiceCallback(true);
}
}
public void setOnNdefPushCompleteCallback(Activity activity,
NfcAdapter.OnNdefPushCompleteCallback callback) {
boolean isResumed;
synchronized (NfcActivityManager.this) {
NfcActivityState state = getActivityState(activity);
state.onNdefPushCompleteCallback = callback;
isResumed = state.resumed;
}
if (isResumed) {
requestNfcServiceCallback(true);
}
}
/**
* Register NfcActivityState with the NFC service.
* Request or unrequest NFC service callbacks for NDEF push.
* Makes IPC call - do not hold lock.
* TODO: Do not do IPC on every onPause/onResume
*/
synchronized void updateNfcService(NfcActivityState state) {
boolean serviceCallbackNeeded = state.ndefMessageCallback != null ||
state.onNdefPushCompleteCallback != null;
void requestNfcServiceCallback(boolean request) {
try {
NfcAdapter.sService.setForegroundNdefPush(state.resumed ? state.ndefMessage : null,
state.resumed && serviceCallbackNeeded ? this : null);
NfcAdapter.sService.setNdefPushCallback(request ? this : null);
} catch (RemoteException e) {
mAdapter.attemptDeadServiceRecovery(e);
}
}
/**
* Callback from NFC service
*/
/** Callback from NFC service, usually on binder thread */
@Override
public NdefMessage createMessage() {
NfcAdapter.CreateNdefMessageCallback callback = null;
NfcAdapter.CreateNdefMessageCallback callback;
NdefMessage message;
synchronized (NfcActivityManager.this) {
for (NfcActivityState state : mNfcState.values()) {
if (state.resumed) {
callback = state.ndefMessageCallback;
}
}
NfcActivityState state = findResumedActivityState();
if (state == null) return null;
callback = state.ndefMessageCallback;
message = state.ndefMessage;
}
// drop lock before making callback
// Make callback without lock
if (callback != null) {
return callback.createNdefMessage(mDefaultEvent);
} else {
return message;
}
return null;
}
/**
* Callback from NFC service
*/
/** Callback from NFC service, usually on binder thread */
@Override
public void onNdefPushComplete() {
NfcAdapter.OnNdefPushCompleteCallback callback = null;
NfcAdapter.OnNdefPushCompleteCallback callback;
synchronized (NfcActivityManager.this) {
for (NfcActivityState state : mNfcState.values()) {
if (state.resumed) {
callback = state.onNdefPushCompleteCallback;
}
}
NfcActivityState state = findResumedActivityState();
if (state == null) return;
callback = state.onNdefPushCompleteCallback;
}
// drop lock before making callback
// Make callback without lock
if (callback != null) {
callback.onNdefPushComplete(mDefaultEvent);
}
}
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { /* NO-OP */ }
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityStarted(Activity activity) { /* NO-OP */ }
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityResumed(Activity activity) {
synchronized (NfcActivityManager.this) {
NfcActivityState state = findActivityState(activity);
if (DBG) Log.d(TAG, "onResume() for " + activity + " " + state);
if (state == null) return;
state.resumed = true;
}
requestNfcServiceCallback(true);
}
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityPaused(Activity activity) {
synchronized (NfcActivityManager.this) {
NfcActivityState state = findActivityState(activity);
if (DBG) Log.d(TAG, "onPause() for " + activity + " " + state);
if (state == null) return;
state.resumed = false;
}
requestNfcServiceCallback(false);
}
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityStopped(Activity activity) { /* NO-OP */ }
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) { /* NO-OP */ }
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityDestroyed(Activity activity) {
synchronized (NfcActivityManager.this) {
NfcActivityState state = findActivityState(activity);
if (DBG) Log.d(TAG, "onDestroy() for " + activity + " " + state);
if (state != null) {
// release all associated references
destroyActivityState(activity);
}
}
}
}

View File

@@ -556,109 +556,230 @@ public final class NfcAdapter {
}
/**
* Set the {@link NdefMessage} to push over NFC during the specified activities.
* Set a static {@link NdefMessage} to send using Android Beam (TM).
*
* <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>This method may be called at any time before {@link Activity#onDestroy},
* but the NDEF message is only made available for NDEF push when the
* specified activity(s) are in resumed (foreground) state. The recommended
* approach is to call this method during your Activity's
* {@link Activity#onCreate} - see sample
* code below. This method does not immediately perform any I/O or blocking work,
* so is safe to call on your main thread.
*
* <p>Only one NDEF message can be pushed by the currently resumed activity.
* If both {@link #setNdefPushMessage} and
* {@link #setNdefPushMessageCallback} are set then
* {@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>If neither {@link #setNdefPushMessage} or
* {@link #setNdefPushMessageCallback} have been called for your activity, then
* the Android OS may choose to send a default NDEF message on your behalf,
* such as a URI for your application.
*
* <p>At least one activity must be specified, and usually only one is necessary.
* <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
* and/or {@link #setNdefPushMessageCallback} is called with a null callback,
* then NDEF push will be completely disabled for the specified activity(s).
* This also disables any default NDEF message the Android OS would have
* otherwise sent on your behalf.
*
* <p>The API allows for multiple activities to be specified at a time,
* but it is strongly recommended to just register one at a time,
* and to do so during the activity's {@link Activity#onCreate}. For example:
* <pre>
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
* if (nfcAdapter == null) return; // NFC not available on this device
* nfcAdapter.setNdefPushMessage(ndefMessage, this);
* }
* </pre>
* And that is it. Only one call per activity is necessary. The Android
* OS will automatically release its references to the NDEF message and the
* Activity object when it is destroyed if you follow this pattern.
*
* <p>If your Activity wants to dynamically generate an NDEF message,
* then set a callback using {@link #setNdefPushMessageCallback} instead
* of a static message.
*
* <p class="note">Do not pass in an Activity that has already been through
* {@link Activity#onDestroy}. This is guaranteed if you call this API
* during {@link Activity#onCreate}.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param message NDEF message to push over NFC, or null to disable
* @param activity an activity in which NDEF push should be enabled to share the provided
* NDEF message
* @param activities optional additional activities that should also enable NDEF push with
* the provided NDEF message
* @param activity activity for which the NDEF message will be pushed
* @param activities optional additional activities, however we strongly recommend
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
*/
public void setNdefPushMessage(NdefMessage message, Activity activity,
Activity ... activities) {
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
mNfcActivityManager.setNdefPushMessage(activity, message);
for (Activity a : activities) {
if (a == null) {
throw new NullPointerException("activities cannot contain null");
int targetSdkVersion = getSdkVersion();
try {
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
mNfcActivityManager.setNdefPushMessage(activity, message);
for (Activity a : activities) {
if (a == null) {
throw new NullPointerException("activities cannot contain null");
}
mNfcActivityManager.setNdefPushMessage(a, message);
}
} catch (IllegalStateException e) {
if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
// Less strict on old applications - just log the error
Log.e(TAG, "Cannot call API with Activity that has already " +
"been destroyed", e);
} else {
// Prevent new applications from making this mistake, re-throw
throw(e);
}
mNfcActivityManager.setNdefPushMessage(a, message);
}
}
/**
* Set the callback to create a {@link NdefMessage} to push over NFC.
* Set a callback that dynamically generates NDEF messages to send using Android Beam (TM).
*
* <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>This method may be called at any time before {@link Activity#onDestroy},
* but the NDEF message callback can only occur when the
* specified activity(s) are in resumed (foreground) state. The recommended
* approach is to call this method during your Activity's
* {@link Activity#onCreate} - see sample
* code below. This method does not immediately perform any I/O or blocking work,
* so is safe to call on your main thread.
*
* <p>Only one NDEF message can be pushed by the currently resumed activity.
* If both {@link #setNdefPushMessage} and
* {@link #setNdefPushMessageCallback} are set then
* {@link #setNdefPushMessageCallback} are set, then
* the callback will take priority.
*
* <p>Pass a null callback to disable the callback in the
* specified activities.
* <p>If neither {@link #setNdefPushMessage} or
* {@link #setNdefPushMessageCallback} have been called for your activity, then
* the Android OS may choose to send a default NDEF message on your behalf,
* such as a URI for your application.
*
* <p>At least one activity must be specified, and usually only one is necessary.
* <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
* and/or {@link #setNdefPushMessageCallback} is called with a null callback,
* then NDEF push will be completely disabled for the specified activity(s).
* This also disables any default NDEF message the Android OS would have
* otherwise sent on your behalf.
*
* <p>The API allows for multiple activities to be specified at a time,
* but it is strongly recommended to just register one at a time,
* and to do so during the activity's {@link Activity#onCreate}. For example:
* <pre>
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
* if (nfcAdapter == null) return; // NFC not available on this device
* nfcAdapter.setNdefPushMessageCallback(callback, this);
* }
* </pre>
* And that is it. Only one call per activity is necessary. The Android
* OS will automatically release its references to the callback and the
* Activity object when it is destroyed if you follow this pattern.
*
* <p class="note">Do not pass in an Activity that has already been through
* {@link Activity#onDestroy}. This is guaranteed if you call this API
* during {@link Activity#onCreate}.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param callback callback, or null to disable
* @param activity an activity in which NDEF push should be enabled to share an NDEF message
* that's retrieved from the provided callback
* @param activities optional additional activities that should also enable NDEF push using
* the provided callback
* @param activity activity for which the NDEF message will be pushed
* @param activities optional additional activities, however we strongly recommend
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
*/
public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
Activity ... activities) {
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
mNfcActivityManager.setNdefPushMessageCallback(activity, callback);
for (Activity a : activities) {
if (a == null) {
throw new NullPointerException("activities cannot contain null");
int targetSdkVersion = getSdkVersion();
try {
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
mNfcActivityManager.setNdefPushMessageCallback(activity, callback);
for (Activity a : activities) {
if (a == null) {
throw new NullPointerException("activities cannot contain null");
}
mNfcActivityManager.setNdefPushMessageCallback(a, callback);
}
} catch (IllegalStateException e) {
if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
// Less strict on old applications - just log the error
Log.e(TAG, "Cannot call API with Activity that has already " +
"been destroyed", e);
} else {
// Prevent new applications from making this mistake, re-throw
throw(e);
}
mNfcActivityManager.setNdefPushMessageCallback(a, callback);
}
}
/**
* Set the callback on a successful NDEF push over NFC.
* Set a callback on successful Android Beam (TM).
*
* <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>This method may be called at any time before {@link Activity#onDestroy},
* but the callback can only occur when the
* specified activity(s) are in resumed (foreground) state. The recommended
* approach is to call this method during your Activity's
* {@link Activity#onCreate} - see sample
* code below. This method does not immediately perform any I/O or blocking work,
* so is safe to call on your main thread.
*
* <p>One or more activities must be specified.
* <p>The API allows for multiple activities to be specified at a time,
* but it is strongly recommended to just register one at a time,
* and to do so during the activity's {@link Activity#onCreate}. For example:
* <pre>
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
* if (nfcAdapter == null) return; // NFC not available on this device
* nfcAdapter.setOnNdefPushCompleteCallback(callback, this);
* }
* </pre>
* And that is it. Only one call per activity is necessary. The Android
* OS will automatically release its references to the callback and the
* Activity object when it is destroyed if you follow this pattern.
*
* <p class="note">Do not pass in an Activity that has already been through
* {@link Activity#onDestroy}. This is guaranteed if you call this API
* during {@link Activity#onCreate}.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param callback callback, or null to disable
* @param activity an activity to enable the callback (at least one is required)
* @param activities zero or more additional activities to enable to callback
* @param activity activity for which the NDEF message will be pushed
* @param activities optional additional activities, however we strongly recommend
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
*/
public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
Activity activity, Activity ... activities) {
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback);
for (Activity a : activities) {
if (a == null) {
throw new NullPointerException("activities cannot contain null");
int targetSdkVersion = getSdkVersion();
try {
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback);
for (Activity a : activities) {
if (a == null) {
throw new NullPointerException("activities cannot contain null");
}
mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
}
} catch (IllegalStateException e) {
if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
// Less strict on old applications - just log the error
Log.e(TAG, "Cannot call API with Activity that has already " +
"been destroyed", e);
} else {
// Prevent new applications from making this mistake, re-throw
throw(e);
}
mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
}
}
@@ -932,4 +1053,12 @@ public final class NfcAdapter {
throw new IllegalStateException("API cannot be called while activity is paused");
}
}
int getSdkVersion() {
if (mContext == null) {
return android.os.Build.VERSION_CODES.GINGERBREAD; // best guess
} else {
return mContext.getApplicationInfo().targetSdkVersion;
}
}
}

View File

@@ -1,96 +0,0 @@
/*
* 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) {
// We allow state loss at this point, because the state is only
// lost when activity is being paused *AND* subsequently destroyed.
// In that case, the app will setup foreground dispatch again anyway.
manager.beginTransaction().remove(fragment).commitAllowingStateLoss();
}
}
@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());
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (sNfcActivityManager != null) {
sNfcActivityManager.onDestroy(getActivity());
}
}
}