diff options
-rw-r--r-- | nfc/api/current.txt | 1 | ||||
-rw-r--r-- | nfc/api/system-current.txt | 10 | ||||
-rw-r--r-- | nfc/java/android/nfc/INfcCardEmulation.aidl | 4 | ||||
-rw-r--r-- | nfc/java/android/nfc/NfcOemExtension.java | 96 | ||||
-rw-r--r-- | nfc/java/android/nfc/RoutingStatus.java | 79 | ||||
-rw-r--r-- | nfc/java/android/nfc/cardemulation/CardEmulation.java | 114 |
6 files changed, 251 insertions, 53 deletions
diff --git a/nfc/api/current.txt b/nfc/api/current.txt index e7cb76c370fd..96b7c1339190 100644 --- a/nfc/api/current.txt +++ b/nfc/api/current.txt @@ -223,6 +223,7 @@ package android.nfc.cardemulation { field public static final String CATEGORY_PAYMENT = "payment"; field public static final String EXTRA_CATEGORY = "category"; field public static final String EXTRA_SERVICE_COMPONENT = "component"; + field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3; // 0x3 field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DH = 0; // 0x0 field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE = 1; // 0x1 field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC = 2; // 0x2 diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index 2db90fe13d4d..4428adee818d 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -58,12 +58,16 @@ package android.nfc { @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension { method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference(); method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.nfc.RoutingStatus getRoutingStatus(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean hasUserEnabledNfc(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAutoChangeEnabled(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagPresent(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overwriteRoutingTable(int, int, int); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void pausePolling(int); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void resumePolling(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAutoChangeEnabled(boolean); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOnMode(int); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void triggerInitialization(); @@ -105,6 +109,12 @@ package android.nfc { method public void onTagDispatch(@NonNull java.util.function.Consumer<java.lang.Boolean>); } + @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingStatus { + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultIsoDepRoute(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultOffHostRoute(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultRoute(); + } + } package android.nfc.cardemulation { diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl index 19b9e0f0b515..1eae3c6f30f1 100644 --- a/nfc/java/android/nfc/INfcCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcCardEmulation.aidl @@ -51,4 +51,8 @@ interface INfcCardEmulation void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg); void recoverRoutingTable(int userHandle); boolean isEuiccSupported(); + void setAutoChangeStatus(boolean state); + boolean isAutoChangeEnabled(); + List<String> getRoutingStatus(); + void overwriteRoutingTable(int userHandle, String emptyAid, String protocol, String tech); } diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index 8484dcafa700..fb63b5c03d00 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -16,6 +16,12 @@ package android.nfc; +import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_DH; +import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE; +import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC; +import static android.nfc.cardemulation.CardEmulation.routeIntToString; + +import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -27,6 +33,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.nfc.cardemulation.ApduServiceInfo; +import android.nfc.cardemulation.CardEmulation; +import android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; @@ -581,6 +589,85 @@ public final class NfcOemExtension { NfcAdapter.callService(() -> NfcAdapter.sService.resumePolling()); } + /** + * Set whether to enable auto routing change or not (enabled by default). + * If disabled, routing targets are limited to a single off-host destination. + * + * @param state status of auto routing change, true if enable, otherwise false + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public void setAutoChangeEnabled(boolean state) { + NfcAdapter.callService(() -> + NfcAdapter.sCardEmulationService.setAutoChangeStatus(state)); + } + + /** + * Check if auto routing change is enabled or not. + * + * @return true if enabled, otherwise false + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public boolean isAutoChangeEnabled() { + return NfcAdapter.callServiceReturn(() -> + NfcAdapter.sCardEmulationService.isAutoChangeEnabled(), false); + } + + /** + * Get current routing status + * + * @return {@link RoutingStatus} indicating the default route, default ISO-DEP + * route and default off-host route. + */ + @NonNull + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public RoutingStatus getRoutingStatus() { + List<String> status = NfcAdapter.callServiceReturn(() -> + NfcAdapter.sCardEmulationService.getRoutingStatus(), new ArrayList<>()); + return new RoutingStatus(routeStringToInt(status.get(0)), + routeStringToInt(status.get(1)), + routeStringToInt(status.get(2))); + } + + /** + * Overwrites NFC controller routing table, which includes Protocol Route, Technology Route, + * and Empty AID Route. + * + * The parameter set to + * {@link ProtocolAndTechnologyRoute#PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET} + * can be used to keep current values for that entry. At least one route should be overridden + * when calling this API, otherwise throw {@link IllegalArgumentException}. + * + * @param protocol ISO-DEP route destination, where the possible inputs are defined in + * {@link ProtocolAndTechnologyRoute}. + * @param technology Tech-A, Tech-B and Tech-F route destination, where the possible inputs + * are defined in + * {@link ProtocolAndTechnologyRoute} + * @param emptyAid Zero-length AID route destination, where the possible inputs are defined in + * {@link ProtocolAndTechnologyRoute} + */ + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + public void overwriteRoutingTable( + @CardEmulation.ProtocolAndTechnologyRoute int protocol, + @CardEmulation.ProtocolAndTechnologyRoute int technology, + @CardEmulation.ProtocolAndTechnologyRoute int emptyAid) { + + String protocolRoute = routeIntToString(protocol); + String technologyRoute = routeIntToString(technology); + String emptyAidRoute = routeIntToString(emptyAid); + + NfcAdapter.callService(() -> + NfcAdapter.sCardEmulationService.overwriteRoutingTable( + mContext.getUser().getIdentifier(), + emptyAidRoute, + protocolRoute, + technologyRoute + )); + } + private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub { @Override @@ -829,6 +916,15 @@ public final class NfcOemExtension { } } + private @CardEmulation.ProtocolAndTechnologyRoute int routeStringToInt(String route) { + return switch (route) { + case "DH" -> PROTOCOL_AND_TECHNOLOGY_ROUTE_DH; + case "eSE" -> PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE; + case "SIM" -> PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC; + default -> throw new IllegalStateException("Unexpected value: " + route); + }; + } + private class ReceiverWrapper<T> implements Consumer<T> { private final ResultReceiver mResultReceiver; diff --git a/nfc/java/android/nfc/RoutingStatus.java b/nfc/java/android/nfc/RoutingStatus.java new file mode 100644 index 000000000000..4a1b1f3cecbc --- /dev/null +++ b/nfc/java/android/nfc/RoutingStatus.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 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.annotation.FlaggedApi; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.nfc.cardemulation.CardEmulation; + +/** + * A class indicating default route, ISO-DEP route and off-host route. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) +public class RoutingStatus { + private final @CardEmulation.ProtocolAndTechnologyRoute int mDefaultRoute; + private final @CardEmulation.ProtocolAndTechnologyRoute int mDefaultIsoDepRoute; + private final @CardEmulation.ProtocolAndTechnologyRoute int mDefaultOffHostRoute; + + RoutingStatus(@CardEmulation.ProtocolAndTechnologyRoute int mDefaultRoute, + @CardEmulation.ProtocolAndTechnologyRoute int mDefaultIsoDepRoute, + @CardEmulation.ProtocolAndTechnologyRoute int mDefaultOffHostRoute) { + this.mDefaultRoute = mDefaultRoute; + this.mDefaultIsoDepRoute = mDefaultIsoDepRoute; + this.mDefaultOffHostRoute = mDefaultOffHostRoute; + } + + /** + * Getter of the default route. + * @return an integer defined in + * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute} + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + @CardEmulation.ProtocolAndTechnologyRoute + public int getDefaultRoute() { + return mDefaultRoute; + } + + /** + * Getter of the default ISO-DEP route. + * @return an integer defined in + * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute} + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + @CardEmulation.ProtocolAndTechnologyRoute + public int getDefaultIsoDepRoute() { + return mDefaultIsoDepRoute; + } + + /** + * Getter of the default off-host route. + * @return an integer defined in + * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute} + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + @CardEmulation.ProtocolAndTechnologyRoute + public int getDefaultOffHostRoute() { + return mDefaultOffHostRoute; + } + +} diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java index 4be082ccc02f..d8f04c50b695 100644 --- a/nfc/java/android/nfc/cardemulation/CardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java @@ -168,6 +168,12 @@ public final class CardEmulation { public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC = 2; /** + * Route to the default value in config file. + */ + @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) + public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3; + + /** * Route unset. */ @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) @@ -895,45 +901,47 @@ public final class CardEmulation { PROTOCOL_AND_TECHNOLOGY_ROUTE_DH, PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE, PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC, - PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET + PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET, + PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT }) @Retention(RetentionPolicy.SOURCE) public @interface ProtocolAndTechnologyRoute {} - /** - * Setting NFC controller routing table, which includes Protocol Route and Technology Route, - * while this Activity is in the foreground. - * - * The parameter set to {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET} - * can be used to keep current values for that entry. Either - * Protocol Route or Technology Route should be override when calling this API, otherwise - * throw {@link IllegalArgumentException}. - * <p> - * Example usage in an Activity that requires to set proto route to "ESE" and keep tech route: - * <pre> - * protected void onResume() { - * mNfcAdapter.overrideRoutingTable( - * this, {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE}, null); - * }</pre> - * </p> - * Also activities must call {@link #recoverRoutingTable(Activity)} - * when it goes to the background. Only the package of the - * currently preferred service (the service set as preferred by the current foreground - * application via {@link CardEmulation#setPreferredService(Activity, ComponentName)} or the - * current Default Wallet Role Holder {@link RoleManager#ROLE_WALLET}), - * otherwise a call to this method will fail and throw {@link SecurityException}. - * @param activity The Activity that requests NFC controller routing table to be changed. - * @param protocol ISO-DEP route destination, where the possible inputs are defined - * in {@link ProtocolAndTechnologyRoute}. - * @param technology Tech-A, Tech-B and Tech-F route destination, where the possible inputs - * are defined in {@link ProtocolAndTechnologyRoute} - * @throws SecurityException if the caller is not the preferred NFC service - * @throws IllegalArgumentException if the activity is not resumed or the caller is not in the - * foreground. - * <p> - * This is a high risk API and only included to support mainline effort - * @hide - */ + /** + * Setting NFC controller routing table, which includes Protocol Route and Technology Route, + * while this Activity is in the foreground. + * + * The parameter set to {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET} + * can be used to keep current values for that entry. Either + * Protocol Route or Technology Route should be override when calling this API, otherwise + * throw {@link IllegalArgumentException}. + * <p> + * Example usage in an Activity that requires to set proto route to "ESE" and keep tech route: + * <pre> + * protected void onResume() { + * mNfcAdapter.overrideRoutingTable( + * this, {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE}, + * {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET}); + * }</pre> + * </p> + * Also activities must call {@link #recoverRoutingTable(Activity)} + * when it goes to the background. Only the package of the + * currently preferred service (the service set as preferred by the current foreground + * application via {@link CardEmulation#setPreferredService(Activity, ComponentName)} or the + * current Default Wallet Role Holder {@link RoleManager#ROLE_WALLET}), + * otherwise a call to this method will fail and throw {@link SecurityException}. + * @param activity The Activity that requests NFC controller routing table to be changed. + * @param protocol ISO-DEP route destination, where the possible inputs are defined + * in {@link ProtocolAndTechnologyRoute}. + * @param technology Tech-A, Tech-B and Tech-F route destination, where the possible inputs + * are defined in {@link ProtocolAndTechnologyRoute} + * @throws SecurityException if the caller is not the preferred NFC service + * @throws IllegalArgumentException if the activity is not resumed or the caller is not in the + * foreground. + * <p> + * This is a high risk API and only included to support mainline effort + * @hide + */ @SystemApi @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) public void overrideRoutingTable( @@ -942,26 +950,14 @@ public final class CardEmulation { if (!activity.isResumed()) { throw new IllegalArgumentException("Activity must be resumed."); } - String protocolRoute = switch (protocol) { - case PROTOCOL_AND_TECHNOLOGY_ROUTE_DH -> "DH"; - case PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE -> "ESE"; - case PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC -> "UICC"; - case PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET -> null; - default -> throw new IllegalStateException("Unexpected value: " + protocol); - }; - String technologyRoute = switch (technology) { - case PROTOCOL_AND_TECHNOLOGY_ROUTE_DH -> "DH"; - case PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE -> "ESE"; - case PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC -> "UICC"; - case PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET -> null; - default -> throw new IllegalStateException("Unexpected value: " + protocol); - }; + String protocolRoute = routeIntToString(protocol); + String technologyRoute = routeIntToString(technology); callService(() -> sService.overrideRoutingTable( - mContext.getUser().getIdentifier(), - protocolRoute, - technologyRoute, - mContext.getPackageName())); + mContext.getUser().getIdentifier(), + protocolRoute, + technologyRoute, + mContext.getPackageName())); } /** @@ -1068,4 +1064,16 @@ public final class CardEmulation { } return defaultReturn; } + + /** @hide */ + public static String routeIntToString(@ProtocolAndTechnologyRoute int route) { + return switch (route) { + case PROTOCOL_AND_TECHNOLOGY_ROUTE_DH -> "DH"; + case PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE -> "eSE"; + case PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC -> "SIM"; + case PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET -> null; + case PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT -> "default"; + default -> throw new IllegalStateException("Unexpected value: " + route); + }; + } } |