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"
|
deprecated="not deprecated"
|
||||||
visibility="public"
|
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"
|
<method name="getDefaultAdapter"
|
||||||
return="android.nfc.NfcAdapter"
|
return="android.nfc.NfcAdapter"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
|
@ -632,7 +632,7 @@ public class Activity extends ContextThemeWrapper
|
|||||||
/*package*/ HashMap<String,Object> mLastNonConfigurationChildInstances;
|
/*package*/ HashMap<String,Object> mLastNonConfigurationChildInstances;
|
||||||
Activity mParent;
|
Activity mParent;
|
||||||
boolean mCalled;
|
boolean mCalled;
|
||||||
private boolean mResumed;
|
/*package*/ boolean mResumed;
|
||||||
private boolean mStopped;
|
private boolean mStopped;
|
||||||
boolean mFinished;
|
boolean mFinished;
|
||||||
boolean mStartedActivity;
|
boolean mStartedActivity;
|
||||||
@ -3827,9 +3827,8 @@ public class Activity extends ContextThemeWrapper
|
|||||||
|
|
||||||
mLastNonConfigurationInstance = null;
|
mLastNonConfigurationInstance = null;
|
||||||
|
|
||||||
// First call onResume() -before- setting mResumed, so we don't
|
|
||||||
// send out any status bar / menu notifications the client makes.
|
|
||||||
mCalled = false;
|
mCalled = false;
|
||||||
|
// mResumed is set by the instrumentation
|
||||||
mInstrumentation.callActivityOnResume(this);
|
mInstrumentation.callActivityOnResume(this);
|
||||||
if (!mCalled) {
|
if (!mCalled) {
|
||||||
throw new SuperNotCalledException(
|
throw new SuperNotCalledException(
|
||||||
@ -3838,7 +3837,6 @@ public class Activity extends ContextThemeWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now really resume, and install the current status bar and menu.
|
// Now really resume, and install the current status bar and menu.
|
||||||
mResumed = true;
|
|
||||||
mCalled = false;
|
mCalled = false;
|
||||||
onPostResume();
|
onPostResume();
|
||||||
if (!mCalled) {
|
if (!mCalled) {
|
||||||
@ -3857,6 +3855,7 @@ public class Activity extends ContextThemeWrapper
|
|||||||
"Activity " + mComponent.toShortString() +
|
"Activity " + mComponent.toShortString() +
|
||||||
" did not call through to super.onPause()");
|
" did not call through to super.onPause()");
|
||||||
}
|
}
|
||||||
|
mResumed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final void performUserLeaving() {
|
final void performUserLeaving() {
|
||||||
@ -3891,10 +3890,12 @@ public class Activity extends ContextThemeWrapper
|
|||||||
|
|
||||||
mStopped = true;
|
mStopped = true;
|
||||||
}
|
}
|
||||||
mResumed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean isResumed() {
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public final boolean isResumed() {
|
||||||
return mResumed;
|
return mResumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +185,9 @@ public final class ActivityThread {
|
|||||||
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
|
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
|
||||||
= new HashMap<IBinder, ProviderClientRecord>();
|
= new HashMap<IBinder, ProviderClientRecord>();
|
||||||
|
|
||||||
|
final HashMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
|
||||||
|
= new HashMap<Activity, ArrayList<OnActivityPausedListener>>();
|
||||||
|
|
||||||
final GcIdler mGcIdler = new GcIdler();
|
final GcIdler mGcIdler = new GcIdler();
|
||||||
boolean mGcIdlerScheduled = false;
|
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) {
|
public final ActivityInfo resolveActivityInfo(Intent intent) {
|
||||||
ActivityInfo aInfo = intent.resolveActivityInfo(
|
ActivityInfo aInfo = intent.resolveActivityInfo(
|
||||||
mInitialApplication.getPackageManager(), PackageManager.GET_SHARED_LIBRARY_FILES);
|
mInitialApplication.getPackageManager(), PackageManager.GET_SHARED_LIBRARY_FILES);
|
||||||
@ -2333,6 +2348,17 @@ public final class ActivityThread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.paused = true;
|
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;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1146,6 +1146,7 @@ public class Instrumentation {
|
|||||||
* @param activity The activity being resumed.
|
* @param activity The activity being resumed.
|
||||||
*/
|
*/
|
||||||
public void callActivityOnResume(Activity activity) {
|
public void callActivityOnResume(Activity activity) {
|
||||||
|
activity.mResumed = true;
|
||||||
activity.onResume();
|
activity.onResume();
|
||||||
|
|
||||||
if (mActivityMonitors != null) {
|
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;
|
package android.nfc;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.nfc.NdefMessage;
|
import android.nfc.NdefMessage;
|
||||||
import android.nfc.Tag;
|
import android.nfc.Tag;
|
||||||
import android.nfc.ILlcpSocket;
|
import android.nfc.ILlcpSocket;
|
||||||
@ -44,6 +47,9 @@ interface INfcAdapter
|
|||||||
NdefMessage localGet();
|
NdefMessage localGet();
|
||||||
void localSet(in NdefMessage message);
|
void localSet(in NdefMessage message);
|
||||||
void openTagConnection(in Tag tag);
|
void openTagConnection(in Tag tag);
|
||||||
|
void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
|
||||||
|
in IntentFilter[] filters);
|
||||||
|
void disableForegroundDispatch(in ComponentName activity);
|
||||||
|
|
||||||
// Non-public methods
|
// Non-public methods
|
||||||
// TODO: check and complete
|
// TODO: check and complete
|
||||||
|
@ -18,8 +18,12 @@ package android.nfc;
|
|||||||
|
|
||||||
import android.annotation.SdkConstant;
|
import android.annotation.SdkConstant;
|
||||||
import android.annotation.SdkConstant.SdkConstantType;
|
import android.annotation.SdkConstant.SdkConstantType;
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
|
import android.app.OnActivityPausedListener;
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.IPackageManager;
|
import android.content.pm.IPackageManager;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.nfc.technology.TagTechnology;
|
import android.nfc.technology.TagTechnology;
|
||||||
@ -211,8 +215,6 @@ public final class NfcAdapter {
|
|||||||
private static INfcAdapter sService;
|
private static INfcAdapter sService;
|
||||||
private static INfcTag sTagService;
|
private static INfcTag sTagService;
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to check if this device has FEATURE_NFC, but without using
|
* Helper to check if this device has FEATURE_NFC, but without using
|
||||||
* a context.
|
* a context.
|
||||||
@ -308,7 +310,6 @@ public final class NfcAdapter {
|
|||||||
if (setupService() == null) {
|
if (setupService() == null) {
|
||||||
throw new UnsupportedOperationException();
|
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
|
* Retrieve a TagTechnology object used to interact with a Tag that is
|
||||||
* in field.
|
* in field.
|
||||||
|
Reference in New Issue
Block a user