Introduce Powered Off Finding API

Bug: 307898240
Test: atest CtsNearbyFastPairTestCases
Test: atest NearbyIntegrationPrivilegedTests
Test: atest NearbyIntegrationUntrustedTests
Change-Id: I57b37ea796c0791d72fec931f731a0143e816dac
diff --git a/nearby/tests/cts/fastpair/Android.bp b/nearby/tests/cts/fastpair/Android.bp
index 4309d7e..560c4df 100644
--- a/nearby/tests/cts/fastpair/Android.bp
+++ b/nearby/tests/cts/fastpair/Android.bp
@@ -33,6 +33,7 @@
         "framework-bluetooth.stubs.module_lib",
         "framework-configinfrastructure",
         "framework-connectivity-t.impl",
+        "framework-location.stubs.module_lib",
     ],
     srcs: ["src/**/*.java"],
     test_suites: [
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
index bc9691d..832ac03 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
@@ -25,12 +25,14 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.UiAutomation;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.cts.BTAdapterUtils;
 import android.content.Context;
+import android.location.LocationManager;
 import android.nearby.BroadcastCallback;
 import android.nearby.BroadcastRequest;
 import android.nearby.NearbyDevice;
@@ -42,6 +44,8 @@
 import android.nearby.ScanCallback;
 import android.nearby.ScanRequest;
 import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
 import android.provider.DeviceConfig;
 
 import androidx.annotation.NonNull;
@@ -50,6 +54,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SdkSuppress;
 
+import com.android.compatibility.common.util.SystemUtil;
 import com.android.modules.utils.build.SdkLevel;
 
 import org.junit.Before;
@@ -57,6 +62,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -189,6 +195,92 @@
         mScanCallback.onError(ERROR_UNSUPPORTED);
     }
 
+    @Test
+    public void testsetPoweredOffFindingEphemeralIds() {
+        // Replace with minSdkVersion when Build.VERSION_CODES.VANILLA_ICE_CREAM can be used.
+        assumeTrue(SdkLevel.isAtLeastV());
+        // Only test supporting devices.
+        if (mNearbyManager.getPoweredOffFindingMode()
+                == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) return;
+
+        mNearbyManager.setPoweredOffFindingEphemeralIds(List.of(new byte[20], new byte[20]));
+    }
+
+    @Test
+    public void testsetPoweredOffFindingEphemeralIds_noPrivilegedPermission() {
+        // Replace with minSdkVersion when Build.VERSION_CODES.VANILLA_ICE_CREAM can be used.
+        assumeTrue(SdkLevel.isAtLeastV());
+        // Only test supporting devices.
+        if (mNearbyManager.getPoweredOffFindingMode()
+                == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) return;
+
+        mUiAutomation.dropShellPermissionIdentity();
+
+        assertThrows(SecurityException.class,
+                () -> mNearbyManager.setPoweredOffFindingEphemeralIds(List.of(new byte[20])));
+    }
+
+
+    @Test
+    public void testSetAndGetPoweredOffFindingMode_enabled() {
+        // Replace with minSdkVersion when Build.VERSION_CODES.VANILLA_ICE_CREAM can be used.
+        assumeTrue(SdkLevel.isAtLeastV());
+        // Only test supporting devices.
+        if (mNearbyManager.getPoweredOffFindingMode()
+                == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) return;
+
+        enableLocation();
+        // enableLocation() has dropped shell permission identity.
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_PRIVILEGED);
+
+        mNearbyManager.setPoweredOffFindingMode(
+                NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+        assertThat(mNearbyManager.getPoweredOffFindingMode())
+                .isEqualTo(NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+    }
+
+    @Test
+    public void testSetAndGetPoweredOffFindingMode_disabled() {
+        // Replace with minSdkVersion when Build.VERSION_CODES.VANILLA_ICE_CREAM can be used.
+        assumeTrue(SdkLevel.isAtLeastV());
+        // Only test supporting devices.
+        if (mNearbyManager.getPoweredOffFindingMode()
+                == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) return;
+
+        mNearbyManager.setPoweredOffFindingMode(
+                NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED);
+        assertThat(mNearbyManager.getPoweredOffFindingMode())
+                .isEqualTo(NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED);
+    }
+
+    @Test
+    public void testSetPoweredOffFindingMode_noPrivilegedPermission() {
+        // Replace with minSdkVersion when Build.VERSION_CODES.VANILLA_ICE_CREAM can be used.
+        assumeTrue(SdkLevel.isAtLeastV());
+        // Only test supporting devices.
+        if (mNearbyManager.getPoweredOffFindingMode()
+                == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) return;
+
+        enableLocation();
+        mUiAutomation.dropShellPermissionIdentity();
+
+        assertThrows(SecurityException.class, () -> mNearbyManager
+                .setPoweredOffFindingMode(NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED));
+    }
+
+    @Test
+    public void testGetPoweredOffFindingMode_noPrivilegedPermission() {
+        // Replace with minSdkVersion when Build.VERSION_CODES.VANILLA_ICE_CREAM can be used.
+        assumeTrue(SdkLevel.isAtLeastV());
+        // Only test supporting devices.
+        if (mNearbyManager.getPoweredOffFindingMode()
+                == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) return;
+
+        mUiAutomation.dropShellPermissionIdentity();
+
+        assertThrows(SecurityException.class, () -> mNearbyManager.getPoweredOffFindingMode());
+    }
+
     private void enableBluetooth() {
         BluetoothManager manager = mContext.getSystemService(BluetoothManager.class);
         BluetoothAdapter bluetoothAdapter = manager.getAdapter();
@@ -197,6 +289,13 @@
         }
     }
 
+    private void enableLocation() {
+        LocationManager locationManager = mContext.getSystemService(LocationManager.class);
+        UserHandle user = Process.myUserHandle();
+        SystemUtil.runWithShellPermissionIdentity(
+                mUiAutomation, () -> locationManager.setLocationEnabledForUser(true, user));
+    }
+
     private static class OffloadCallback implements Consumer<OffloadCapability> {
         @Override
         public void accept(OffloadCapability aBoolean) {