Add half sheet apk to nearby
Test: start activity show half sheet half sheet can also send signal
back to nearby service
Bug: 202335820
Change-Id: I663ad2ee43a0df35a063472af2835087719828c0
diff --git a/nearby/service/Android.bp b/nearby/service/Android.bp
index bc3f91d..63e2748 100644
--- a/nearby/service/Android.bp
+++ b/nearby/service/Android.bp
@@ -23,6 +23,20 @@
],
}
+filegroup {
+ name: "nearby-service-string-res",
+ srcs: [
+ "java/**/Constant.java",
+ ],
+}
+
+java_library {
+ name: "nearby-service-string",
+ srcs: [":nearby-service-string-res"],
+ sdk_version: "module_current",
+}
+
+
// Main lib for nearby services.
java_library {
name: "service-nearby",
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/Constant.java b/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
new file mode 100644
index 0000000..bf73360
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 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.android.server.nearby.fastpair;
+
+/**
+ * String constant for half sheet.
+ */
+public class Constant {
+ public static final String EXTRA_BINDER = "com.android.server.nearby.fastpair.BINDER";
+ public static final String EXTRA_BUNDLE = "com.android.server.nearby.fastpair.BUNDLE_EXTRA";
+}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
index ff4bce2..56650ce 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
@@ -16,17 +16,29 @@
package com.android.server.nearby.fastpair;
+import static com.android.server.nearby.fastpair.Constant.EXTRA_BINDER;
+import static com.android.server.nearby.fastpair.Constant.EXTRA_BUNDLE;
+
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.app.KeyguardManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.nearby.NearbyDevice;
+import android.nearby.ScanCallback;
+import android.os.Bundle;
+import android.os.UserHandle;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import com.android.server.nearby.common.bluetooth.BluetoothException;
import com.android.server.nearby.common.bluetooth.fastpair.FastPairConnection;
import com.android.server.nearby.common.bluetooth.fastpair.FastPairDualConnection;
@@ -42,9 +54,12 @@
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
import com.android.server.nearby.fastpair.footprint.FootprintsDeviceManager;
+import com.android.server.nearby.fastpair.halfsheet.HalfSheetCallback;
import com.android.server.nearby.fastpair.pairinghandler.PairingProgressHandlerBase;
+import com.android.server.nearby.util.Environment;
import java.security.GeneralSecurityException;
+import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -52,6 +67,7 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
import service.proto.Rpcs;
@@ -63,13 +79,18 @@
public class FastPairManager {
private static final String ACTION_PREFIX = UserActionHandler.PREFIX;
private static final int WAIT_FOR_UNLOCK_MILLIS = 5000;
+ private static final String ACTIVITY_INTENT_ACTION = "android.nearby.SHOW_HALFSHEET";
/** A notification ID which should be dismissed*/
public static final String EXTRA_NOTIFICATION_ID = ACTION_PREFIX + "EXTRA_NOTIFICATION_ID";
+ public static final String ACTION_RESOURCES_APK = "android.nearby.SHOW_HALFSHEET";
+
private static Executor sFastPairExecutor;
- LocatorContextWrapper mLocatorContextWrapper;
- IntentFilter mIntentFilter;
- Locator mLocator;
+ private String mHalfSheetApkPkgName;
+
+ final LocatorContextWrapper mLocatorContextWrapper;
+ final IntentFilter mIntentFilter;
+ final Locator mLocator;
private final BroadcastReceiver mScreenBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -91,12 +112,29 @@
Rpcs.GetObservedDeviceResponse.newBuilder().build();
}
+ final ScanCallback mScanCallback = new ScanCallback() {
+ @Override
+ public void onDiscovered(@NonNull NearbyDevice device) {
+ Log.d("FastPair", "Ondiscovery " + device.getName());
+ }
+
+ @Override
+ public void onUpdated(@NonNull NearbyDevice device) {
+
+ }
+
+ @Override
+ public void onLost(@NonNull NearbyDevice device) {
+
+ }
+ };
/**
* Function called when nearby service start.
*/
public void initiate() {
mIntentFilter.addAction(Intent.ACTION_SCREEN_ON);
mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+
mLocatorContextWrapper.getContext()
.registerReceiver(mScreenBroadcastReceiver, mIntentFilter);
@@ -110,7 +148,6 @@
mLocatorContextWrapper.getContext().unregisterReceiver(mScreenBroadcastReceiver);
}
-
/**
* Starts fast pair process.
*/
@@ -251,6 +288,9 @@
}
}
+ /**
+ * This function should only be called on main thread since there is no lock
+ */
private static Executor getExecutor() {
if (sFastPairExecutor != null) {
return sFastPairExecutor;
@@ -267,4 +307,64 @@
BluetoothManager manager = context.getSystemService(BluetoothManager.class);
return manager == null ? null : manager.getAdapter();
}
+
+ /** Gets the package name of HalfSheet.apk
+ * getHalfSheetApkPkgName may invoke PackageManager multiple times and it does not have
+ * race condition check. Since there is no lock for mHalfSheetApkPkgName.
+ */
+ String getHalfSheetApkPkgName() {
+ if (mHalfSheetApkPkgName != null) {
+ return mHalfSheetApkPkgName;
+ }
+ List<ResolveInfo> resolveInfos = mLocatorContextWrapper.getContext()
+ .getPackageManager().queryIntentActivities(
+ new Intent(ACTION_RESOURCES_APK),
+ PackageManager.MATCH_SYSTEM_ONLY);
+
+ // remove apps that don't live in the nearby apex
+ resolveInfos.removeIf(info ->
+ !Environment.isAppInNearbyApex(info.activityInfo.applicationInfo));
+
+ if (resolveInfos.isEmpty()) {
+ // Resource APK not loaded yet, print a stack trace to see where this is called from
+ Log.e("FastPairManager", "Attempted to fetch resources before halfsheet "
+ + " APK is installed or package manager can't resolve correctly!",
+ new IllegalStateException());
+ return null;
+ }
+
+ if (resolveInfos.size() > 1) {
+ // multiple apps found, log a warning, but continue
+ Log.w("FastPairManager", "Found > 1 APK that can resolve halfsheet APK intent: "
+ + resolveInfos.stream()
+ .map(info -> info.activityInfo.applicationInfo.packageName)
+ .collect(Collectors.joining(", ")));
+ }
+
+ // Assume the first ResolveInfo is the one we're looking for
+ ResolveInfo info = resolveInfos.get(0);
+ mHalfSheetApkPkgName = info.activityInfo.applicationInfo.packageName;
+ Log.i("FastPairManager", "Found halfsheet APK at: " + mHalfSheetApkPkgName);
+ return mHalfSheetApkPkgName;
+ }
+
+ /**
+ * Invokes half sheet in the other apk. This function can only be called in Nearby because other
+ * app can't get the correct component name.
+ */
+ void showHalfSheet() {
+ if (mLocatorContextWrapper != null) {
+ String packageName = getHalfSheetApkPkgName();
+ HalfSheetCallback callback = new HalfSheetCallback();
+ Bundle bundle = new Bundle();
+ bundle.putBinder(EXTRA_BINDER, callback);
+ mLocatorContextWrapper.getContext()
+ .startActivityAsUser(new Intent(ACTIVITY_INTENT_ACTION)
+ .putExtra(EXTRA_BUNDLE, bundle)
+ .setComponent(new ComponentName(packageName,
+ packageName + ".HalfSheetActivity")),
+ UserHandle.CURRENT);
+
+ }
+ }
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
new file mode 100644
index 0000000..fd9e460
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 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.android.server.nearby.fastpair.halfsheet;
+
+import android.nearby.IFastPairHalfSheetCallback;
+import android.util.Log;
+
+/**
+ * Callback to send ux action back to nearby service.
+ */
+public class HalfSheetCallback extends IFastPairHalfSheetCallback.Stub {
+ @Override
+ public void onHalfSheetConnectionConfirm() {
+ Log.d("FastPairHalfSheet", "Call back receiver");
+ }
+}
diff --git a/nearby/service/java/com/android/server/nearby/util/Environment.java b/nearby/service/java/com/android/server/nearby/util/Environment.java
new file mode 100644
index 0000000..dc131e7
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/util/Environment.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 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.android.server.nearby.util;
+
+import android.content.ApexEnvironment;
+import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
+
+import java.io.File;
+
+/**
+ * Provides function to make sure the function caller is from the same apex.
+ */
+public class Environment {
+ /**
+ * NEARBY apex name.
+ */
+ private static final String NEARBY_APEX_NAME = "com.android.nearby";
+
+ /**
+ * The path where the Nearby apex is mounted.
+ * Current value = "/apex/com.android.nearby"
+ */
+ private static final String NEARBY_APEX_PATH =
+ new File("/apex", NEARBY_APEX_NAME).getAbsolutePath();
+
+ /**
+ * Nearby shared folder.
+ */
+ public static File getNearbyDirectory() {
+ return ApexEnvironment.getApexEnvironment(NEARBY_APEX_NAME).getDeviceProtectedDataDir();
+ }
+
+ /**
+ * Nearby user specific folder.
+ */
+ public static File getNearbyDirectory(int userId) {
+ return ApexEnvironment.getApexEnvironment(NEARBY_APEX_NAME)
+ .getCredentialProtectedDataDirForUser(UserHandle.of(userId));
+ }
+
+ /**
+ * Returns true if the app is in the nearby apex, false otherwise.
+ * Checks if the app's path starts with "/apex/com.android.nearby".
+ */
+ public static boolean isAppInNearbyApex(ApplicationInfo appInfo) {
+ return appInfo.sourceDir.startsWith(NEARBY_APEX_PATH);
+ }
+}