Allows Test Data Elements with Filter

Bug: 259299293
Test: atest NearbyUnitTests and on device test
Ignore-AOSP-First: nearby_not_in_aosp_yet
Merged-In: I2d0a537d38ac7b602bc49dcf2113c43f1b654cb2
Change-Id: I2d0a537d38ac7b602bc49dcf2113c43f1b654cb2
diff --git a/nearby/framework/java/android/nearby/DataElement.java b/nearby/framework/java/android/nearby/DataElement.java
index 4592c33..02548cb 100644
--- a/nearby/framework/java/android/nearby/DataElement.java
+++ b/nearby/framework/java/android/nearby/DataElement.java
@@ -55,7 +55,9 @@
             DataType.ACCOUNT_KEY_DATA,
             DataType.CONNECTION_STATUS,
             DataType.BATTERY,
-            DataType.SCAN_MODE
+            DataType.SCAN_MODE,
+            DataType.TEST_DE_BEGIN,
+            DataType.TEST_DE_END
     })
     public @interface DataType {
         int BLE_SERVICE_DATA = 100;
@@ -74,6 +76,10 @@
         int ACCOUNT_KEY_DATA = 9;
         int CONNECTION_STATUS = 10;
         int BATTERY = 11;
+        // Reserves test DE ranges from {@link DataElement.DataType#TEST_DE_BEGIN}
+        // to {@link DataElement.DataType#TEST_DE_END}, inclusive.
+        int TEST_DE_BEGIN = 256;
+        int TEST_DE_END = 260;
     }
 
     /**
@@ -109,6 +115,14 @@
     }
 
     /**
+     * @return {@code true} if this is test data element type.
+     * @hide
+     */
+    public static boolean isTestDeType(int type) {
+        return type >= DataType.TEST_DE_BEGIN && type <= DataType.TEST_DE_END;
+    }
+
+    /**
      * Constructs a {@link DataElement}.
      */
     public DataElement(int key, @NonNull byte[] value) {
diff --git a/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java b/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
index 6aefae9..93acede 100644
--- a/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
@@ -20,10 +20,6 @@
 
 import static com.android.server.nearby.NearbyService.TAG;
 
-import static service.proto.Blefilter.DataElement.ElementType.DE_BATTERY_STATUS;
-import static service.proto.Blefilter.DataElement.ElementType.DE_CONNECTION_STATUS;
-import static service.proto.Blefilter.DataElement.ElementType.DE_FAST_PAIR_ACCOUNT_KEY;
-
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -41,9 +37,11 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.nearby.NearbyConfiguration;
 
 import com.google.protobuf.ByteString;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -54,13 +52,17 @@
 public class ChreDiscoveryProvider extends AbstractDiscoveryProvider {
     // Nanoapp ID reserved for Nearby Presence.
     /** @hide */
-    @VisibleForTesting public static final long NANOAPP_ID = 0x476f6f676c001031L;
+    @VisibleForTesting
+    public static final long NANOAPP_ID = 0x476f6f676c001031L;
     /** @hide */
-    @VisibleForTesting public static final int NANOAPP_MESSAGE_TYPE_FILTER = 3;
+    @VisibleForTesting
+    public static final int NANOAPP_MESSAGE_TYPE_FILTER = 3;
     /** @hide */
-    @VisibleForTesting public static final int NANOAPP_MESSAGE_TYPE_FILTER_RESULT = 4;
+    @VisibleForTesting
+    public static final int NANOAPP_MESSAGE_TYPE_FILTER_RESULT = 4;
     /** @hide */
-    @VisibleForTesting public static final int NANOAPP_MESSAGE_TYPE_CONFIG = 5;
+    @VisibleForTesting
+    public static final int NANOAPP_MESSAGE_TYPE_CONFIG = 5;
 
     private static final int FP_ACCOUNT_KEY_LENGTH = 16;
 
@@ -71,6 +73,7 @@
     private boolean mChreStarted = false;
     private Blefilter.BleFilters mFilters = null;
     private Context mContext;
+    private NearbyConfiguration mNearbyConfiguration;
     private final IntentFilter mIntentFilter;
     // Null when the filters are never set
     @GuardedBy("mLock")
@@ -101,6 +104,7 @@
     /** Initialize the CHRE discovery provider. */
     public void init() {
         mChreCommunication.start(mChreCallback, Collections.singleton(NANOAPP_ID));
+        mNearbyConfiguration = new NearbyConfiguration();
     }
 
     @Override
@@ -162,6 +166,9 @@
             for (DataElement dataElement : presenceScanFilter.getExtendedProperties()) {
                 if (dataElement.getKey() == DataElement.DataType.ACCOUNT_KEY_DATA) {
                     filterBuilder.addDataElement(toProtoDataElement(dataElement));
+                } else if (mNearbyConfiguration.isTestAppSupported()
+                        && DataElement.isTestDeType(dataElement.getKey())) {
+                    filterBuilder.addDataElement(toProtoDataElement(dataElement));
                 }
             }
             if (!presenceScanFilter.getPresenceActions().isEmpty()) {
@@ -177,7 +184,8 @@
 
     private Blefilter.PublicateCertificate toProtoPublicCredential(PublicCredential credential) {
         Log.d(TAG, String.format("Returns a PublicCertificate with authenticity key size %d and"
-                + " encrypted metadata key tag size %d", credential.getAuthenticityKey().length,
+                        + " encrypted metadata key tag size %d",
+                credential.getAuthenticityKey().length,
                 credential.getEncryptedMetadataKeyTag().length));
         return Blefilter.PublicateCertificate.newBuilder()
                 .setAuthenticityKey(ByteString.copyFrom(credential.getAuthenticityKey()))
@@ -188,12 +196,13 @@
 
     private Blefilter.DataElement toProtoDataElement(DataElement dataElement) {
         return Blefilter.DataElement.newBuilder()
-                        .setKey(
-                                Blefilter.DataElement.ElementType
-                                        .DE_FAST_PAIR_ACCOUNT_KEY)
-                        .setValue(ByteString.copyFrom(dataElement.getValue()))
-                        .setValueLength(FP_ACCOUNT_KEY_LENGTH)
-                        .build();
+                .setKey(Arrays.stream(Blefilter.DataElement.ElementType.values())
+                        .filter(p -> p.getNumber() == dataElement.getKey())
+                        .findFirst()
+                        .get())
+                .setValue(ByteString.copyFrom(dataElement.getValue()))
+                .setValueLength(dataElement.getValue().length)
+                .build();
     }
 
     private void sendFilters(Blefilter.BleFilters filters) {
@@ -282,10 +291,10 @@
                         }
                         PresenceDevice.Builder presenceDeviceBuilder =
                                 new PresenceDevice.Builder(
-                                                String.valueOf(filterResult.hashCode()),
-                                                salt,
-                                                secretId,
-                                                encryptedMetaData)
+                                        String.valueOf(filterResult.hashCode()),
+                                        salt,
+                                        secretId,
+                                        encryptedMetaData)
                                         .setRssi(filterResult.getRssi())
                                         .addMedium(NearbyDevice.Medium.BLE);
                         // Data Elements reported from nanoapp added to Data Elements.
@@ -330,11 +339,11 @@
 
                         PublicCredential publicCredential =
                                 new PublicCredential.Builder(
-                                                secretId,
-                                                authenticityKey,
-                                                publicKey,
-                                                encryptedMetaData,
-                                                encryptedMetaDataTag)
+                                        secretId,
+                                        authenticityKey,
+                                        publicKey,
+                                        encryptedMetaData,
+                                        encryptedMetaDataTag)
                                         .build();
 
                         NearbyDeviceParcelable device =
@@ -377,6 +386,16 @@
                                     element.getValue().substring(0, endIndex).toByteArray()));
                     break;
                 default:
