diff options
Diffstat (limited to 'wifi/java')
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) { |