UsbMidiDeviceFactoryAndroid.java revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.media; 6 7import android.app.PendingIntent; 8import android.content.BroadcastReceiver; 9import android.content.Context; 10import android.content.Intent; 11import android.content.IntentFilter; 12import android.hardware.usb.UsbConstants; 13import android.hardware.usb.UsbDevice; 14import android.hardware.usb.UsbInterface; 15import android.hardware.usb.UsbManager; 16 17import org.chromium.base.CalledByNative; 18import org.chromium.base.JNINamespace; 19 20import java.util.ArrayList; 21import java.util.HashSet; 22import java.util.List; 23import java.util.Map; 24import java.util.Set; 25 26/** 27 * Owned by its native counterpart declared in 28 * usb_midi_device_factory_android.h. Refer to that class for general comments. 29 */ 30@JNINamespace("media") 31class UsbMidiDeviceFactoryAndroid { 32 /** 33 * The UsbManager of this system. 34 */ 35 private UsbManager mUsbManager; 36 37 /** 38 * A BroadcastReceiver for USB device permission requests. 39 */ 40 private BroadcastReceiver mReceiver; 41 42 /** 43 * Accessible USB-MIDI devices got so far. 44 */ 45 private final List<UsbMidiDeviceAndroid> mDevices = new ArrayList<UsbMidiDeviceAndroid>(); 46 47 /** 48 * Devices whose access permission requested but not resolved so far. 49 */ 50 private Set<UsbDevice> mRequestedDevices; 51 52 /** 53 * The identifier of this factory. 54 */ 55 private long mNativePointer; 56 57 private static final String ACTION_USB_PERMISSION = 58 "org.chromium.media.USB_PERMISSION"; 59 60 /** 61 * Constructs a UsbMidiDeviceAndroid. 62 * @param natviePointer The native pointer to which the created factory is associated. 63 */ 64 UsbMidiDeviceFactoryAndroid(long nativePointer) { 65 mNativePointer = nativePointer; 66 } 67 68 /** 69 * Constructs a UsbMidiDeviceAndroid. 70 * @param nativePointer The native pointer to which the created factory is associated. 71 */ 72 @CalledByNative 73 static UsbMidiDeviceFactoryAndroid create(long nativePointer) { 74 return new UsbMidiDeviceFactoryAndroid(nativePointer); 75 } 76 77 /** 78 * Enumerates USB-MIDI devices. 79 * If there are devices having USB-MIDI interfaces, this function requests permission for 80 * accessing the device to the user. 81 * When the permission request is accepted or rejected onRequestDone will be called. 82 * 83 * If there are no USB-MIDI interfaces, this function returns false. 84 * @return true if some permission requests are in progress. 85 */ 86 @CalledByNative 87 boolean enumerateDevices(Context context) { 88 mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); 89 Map<String, UsbDevice> devices = mUsbManager.getDeviceList(); 90 PendingIntent pendingIntent = PendingIntent.getBroadcast( 91 context, 0, new Intent(ACTION_USB_PERMISSION), 0); 92 mRequestedDevices = new HashSet<UsbDevice>(); 93 for (UsbDevice device : devices.values()) { 94 boolean found = false; 95 for (int i = 0; i < device.getInterfaceCount() && !found; ++i) { 96 UsbInterface iface = device.getInterface(i); 97 if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO && 98 iface.getInterfaceSubclass() == UsbMidiDeviceAndroid.MIDI_SUBCLASS) { 99 found = true; 100 } 101 } 102 if (found) { 103 mUsbManager.requestPermission(device, pendingIntent); 104 mRequestedDevices.add(device); 105 } 106 } 107 if (mRequestedDevices.isEmpty()) { 108 // No USB-MIDI devices are found. 109 return false; 110 } 111 112 IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); 113 mReceiver = new BroadcastReceiver() { 114 public void onReceive(Context context, Intent intent) { 115 if (ACTION_USB_PERMISSION.equals(intent.getAction())) { 116 onRequestDone(context, intent); 117 } 118 } 119 }; 120 context.registerReceiver(mReceiver, filter); 121 return true; 122 } 123 124 /** 125 * Called when the user accepts or rejects the permission request requested by 126 * EnumerateDevices. 127 * If all permission requests are responded, this function calls 128 * nativeOnUsbMidiDeviceRequestDone with the accessible USB-MIDI devices. 129 */ 130 private void onRequestDone(Context context, Intent intent) { 131 UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 132 if (!mRequestedDevices.contains(device)) { 133 // We are not interested in the device. 134 return; 135 } 136 mRequestedDevices.remove(device); 137 if (!intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 138 // The request was rejected. 139 device = null; 140 } 141 if (device != null) { 142 // Now we can add the device. 143 mDevices.add(new UsbMidiDeviceAndroid(mUsbManager, device)); 144 } 145 if (mRequestedDevices.isEmpty()) { 146 // All requests are done. 147 context.unregisterReceiver(mReceiver); 148 if (mNativePointer != 0) { 149 nativeOnUsbMidiDeviceRequestDone(mNativePointer, mDevices.toArray()); 150 } 151 } 152 } 153 154 /** 155 * Disconnects the native object. 156 */ 157 @CalledByNative 158 void close() { 159 mNativePointer = 0; 160 } 161 162 private static native void nativeOnUsbMidiDeviceRequestDone( 163 long nativeUsbMidiDeviceFactoryAndroid, Object[] devices); 164} 165