[uwb] Add Ranging report metadata bundle for oem extension

RangingReportMetadata contains session Id and raw ntf data
which is used by oem extesnion for pre-processing

Made api change to send RangingReport instead of
PersistableBundle

Bug: 243555651
Test: atest UwbSupportLibTests, CtsUwbTestCases
Change-Id: I12cbd2997055a93ee8a88a11f687ae0b3eb181bb
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 93f991b..5ce39a1 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -229,7 +229,7 @@
 
   public static interface UwbManager.UwbOemExtensionCallback {
     method public void onDeviceStatusNotificationReceived(@NonNull android.os.PersistableBundle);
-    method @NonNull public android.os.PersistableBundle onRangingReportReceived(@NonNull android.os.PersistableBundle);
+    method @NonNull public android.uwb.RangingReport onRangingReportReceived(@NonNull android.uwb.RangingReport);
     method @NonNull public int onSessionConfigurationComplete(@NonNull android.os.PersistableBundle);
     method public void onSessionStatusNotificationReceived(@NonNull android.os.PersistableBundle);
   }
diff --git a/framework/java/android/uwb/IUwbOemExtensionCallback.aidl b/framework/java/android/uwb/IUwbOemExtensionCallback.aidl
index 44a5e1a..f099f9a 100644
--- a/framework/java/android/uwb/IUwbOemExtensionCallback.aidl
+++ b/framework/java/android/uwb/IUwbOemExtensionCallback.aidl
@@ -25,5 +25,5 @@
     oneway void onSessionStatusNotificationReceived(in PersistableBundle bundle);
     oneway void onDeviceStatusNotificationReceived(in PersistableBundle bundle);
     int onSessionConfigurationReceived(in PersistableBundle bundle);
-    PersistableBundle onRangingReportReceived(in PersistableBundle bundle);
+    RangingReport onRangingReportReceived(in RangingReport bundle);
 }
\ No newline at end of file
diff --git a/framework/java/android/uwb/UwbManager.java b/framework/java/android/uwb/UwbManager.java
index 4d12920..d287129 100644
--- a/framework/java/android/uwb/UwbManager.java
+++ b/framework/java/android/uwb/UwbManager.java
@@ -369,11 +369,11 @@
         /**
          * Invoked when ranging report is generated
          *
-         * @param rangingReportBundle ranging report generated
+         * @param rangingReport ranging report generated
          * @return Oem modified ranging report
          */
