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

Commit 3b7b0a7c authored by Sal Savage's avatar Sal Savage Committed by Automerger Merge Worker
Browse files

Disconnect and reconnect the OBEX session on change path am: 8e8221af

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Bluetooth/+/10777717

Change-Id: Iadd027a47a2059b0e103f8f697c99160c1d67e76
parents 3bf8eb44 8e8221af
Loading
Loading
Loading
Loading
+80 −4
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ public class AvrcpBipClient {
    private static final int CONNECT = 0;
    private static final int DISCONNECT = 1;
    private static final int REQUEST = 2;
    private static final int REFRESH_OBEX_SESSION = 3;

    private final Handler mHandler;
    private final HandlerThread mThread;
@@ -140,6 +141,24 @@ public class AvrcpBipClient {
        mHandler.obtainMessage(CONNECT).sendToTarget();
    }

    /**
     * Refreshes this client's OBEX session
     */
    public void refreshSession() {
        debug("Refresh client session");
        if (!isConnected()) {
            error("Tried to do a reconnect operation on a client that is not connected");
            return;
        }
        try {
            mHandler.obtainMessage(REFRESH_OBEX_SESSION).sendToTarget();
        } catch (IllegalStateException e) {
            // Means we haven't been started or we're already stopped. Doing this makes this call
            // always safe no matter the state.
            return;
        }
    }

    /**
     * Safely disconnects the client from the server
     */
@@ -173,6 +192,15 @@ public class AvrcpBipClient {
        return getState() == BluetoothProfile.STATE_CONNECTED;
    }

    /**
     * Return the L2CAP PSM used to connect to the server.
     *
     * @return The L2CAP PSM
     */
    public int getL2capPsm() {
        return mPsm;
    }

    /**
     * Retrieve the image properties associated with the given imageHandle
     */
@@ -239,18 +267,54 @@ public class AvrcpBipClient {
            int responseCode = headerSet.getResponseCode();
            if (responseCode == ResponseCodes.OBEX_HTTP_OK) {
                setConnectionState(BluetoothProfile.STATE_CONNECTED);
                debug("Connection established");
            } else {
                error("Error connecting, code: " + responseCode);
                disconnect();
            }
            debug("Connection established");

        } catch (IOException e) {
            error("Exception while connecting to AVRCP BIP server", e);
            disconnect();
        }
    }

    /**
     * Disconnect and reconnect the OBEX session.
     */
    private synchronized void refreshObexSession() {
        if (mSession == null) return;

        try {
            setConnectionState(BluetoothProfile.STATE_DISCONNECTING);
            mSession.disconnect(null);
            debug("Disconnected from OBEX session");
        } catch (IOException e) {
            error("Exception while disconnecting from AVRCP BIP server", e);
            disconnect();
            return;
        }

        try {
            setConnectionState(BluetoothProfile.STATE_CONNECTING);

            HeaderSet headerSet = new HeaderSet();
            headerSet.setHeader(HeaderSet.TARGET, BLUETOOTH_UUID_AVRCP_COVER_ART);

            headerSet = mSession.connect(headerSet);
            int responseCode = headerSet.getResponseCode();
            if (responseCode == ResponseCodes.OBEX_HTTP_OK) {
                setConnectionState(BluetoothProfile.STATE_CONNECTED);
                debug("Reconnection established");
            } else {
                error("Error reconnecting, code: " + responseCode);
                disconnect();
            }
        } catch (IOException e) {
            error("Exception while reconnecting to AVRCP BIP server", e);
            disconnect();
        }
    }

    /**
     * Permanently disconnects this client from the remote device's BIP server and notifies of the
     * new connection status.
@@ -262,17 +326,23 @@ public class AvrcpBipClient {

            try {
                mSession.disconnect(null);
                debug("Disconnected from OBEX session");
            } catch (IOException e) {
                error("Exception while disconnecting from AVRCP BIP server: " + e.toString());
            }

            try {
                mSession.close();
                mTransport.close();
                mSocket.close();
                debug("Closed underlying session, transport and socket");
            } catch (IOException e) {
                error("Exception while closing AVRCP BIP session: " + e.toString());
                error("Exception while closing AVRCP BIP session: ", e);
            }

            mSession = null;
            mTransport = null;
            mSocket = null;
        }
        setConnectionState(BluetoothProfile.STATE_DISCONNECTED);
    }
@@ -312,7 +382,7 @@ public class AvrcpBipClient {
            case BipRequest.TYPE_GET_IMAGE:
                imageHandle = ((RequestGetImage) request).getImageHandle();
                BipImage image = ((RequestGetImage) request).getImage();
                mCallback.onGetImageComplete(responseCode, imageHandle, image); // TODO: add handle
                mCallback.onGetImageComplete(responseCode, imageHandle, image);
                break;
        }
    }
@@ -344,6 +414,12 @@ public class AvrcpBipClient {
                    }
                    break;

                case REFRESH_OBEX_SESSION:
                    if (inst.isConnected()) {
                        inst.refreshObexSession();
                    }
                    break;

                case REQUEST:
                    if (inst.isConnected()) {
                        inst.executeRequest((BipRequest) msg.obj);
+14 −1
Original line number Diff line number Diff line
@@ -303,12 +303,21 @@ class AvrcpControllerStateMachine extends StateMachine {

    synchronized void connectCoverArt() {
        // Called from "connected" state, which assumes either control or browse is connected
        if (mCoverArtManager != null && mCoverArtPsm != 0) {
        if (mCoverArtManager != null && mCoverArtPsm != 0
                && mCoverArtManager.getState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
            logD("Attempting to connect to AVRCP BIP, psm: " + mCoverArtPsm);
            mCoverArtManager.connect(mDevice, /* psm */ mCoverArtPsm);
        }
    }

    synchronized void refreshCoverArt() {
        if (mCoverArtManager != null && mCoverArtPsm != 0
                && mCoverArtManager.getState(mDevice) == BluetoothProfile.STATE_CONNECTED) {
            logD("Attempting to refresh AVRCP BIP OBEX session, psm: " + mCoverArtPsm);
            mCoverArtManager.refreshSession(mDevice);
        }
    }

    synchronized void disconnectCoverArt() {
        // Safe to call even if we're not connected
        if (mCoverArtManager != null) {
@@ -724,6 +733,10 @@ class AvrcpControllerStateMachine extends StateMachine {
                    mBrowseTree.setCurrentBrowsedFolder(mNextStep.getID());
                    mBrowseTree.getCurrentBrowsedFolder().setExpectedChildren(msg.arg1);

                    // AVRCP Specification says, if we're not database aware, we must disconnect and
                    // reconnect our BIP client each time we successfully change path
                    refreshCoverArt();

                    if (mAbort) {
                        transitionTo(mConnected);
                    } else {
+32 −5
Original line number Diff line number Diff line
@@ -106,19 +106,36 @@ public class AvrcpCoverArtManager {
        return true;
    }

    /**
     * Refresh the OBEX session of a connected client
     *
     * @param device The remote Bluetooth device you wish to refresh
     * @return True if the refresh is successfully queued, False otherwise.
     */
    public synchronized boolean refreshSession(BluetoothDevice device) {
        debug("Refresh OBEX session for " + device.getAddress());
        AvrcpBipClient client = getClient(device);
        if (client == null) {
            warn("No client for " + device.getAddress());
            return false;
        }
        client.refreshSession();
        return true;
    }

    /**
     * Disconnect from a remote device's BIP Image Pull Server
     *
     * @param device The remote Bluetooth device you wish to connect to
     * @return True if the connection is successfully queued, False otherwise.
     * @param device The remote Bluetooth device you wish to disconnect from
     * @return True if the disconnection is successfully queued, False otherwise.
     */
    public synchronized boolean disconnect(BluetoothDevice device) {
        debug("Disconnect " + device.getAddress());
        if (!mClients.containsKey(device)) {
        AvrcpBipClient client = getClient(device);
        if (client == null) {
            warn("No client for " + device.getAddress());
            return false;
        }
        AvrcpBipClient client = getClient(device);
        client.shutdown();
        mClients.remove(device);
        mCoverArtStorage.removeImagesForDevice(device);
@@ -145,7 +162,7 @@ public class AvrcpCoverArtManager {
     * @return Connection status, based on BluetoothProfile.STATE_* constants
     */
    public int getState(BluetoothDevice device) {
        AvrcpBipClient client = mClients.get(device);
        AvrcpBipClient client = getClient(device);
        if (client == null) return BluetoothProfile.STATE_DISCONNECTED;
        return client.getState();
    }
@@ -262,11 +279,21 @@ public class AvrcpCoverArtManager {
        public void onConnectionStateChanged(int oldState, int newState) {
            debug(mDevice.getAddress() + ": " + oldState + " -> " + newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // The spec says handles are only good for the life an an OBEX connection. If we're
                // refreshing it, then we need to clear out our storage since its handle mapped.
                mCoverArtStorage.removeImagesForDevice(mDevice);

                // Once we're connected fetch the current metadata again in case the target has an
                // image handle they can now give us
                mService.getCurrentMetadataNative(Utils.getByteAddress(mDevice));
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                AvrcpBipClient client = getClient(mDevice);
                boolean shouldReconnect = (client != null);
                disconnect(mDevice);
                if (shouldReconnect) {
                    debug("Disconnect was not expected by us. Attempt to reconnect.");
                    connect(mDevice, client.getL2capPsm());
                }
            }
        }