+                    if (mNearbyConfiguration.isTestAppSupported()
+                            && DataElement.isTestDeType(element.getKey().getNumber())) {
+                        presenceDeviceBuilder.addExtendedProperty(
+                                new DataElement(Arrays.stream(
+                                                Blefilter.DataElement.ElementType.values())
+                                        .filter(p -> p.getNumber() == element.getKey().getNumber())
+                                        .findFirst()
+                                        .get().getNumber(),
+                                        element.getValue().substring(0, endIndex).toByteArray()));
+                    }
                     break;
             }
         }
diff --git a/nearby/service/proto/src/presence/blefilter.proto b/nearby/service/proto/src/presence/blefilter.proto
index 6e1ba6d..9b760c1 100644
--- a/nearby/service/proto/src/presence/blefilter.proto
+++ b/nearby/service/proto/src/presence/blefilter.proto
@@ -58,10 +58,20 @@
 
 message DataElement {
   enum ElementType {
+    option allow_alias = true;
+
     DE_NONE = 0;
     DE_FAST_PAIR_ACCOUNT_KEY = 9;
     DE_CONNECTION_STATUS = 10;
     DE_BATTERY_STATUS = 11;
+    // Reserves Test DEs.
+    DE_TEST_BEGIN = 256;
+    DE_TEST_1 = 256;
+    DE_TEST_2 = 257;
+    DE_TEST_3 = 258;
+    DE_TEST_4 = 259;
+    DE_TEST_5 = 260;
+    DE_TEST_END = 260;
   }
 
   optional ElementType key = 1;
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java
index 270de52..d06a447 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java
@@ -16,6 +16,12 @@
 
 package com.android.server.nearby.provider;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
+import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
+
+import static com.android.server.nearby.NearbyConfiguration.NEARBY_SUPPORT_TEST_APP;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -25,10 +31,12 @@
 import android.hardware.location.NanoAppMessage;
 import android.nearby.DataElement;
 import android.nearby.NearbyDeviceParcelable;
+import android.provider.DeviceConfig;
 
 import androidx.test.filters.SdkSuppress;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.server.nearby.NearbyConfiguration;
 import com.android.server.nearby.presence.PresenceDiscoveryResult;
 
 import com.google.protobuf.ByteString;
@@ -59,11 +67,20 @@
     private static final int DATA_TYPE_BLUETOOTH_ADDR_KEY = 101;
     private static final int DATA_TYPE_FP_ACCOUNT_KEY = 9;
     private static final int DATA_TYPE_BLE_SERVICE_DATA_KEY = 100;
+    private static final int DATA_TYPE_TEST_1_KEY = 256;
+    private static final int DATA_TYPE_TEST_2_KEY = 257;
+    private static final int DATA_TYPE_TEST_3_KEY = 258;
+    private static final int DATA_TYPE_TEST_4_KEY = 259;
+    private static final int DATA_TYPE_TEST_5_KEY = 260;
 
     private ChreDiscoveryProvider mChreDiscoveryProvider;
 
+
     @Before
     public void setUp() {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(WRITE_DEVICE_CONFIG, READ_DEVICE_CONFIG);
+
         MockitoAnnotations.initMocks(this);
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
         mChreDiscoveryProvider =
@@ -113,6 +130,14 @@
     @Test
     @SdkSuppress(minSdkVersion = 32, codeName = "T")
     public void testOnNearbyDeviceDiscoveredWithDataElements() {
+        // Disables the setting of test app support
+        boolean isSupportedTestApp = getDeviceConfigBoolean(
+                NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);
+        if (isSupportedTestApp) {
+            DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "false", false);
+        }
+        assertThat(new NearbyConfiguration().isTestAppSupported()).isFalse();
+
         final byte [] connectionStatus = new byte[] {1, 2, 3};
         final byte [] batteryStatus = new byte[] {4, 5, 6};
         final byte [] txPower = new byte[] {2};
@@ -120,6 +145,7 @@
         final byte [] fastPairAccountKey = new byte[16];
         // First byte is length of service data, padding zeros should be thrown away.
         final byte [] bleServiceData = new byte[] {5, 1, 2, 3, 4, 5, 0, 0, 0, 0};
+        final byte [] testData = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
         final List<DataElement> expectedExtendedProperties = new ArrayList<>();
         expectedExtendedProperties.add(new DataElement(DATA_TYPE_CONNECTION_STATUS_KEY,
@@ -169,6 +195,41 @@
                                 .setValue(ByteString.copyFrom(fastPairAccountKey))
                                 .setValueLength(fastPairAccountKey.length)
                         )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_1)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_2)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_3)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_4)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_5)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
                         .build();
         Blefilter.BleFilterResults results =
                 Blefilter.BleFilterResults.newBuilder().addResult(result).build();