-        @NonNull PersistableBundle onRangingReportReceived(
-                @NonNull PersistableBundle rangingReportBundle);
+        @NonNull RangingReport onRangingReportReceived(
+                @NonNull RangingReport rangingReport);
     }
 
     /**
diff --git a/framework/java/android/uwb/UwbOemExtensionCallbackListener.java b/framework/java/android/uwb/UwbOemExtensionCallbackListener.java
index 4a43318..08a089a 100644
--- a/framework/java/android/uwb/UwbOemExtensionCallbackListener.java
+++ b/framework/java/android/uwb/UwbOemExtensionCallbackListener.java
@@ -140,22 +140,22 @@
     }
 
     @Override
-    public PersistableBundle onRangingReportReceived(PersistableBundle rangingReportBundle)
+    public RangingReport onRangingReportReceived(RangingReport rangingReport)
             throws RemoteException {
         synchronized (this) {
             final long identity = Binder.clearCallingIdentity();
-            PersistableBundle vendorRangingReportBundle = rangingReportBundle;
+            RangingReport vendorRangingReport = rangingReport;
             try {
                 ExecutorService executor = Executors.newSingleThreadExecutor();
-                FutureTask<PersistableBundle> getOemRangingReport = new FutureTask<>(
-                        () -> mCallback.onRangingReportReceived(rangingReportBundle)
+                FutureTask<RangingReport> getOemRangingReport = new FutureTask<RangingReport>(
+                        () -> mCallback.onRangingReportReceived(rangingReport)
                 );
                 executor.submit(getOemRangingReport);
                 try {
-                    vendorRangingReportBundle = getOemRangingReport.get(
+                    vendorRangingReport = getOemRangingReport.get(
                             OEM_EXTENSION_RESPONSE_THRESHOLD_MS, TimeUnit.MILLISECONDS);
-                    return vendorRangingReportBundle == null ? rangingReportBundle
-                            : vendorRangingReportBundle;
+                    return vendorRangingReport == null ? rangingReport
+                            : vendorRangingReport;
                 } catch (ExecutionException | InterruptedException e) {
                     e.printStackTrace();
                 } catch (TimeoutException e) {
@@ -165,7 +165,7 @@
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
-            return vendorRangingReportBundle;
+            return vendorRangingReport;
         }
     }
 }
diff --git a/service/java/com/android/server/uwb/UwbSessionNotificationManager.java b/service/java/com/android/server/uwb/UwbSessionNotificationManager.java
index 304457c..2e3be42 100644
--- a/service/java/com/android/server/uwb/UwbSessionNotificationManager.java
+++ b/service/java/com/android/server/uwb/UwbSessionNotificationManager.java
@@ -41,6 +41,7 @@
 import com.google.uwb.support.ccc.CccRangingReconfiguredParams;
 import com.google.uwb.support.fira.FiraOpenSessionParams;
 import com.google.uwb.support.fira.FiraParams;
+import com.google.uwb.support.oemextension.RangingReportMetadata;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -67,11 +68,11 @@
 
         RangingReport rangingReport = getRangingReport(rangingData, uwbSession.getProtocolName(),
                 uwbSession.getParams(), mUwbInjector.getElapsedSinceBootNanos());
-        PersistableBundle bundle = new PersistableBundle();
+
         if (mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) {
             try {
-                bundle = mUwbInjector.getUwbServiceCore().getOemExtensionCallback()
-                                .onRangingReportReceived(bundle);
+                rangingReport = mUwbInjector.getUwbServiceCore().getOemExtensionCallback()
+                                .onRangingReportReceived(rangingReport);
             } catch (RemoteException e) {
                 e.printStackTrace();
             }
@@ -321,9 +322,11 @@
         boolean isAoaElevationEnabled = true;
         boolean isDestAoaAzimuthEnabled = false;
         boolean isDestAoaElevationEnabled = false;
+        long sessionId = 0;
         // For FIRA sessions, check if AOA is enabled for the session or not.
         if (protocolName.equals(FiraParams.PROTOCOL_NAME)) {
             FiraOpenSessionParams openSessionParams = (FiraOpenSessionParams) sessionParams;
+            sessionId = openSessionParams.getSessionId();
             switch (openSessionParams.getAoaResultRequest()) {
                 case FiraParams.AOA_RESULT_REQUEST_MODE_NO_AOA_REPORT:
                     isAoaAzimuthEnabled = false;
@@ -426,13 +429,18 @@
             if (rssi < 0) {
                 rangingMeasurementBuilder.setRssiDbm(rssi);
             }
-            // TODO: Fill this with vendor data
+            // TODO: No ranging measurement metadata defined, added for future usage
             PersistableBundle rangingMeasurementMetadata = new PersistableBundle();
             rangingMeasurementBuilder.setRangingMeasurementMetadata(rangingMeasurementMetadata);
             rangingMeasurements.add(rangingMeasurementBuilder.build());
         }
-        // TODO: Fill this with vendor data
-        PersistableBundle rangingReportMetadata = new PersistableBundle();
+
+        PersistableBundle rangingReportMetadata = new RangingReportMetadata.Builder()
+                .setSessionId(sessionId)
+                .setRawNtfData(rangingData.getRawNtfData())
+                .build()
+                .toBundle();
+
         if (rangingMeasurements.size() == 1) {
             return new RangingReport.Builder()
                     .addMeasurement(rangingMeasurements.get(0))
diff --git a/service/java/com/android/server/uwb/UwbTestUtils.java b/service/java/com/android/server/uwb/UwbTestUtils.java
index 4387a9e..64de26d 100644
--- a/service/java/com/android/server/uwb/UwbTestUtils.java
+++ b/service/java/com/android/server/uwb/UwbTestUtils.java
@@ -71,7 +71,7 @@
                 TEST_AOA_DEST_ELEVATION_FOM, TEST_SLOT_IDX, TEST_RSSI);
         return new UwbRangingData(TEST_SEQ_COUNTER, TEST_SESSION_ID,
                 TEST_RCR_INDICATION, TEST_CURR_RANGING_INTERVAL, TEST_RANGING_MEASURES_TYPE,
-                TEST_MAC_ADDRESS_MODE, noOfRangingMeasures, uwbTwoWayMeasurements);
+                TEST_MAC_ADDRESS_MODE, noOfRangingMeasures, uwbTwoWayMeasurements, new byte[0]);
     }
 
     // Helper method to generate a UwbRangingData instance and corresponding RangingMeasurement
diff --git a/service/java/com/android/server/uwb/data/UwbRangingData.java b/service/java/com/android/server/uwb/data/UwbRangingData.java
index 44be8d5..64dbbe6 100644
--- a/service/java/com/android/server/uwb/data/UwbRangingData.java
+++ b/service/java/com/android/server/uwb/data/UwbRangingData.java
@@ -26,10 +26,12 @@
     public int mMacAddressMode;
     public int mNoOfRangingMeasures;
     public UwbTwoWayMeasurement[] mRangingTwoWayMeasures;
+    public byte[] mRawNtfData;
 
     public UwbRangingData(long seqCounter, long sessionId, int rcrIndication,
             long currRangingInterval, int rangingMeasuresType, int macAddressMode,
-            int noOfRangingMeasures, UwbTwoWayMeasurement[] rangingTwoWayMeasures) {
+            int noOfRangingMeasures, UwbTwoWayMeasurement[] rangingTwoWayMeasures,
+            byte[] rawNtfData) {
         this.mSeqCounter = seqCounter;
         this.mSessionId = sessionId;
         this.mRcrIndication = rcrIndication;
@@ -38,6 +40,7 @@
         this.mMacAddressMode = macAddressMode;
         this.mNoOfRangingMeasures = noOfRangingMeasures;
         this.mRangingTwoWayMeasures = rangingTwoWayMeasures;
+        this.mRawNtfData = rawNtfData;
     }
 
     public long getSequenceCounter() {
@@ -72,6 +75,10 @@
         return mRangingTwoWayMeasures;
     }
 
+    public byte[] getRawNtfData() {
+        return mRawNtfData;
+    }
+
     public String toString() {
         if (mRangingMeasuresType == UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY) {
             return "UwbRangingData { "
@@ -83,6 +90,7 @@
                     + ", MacAddressMode = " + mMacAddressMode
                     + ", NoOfRangingMeasures = " + mNoOfRangingMeasures
                     + ", RangingTwoWayMeasures = " + Arrays.toString(mRangingTwoWayMeasures)
+                    + ", RawNotificationData = " + Arrays.toString(mRawNtfData)
                     + '}';
         } else {
             // TODO(jh0.jang) : ONE WAY RANGING(TDOA)?
diff --git a/service/support_lib/src/com/google/uwb/support/oemextension/RangingReportMetadata.java b/service/support_lib/src/com/google/uwb/support/oemextension/RangingReportMetadata.java
new file mode 100644
index 0000000..49c363d
--- /dev/null
+++ b/service/support_lib/src/com/google/uwb/support/oemextension/RangingReportMetadata.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2022 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 com.google.uwb.support.oemextension;
+
+import android.os.PersistableBundle;
+import android.uwb.RangingReport;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Ranging report metadata for post-processing with oem extension
+ *
+ * <p> This is passed as bundle with RangingReport
+ * {@link RangingReport#getRangingReportMetadata()}
+ */
+public class RangingReportMetadata {
+    private static final int BUNDLE_VERSION_1 = 1;
+    private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1;
+
+    public static final String KEY_BUNDLE_VERSION = "bundle_version";
+    public static final String SESSION_ID = "session_id";
+    public static final String RAW_NTF_DATA = "raw_ntf_data";
+
+    private final long mSessionId;
+    private final byte[] mRawNtfData;
+
+    public static int getBundleVersion() {
+        return BUNDLE_VERSION_CURRENT;
+    }
+
+    public long getSessionId() {
+        return mSessionId;
+    }
+
+    public byte[] getRawNtfData() {
+        return mRawNtfData;
+    }
+
+    private RangingReportMetadata(long sessionId, byte[] rawNtfData) {
+        mSessionId = sessionId;
+        mRawNtfData = rawNtfData;
+    }
+
+    @Nullable
+    private static int[] byteArrayToIntArray(@Nullable byte[] bytes) {
+        if (bytes == null) {
+            return null;
+        }
+        int[] values = new int[bytes.length];
+        for (int i = 0; i < values.length; i++) {
+            values[i] = (bytes[i]);
+        }
+        return values;
+    }
+
+    @Nullable
+    private static byte[] intArrayToByteArray(@Nullable int[] values) {
+        if (values == null) {
+            return null;
+        }
+        byte[] bytes = new byte[values.length];
+        for (int i = 0; i < values.length; i++) {
+            bytes[i] = (byte) values[i];
+        }
+        return bytes;
+    }
+
+    public PersistableBundle toBundle() {
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putInt(KEY_BUNDLE_VERSION, getBundleVersion());
+        bundle.putLong(SESSION_ID, mSessionId);
+        bundle.putIntArray(RAW_NTF_DATA, byteArrayToIntArray(mRawNtfData));
+        return bundle;
+    }
+
+    public static RangingReportMetadata fromBundle(PersistableBundle bundle) {
+        switch (bundle.getInt(KEY_BUNDLE_VERSION)) {
+            case BUNDLE_VERSION_1:
+                return parseVersion1(bundle);
+            default:
+                throw new IllegalArgumentException("Invalid bundle version");
+        }
+    }
+
+    private static RangingReportMetadata parseVersion1(PersistableBundle bundle) {
+        return new RangingReportMetadata.Builder()
+                .setSessionId(bundle.getLong(SESSION_ID))
+                .setRawNtfData(intArrayToByteArray(bundle.getIntArray(RAW_NTF_DATA)))
+                .build();
+    }
+
+    /** Builder */
+    public static class Builder {
+        private long mSessionId;
+        private byte[] mRawNtfData;
+
+        public RangingReportMetadata.Builder setSessionId(long sessionId) {
+            mSessionId = sessionId;
+            return this;
+        }
+
+        public RangingReportMetadata.Builder setRawNtfData(byte[] rawNtfData) {
+            mRawNtfData = rawNtfData;
+            return this;
+        }
+
+        public RangingReportMetadata build() {
+            return new RangingReportMetadata(mSessionId, mRawNtfData);
+        }
+    }
+}
diff --git a/service/support_lib/test/OemExtensionTests.java b/service/support_lib/test/OemExtensionTests.java
index dc469b1..4885dbd 100644
--- a/service/support_lib/test/OemExtensionTests.java
+++ b/service/support_lib/test/OemExtensionTests.java
@@ -20,11 +20,14 @@
 import androidx.test.filters.SmallTest;
 
 import com.google.uwb.support.oemextension.DeviceStatus;
