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

Commit f9bbe1e7 authored by Zhu Lan's avatar Zhu Lan Committed by Nick Pelly
Browse files

Bluetooth A2DP suspend/resume functionality

Change-Id: I8366852fa9b6ff9dacf18db00ea1c2be0c00ff34
parent 4c232c5b
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -133,6 +133,38 @@ public final class BluetoothA2dp {
        }
    }

    /** Initiate suspend from an A2DP sink.
     *  Listen for SINK_STATE_CHANGED_ACTION to find out when
     *  suspend is completed.
     *  @param device Remote BT device.
     *  @return false on immediate error, true otherwise
     *  @hide
     */
    public int suspendSink(BluetoothDevice device) {
        try {
            return mService.suspendSink(device);
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
            return false;
        }
    }

    /** Initiate resume from an suspended A2DP sink.
     *  Listen for SINK_STATE_CHANGED_ACTION to find out when
     *  resume is completed.
     *  @param device Remote BT device.
     *  @return false on immediate error, true otherwise
     *  @hide
     */
    public int resumeSink(BluetoothDevice device) {
        try {
            return mService.resumeSink(device);
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
            return false;
        }
    }

    /** Check if a specified A2DP sink is connected.
     *  @param device Remote BT device.
     *  @return True if connected (or playing), false otherwise and on error.
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.bluetooth.BluetoothDevice;
interface IBluetoothA2dp {
    boolean connectSink(in BluetoothDevice device);
    boolean disconnectSink(in BluetoothDevice device);
    boolean suspendSink(in BluetoothDevice device);
    boolean resumeSink(in BluetoothDevice device);
    BluetoothDevice[] getConnectedSinks();  // change to Set<> once AIDL supports
    int getSinkState(in BluetoothDevice device);
    boolean setSinkPriority(in BluetoothDevice device, int priority);
+44 −0
Original line number Diff line number Diff line
@@ -325,6 +325,48 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
        }
    }

    public synchronized boolean suspendSink(BluetoothDevice device) {
        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                            "Need BLUETOOTH_ADMIN permission");
        if (DBG) log("suspendSink(" + device + ")");
        if (device == null || mAudioDevices == null) {
            return false;
        }
        String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
        if (path == null) {
            return false;
        }
        switch (mAudioDevices.get(device)) {
        case BluetoothA2dp.STATE_CONNECTED:
            return true;
        case BluetoothA2dp.STATE_PLAYING:
            return suspendSinkNative(path);
        default:
            return false;
        }
    }

    public synchronized boolean resumeSink(BluetoothDevice device) {
        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                            "Need BLUETOOTH_ADMIN permission");
        if (DBG) log("resumeSink(" + device + ")");
        if (device == null || mAudioDevices == null) {
            return false;
        }
        String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
        if (path == null) {
            return false;
        }
        switch (mAudioDevices.get(device)) {
        case BluetoothA2dp.STATE_PLAYING:
            return true;
        case BluetoothA2dp.STATE_CONNECTED:
            return resumeSinkNative(path);
        default:
            return false;
        }
    }

    public synchronized BluetoothDevice[] getConnectedSinks() {
        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
@@ -445,5 +487,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
    private native void cleanupNative();
    private synchronized native boolean connectSinkNative(String path);
    private synchronized native boolean disconnectSinkNative(String path);
    private synchronized native boolean suspendSinkNative(String path);
    private synchronized native boolean resumeSinkNative(String path);
    private synchronized native Object []getSinkPropertiesNative(String path);
}
+34 −0
Original line number Diff line number Diff line
@@ -163,6 +163,38 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
    return JNI_FALSE;
}

static jboolean suspendSinkNative(JNIEnv *env, jobject object,
                                     jstring path) {
#ifdef HAVE_BLUETOOTH
    LOGV(__FUNCTION__);
    if (nat) {
        const char *c_path = env->GetStringUTFChars(path, NULL);
        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
                           c_path, "org.bluez.audio.Sink", "Suspend",
                           DBUS_TYPE_INVALID);
        env->ReleaseStringUTFChars(path, c_path);
        return ret ? JNI_TRUE : JNI_FALSE;
    }
#endif
    return JNI_FALSE;
}

static jboolean resumeSinkNative(JNIEnv *env, jobject object,
                                     jstring path) {
#ifdef HAVE_BLUETOOTH
    LOGV(__FUNCTION__);
    if (nat) {
        const char *c_path = env->GetStringUTFChars(path, NULL);
        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
                           c_path, "org.bluez.audio.Sink", "Resume",
                           DBUS_TYPE_INVALID);
        env->ReleaseStringUTFChars(path, c_path);
        return ret ? JNI_TRUE : JNI_FALSE;
    }
#endif
    return JNI_FALSE;
}

#ifdef HAVE_BLUETOOTH
DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
    DBusError err;
@@ -215,6 +247,8 @@ static JNINativeMethod sMethods[] = {
    /* Bluez audio 4.40 API */
    {"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative},
    {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative},
    {"suspendSinkNative", "(Ljava/lang/String;)Z", (void*)suspendSinkNative},
    {"resumeSinkNative", "(Ljava/lang/String;)Z", (void*)resumeSinkNative},
    {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
                                    (void *)getSinkPropertiesNative},
};