summaryrefslogtreecommitdiff
path: root/wifi/java
diff options
context:
space:
mode:
Diffstat (limited to 'wifi/java')
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java19
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java135
2 files changed, 133 insertions, 21 deletions
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java
index f62bfd451d5e..d2b9be783bca 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java
@@ -64,5 +64,24 @@ public interface SharedConnectivityClientCallback {
* @param status The new status.
*/
void onKnownNetworkConnectionStatusChanged(@NonNull KnownNetworkConnectionStatus status);
+
+ /**
+ * This method is being called when the service is ready to be used.
+ */
+ void onServiceConnected();
+
+ /**
+ * This method is being called when the service is no longer available.
+ */
+ void onServiceDisconnected();
+
+ /**
+ * This method is called when the registration of the callback with the shared connectivity
+ * service failed.
+ *
+ * @param exception The exception received from the system when trying to connect to the
+ * service.
+ */
+ void onRegisterCallbackFailed(@NonNull Exception exception);
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index 8aa369e31ce8..74b42d41d9d1 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -47,6 +47,12 @@ import java.util.concurrent.Executor;
* This class is the library used by consumers of Shared Connectivity data to bind to the service,
* receive callbacks from, and send user actions to the service.
*
+ * The methods {@link #connectTetherNetwork}, {@link #disconnectTetherNetwork},
+ * {@link #connectKnownNetwork} and {@link #forgetKnownNetwork} are not valid and will return false
+ * if not called between {@link SharedConnectivityClientCallback#onServiceConnected()}
+ * and {@link SharedConnectivityClientCallback#onServiceDisconnected()} or if
+ * {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} was called.
+ *
* @hide
*/
@SystemApi
@@ -135,6 +141,10 @@ public class SharedConnectivityManager {
private ISharedConnectivityService mService;
private final Map<SharedConnectivityClientCallback, SharedConnectivityCallbackProxy>
mProxyMap = new HashMap<>();
+ private final Map<SharedConnectivityClientCallback, SharedConnectivityCallbackProxy>
+ mCallbackProxyCache = new HashMap<>();
+ // Used for testing
+ private final ServiceConnection mServiceConnection;
/**
* Creates a new instance of {@link SharedConnectivityManager}.
@@ -164,23 +174,58 @@ public class SharedConnectivityManager {
private SharedConnectivityManager(@NonNull Context context, String servicePackageName,
String serviceIntentAction) {
- ServiceConnection serviceConnection = new ServiceConnection() {
+ mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ISharedConnectivityService.Stub.asInterface(service);
+ if (!mCallbackProxyCache.isEmpty()) {
+ synchronized (mCallbackProxyCache) {
+ mCallbackProxyCache.keySet().forEach(callback -> {
+ registerCallbackInternal(callback, mCallbackProxyCache.get(callback));
+ });
+ mCallbackProxyCache.clear();
+ }
+ }
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.i(TAG, "onServiceDisconnected");
mService = null;
- mProxyMap.clear();
+ if (!mCallbackProxyCache.isEmpty()) {
+ synchronized (mCallbackProxyCache) {
+ mCallbackProxyCache.keySet().forEach(
+ SharedConnectivityClientCallback::onServiceDisconnected);
+ mCallbackProxyCache.clear();
+ }
+ }
+ if (!mProxyMap.isEmpty()) {
+ synchronized (mProxyMap) {
+ mProxyMap.keySet().forEach(
+ SharedConnectivityClientCallback::onServiceDisconnected);
+ mProxyMap.clear();
+ }
+ }
}
};
context.bindService(
new Intent().setPackage(servicePackageName).setAction(serviceIntentAction),
- serviceConnection, Context.BIND_AUTO_CREATE);
+ mServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private void registerCallbackInternal(SharedConnectivityClientCallback callback,
+ SharedConnectivityCallbackProxy proxy) {
+ try {
+ mService.registerCallback(proxy);
+ synchronized (mProxyMap) {
+ mProxyMap.put(callback, proxy);
+ }
+ callback.onServiceConnected();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception in registerCallback", e);
+ callback.onRegisterCallbackFailed(e);
+ }
}
/**
@@ -192,29 +237,45 @@ public class SharedConnectivityManager {
}
/**
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public ServiceConnection getServiceConnection() {
+ return mServiceConnection;
+ }
+
+ /**
* Registers a callback for receiving updates to the list of Tether Networks and Known Networks.
+ * The {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} will be called if the
+ * registration failed.
*
* @param executor The Executor used to invoke the callback.
* @param callback The callback of type {@link SharedConnectivityClientCallback} that is invoked
* when the service updates either the list of Tether Networks or Known
* Networks.
- * @return Returns true if the registration was successful, false otherwise.
*/
- public boolean registerCallback(@NonNull @CallbackExecutor Executor executor,
+ public void registerCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull SharedConnectivityClientCallback callback) {
Objects.requireNonNull(executor, "executor cannot be null");
Objects.requireNonNull(callback, "callback cannot be null");
- if (mService == null || mProxyMap.containsKey(callback)) return false;
- try {
- SharedConnectivityCallbackProxy proxy =
- new SharedConnectivityCallbackProxy(executor, callback);
- mService.registerCallback(proxy);
- mProxyMap.put(callback, proxy);
- } catch (RemoteException e) {
- Log.e(TAG, "Exception in registerCallback", e);
- return false;
+
+ if (mProxyMap.containsKey(callback) || mCallbackProxyCache.containsKey(callback)) {
+ Log.e(TAG, "Callback already registered");
+ callback.onRegisterCallbackFailed(new IllegalStateException(
+ "Callback already registered"));
+ return;
}
- return true;
+
+ SharedConnectivityCallbackProxy proxy =
+ new SharedConnectivityCallbackProxy(executor, callback);
+ if (mService == null) {
+ synchronized (mCallbackProxyCache) {
+ mCallbackProxyCache.put(callback, proxy);
+ }
+ return;
+ }
+ registerCallbackInternal(callback, proxy);
}
/**
@@ -225,10 +286,24 @@ public class SharedConnectivityManager {
public boolean unregisterCallback(
@NonNull SharedConnectivityClientCallback callback) {
Objects.requireNonNull(callback, "callback cannot be null");
- if (mService == null || !mProxyMap.containsKey(callback)) return false;
+
+ if (!mProxyMap.containsKey(callback) && !mCallbackProxyCache.containsKey(callback)) {
+ Log.e(TAG, "Callback not found, cannot unregister");
+ return false;
+ }
+
+ if (mService == null) {
+ synchronized (mCallbackProxyCache) {
+ mCallbackProxyCache.remove(callback);
+ }
+ return true;
+ }
+
try {
mService.unregisterCallback(mProxyMap.get(callback));
- mProxyMap.remove(callback);
+ synchronized (mProxyMap) {
+ mProxyMap.remove(callback);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Exception in unregisterCallback", e);
return false;
@@ -246,7 +321,12 @@ public class SharedConnectivityManager {
* connection was successful.
*/
public boolean connectTetherNetwork(@NonNull TetherNetwork network) {
- if (mService == null) return false;
+ Objects.requireNonNull(network, "Tether network cannot be null");
+
+ if (mService == null) {
+ return false;
+ }
+
try {
mService.connectTetherNetwork(network);
} catch (RemoteException e) {
@@ -264,7 +344,10 @@ public class SharedConnectivityManager {
* disconnection was successful.
*/
public boolean disconnectTetherNetwork() {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
+
try {
mService.disconnectTetherNetwork();
} catch (RemoteException e) {
@@ -284,7 +367,12 @@ public class SharedConnectivityManager {
* connection was successful.
*/
public boolean connectKnownNetwork(@NonNull KnownNetwork network) {
- if (mService == null) return false;
+ Objects.requireNonNull(network, "Known network cannot be null");
+
+ if (mService == null) {
+ return false;
+ }
+
try {
mService.connectKnownNetwork(network);
} catch (RemoteException e) {
@@ -302,7 +390,12 @@ public class SharedConnectivityManager {
* forget action was successful.
*/
public boolean forgetKnownNetwork(@NonNull KnownNetwork network) {
- if (mService == null) return false;
+ Objects.requireNonNull(network, "Known network cannot be null");
+
+ if (mService == null) {
+ return false;
+ }
+
try {
mService.forgetKnownNetwork(network);
} catch (RemoteException e) {