Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e8fc027 authored by Isaac Katzenelson's avatar Isaac Katzenelson
Browse files

Notify client via callback when service is connected.

Bug: 268743198
API-Coverage-Bug: 265968015
Test: atest SharedConnectivityManagerTest
Change-Id: Ia71747875e04e587c3f6569fe10332ba93980d59
parent 1a936d17
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -10041,6 +10041,9 @@ package android.net.wifi.sharedconnectivity.app {
  public interface SharedConnectivityClientCallback {
    method public void onKnownNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus);
    method public void onKnownNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>);
    method public void onRegisterCallbackFailed(@NonNull Exception);
    method public void onServiceConnected();
    method public void onServiceDisconnected();
    method public void onSharedConnectivitySettingsChanged(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState);
    method public void onTetherNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus);
    method public void onTetherNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork>);
@@ -10051,7 +10054,7 @@ package android.net.wifi.sharedconnectivity.app {
    method public boolean connectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
    method public boolean disconnectTetherNetwork();
    method public boolean forgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
    method public boolean registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
    method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
    method public boolean unregisterCallback(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
  }
+1 −0
Original line number Diff line number Diff line
@@ -1947,6 +1947,7 @@ package android.net {
package android.net.wifi.sharedconnectivity.app {

  public class SharedConnectivityManager {
    method @Nullable public android.content.ServiceConnection getServiceConnection();
    method public void setService(@Nullable android.os.IInterface);
  }

+19 −0
Original line number Diff line number Diff line
@@ -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);
}
+114 −21
Original line number Diff line number Diff line
@@ -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;
                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);
        }
    }

    /**
@@ -191,30 +236,46 @@ public class SharedConnectivityManager {
        mService = (ISharedConnectivityService) service;
    }

    /**
     * @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 {

        if (mProxyMap.containsKey(callback) || mCallbackProxyCache.containsKey(callback)) {
            Log.e(TAG, "Callback already registered");
            callback.onRegisterCallbackFailed(new IllegalStateException(
                    "Callback already registered"));
            return;
        }

        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 (mService == null) {
            synchronized (mCallbackProxyCache) {
                mCallbackProxyCache.put(callback, proxy);
            }
        return true;
            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));
            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) {
+179 −48

File changed.

Preview size limit exceeded, changes collapsed.