Add dispatching overrides for foreground apps.
Apps can register to override the default dispatching but only when they're in the foreground. Change-Id: I8e9a9254d3f79f097fb3c8c677d806043574ba4d
This commit is contained in:
@ -100406,6 +100406,36 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<method name="disableForegroundDispatch"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="activity" type="android.app.Activity">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="enableForegroundDispatch"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="activity" type="android.app.Activity">
|
||||
</parameter>
|
||||
<parameter name="intent" type="android.app.PendingIntent">
|
||||
</parameter>
|
||||
<parameter name="filters" type="android.content.IntentFilter...">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getDefaultAdapter"
|
||||
return="android.nfc.NfcAdapter"
|
||||
abstract="false"
|
||||
|
@ -632,7 +632,7 @@ public class Activity extends ContextThemeWrapper
|
||||
/*package*/ HashMap<String,Object> mLastNonConfigurationChildInstances;
|
||||
Activity mParent;
|
||||
boolean mCalled;
|
||||
private boolean mResumed;
|
||||
/*package*/ boolean mResumed;
|
||||
private boolean mStopped;
|
||||
boolean mFinished;
|
||||
boolean mStartedActivity;
|
||||
@ -3827,9 +3827,8 @@ public class Activity extends ContextThemeWrapper
|
||||
|
||||
mLastNonConfigurationInstance = null;
|
||||
|
||||
// First call onResume() -before- setting mResumed, so we don't
|
||||
// send out any status bar / menu notifications the client makes.
|
||||
mCalled = false;
|
||||
// mResumed is set by the instrumentation
|
||||
mInstrumentation.callActivityOnResume(this);
|
||||
if (!mCalled) {
|
||||
throw new SuperNotCalledException(
|
||||
@ -3838,7 +3837,6 @@ public class Activity extends ContextThemeWrapper
|
||||
}
|
||||
|
||||
// Now really resume, and install the current status bar and menu.
|
||||
mResumed = true;
|
||||
mCalled = false;
|
||||
onPostResume();
|
||||
if (!mCalled) {
|
||||
@ -3857,6 +3855,7 @@ public class Activity extends ContextThemeWrapper
|
||||
"Activity " + mComponent.toShortString() +
|
||||
" did not call through to super.onPause()");
|
||||
}
|
||||
mResumed = false;
|
||||
}
|
||||
|
||||
final void performUserLeaving() {
|
||||
@ -3891,10 +3890,12 @@ public class Activity extends ContextThemeWrapper
|
||||
|
||||
mStopped = true;
|
||||
}
|
||||
mResumed = false;
|
||||
}
|
||||
|
||||
final boolean isResumed() {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final boolean isResumed() {
|
||||
return mResumed;
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,9 @@ public final class ActivityThread {
|
||||
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
|
||||
= new HashMap<IBinder, ProviderClientRecord>();
|
||||
|
||||
final HashMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
|
||||
= new HashMap<Activity, ArrayList<OnActivityPausedListener>>();
|
||||
|
||||
final GcIdler mGcIdler = new GcIdler();
|
||||
boolean mGcIdlerScheduled = false;
|
||||
|
||||
@ -1424,6 +1427,18 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
public void registerOnActivityPausedListener(Activity activity,
|
||||
OnActivityPausedListener listener) {
|
||||
synchronized (mOnPauseListeners) {
|
||||
ArrayList<OnActivityPausedListener> list = mOnPauseListeners.get(activity);
|
||||
if (list == null) {
|
||||
list = new ArrayList<OnActivityPausedListener>();
|
||||
mOnPauseListeners.put(activity, list);
|
||||
}
|
||||
list.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public final ActivityInfo resolveActivityInfo(Intent intent) {
|
||||
ActivityInfo aInfo = intent.resolveActivityInfo(
|
||||
mInitialApplication.getPackageManager(), PackageManager.GET_SHARED_LIBRARY_FILES);
|
||||
@ -2333,6 +2348,17 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
r.paused = true;
|
||||
|
||||
// Notify any outstanding on paused listeners
|
||||
ArrayList<OnActivityPausedListener> listeners;
|
||||
synchronized (mOnPauseListeners) {
|
||||
listeners = mOnPauseListeners.remove(r.activity);
|
||||
}
|
||||
int size = (listeners != null ? listeners.size() : 0);
|
||||
for (int i = 0; i < size; i++) {
|
||||
listeners.get(i).onPaused(r.activity);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -1146,6 +1146,7 @@ public class Instrumentation {
|
||||
* @param activity The activity being resumed.
|
||||
*/
|
||||
public void callActivityOnResume(Activity activity) {
|
||||
activity.mResumed = true;
|
||||
activity.onResume();
|
||||
|
||||
if (mActivityMonitors != null) {
|
||||
|
31
core/java/android/app/OnActivityPausedListener.java
Normal file
31
core/java/android/app/OnActivityPausedListener.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* 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.app;
|
||||
|
||||
/**
|
||||
* A listener that is called when an Activity is paused. Since this is tracked client side
|
||||
* it should not be trusted to represent the exact current state, but can be used as a hint
|
||||
* for cleanup.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface OnActivityPausedListener {
|
||||
/**
|
||||
* Called when the given activity is paused.
|
||||
*/
|
||||
public void onPaused(Activity activity);
|
||||
}
|
@ -16,6 +16,9 @@
|
||||
|
||||
package android.nfc;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.IntentFilter;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.Tag;
|
||||
import android.nfc.ILlcpSocket;
|
||||
@ -44,6 +47,9 @@ interface INfcAdapter
|
||||
NdefMessage localGet();
|
||||
void localSet(in NdefMessage message);
|
||||
void openTagConnection(in Tag tag);
|
||||
void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
|
||||
in IntentFilter[] filters);
|
||||
void disableForegroundDispatch(in ComponentName activity);
|
||||
|
||||
// Non-public methods
|
||||
// TODO: check and complete
|
||||
|
@ -18,8 +18,12 @@ package android.nfc;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.OnActivityPausedListener;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.nfc.technology.TagTechnology;
|
||||
@ -211,8 +215,6 @@ public final class NfcAdapter {
|
||||
private static INfcAdapter sService;
|
||||
private static INfcTag sTagService;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
/**
|
||||
* Helper to check if this device has FEATURE_NFC, but without using
|
||||
* a context.
|
||||
@ -308,7 +310,6 @@ public final class NfcAdapter {
|
||||
if (setupService() == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -410,6 +411,66 @@ public final class NfcAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
class ForegroundDispatchPausedListener implements OnActivityPausedListener {
|
||||
@Override
|
||||
public void onPaused(Activity activity) {
|
||||
disableForegroundDispatchInternal(activity, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables foreground dispatching to the given Activity. This will force all NFC Intents that
|
||||
* match the given filters to be delivered to the activity bypassing the standard dispatch
|
||||
* mechanism.
|
||||
*
|
||||
* This method must be called from the main thread.
|
||||
*
|
||||
* @param activity the Activity to dispatch to
|
||||
* @param intent the PendingIntent to start for the dispatch
|
||||
* @param filters the IntentFilters to override dispatching for
|
||||
* @throws IllegalStateException
|
||||
*/
|
||||
public void enableForegroundDispatch(Activity activity, PendingIntent intent,
|
||||
IntentFilter... filters) {
|
||||
if (activity == null || intent == null || filters == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (!activity.isResumed()) {
|
||||
throw new IllegalStateException("Foregorund dispatching can onlly be enabled " +
|
||||
"when your activity is resumed");
|
||||
}
|
||||
try {
|
||||
ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
|
||||
new ForegroundDispatchPausedListener());
|
||||
sService.enableForegroundDispatch(activity.getComponentName(), intent, filters);
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables foreground activity dispatching setup with
|
||||
* {@link #enableForegroundDispatch}. This must be called before the Activity returns from
|
||||
* it's <code>onPause()</code> or this method will throw an IllegalStateException.
|
||||
*
|
||||
* This method must be called from the main thread.
|
||||
*/
|
||||
public void disableForegroundDispatch(Activity activity) {
|
||||
disableForegroundDispatchInternal(activity, false);
|
||||
}
|
||||
|
||||
void disableForegroundDispatchInternal(Activity activity, boolean force) {
|
||||
try {
|
||||
sService.disableForegroundDispatch(activity.getComponentName());
|
||||
if (!force && !activity.isResumed()) {
|
||||
throw new IllegalStateException("You must disable forgeground dispatching " +
|
||||
"while your activity is still resumed");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a TagTechnology object used to interact with a Tag that is
|
||||
* in field.
|
||||
|
Reference in New Issue
Block a user