Add NFC TagIntentAppPreference System API
Add System APIs for setting a preference list by filtering package names before sending NFC TAG intents. ACTION_NDEF_DISCOVERED, ACTION_TECH_DISCOVERED and ACTION_TAG_DISCOVERED will not be dispatched to an Activity if its package is disallowed. An app is added to the preference list with the allowed flag set to true when a Tag intent is dispatched to the package for the first time. The System APIs are called by settings to note that the user wants to change this default preference. Bug: 244272155 Test: atest NfcFeatureFlagTest Test: atest android.permission.cts.NfcPermissionTest Change-Id: I9d353cf794dbe7dbcbfeb3a8b37ef29fe86387f1
This commit is contained in:
@@ -9686,12 +9686,18 @@ package android.nfc {
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
|
||||
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
|
||||
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
|
||||
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
|
||||
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
|
||||
field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
|
||||
field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
|
||||
field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
|
||||
}
|
||||
|
||||
public static interface NfcAdapter.ControllerAlwaysOnListener {
|
||||
|
||||
@@ -73,4 +73,10 @@ interface INfcAdapter
|
||||
boolean isControllerAlwaysOnSupported();
|
||||
void registerControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
|
||||
void unregisterControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
|
||||
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
|
||||
boolean isTagIntentAppPreferenceSupported();
|
||||
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
|
||||
Map getTagIntentAppPreferenceForUser(int userId);
|
||||
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
|
||||
int setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow);
|
||||
}
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
package android.nfc;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.OnActivityPausedListener;
|
||||
@@ -46,9 +48,14 @@ import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@@ -374,6 +381,45 @@ public final class NfcAdapter {
|
||||
public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
|
||||
"android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
|
||||
|
||||
/**
|
||||
* The requested app is correctly added to the Tag intent app preference.
|
||||
*
|
||||
* @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* The requested app is not installed on the device.
|
||||
*
|
||||
* @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1;
|
||||
|
||||
/**
|
||||
* The NfcService is not available.
|
||||
*
|
||||
* @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2;
|
||||
|
||||
/**
|
||||
* Possible response codes from {@link #setTagIntentAppPreferenceForUser}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = { "TAG_INTENT_APP_PREF_RESULT" }, value = {
|
||||
TAG_INTENT_APP_PREF_RESULT_SUCCESS,
|
||||
TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND,
|
||||
TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface TagIntentAppPreferenceResult {}
|
||||
|
||||
// Guarded by NfcAdapter.class
|
||||
static boolean sIsInitialized = false;
|
||||
static boolean sHasNfcFeature;
|
||||
@@ -2190,4 +2236,133 @@ public final class NfcAdapter {
|
||||
@NonNull ControllerAlwaysOnListener listener) {
|
||||
mControllerAlwaysOnListener.unregister(listener);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets whether we dispatch NFC Tag intents to the package.
|
||||
*
|
||||
* <p>{@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
|
||||
* {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
|
||||
* disallowed.
|
||||
* <p>An app is added to the preference list with the allowed flag set to {@code true}
|
||||
* when a Tag intent is dispatched to the package for the first time. This API is called
|
||||
* by settings to note that the user wants to change this default preference.
|
||||
*
|
||||
* @param userId the user to whom this package name will belong to
|
||||
* @param pkg the full name (i.e. com.google.android.tag) of the package that will be added to
|
||||
* the preference list
|
||||
* @param allow {@code true} to allow dispatching Tag intents to the package's activity,
|
||||
* {@code false} otherwise
|
||||
* @return the {@link #TagIntentAppPreferenceResult} value
|
||||
* @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
|
||||
* {@code false}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
@TagIntentAppPreferenceResult
|
||||
public int setTagIntentAppPreferenceForUser(@UserIdInt int userId,
|
||||
@NonNull String pkg, boolean allow) {
|
||||
Objects.requireNonNull(pkg, "pkg cannot be null");
|
||||
if (!isTagIntentAppPreferenceSupported()) {
|
||||
Log.e(TAG, "TagIntentAppPreference is not supported");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
try {
|
||||
return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
// Try one more time
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover NFC Service.");
|
||||
}
|
||||
try {
|
||||
return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to recover NFC Service.");
|
||||
}
|
||||
return TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Tag dispatch preference list of the UserId.
|
||||
*
|
||||
* <p>This returns a mapping of package names for this user id to whether we dispatch Tag
|
||||
* intents to the package. {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
|
||||
* {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
|
||||
* disallowed.
|
||||
*
|
||||
* @param userId the user to whom this preference list will belong to
|
||||
* @return a map of the UserId which indicates the mapping from package name to
|
||||
* boolean(allow status), otherwise return an empty map
|
||||
* @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
|
||||
* {@code false}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
@NonNull
|
||||
public Map<String, Boolean> getTagIntentAppPreferenceForUser(@UserIdInt int userId) {
|
||||
if (!isTagIntentAppPreferenceSupported()) {
|
||||
Log.e(TAG, "TagIntentAppPreference is not supported");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
try {
|
||||
Map<String, Boolean> result = (Map<String, Boolean>) sService
|
||||
.getTagIntentAppPreferenceForUser(userId);
|
||||
return result;
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
// Try one more time
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover NFC Service.");
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
try {
|
||||
Map<String, Boolean> result = (Map<String, Boolean>) sService
|
||||
.getTagIntentAppPreferenceForUser(userId);
|
||||
return result;
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to recover NFC Service.");
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the device supports Tag application preference.
|
||||
*
|
||||
* @return {@code true} if the device supports Tag application preference, {@code false}
|
||||
* otherwise
|
||||
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
public boolean isTagIntentAppPreferenceSupported() {
|
||||
if (!sHasNfcFeature) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
try {
|
||||
return sService.isTagIntentAppPreferenceSupported();
|
||||
} catch (RemoteException e) {
|
||||
attemptDeadServiceRecovery(e);
|
||||
// Try one more time
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover NFC Service.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.isTagIntentAppPreferenceSupported();
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to recover NFC Service.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user