summaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothPan.java
diff options
context:
space:
mode:
authorEtienne Ruffieux <eruffieux@google.com>2021-11-08 13:40:29 +0000
committerEtienne Ruffieux <eruffieux@google.com>2022-01-19 16:25:42 +0000
commit225dcd9507481ed719b67149608b9c0cb090488f (patch)
tree53cc47fe7b37b5055cb814889a131ea71375d360 /framework/java/android/bluetooth/BluetoothPan.java
parentc35fd28f4a290ffbd98c863de9d7cdff7af53a9e (diff)
Add new callback to notify Tethering when PAN is ready
In order to remove hidden networking APIs we need to add a new way to communicate between Tethering and Bluetooth. Tag: #feature Bug: 190438212 Test: Manual Change-Id: I939c46ef341573f4fc351ae886cf2c8251655e43
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothPan.java')
-rw-r--r--framework/java/android/bluetooth/BluetoothPan.java118
1 files changed, 116 insertions, 2 deletions
diff --git a/framework/java/android/bluetooth/BluetoothPan.java b/framework/java/android/bluetooth/BluetoothPan.java
index d4ad4ef47a..46410241a3 100644
--- a/framework/java/android/bluetooth/BluetoothPan.java
+++ b/framework/java/android/bluetooth/BluetoothPan.java
@@ -16,10 +16,12 @@
package android.bluetooth;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
import static android.bluetooth.BluetoothUtils.getSyncTimeout;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -30,6 +32,9 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
import android.content.Context;
+import android.net.ITetheredInterfaceCallback;
+import android.net.TetheringManager.TetheredInterfaceCallback;
+import android.net.TetheringManager.TetheredInterfaceRequest;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
@@ -41,6 +46,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
/**
@@ -183,6 +190,49 @@ public final class BluetoothPan implements BluetoothProfile {
*/
public static final int PAN_OPERATION_SUCCESS = 1004;
+ /**
+ * Request class used by Tethering to notify that the interface is closed.
+ *
+ * @see #requestTetheredInterface
+ * @hide
+ */
+ public class BluetoothTetheredInterfaceRequest implements TetheredInterfaceRequest {
+ private IBluetoothPan mService;
+ private ITetheredInterfaceCallback mCb;
+
+ private BluetoothTetheredInterfaceRequest(@NonNull IBluetoothPan service,
+ @NonNull ITetheredInterfaceCallback cb) {
+ this.mService = service;
+ this.mCb = cb;
+ }
+
+ /**
+ * Called when the Tethering interface has been released.
+ */
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ })
+ @Override
+ public void release() {
+ if (mService == null || mCb == null) {
+ throw new IllegalStateException(
+ "The tethered interface has already been released.");
+ }
+ try {
+ final SynchronousResultReceiver recv = new SynchronousResultReceiver();
+ mService.setBluetoothTethering(mCb, false, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ } catch (RemoteException | TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mService = null;
+ mCb = null;
+ }
+ }
+ }
+
private final Context mContext;
private final BluetoothAdapter mAdapter;
@@ -450,9 +500,12 @@ public final class BluetoothPan implements BluetoothProfile {
}
/**
- * Turns on/off bluetooth tethering
+ * Turns on/off bluetooth tethering.
*
* @param value is whether to enable or disable bluetooth tethering
+ *
+ * @deprecated Use {@link #requestTetheredInterface} with
+ * {@link TetheredInterfaceCallback} instead.
* @hide
*/
@SystemApi
@@ -462,6 +515,7 @@ public final class BluetoothPan implements BluetoothProfile {
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
android.Manifest.permission.TETHER_PRIVILEGED,
})
+ @Deprecated
public void setBluetoothTethering(boolean value) {
String pkgName = mContext.getOpPackageName();
if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
@@ -472,12 +526,72 @@ public final class BluetoothPan implements BluetoothProfile {
} else if (isEnabled()) {
try {
final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setBluetoothTethering(value, mAttributionSource, recv);
+ service.setBluetoothTethering(null, value, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ } catch (RemoteException | TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ }
+ }
+ }
+
+ /**
+ * Turns on Bluetooth tethering.
+ *
+ * <p>When one or more devices are connected, the PAN service will trigger
+ * {@link TetheredInterfaceCallback#onAvailable} to inform the caller that
+ * it is ready to tether. On the contrary, when all devices have been disconnected,
+ * the PAN service will trigger {@link TetheredInterfaceCallback#onUnavailable}.
+ * <p>To turn off Bluetooth tethering, the caller must use
+ * {@link TetheredInterfaceRequest#release} method.
+ *
+ * @param executor thread to execute callback methods
+ * @param callback is the tethering callback to indicate PAN service is ready
+ * or not to tether to one or more devices
+ *
+ * @return new instance of {@link TetheredInterfaceRequest} which can be
+ * used to turn off Bluetooth tethering or {@code null} if service
+ * is not enabled
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ })
+ @Nullable
+ public TetheredInterfaceRequest requestTetheredInterface(
+ @NonNull final Executor executor,
+ @NonNull final TetheredInterfaceCallback callback) {
+ Objects.requireNonNull(callback, "Callback must be non-null");
+ Objects.requireNonNull(executor, "Executor must be non-null");
+ final IBluetoothPan service = getService();
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ } else if (isEnabled()) {
+ final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
+ @Override
+ public void onAvailable(String iface) {
+ executor.execute(() -> callback.onAvailable(iface));
+ }
+
+ @Override
+ public void onUnavailable() {
+ executor.execute(() -> callback.onUnavailable());
+ }
+ };
+ try {
+ final SynchronousResultReceiver recv = new SynchronousResultReceiver();
+ service.setBluetoothTethering(cbInternal, true, mAttributionSource, recv);
recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ return new BluetoothTetheredInterfaceRequest(service, cbInternal);
} catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
}
}
+ return null;
}
/**