Add BLE MIDI peripheral connection to standard BT connect UI

Bug: 25689266
Test: Connect to various BT MIDI peripherals and test function
with software synthesizer (DRC)

Change-Id: I1df2f3bfbc6302eb9d139546e825f2eb9b4abdd5
This commit is contained in:
Paul McLean
2021-11-30 14:16:01 -07:00
parent dbbc6fc44b
commit fff1797319
4 changed files with 114 additions and 1 deletions

View File

@@ -99,6 +99,12 @@ public class MidiFramer extends MidiReceiver {
}
} else { // data byte
if (!mInSysEx) {
// Hack to avoid crashing if we start parsing in the middle
// of a data stream
if (mNeeded <= 0) {
break;
}
mBuffer[mCount++] = currentByte;
if (--mNeeded == 0) {
if (mRunningStatus != 0) {

View File

@@ -31,12 +31,15 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
// BLE-MIDI
/**
* This class is the public application interface to the MIDI service.
*/
@@ -399,9 +402,11 @@ public final class MidiManager {
final OnDeviceOpenedListener listenerF = listener;
final Handler handlerF = handler;
Log.d(TAG, "openBluetoothDevice() " + bluetoothDevice);
IMidiDeviceOpenCallback callback = new IMidiDeviceOpenCallback.Stub() {
@Override
public void onDeviceOpened(IMidiDeviceServer server, IBinder deviceToken) {
Log.d(TAG, "onDeviceOpened() server:" + server);
MidiDevice device = null;
if (server != null) {
try {
@@ -423,6 +428,15 @@ public final class MidiManager {
}
}
/** @hide */ // for now
public void closeBluetoothDevice(@NonNull MidiDevice midiDevice) {
try {
midiDevice.close();
} catch (IOException ex) {
Log.e(TAG, "Exception closing BLE-MIDI device" + ex);
}
}
/** @hide */
public MidiDeviceServer createDeviceServer(MidiReceiver[] inputPortReceivers,
int numOutputPorts, String[] inputPortNames, String[] outputPortNames,

View File

@@ -24,6 +24,7 @@ import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.midi.MidiDevice;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceServer;
import android.media.midi.MidiDeviceStatus;
@@ -63,6 +64,7 @@ public final class BluetoothMidiDevice {
"00002902-0000-1000-8000-00805f9b34fb");
private final BluetoothDevice mBluetoothDevice;
private final Context mContext;
private final BluetoothMidiService mService;
private final MidiManager mMidiManager;
private MidiReceiver mOutputReceiver;
@@ -136,6 +138,8 @@ public final class BluetoothMidiDevice {
// switch to receiving notifications
mBluetoothGatt.readCharacteristic(characteristic);
}
openBluetoothDevice(mBluetoothDevice);
}
} else {
Log.e(TAG, "onServicesDiscovered received: " + status);
@@ -249,6 +253,7 @@ public final class BluetoothMidiDevice {
mBluetoothGatt = mBluetoothDevice.connectGatt(context, false, mGattCallback);
mContext = context;
mMidiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
Bundle properties = new Bundle();
@@ -310,6 +315,18 @@ public final class BluetoothMidiDevice {
}
}
void openBluetoothDevice(BluetoothDevice btDevice) {
Log.d(TAG, "openBluetoothDevice() device: " + btDevice);
MidiManager midiManager = mContext.getSystemService(MidiManager.class);
midiManager.openBluetoothDevice(btDevice,
new MidiManager.OnDeviceOpenedListener() {
@Override
public void onDeviceOpened(MidiDevice device) {
}
}, null);
}
public IBinder getBinder() {
return mDeviceServer.asBinder();
}

View File

@@ -18,9 +18,11 @@ package com.android.server.midi;
import android.annotation.NonNull;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -33,6 +35,7 @@ import android.media.midi.IMidiDeviceListener;
import android.media.midi.IMidiDeviceOpenCallback;
import android.media.midi.IMidiDeviceServer;
import android.media.midi.IMidiManager;
import android.media.midi.MidiDevice;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceService;
import android.media.midi.MidiDeviceStatus;
@@ -55,6 +58,7 @@ import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
@@ -96,9 +100,12 @@ public class MidiService extends IMidiManager.Stub {
= new HashMap<MidiDeviceInfo, Device>();
// list of all Bluetooth devices, keyed by BluetoothDevice
private final HashMap<BluetoothDevice, Device> mBluetoothDevices
private final HashMap<BluetoothDevice, Device> mBluetoothDevices
= new HashMap<BluetoothDevice, Device>();
private final HashMap<BluetoothDevice, MidiDevice> mBleMidiDeviceMap =
new HashMap<BluetoothDevice, MidiDevice>();
// list of all devices, keyed by IMidiDeviceServer
private final HashMap<IBinder, Device> mDevicesByServer = new HashMap<IBinder, Device>();
@@ -569,10 +576,45 @@ public class MidiService extends IMidiManager.Stub {
}
}
private final BroadcastReceiver mBleMidiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
Log.w(TAG, "MidiService, action is null");
return;
}
switch (action) {
case BluetoothDevice.ACTION_ACL_CONNECTED: {
Log.d(TAG, "ACTION_ACL_CONNECTED");
BluetoothDevice btDevice =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
openBluetoothDevice(btDevice);
}
break;
case BluetoothDevice.ACTION_ACL_DISCONNECTED: {
Log.d(TAG, "ACTION_ACL_DISCONNECTED");
BluetoothDevice btDevice =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
closeBluetoothDevice(btDevice);
}
break;
}
}
};
public MidiService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
// Setup broadcast receivers
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
context.registerReceiver(mBleMidiReceiver, filter);
mBluetoothServiceUid = -1;
}
@@ -701,9 +743,43 @@ public class MidiService extends IMidiManager.Stub {
}
}
private void openBluetoothDevice(BluetoothDevice bluetoothDevice) {
Log.d(TAG, "openBluetoothDevice() device: " + bluetoothDevice);
MidiManager midiManager = mContext.getSystemService(MidiManager.class);
midiManager.openBluetoothDevice(bluetoothDevice,
new MidiManager.OnDeviceOpenedListener() {
@Override
public void onDeviceOpened(MidiDevice device) {
synchronized (mBleMidiDeviceMap) {
mBleMidiDeviceMap.put(bluetoothDevice, device);
}
}
}, null);
}
private void closeBluetoothDevice(BluetoothDevice bluetoothDevice) {
Log.d(TAG, "closeBluetoothDevice() device: " + bluetoothDevice);
MidiDevice midiDevice;
synchronized (mBleMidiDeviceMap) {
midiDevice = mBleMidiDeviceMap.remove(bluetoothDevice);
}
if (midiDevice != null) {
try {
midiDevice.close();
} catch (IOException ex) {
Log.e(TAG, "Exception closing BLE-MIDI device" + ex);
}
}
}
@Override
public void openBluetoothDevice(IBinder token, BluetoothDevice bluetoothDevice,
IMidiDeviceOpenCallback callback) {
Log.d(TAG, "openBluetoothDevice()");
Client client = getClient(token);
if (client == null) return;