blob: c6048e897d41dfdbc0ab484569dcc11e31be7ebf [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.media.midi;
import android.annotation.TargetApi;
import android.content.Context;
import android.media.midi.MidiDevice;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiManager;
import android.os.Build;
import android.os.Handler;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* A Java class implementing media::midi::MidiManagerAndroid functionality.
*/
@JNINamespace("media::midi")
@TargetApi(Build.VERSION_CODES.M)
class MidiManagerAndroid {
/**
* Set true while this instance is being initialized.
*/
private boolean mIsInitializing = true;
/**
* The devices held by this manager.
*/
private final List<MidiDeviceAndroid> mDevices = new ArrayList<>();
/**
* The device information instances which are being initialized.
*/
private final Set<MidiDeviceInfo> mPendingDevices = new HashSet<>();
/**
* The underlying MidiManager.
*/
private final MidiManager mManager;
/**
* Callbacks will run on the message queue associated with this handler.
*/
private final Handler mHandler;
/**
* The associated media::midi::MidiDeviceAndroid instance.
*/
private final long mNativeManagerPointer;
@CalledByNative
/**
* A creation function called by C++.
* @param context
* @param nativeManagerPointer The native pointer to a media::midi::MidiManagerAndroid object.
*/
static MidiManagerAndroid create(Context context, long nativeManagerPointer) {
return new MidiManagerAndroid(context, nativeManagerPointer);
}
/**
* @param context
* @param nativeManagerPointer The native pointer to a media::midi::MidiManagerAndroid object.
*/
MidiManagerAndroid(Context context, long nativeManagerPointer) {
assert ThreadUtils.runningOnUiThread();
mManager = (MidiManager) context.getSystemService(Context.MIDI_SERVICE);
mHandler = new Handler(ThreadUtils.getUiThreadLooper());
mNativeManagerPointer = nativeManagerPointer;
}
/**
* Initializes this object.
* This function must be called right after creation.
*/
@CalledByNative
void initialize() {
mManager.registerDeviceCallback(new MidiManager.DeviceCallback() {
@Override
public void onDeviceAdded(MidiDeviceInfo device) {
MidiManagerAndroid.this.onDeviceAdded(device);
}
@Override
public void onDeviceRemoved(MidiDeviceInfo device) {
MidiManagerAndroid.this.onDeviceRemoved(device);
}
}, mHandler);
MidiDeviceInfo[] infos = mManager.getDevices();
for (final MidiDeviceInfo info : infos) {
mPendingDevices.add(info);
openDevice(info);
}
mHandler.post(new Runnable() {
@Override
public void run() {
if (mPendingDevices.isEmpty() && mIsInitializing) {
nativeOnInitialized(
mNativeManagerPointer, mDevices.toArray(new MidiDeviceAndroid[0]));
mIsInitializing = false;
}
}
});
}
private void openDevice(final MidiDeviceInfo info) {
mManager.openDevice(info, new MidiManager.OnDeviceOpenedListener() {
@Override
public void onDeviceOpened(MidiDevice device) {
MidiManagerAndroid.this.onDeviceOpened(device, info);
}
}, mHandler);
}
/**
* Called when a midi device is attached.
* @param info the attached device information.
*/
private void onDeviceAdded(final MidiDeviceInfo info) {
if (mIsInitializing) {
mPendingDevices.add(info);
}
openDevice(info);
}
/**
* Called when a midi device is detached.
* @param info the detached device information.
*/
private void onDeviceRemoved(MidiDeviceInfo info) {
for (MidiDeviceAndroid device : mDevices) {
if (device.isOpen() && device.getInfo().getId() == info.getId()) {
device.close();
nativeOnDetached(mNativeManagerPointer, device);
}
}
}
private void onDeviceOpened(MidiDevice device, MidiDeviceInfo info) {
mPendingDevices.remove(info);
if (device != null) {
MidiDeviceAndroid xdevice = new MidiDeviceAndroid(device);
mDevices.add(xdevice);
if (!mIsInitializing) {
nativeOnAttached(mNativeManagerPointer, xdevice);
}
}
if (mIsInitializing && mPendingDevices.isEmpty()) {
nativeOnInitialized(mNativeManagerPointer, mDevices.toArray(new MidiDeviceAndroid[0]));
mIsInitializing = false;
}
}
static native void nativeOnInitialized(
long nativeMidiManagerAndroid, MidiDeviceAndroid[] devices);
static native void nativeOnAttached(long nativeMidiManagerAndroid, MidiDeviceAndroid device);
static native void nativeOnDetached(long nativeMidiManagerAndroid, MidiDeviceAndroid device);
}