MidiManager: Add USB peripheral MIDI support
This allows the android device to appear as a USB MIDI device to
a USB host (like a Mac or a PC) using the f_midi USB gadget driver.
Change-Id: I14f1ba73bcce2c894e77efb8810beac4ffe246d8
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f64ef87..f283051 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -68,6 +68,8 @@
* accessory function is enabled
* <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
* audio source function is enabled
+ * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the
+ * MIDI function is enabled
* </ul>
*
* {@hide}
@@ -188,6 +190,14 @@
public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
/**
+ * Name of the MIDI USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_MIDI = "midi";
+
+ /**
* Name of the Accessory USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f51e82c9..efdc3c8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5188,4 +5188,9 @@
<string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
<string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
+ <!-- Manufacturer name for USB MIDI Peripheral port -->
+ <string name="usb_midi_peripheral_manufacturer_name">Android</string>
+ <!-- Model name for USB MIDI Peripheral port -->
+ <string name="usb_midi_peripheral_model_name">USB Peripheral Port</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b04349e..607744f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2156,4 +2156,7 @@
<java-symbol type="bool" name="config_use_sim_language_file" />
<java-symbol type="bool" name="config_LTE_eri_for_network_name" />
<java-symbol type="bool" name="config_defaultInTouchMode" />
+
+ <java-symbol type="string" name="usb_midi_peripheral_manufacturer_name" />
+ <java-symbol type="string" name="usb_midi_peripheral_model_name" />
</resources>
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 01a044e..ce3b6e3 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -20,12 +20,15 @@
import android.alsa.AlsaDevicesParser;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.media.AudioSystem;
import android.media.IAudioService;
+import android.midi.MidiDeviceInfo;
import android.os.FileObserver;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -73,6 +76,9 @@
private UsbAudioDevice mSelectedAudioDevice = null;
+ // UsbMidiDevice for USB peripheral mode (gadget) device
+ private UsbMidiDevice mPeripheralMidiDevice = null;
+
private final class AlsaDevice {
public static final int TYPE_UNKNOWN = 0;
public static final int TYPE_PLAYBACK = 1;
@@ -391,7 +397,17 @@
int device = mDevicesParser.getDefaultDeviceNum(addedCard);
AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI);
if (alsaDevice != null) {
- UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, usbDevice,
+ Bundle properties = new Bundle();
+ properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER,
+ usbDevice.getManufacturerName());
+ properties.putString(MidiDeviceInfo.PROPERTY_MODEL, usbDevice.getProductName());
+ properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+ usbDevice.getSerialNumber());
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, alsaDevice.mDevice);
+ properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
+
+ UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
alsaDevice.mCard, alsaDevice.mDevice);
if (usbMidiDevice != null) {
mMidiDevices.put(usbDevice, usbMidiDevice);
@@ -437,6 +453,23 @@
}
}
+ /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {
+ if (enabled) {
+ Bundle properties = new Bundle();
+ Resources r = mContext.getResources();
+ properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
+ com.android.internal.R.string.usb_midi_peripheral_manufacturer_name));
+ properties.putString(MidiDeviceInfo.PROPERTY_MODEL, r.getString(
+ com.android.internal.R.string.usb_midi_peripheral_model_name));
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
+ mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
+ } else if (mPeripheralMidiDevice != null) {
+ IoUtils.closeQuietly(mPeripheralMidiDevice);
+ mPeripheralMidiDevice = null;
+ }
+ }
+
//
// Devices List
//
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1426551..2fb6dbf 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -31,6 +31,7 @@
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.media.AudioManager;
+import android.midi.MidiDeviceInfo;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
@@ -85,6 +86,8 @@
"/sys/class/android_usb/android0/f_rndis/ethaddr";
private static final String AUDIO_SOURCE_PCM_PATH =
"/sys/class/android_usb/android0/f_audio_source/pcm";
+ private static final String MIDI_ALSA_PATH =
+ "/sys/class/android_usb/android0/f_midi/alsa";
private static final int MSG_UPDATE_STATE = 0;
private static final int MSG_ENABLE_ADB = 1;
@@ -124,6 +127,7 @@
private boolean mUseUsbNotification;
private boolean mAdbEnabled;
private boolean mAudioSourceEnabled;
+ private boolean mMidiEnabled;
private Map<String, List<Pair<String, String>>> mOemModeMap;
private String[] mAccessoryStrings;
private UsbDebuggingManager mDebuggingManager;
@@ -618,6 +622,31 @@
}
}
+ private void updateMidiFunction() {
+ boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
+ if (enabled != mMidiEnabled) {
+ int card = -1;
+ int device = -1;
+
+ if (enabled) {
+ Scanner scanner = null;
+ try {
+ scanner = new Scanner(new File(MIDI_ALSA_PATH));
+ card = scanner.nextInt();
+ device = scanner.nextInt();
+ } catch (FileNotFoundException e) {
+ Slog.e(TAG, "could not open MIDI PCM file", e);
+ } finally {
+ if (scanner != null) {
+ scanner.close();
+ }
+ }
+ }
+ mUsbAlsaManager.setPeripheralMidiState(enabled, card, device);
+ mMidiEnabled = enabled;
+ }
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -636,6 +665,7 @@
if (mBootCompleted) {
updateUsbState();
updateAudioSourceFunction();
+ updateMidiFunction();
}
break;
case MSG_ENABLE_ADB:
@@ -651,6 +681,7 @@
updateAdbNotification();
updateUsbState();
updateAudioSourceFunction();
+ updateMidiFunction();
break;
case MSG_BOOT_COMPLETED:
mBootCompleted = true;
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 0ca52f6..8d44905 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -17,7 +17,6 @@
package com.android.server.usb;
import android.content.Context;
-import android.hardware.usb.UsbDevice;
import android.midi.MidiDeviceInfo;
import android.midi.MidiDeviceServer;
import android.midi.MidiManager;
@@ -50,7 +49,7 @@
// streams for writing to ALSA driver
private final FileOutputStream[] mOutputStreams;
- public static UsbMidiDevice create(Context context, UsbDevice usbDevice, int card, int device) {
+ public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
if (midiManager == null) {
Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
@@ -71,13 +70,6 @@
return null;
}
- Bundle properties = new Bundle();
- properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, usbDevice.getManufacturerName());
- properties.putString(MidiDeviceInfo.PROPERTY_MODEL, usbDevice.getProductName());
- properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER, usbDevice.getSerialNumber());
- properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
- properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
- properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
MidiDeviceServer server = midiManager.createDeviceServer(subDevices, subDevices, properties,
false, MidiDeviceInfo.TYPE_USB);
if (server == null) {