+import com.google.uwb.support.oemextension.RangingReportMetadata;
 import com.google.uwb.support.oemextension.SessionStatus;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class OemExtensionTests {
@@ -70,4 +73,22 @@
         assertEquals(fromBundle.getState(), state);
         assertEquals(fromBundle.getReasonCode(), reasonCode);
     }
+
+    @Test
+    public void testRangingReportMetadata() {
+        byte[] testRawDataNtf = {0x0a, 0x0b, 0x10, 0x20, 0x6f};
+        long sessionId = 3;
+        RangingReportMetadata rangingReportMetadata = new RangingReportMetadata.Builder()
+                .setSessionId(sessionId)
+                .setRawNtfData(testRawDataNtf)
+                .build();
+
+        assertEquals(rangingReportMetadata.getRawNtfData(), testRawDataNtf);
+
+        RangingReportMetadata fromBundle = RangingReportMetadata
+                .fromBundle(rangingReportMetadata.toBundle());
+
+        assertEquals(fromBundle.getSessionId(), sessionId);
+        assertEquals(Arrays.toString(fromBundle.getRawNtfData()), Arrays.toString(testRawDataNtf));
+    }
 }
diff --git a/service/tests/src/com/android/server/uwb/data/UwbRangingDataTest.java b/service/tests/src/com/android/server/uwb/data/UwbRangingDataTest.java
index 33a00e1..5a009a0 100644
--- a/service/tests/src/com/android/server/uwb/data/UwbRangingDataTest.java
+++ b/service/tests/src/com/android/server/uwb/data/UwbRangingDataTest.java
@@ -66,6 +66,7 @@
     @Test
     public void testInitializeUwbRangingData() throws Exception {
         final int noOfRangingMeasures = 1;
+        final byte[] rawNtfData = {0x10, 0x01};
         final UwbTwoWayMeasurement[] uwbTwoWayMeasurements =
                 new UwbTwoWayMeasurement[noOfRangingMeasures];
         uwbTwoWayMeasurements[0] = new UwbTwoWayMeasurement(TEST_MAC_ADDRESS, TEST_STATUS, TEST_LOS,
@@ -76,7 +77,7 @@
                 TEST_AOA_DEST_ELEVATION_FOM, TEST_SLOT_IDX, TEST_RSSI);
         mUwbRangingData = new UwbRangingData(TEST_SEQ_COUNTER, TEST_SESSION_ID,
                 TEST_RCR_INDICATION, TEST_CURR_RANGING_INTERVAL, TEST_RANGING_MEASURES_TYPE,
-                TEST_MAC_ADDRESS_MODE, noOfRangingMeasures, uwbTwoWayMeasurements);
+                TEST_MAC_ADDRESS_MODE, noOfRangingMeasures, uwbTwoWayMeasurements, rawNtfData);
 
         assertThat(mUwbRangingData.getSequenceCounter()).isEqualTo(TEST_SEQ_COUNTER);
         assertThat(mUwbRangingData.getSessionId()).isEqualTo(TEST_SESSION_ID);
@@ -85,6 +86,7 @@
         assertThat(mUwbRangingData.getRangingMeasuresType()).isEqualTo(TEST_RANGING_MEASURES_TYPE);
         assertThat(mUwbRangingData.getMacAddressMode()).isEqualTo(TEST_MAC_ADDRESS_MODE);
         assertThat(mUwbRangingData.getNoOfRangingMeasures()).isEqualTo(1);
+        assertThat(mUwbRangingData.getRawNtfData()).isEqualTo(rawNtfData);
 
         final String testString = "UwbRangingData { "
                 + " SeqCounter = " + TEST_SEQ_COUNTER
@@ -95,6 +97,7 @@
                 + ", MacAddressMode = " + TEST_MAC_ADDRESS_MODE
                 + ", NoOfRangingMeasures = " + noOfRangingMeasures
                 + ", RangingTwoWayMeasures = " + Arrays.toString(uwbTwoWayMeasurements)
+                + ", RawNotificationData = " + Arrays.toString(rawNtfData)
                 + '}';
 
         assertThat(mUwbRangingData.toString()).isEqualTo(testString);