diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt index c64f2a874c..6cbed46ca3 100644 --- a/framework-t/api/system-current.txt +++ b/framework-t/api/system-current.txt @@ -262,6 +262,7 @@ package android.nearby { public class NearbyManager { method public static boolean isFastPairScanEnabled(@NonNull android.content.Context); + method public void queryOffloadScanSupport(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void setFastPairScanEnabled(@NonNull android.content.Context, boolean); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void startBroadcast(@NonNull android.nearby.BroadcastRequest, @NonNull java.util.concurrent.Executor, @NonNull android.nearby.BroadcastCallback); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int startScan(@NonNull android.nearby.ScanRequest, @NonNull java.util.concurrent.Executor, @NonNull android.nearby.ScanCallback); diff --git a/nearby/framework/java/android/nearby/INearbyManager.aidl b/nearby/framework/java/android/nearby/INearbyManager.aidl index 0291fff5cb..402e3a667b 100644 --- a/nearby/framework/java/android/nearby/INearbyManager.aidl +++ b/nearby/framework/java/android/nearby/INearbyManager.aidl @@ -20,6 +20,7 @@ import android.nearby.IBroadcastListener; import android.nearby.IScanListener; import android.nearby.BroadcastRequestParcelable; import android.nearby.ScanRequest; +import android.nearby.aidl.IOffloadCallback; /** * Interface for communicating with the nearby services. @@ -37,4 +38,6 @@ interface INearbyManager { in IBroadcastListener callback, String packageName, @nullable String attributionTag); void stopBroadcast(in IBroadcastListener callback, String packageName, @nullable String attributionTag); + + void queryOffloadScanSupport(in IOffloadCallback callback) ; } \ No newline at end of file diff --git a/nearby/framework/java/android/nearby/NearbyManager.java b/nearby/framework/java/android/nearby/NearbyManager.java index fba6ae50f6..6e4052457d 100644 --- a/nearby/framework/java/android/nearby/NearbyManager.java +++ b/nearby/framework/java/android/nearby/NearbyManager.java @@ -26,6 +26,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.nearby.aidl.IOffloadCallback; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; @@ -37,6 +38,7 @@ import java.lang.ref.WeakReference; import java.util.Objects; import java.util.WeakHashMap; import java.util.concurrent.Executor; +import java.util.function.Consumer; /** * This class provides a way to perform Nearby related operations such as scanning, broadcasting @@ -267,6 +269,22 @@ public class NearbyManager { } } + /** + * Query if offload scan is available in a device. The query is asynchronous and + * result is called back in {@link Consumer}, which is set to true if offload is supported. + * + * @param executor the callback will take place on this {@link Executor} + * @param callback the callback invoked with {@code true} if offload is supported + */ + public void queryOffloadScanSupport(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer callback) { + try { + mService.queryOffloadScanSupport(new OffloadTransport(executor, callback)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Read from {@link Settings} whether Fast Pair scan is enabled. * @@ -297,6 +315,29 @@ public class NearbyManager { "successfully %s Fast Pair scan", enable ? "enables" : "disables")); } + private static class OffloadTransport extends IOffloadCallback.Stub { + + private final Executor mExecutor; + // Null when cancelled + volatile @Nullable Consumer mConsumer; + + OffloadTransport(Executor executor, Consumer consumer) { + Preconditions.checkArgument(executor != null, "illegal null executor"); + Preconditions.checkArgument(consumer != null, "illegal null consumer"); + mExecutor = executor; + mConsumer = consumer; + } + + @Override + public void onQueryComplete(boolean isOffloadSupported) { + mExecutor.execute(() -> { + if (mConsumer != null) { + mConsumer.accept(isOffloadSupported); + } + }); + } + } + private static class ScanListenerTransport extends IScanListener.Stub { private @ScanRequest.ScanType int mScanType; diff --git a/nearby/framework/java/android/nearby/aidl/IOffloadCallback.aidl b/nearby/framework/java/android/nearby/aidl/IOffloadCallback.aidl new file mode 100644 index 0000000000..f353affb44 --- /dev/null +++ b/nearby/framework/java/android/nearby/aidl/IOffloadCallback.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023, 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.nearby.aidl; + +import android.nearby.NearbyDeviceParcelable; + +/** + * Listener for offload queries. + * + * {@hide} + */ +oneway interface IOffloadCallback { + /** Invokes when ContextHub transaction completes. */ + void onQueryComplete(boolean isOffloadSupported); +} diff --git a/nearby/service/java/com/android/server/nearby/NearbyService.java b/nearby/service/java/com/android/server/nearby/NearbyService.java index a1bca1977c..b70930a65e 100644 --- a/nearby/service/java/com/android/server/nearby/NearbyService.java +++ b/nearby/service/java/com/android/server/nearby/NearbyService.java @@ -37,6 +37,7 @@ import android.nearby.INearbyManager; import android.nearby.IScanListener; import android.nearby.NearbyManager; import android.nearby.ScanRequest; +import android.nearby.aidl.IOffloadCallback; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -145,6 +146,11 @@ public class NearbyService extends INearbyManager.Stub { mBroadcastProviderManager.stopBroadcast(listener); } + @Override + public void queryOffloadScanSupport(IOffloadCallback callback) { + + } + /** * Called by the service initializer. * 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 bb262909c8..f733266b90 100644 --- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java +++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java @@ -57,6 +57,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; /** * TODO(b/215435939) This class doesn't include any logic yet. Because SELinux denies access to @@ -99,6 +100,7 @@ public class NearbyManagerTest { public void onError(int errorCode) { } }; + private static final Executor EXECUTOR = Executors.newSingleThreadExecutor(); @Before @@ -171,6 +173,13 @@ public class NearbyManagerTest { assertThat(mNearbyManager.isFastPairScanEnabled(mContext)).isFalse(); } + @Test + @SdkSuppress(minSdkVersion = 34, codeName = "U") + public void queryOffloadScanSupport() { + OffloadCallback callback = new OffloadCallback(); + mNearbyManager.queryOffloadScanSupport(EXECUTOR, callback); + } + private void enableBluetooth() { BluetoothManager manager = mContext.getSystemService(BluetoothManager.class); BluetoothAdapter bluetoothAdapter = manager.getAdapter(); @@ -178,4 +187,11 @@ public class NearbyManagerTest { assertThat(BTAdapterUtils.enableAdapter(bluetoothAdapter, mContext)).isTrue(); } } + + private class OffloadCallback implements Consumer { + @Override + public void accept(Boolean aBoolean) { + // no-op for now + } + } }