Move USB bus scan to SynthesizerService

This patch moves the scan of the USB bus to the service, while plumbing
the display of the permission dialog to the activity that binds it. Also
a little cleanup of the USB device thread (less logging, using a hacky
timeout to make sure the thread gets shut down properly).
master
Raph Levien 11 years ago
parent a762514187
commit 16e99a3860
  1. 1
      android/.classpath
  2. 60
      android/src/com/levien/synthesizer/android/service/SynthesizerService.java
  3. 46
      android/src/com/levien/synthesizer/android/ui/PianoActivity2.java
  4. 10
      android/src/com/levien/synthesizer/android/usb/UsbMidiDevice.java

@ -8,5 +8,6 @@
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="lib" path="core-lib/libprotobuf.jar"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

@ -19,6 +19,7 @@ package com.levien.synthesizer.android.service;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.annotation.TargetApi;
@ -69,6 +70,7 @@ public class SynthesizerService extends Service {
* Run when the Service is first created.
*/
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public void onCreate() {
Log.d("synth", "service onCreate");
if (androidGlue_ == null) {
@ -98,12 +100,10 @@ public class SynthesizerService extends Service {
}
}
androidGlue_.setPlayState(true);
if (usbDevice_ != null && usbMidiConnection_ == null) {
connectUsbMidi(usbDevice_);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(usbReceiver_, filter);
scanUsbMidi();
}
}
@ -112,6 +112,7 @@ public class SynthesizerService extends Service {
*/
@Override
public void onDestroy() {
Log.d("synth", "service onDestroy");
androidGlue_.setPlayState(false);
setMidiInterface(null, null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
@ -144,6 +145,27 @@ public class SynthesizerService extends Service {
return patchNames_;
}
public boolean connectUsbMidi(UsbDevice device) {
usbDeviceNeedsPermission_ = null;
if (usbDevice_ == device) {
return device != null;
}
UsbInterface intf = device != null ? UsbMidiDevice.findMidiInterface(device) : null;
boolean success = setMidiInterface(device, intf);
usbDevice_ = success ? device : null;
return success;
}
/**
* Call to find out whether there is a device that has been scanned
* but not connected to because of missing permission.
*
* @return Device that needs permission, or null if none.
*/
public UsbDevice usbDeviceNeedsPermission() {
return usbDeviceNeedsPermission_;
}
class AudioParams {
AudioParams(int sr, int bs) {
confident = false;
@ -159,7 +181,7 @@ public class SynthesizerService extends Service {
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
void getJbMr1Params(AudioParams params) {
private void getJbMr1Params(AudioParams params) {
AudioManager audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
String sr = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
String bs = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
@ -180,6 +202,7 @@ public class SynthesizerService extends Service {
// based on experimentation just closing seems more robust
//usbMidiConnection_.releaseInterface(usbMidiInterface_);
}
Log.d("synth", "closing connection " + usbMidiConnection_);
usbMidiConnection_.close();
usbMidiConnection_ = null;
}
@ -205,14 +228,24 @@ public class SynthesizerService extends Service {
return false;
}
// Handles both connect and disconnect actions
public boolean connectUsbMidi(UsbDevice device) {
UsbInterface intf = device != null ? UsbMidiDevice.findMidiInterface(device) : null;
Log.d("synth", "connecting USB");
boolean success = setMidiInterface(device, intf);
Log.d("synth", "connecting USB done");
usbDevice_ = success ? device : null;
return success;
// scan for MIDI devices on the USB bus
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
private void scanUsbMidi() {
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
Log.i("synth", "USB device count=" + deviceList.size());
for (UsbDevice device : deviceList.values()) {
UsbInterface intf = UsbMidiDevice.findMidiInterface(device);
if (intf != null) {
if (usbManager.hasPermission(device)) {
if (connectUsbMidi(device)) {
break;
}
} else {
usbDeviceNeedsPermission_ = device;
}
}
}
}
private final BroadcastReceiver usbReceiver_ = new BroadcastReceiver() {
@ -237,8 +270,9 @@ public class SynthesizerService extends Service {
private static List<String> patchNames_;
// State for USB MIDI keyboard connection
private static UsbDevice usbDevice_;
private UsbDevice usbDevice_;
private UsbDeviceConnection usbMidiConnection_;
private UsbMidiDevice usbMidiDevice_;
private UsbInterface usbMidiInterface_;
private UsbDevice usbDeviceNeedsPermission_;
}

@ -145,32 +145,6 @@ public class PianoActivity2 extends Activity {
connectUsbFromIntent(intent);
}
// scan for MIDI devices on the USB bus
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
private void scanUsbMidi() {
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
Log.i("synth", "USB device count=" + deviceList.size());
for (UsbDevice device : deviceList.values()) {
UsbInterface intf = UsbMidiDevice.findMidiInterface(device);
if (intf != null) {
if (usbManager.hasPermission(device)) {
if (connectUsbMidi(device)) {
break;
}
} else {
synchronized (usbReceiver_) {
if (!permissionRequestPending_) {
permissionRequestPending_ = true;
usbManager.requestPermission(device, permissionIntent_);
}
}
break; // Don't try to connect anything else after perms dialog up
}
}
}
}
boolean connectUsbMidi(UsbDevice device) {
if (synthesizerService_ != null) {
return synthesizerService_.connectUsbMidi(device);
@ -196,9 +170,7 @@ public class PianoActivity2 extends Activity {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
registerReceiver(usbReceiver_, filter);
if (!connectUsbFromIntent(intent)) {
scanUsbMidi();
}
connectUsbFromIntent(intent);
}
private static final String ACTION_USB_PERMISSION = "com.levien.synthesizer.USB_PERSMISSION";
@ -222,10 +194,13 @@ public class PianoActivity2 extends Activity {
public void sendMidiBytes(byte[] buf) {
// TODO: in future we'll want to reflect MIDI to UI (knobs turn, keys press)
synthesizerService_.sendRawMidi(buf);
if (synthesizerService_ != null) {
synthesizerService_.sendRawMidi(buf);
}
}
private ServiceConnection synthesizerConnection_ = new ServiceConnection() {
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public void onServiceConnected(ComponentName className, IBinder service) {
SynthesizerService.LocalBinder binder = (SynthesizerService.LocalBinder)service;
synthesizerService_ = binder.getService();
@ -238,6 +213,17 @@ public class PianoActivity2 extends Activity {
if (usbDevicePending_ != null) {
synthesizerService_.connectUsbMidi(usbDevicePending_);
usbDevicePending_ = null;
} else {
UsbDevice device = synthesizerService_.usbDeviceNeedsPermission();
if (device != null) {
synchronized (usbReceiver_) {
if (!permissionRequestPending_) {
permissionRequestPending_ = true;
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
usbManager.requestPermission(device, permissionIntent_);
}
}
}
}
}
public void onServiceDisconnected(ComponentName className) {

@ -95,10 +95,14 @@ public class UsbMidiDevice {
return;
}
}
final int TIMEOUT = 0;
// Using a timeout here is a hacky workaround to shut down the
// thread. If we could call releaseInterface, that would cause
// the bulkTransfer to return immediately, but that causes other
// problems.
final int TIMEOUT = 1000;
int nBytes = mDeviceConnection.bulkTransfer(mEndpoint, buf, buf.length, TIMEOUT);
if (nBytes < 0) {
Log.e("synth", "bulkTransfer error " + nBytes);
//Log.e("synth", "bulkTransfer error " + nBytes);
// break;
}
for (int i = 0; i < nBytes; i += 4) {
@ -113,7 +117,7 @@ public class UsbMidiDevice {
if (payloadBytes > 0) {
byte[] newBuf = new byte[payloadBytes];
System.arraycopy(buf, i + 1, newBuf, 0, payloadBytes);
Log.d("synth", "sending midi");
//Log.d("synth", "sending midi");
mReceiver.sendMidi(newBuf);
}
}

Loading…
Cancel
Save