@@ -187,6 +248,158 @@
         List<DataElement> extendedProperties = PresenceDiscoveryResult
                 .fromDevice(mNearbyDevice.getValue()).getExtendedProperties();
         assertThat(extendedProperties).containsExactlyElementsIn(expectedExtendedProperties);
+        // Reverts the setting of test app support
+        if (isSupportedTestApp) {
+            DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "true", false);
+            assertThat(new NearbyConfiguration().isTestAppSupported()).isTrue();
+        }
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testOnNearbyDeviceDiscoveredWithTestDataElements() {
+        // Enables the setting of test app support
+        boolean isSupportedTestApp = getDeviceConfigBoolean(
+                NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);
+        if (!isSupportedTestApp) {
+            DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "true", false);
+        }
+        assertThat(new NearbyConfiguration().isTestAppSupported()).isTrue();
+
+        final byte [] connectionStatus = new byte[] {1, 2, 3};
+        final byte [] batteryStatus = new byte[] {4, 5, 6};
+        final byte [] txPower = new byte[] {2};
+        final byte [] bluetoothAddr = new byte[] {1, 2, 3, 4, 5, 6};
+        final byte [] fastPairAccountKey = new byte[16];
+        // First byte is length of service data, padding zeros should be thrown away.
+        final byte [] bleServiceData = new byte[] {5, 1, 2, 3, 4, 5, 0, 0, 0, 0};
+        final byte [] testData = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+        final List<DataElement> expectedExtendedProperties = new ArrayList<>();
+        expectedExtendedProperties.add(new DataElement(DATA_TYPE_CONNECTION_STATUS_KEY,
+                connectionStatus));
+        expectedExtendedProperties.add(new DataElement(DATA_TYPE_BATTERY_KEY, batteryStatus));
+        expectedExtendedProperties.add(new DataElement(DATA_TYPE_TX_POWER_KEY, txPower));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_BLUETOOTH_ADDR_KEY, bluetoothAddr));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_FP_ACCOUNT_KEY, fastPairAccountKey));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_BLE_SERVICE_DATA_KEY, new byte[] {1, 2, 3, 4, 5}));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_TEST_1_KEY, testData));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_TEST_2_KEY, testData));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_TEST_3_KEY, testData));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_TEST_4_KEY, testData));
+        expectedExtendedProperties.add(
+                new DataElement(DATA_TYPE_TEST_5_KEY, testData));
+
+        Blefilter.PublicCredential credential =
+                Blefilter.PublicCredential.newBuilder()
+                        .setSecretId(ByteString.copyFrom(new byte[] {1}))
+                        .setAuthenticityKey(ByteString.copyFrom(new byte[2]))
+                        .setPublicKey(ByteString.copyFrom(new byte[3]))
+                        .setEncryptedMetadata(ByteString.copyFrom(new byte[4]))
+                        .setEncryptedMetadataTag(ByteString.copyFrom(new byte[5]))
+                        .build();
+        Blefilter.BleFilterResult result =
+                Blefilter.BleFilterResult.newBuilder()
+                        .setTxPower(2)
+                        .setRssi(1)
+                        .setBluetoothAddress(ByteString.copyFrom(bluetoothAddr))
+                        .setBleServiceData(ByteString.copyFrom(bleServiceData))
+                        .setPublicCredential(credential)
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_CONNECTION_STATUS)
+                                .setValue(ByteString.copyFrom(connectionStatus))
+                                .setValueLength(connectionStatus.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_BATTERY_STATUS)
+                                .setValue(ByteString.copyFrom(batteryStatus))
+                                .setValueLength(batteryStatus.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_FAST_PAIR_ACCOUNT_KEY)
+                                .setValue(ByteString.copyFrom(fastPairAccountKey))
+                                .setValueLength(fastPairAccountKey.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_1)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_2)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_3)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_4)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .addDataElement(Blefilter.DataElement.newBuilder()
+                                .setKey(
+                                        Blefilter.DataElement.ElementType
+                                                .DE_TEST_5)
+                                .setValue(ByteString.copyFrom(testData))
+                                .setValueLength(testData.length)
+                        )
+                        .build();
+        Blefilter.BleFilterResults results =
+                Blefilter.BleFilterResults.newBuilder().addResult(result).build();
+        NanoAppMessage chre_message =
+                NanoAppMessage.createMessageToNanoApp(
+                        ChreDiscoveryProvider.NANOAPP_ID,
+                        ChreDiscoveryProvider.NANOAPP_MESSAGE_TYPE_FILTER_RESULT,
+                        results.toByteArray());
+        mChreDiscoveryProvider.getController().setListener(mListener);
+        mChreDiscoveryProvider.init();
+        mChreDiscoveryProvider.onStart();
+        verify(mChreCommunication).start(mChreCallbackCaptor.capture(), any());
+        mChreCallbackCaptor.getValue().onMessageFromNanoApp(chre_message);
+        verify(mListener).onNearbyDeviceDiscovered(mNearbyDevice.capture());
+
+        List<DataElement> extendedProperties = PresenceDiscoveryResult
+                .fromDevice(mNearbyDevice.getValue()).getExtendedProperties();
+        assertThat(extendedProperties).containsExactlyElementsIn(expectedExtendedProperties);
+        // Reverts the setting of test app support
+        if (!isSupportedTestApp) {
+            DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "false", false);
+            assertThat(new NearbyConfiguration().isTestAppSupported()).isFalse();
+        }
+    }
+
+    private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) {
+        final String value = getDeviceConfigProperty(name);
+        return value != null ? Boolean.parseBoolean(value) : defaultValue;
+    }
+
+    private String getDeviceConfigProperty(String name) {
+        return DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TETHERING, name);
     }
 
     private static class InLineExecutor implements Executor {