Merge "Implement queryOffloadCapability" into udc-dev
diff --git a/nearby/service/java/com/android/server/nearby/NearbyService.java b/nearby/service/java/com/android/server/nearby/NearbyService.java
index 514de16..2878fb1 100644
--- a/nearby/service/java/com/android/server/nearby/NearbyService.java
+++ b/nearby/service/java/com/android/server/nearby/NearbyService.java
@@ -147,7 +147,7 @@
@Override
public void queryOffloadCapability(IOffloadCallback callback) {
-
+ mProviderManager.queryOffloadCapability(callback);
}
/**
diff --git a/nearby/service/java/com/android/server/nearby/provider/ChreCommunication.java b/nearby/service/java/com/android/server/nearby/provider/ChreCommunication.java
index b24e7d9..020c7b2 100644
--- a/nearby/service/java/com/android/server/nearby/provider/ChreCommunication.java
+++ b/nearby/service/java/com/android/server/nearby/provider/ChreCommunication.java
@@ -39,7 +39,9 @@
import java.util.List;
import java.util.Locale;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
/**
* Responsible for setting up communication with the appropriate contexthub on the device and
@@ -47,6 +49,8 @@
*/
public class ChreCommunication extends ContextHubClientCallback {
+ public static final int INVALID_NANO_APP_VERSION = -1;
+
/** Callback that receives messages forwarded from the context hub. */
public interface ContextHubCommsCallback {
/** Indicates whether {@link ChreCommunication} was started successfully. */
@@ -72,8 +76,10 @@
private boolean mStarted = false;
// null when CHRE availability result has not been returned
@Nullable private Boolean mChreSupport = null;
+ private long mNanoAppVersion = INVALID_NANO_APP_VERSION;
@Nullable private ContextHubCommsCallback mCallback;
@Nullable private ContextHubClient mContextHubClient;
+ private CountDownLatch mCountDownLatch;
public ChreCommunication(Injector injector, Context context, Executor executor) {
mInjector = injector;
@@ -169,6 +175,25 @@
return true;
}
+ /**
+ * Checks the Nano App version
+ */
+ public long queryNanoAppVersion() {
+ if (mCountDownLatch == null || mCountDownLatch.getCount() == 0) {
+ // already gets result from CHRE
+ return mNanoAppVersion;
+ }
+ try {
+ boolean success = mCountDownLatch.await(1, TimeUnit.SECONDS);
+ if (!success) {
+ Log.w(TAG, "Failed to get ContextHubTransaction result before the timeout.");
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return mNanoAppVersion;
+ }
+
@Override
public synchronized void onMessageFromNanoApp(ContextHubClient client, NanoAppMessage message) {
mCallback.onMessageFromNanoApp(message);
@@ -245,6 +270,7 @@
return;
}
+ mCountDownLatch = new CountDownLatch(1);
if (response.getResult() == ContextHubTransaction.RESULT_SUCCESS) {
for (NanoAppState state : response.getContents()) {
long version = state.getNanoAppVersion();
@@ -264,6 +290,8 @@
mExecutor, ChreCommunication.this);
mChreSupport = true;
mCallback.started(true);
+ mNanoAppVersion = version;
+ mCountDownLatch.countDown();
return;
}
}
@@ -281,6 +309,7 @@
}
mContextHubs.remove(mQueriedContextHub);
+ mCountDownLatch.countDown();
// If this is the last context hub response left to receive, indicate that
// there isn't a valid context available on this device.
if (mContextHubs.isEmpty()) {
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 40a9ee9..ff18e49 100644
--- a/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
@@ -29,10 +29,13 @@
import android.nearby.DataElement;
import android.nearby.NearbyDevice;
import android.nearby.NearbyDeviceParcelable;
+import android.nearby.OffloadCapability;
import android.nearby.PresenceDevice;
import android.nearby.PresenceScanFilter;
import android.nearby.PublicCredential;
import android.nearby.ScanFilter;
+import android.nearby.aidl.IOffloadCallback;
+import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -141,6 +144,23 @@
return mChreCommunication.available();
}
+ /**
+ * Query offload capability in a device.
+ */
+ public void queryOffloadCapability(IOffloadCallback callback) {
+ OffloadCapability.Builder builder = new OffloadCapability.Builder();
+ mExecutor.execute(() -> {
+ long version = mChreCommunication.queryNanoAppVersion();
+ builder.setVersion(version);
+ builder.setFastPairSupported(version != ChreCommunication.INVALID_NANO_APP_VERSION);
+ try {
+ callback.onQueryComplete(builder.build());
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
@VisibleForTesting
List<ScanFilter> getFiltersLocked() {
synchronized (mLock) {
diff --git a/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java b/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java
index 8d973d9..6ee924a 100644
--- a/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java
+++ b/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderManager.java
@@ -31,6 +31,7 @@
import android.nearby.ScanCallback;
import android.nearby.ScanFilter;
import android.nearby.ScanRequest;
+import android.nearby.aidl.IOffloadCallback;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -278,6 +279,13 @@
}
/**
+ * Query offload capability in a device.
+ */
+ public void queryOffloadCapability(IOffloadCallback callback) {
+ mChreDiscoveryProvider.queryOffloadCapability(callback);
+ }
+
+ /**
* @return {@code null} when all providers are initializing
* {@code false} when fail to start all the providers
* {@code true} when any one of the provider starts successfully
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreCommunicationTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreCommunicationTest.java
index 58b8584..fe28a8c 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreCommunicationTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreCommunicationTest.java
@@ -21,6 +21,7 @@
import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
import static com.android.server.nearby.NearbyConfiguration.NEARBY_MAINLINE_NANO_APP_MIN_VERSION;
+import static com.android.server.nearby.provider.ChreCommunication.INVALID_NANO_APP_VERSION;
import static com.google.common.truth.Truth.assertThat;
@@ -36,8 +37,10 @@
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppMessage;
import android.hardware.location.NanoAppState;
+import android.os.Build;
import android.provider.DeviceConfig;
+import androidx.test.filters.SdkSuppress;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.nearby.injector.Injector;
@@ -54,6 +57,8 @@
import java.util.concurrent.Executor;
public class ChreCommunicationTest {
+ private static final int APP_VERSION = 1;
+
@Mock Injector mInjector;
@Mock Context mContext;
@Mock ContextHubManager mManager;
@@ -83,7 +88,10 @@
when(mTransactionResponse.getContents())
.thenReturn(
Collections.singletonList(
- new NanoAppState(ChreDiscoveryProvider.NANOAPP_ID, 1, true)));
+ new NanoAppState(
+ ChreDiscoveryProvider.NANOAPP_ID,
+ APP_VERSION,
+ true)));
mChreCommunication = new ChreCommunication(mInjector, mContext, new InlineExecutor());
}
@@ -121,6 +129,19 @@
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public void test_getNanoVersion() {
+ assertThat(mChreCommunication.queryNanoAppVersion()).isEqualTo(INVALID_NANO_APP_VERSION);
+
+ mChreCommunication.start(
+ mChreCallback, Collections.singleton(ChreDiscoveryProvider.NANOAPP_ID));
+ verify(mTransaction).setOnCompleteListener(mOnQueryCompleteListenerCaptor.capture(), any());
+ mOnQueryCompleteListenerCaptor.getValue().onComplete(mTransaction, mTransactionResponse);
+
+ assertThat(mChreCommunication.queryNanoAppVersion()).isEqualTo(APP_VERSION);
+ }
+
+ @Test
public void testSendMessageToNanApp() {
mChreCommunication.start(
mChreCallback, Collections.singleton(ChreDiscoveryProvider.NANOAPP_ID));
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 25d3f73..5a56c3c 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
@@ -26,11 +26,17 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.location.NanoAppMessage;
import android.nearby.DataElement;
import android.nearby.NearbyDeviceParcelable;
+import android.nearby.OffloadCapability;
+import android.nearby.aidl.IOffloadCallback;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.provider.DeviceConfig;
import androidx.test.filters.SdkSuppress;
@@ -57,6 +63,7 @@
public class ChreDiscoveryProviderTest {
@Mock AbstractDiscoveryProvider.Listener mListener;
@Mock ChreCommunication mChreCommunication;
+ @Mock IBinder mIBinder;
@Captor ArgumentCaptor<ChreCommunication.ContextHubCommsCallback> mChreCallbackCaptor;
@Captor ArgumentCaptor<NearbyDeviceParcelable> mNearbyDevice;
@@ -70,7 +77,9 @@
private static final int DATA_TYPE_TEST_DE_BEGIN_KEY = 2147483520;
private static final int DATA_TYPE_TEST_DE_END_KEY = 2147483647;
+ private final Object mLock = new Object();
private ChreDiscoveryProvider mChreDiscoveryProvider;
+ private OffloadCapability mOffloadCapability;
@Before
public void setUp() {
@@ -92,6 +101,64 @@
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public void test_queryInvalidVersion() {
+ when(mChreCommunication.queryNanoAppVersion()).thenReturn(
+ (long) ChreCommunication.INVALID_NANO_APP_VERSION);
+ IOffloadCallback callback = new IOffloadCallback() {
+ @Override
+ public void onQueryComplete(OffloadCapability capability) throws RemoteException {
+ synchronized (mLock) {
+ mOffloadCapability = capability;
+ mLock.notify();
+ }
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return mIBinder;
+ }
+ };
+ mChreDiscoveryProvider.queryOffloadCapability(callback);
+ OffloadCapability capability =
+ new OffloadCapability
+ .Builder()
+ .setFastPairSupported(false)
+ .setVersion(ChreCommunication.INVALID_NANO_APP_VERSION)
+ .build();
+ assertThat(mOffloadCapability).isEqualTo(capability);
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public void test_queryVersion() {
+ long version = 500L;
+ when(mChreCommunication.queryNanoAppVersion()).thenReturn(version);
+ IOffloadCallback callback = new IOffloadCallback() {
+ @Override
+ public void onQueryComplete(OffloadCapability capability) throws RemoteException {
+ synchronized (mLock) {
+ mOffloadCapability = capability;
+ mLock.notify();
+ }
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return mIBinder;
+ }
+ };
+ mChreDiscoveryProvider.queryOffloadCapability(callback);
+ OffloadCapability capability =
+ new OffloadCapability
+ .Builder()
+ .setFastPairSupported(true)
+ .setVersion(version)
+ .build();
+ assertThat(mOffloadCapability).isEqualTo(capability);
+ }
+
+ @Test
@SdkSuppress(minSdkVersion = 32, codeName = "T")
public void testOnNearbyDeviceDiscovered() {
Blefilter.PublicCredential credential =