15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)package org.chromium.media; 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.app.PendingIntent; 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.content.BroadcastReceiver; 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.content.Context; 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.content.Intent; 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.content.IntentFilter; 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.hardware.usb.UsbConstants; 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.hardware.usb.UsbDevice; 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.hardware.usb.UsbInterface; 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.hardware.usb.UsbManager; 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.base.CalledByNative; 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.base.JNINamespace; 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.ArrayList; 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.HashSet; 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.List; 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.Map; 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.Set; 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/** 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Owned by its native counterpart declared in 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * usb_midi_device_factory_android.h. Refer to that class for general comments. 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)@JNINamespace("media") 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class UsbMidiDeviceFactoryAndroid { 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * The UsbManager of this system. 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private UsbManager mUsbManager; 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * A BroadcastReceiver for USB device permission requests. 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private BroadcastReceiver mReceiver; 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Accessible USB-MIDI devices got so far. 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private final List<UsbMidiDeviceAndroid> mDevices = new ArrayList<UsbMidiDeviceAndroid>(); 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Devices whose access permission requested but not resolved so far. 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private Set<UsbDevice> mRequestedDevices; 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * The identifier of this factory. 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private long mNativePointer; 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private static final String ACTION_USB_PERMISSION = 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "org.chromium.media.USB_PERMISSION"; 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Constructs a UsbMidiDeviceAndroid. 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param nativePointer The native pointer to which the created factory is associated. 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UsbMidiDeviceFactoryAndroid(long nativePointer) { 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mNativePointer = nativePointer; 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Constructs a UsbMidiDeviceAndroid. 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * @param nativePointer The native pointer to which the created factory is associated. 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @CalledByNative 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static UsbMidiDeviceFactoryAndroid create(long nativePointer) { 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return new UsbMidiDeviceFactoryAndroid(nativePointer); 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Enumerates USB-MIDI devices. 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * If there are devices having USB-MIDI interfaces, this function requests permission for 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * accessing the device to the user. 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * When the permission request is accepted or rejected onRequestDone will be called. 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * If there are no USB-MIDI interfaces, this function returns false. 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * @return true if some permission requests are in progress. 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @CalledByNative 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) boolean enumerateDevices(Context context) { 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Map<String, UsbDevice> devices = mUsbManager.getDeviceList(); 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PendingIntent pendingIntent = PendingIntent.getBroadcast( 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) context, 0, new Intent(ACTION_USB_PERMISSION), 0); 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mRequestedDevices = new HashSet<UsbDevice>(); 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (UsbDevice device : devices.values()) { 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) boolean found = false; 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int i = 0; i < device.getInterfaceCount() && !found; ++i) { 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UsbInterface iface = device.getInterface(i); 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO && 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iface.getInterfaceSubclass() == UsbMidiDeviceAndroid.MIDI_SUBCLASS) { 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found = true; 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (found) { 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mUsbManager.requestPermission(device, pendingIntent); 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mRequestedDevices.add(device); 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (mRequestedDevices.isEmpty()) { 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // No USB-MIDI devices are found. 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mReceiver = new BroadcastReceiver() { 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public void onReceive(Context context, Intent intent) { 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ACTION_USB_PERMISSION.equals(intent.getAction())) { 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) onRequestDone(context, intent); 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }; 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) context.registerReceiver(mReceiver, filter); 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Called when the user accepts or rejects the permission request requested by 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * EnumerateDevices. 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * If all permission requests are responded, this function calls 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * nativeOnUsbMidiDeviceRequestDone with the accessible USB-MIDI devices. 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void onRequestDone(Context context, Intent intent) { 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!mRequestedDevices.contains(device)) { 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We are not interested in the device. 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mRequestedDevices.remove(device); 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The request was rejected. 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device = null; 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (device != null) { 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Now we can add the device. 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mDevices.add(new UsbMidiDeviceAndroid(mUsbManager, device)); 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (mRequestedDevices.isEmpty()) { 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // All requests are done. 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) context.unregisterReceiver(mReceiver); 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (mNativePointer != 0) { 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) nativeOnUsbMidiDeviceRequestDone(mNativePointer, mDevices.toArray()); 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Disconnects the native object. 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @CalledByNative 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void close() { 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mNativePointer = 0; 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private static native void nativeOnUsbMidiDeviceRequestDone( 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) long nativeUsbMidiDeviceFactoryAndroid, Object[] devices); 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 166