Bluetooth A2DP suspend/resume functionality
Change-Id: I8366852fa9b6ff9dacf18db00ea1c2be0c00ff34
This commit is contained in:
committed by
android-build SharedAccount
parent
30ef37ffb7
commit
f92c106c40
@@ -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.
|
/** Check if a specified A2DP sink is connected.
|
||||||
* @param device Remote BT device.
|
* @param device Remote BT device.
|
||||||
* @return True if connected (or playing), false otherwise and on error.
|
* @return True if connected (or playing), false otherwise and on error.
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
interface IBluetoothA2dp {
|
interface IBluetoothA2dp {
|
||||||
boolean connectSink(in BluetoothDevice device);
|
boolean connectSink(in BluetoothDevice device);
|
||||||
boolean disconnectSink(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
|
BluetoothDevice[] getConnectedSinks(); // change to Set<> once AIDL supports
|
||||||
int getSinkState(in BluetoothDevice device);
|
int getSinkState(in BluetoothDevice device);
|
||||||
boolean setSinkPriority(in BluetoothDevice device, int priority);
|
boolean setSinkPriority(in BluetoothDevice device, int priority);
|
||||||
|
|||||||
@@ -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() {
|
public synchronized BluetoothDevice[] getConnectedSinks() {
|
||||||
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
|
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
|
||||||
Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
|
Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
|
||||||
@@ -445,5 +487,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
|
|||||||
private native void cleanupNative();
|
private native void cleanupNative();
|
||||||
private synchronized native boolean connectSinkNative(String path);
|
private synchronized native boolean connectSinkNative(String path);
|
||||||
private synchronized native boolean disconnectSinkNative(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);
|
private synchronized native Object []getSinkPropertiesNative(String path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,38 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
|
|||||||
return JNI_FALSE;
|
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
|
#ifdef HAVE_BLUETOOTH
|
||||||
DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
|
DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
|
||||||
DBusError err;
|
DBusError err;
|
||||||
@@ -215,6 +247,8 @@ static JNINativeMethod sMethods[] = {
|
|||||||
/* Bluez audio 4.40 API */
|
/* Bluez audio 4.40 API */
|
||||||
{"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative},
|
{"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative},
|
||||||
{"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative},
|
{"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;",
|
{"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
|
||||||
(void *)getSinkPropertiesNative},
|
(void *)getSinkPropertiesNative},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user