From fff1797319f048745fa16725dc57e93742d0bdf3 Mon Sep 17 00:00:00 2001 From: Paul McLean Date: Tue, 30 Nov 2021 14:16:01 -0700 Subject: [PATCH] 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 --- .../com/android/internal/midi/MidiFramer.java | 6 ++ .../java/android/media/midi/MidiManager.java | 14 ++++ .../BluetoothMidiDevice.java | 17 ++++ .../com/android/server/midi/MidiService.java | 78 ++++++++++++++++++- 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/core/java/com/android/internal/midi/MidiFramer.java b/core/java/com/android/internal/midi/MidiFramer.java index 62517fa829532..bf23ad190ef1a 100644 --- a/core/java/com/android/internal/midi/MidiFramer.java +++ b/core/java/com/android/internal/midi/MidiFramer.java @@ -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) { diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java index a049a8891f48f..831649e5bae94 100644 --- a/media/java/android/media/midi/MidiManager.java +++ b/media/java/android/media/midi/MidiManager.java @@ -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, diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java index 2dd9525867b6b..4c3b68958c0f6 100644 --- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java +++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java @@ -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(); } diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java index 715fe6e5f85e2..6e724792b6e9f 100644 --- a/services/midi/java/com/android/server/midi/MidiService.java +++ b/services/midi/java/com/android/server/midi/MidiService.java @@ -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(); // list of all Bluetooth devices, keyed by BluetoothDevice - private final HashMap mBluetoothDevices + private final HashMap mBluetoothDevices = new HashMap(); + private final HashMap mBleMidiDeviceMap = + new HashMap(); + // list of all devices, keyed by IMidiDeviceServer private final HashMap mDevicesByServer = new HashMap(); @@ -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;