blob: dd3b6dbd6a399922c9001208e7ed491ada34704a [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.media.midi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
/**
* This class contains information to describe a MIDI device.
* For now we only have information that can be retrieved easily for USB devices,
* but we will probably expand this in the future.
*
* This class is just an immutable object to encapsulate the MIDI device description.
* Use the MidiDevice class to actually communicate with devices.
*/
public final class MidiDeviceInfo implements Parcelable {
private static final String TAG = "MidiDeviceInfo";
/*
* Please note that constants and (un)marshalling code need to be kept in sync
* with the native implementation (MidiDeviceInfo.h|cpp)
*/
/**
* Constant representing USB MIDI devices for {@link #getType}
*/
public static final int TYPE_USB = 1;
/**
* Constant representing virtual (software based) MIDI devices for {@link #getType}
*/
public static final int TYPE_VIRTUAL = 2;
/**
* Constant representing Bluetooth MIDI devices for {@link #getType}
*/
public static final int TYPE_BLUETOOTH = 3;
/**
* Bundle key for the device's user visible name property.
* The value for this property is of type {@link java.lang.String}.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
* For USB devices, this is a concatenation of the manufacturer and product names.
*/
public static final String PROPERTY_NAME = "name";
/**
* Bundle key for the device's manufacturer name property.
* The value for this property is of type {@link java.lang.String}.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
* Matches the USB device manufacturer name string for USB MIDI devices.
*/
public static final String PROPERTY_MANUFACTURER = "manufacturer";
/**
* Bundle key for the device's product name property.
* The value for this property is of type {@link java.lang.String}.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
* Matches the USB device product name string for USB MIDI devices.
*/
public static final String PROPERTY_PRODUCT = "product";
/**
* Bundle key for the device's version property.
* The value for this property is of type {@link java.lang.String}.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
* Matches the USB device version number for USB MIDI devices.
*/
public static final String PROPERTY_VERSION = "version";
/**
* Bundle key for the device's serial number property.
* The value for this property is of type {@link java.lang.String}.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
* Matches the USB device serial number for USB MIDI devices.
*/
public static final String PROPERTY_SERIAL_NUMBER = "serial_number";
/**
* Bundle key for the device's corresponding USB device.
* The value for this property is of type {@link android.hardware.usb.UsbDevice}.
* Only set for USB MIDI devices.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
*/
public static final String PROPERTY_USB_DEVICE = "usb_device";
/**
* Bundle key for the device's corresponding Bluetooth device.
* The value for this property is of type {@link android.bluetooth.BluetoothDevice}.
* Only set for Bluetooth MIDI devices.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
*/
public static final String PROPERTY_BLUETOOTH_DEVICE = "bluetooth_device";
/**
* Bundle key for the device's ALSA card number.
* The value for this property is an integer.
* Only set for USB MIDI devices.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
*
* @hide
*/
public static final String PROPERTY_ALSA_CARD = "alsa_card";
/**
* Bundle key for the device's ALSA device number.
* The value for this property is an integer.
* Only set for USB MIDI devices.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
*
* @hide
*/
public static final String PROPERTY_ALSA_DEVICE = "alsa_device";
/**
* ServiceInfo for the service hosting the device implementation.
* The value for this property is of type {@link android.content.pm.ServiceInfo}.
* Only set for Virtual MIDI devices.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}
*
* @hide
*/
public static final String PROPERTY_SERVICE_INFO = "service_info";
/**
* Contains information about an input or output port.
*/
public static final class PortInfo {
/**
* Port type for input ports
*/
public static final int TYPE_INPUT = 1;
/**
* Port type for output ports
*/
public static final int TYPE_OUTPUT = 2;
private final int mPortType;
private final int mPortNumber;
private final String mName;
PortInfo(int type, int portNumber, String name) {
mPortType = type;
mPortNumber = portNumber;
mName = (name == null ? "" : name);
}
/**
* Returns the port type of the port (either {@link #TYPE_INPUT} or {@link #TYPE_OUTPUT})
* @return the port type
*/
public int getType() {
return mPortType;
}
/**
* Returns the port number of the port
* @return the port number
*/
public int getPortNumber() {
return mPortNumber;
}
/**
* Returns the name of the port, or empty string if the port has no name
* @return the port name
*/
public String getName() {
return mName;
}
}
private final int mType; // USB or virtual
private final int mId; // unique ID generated by MidiService. Accessed from native code.
private final int mInputPortCount;
private final int mOutputPortCount;
private final String[] mInputPortNames;
private final String[] mOutputPortNames;
private final Bundle mProperties;
private final boolean mIsPrivate;
/**
* MidiDeviceInfo should only be instantiated by MidiService implementation
* @hide
*/
public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
String[] inputPortNames, String[] outputPortNames, Bundle properties,
boolean isPrivate) {
// Check num ports for out-of-range values. Typical values will be
// between zero and three. More than 16 would be very unlikely
// because the port index field in the USB packet is only 4 bits.
// This check is mainly just to prevent OutOfMemoryErrors when
// fuzz testing.
final int maxPorts = 256; // arbitrary and very high
if (numInputPorts < 0 || numInputPorts > maxPorts) {
throw new IllegalArgumentException("numInputPorts out of range = "
+ numInputPorts);
}
if (numOutputPorts < 0 || numOutputPorts > maxPorts) {
throw new IllegalArgumentException("numOutputPorts out of range = "
+ numOutputPorts);
}
mType = type;
mId = id;
mInputPortCount = numInputPorts;
mOutputPortCount = numOutputPorts;
if (inputPortNames == null) {
mInputPortNames = new String[numInputPorts];
} else {
mInputPortNames = inputPortNames;
}
if (outputPortNames == null) {
mOutputPortNames = new String[numOutputPorts];
} else {
mOutputPortNames = outputPortNames;
}
mProperties = properties;
mIsPrivate = isPrivate;
}
/**
* Returns the type of the device.
*
* @return the device's type
*/
public int getType() {
return mType;
}
/**
* Returns the ID of the device.
* This ID is generated by the MIDI service and is not persistent across device unplugs.
*
* @return the device's ID
*/
public int getId() {
return mId;
}
/**
* Returns the device's number of input ports.
*
* @return the number of input ports
*/
public int getInputPortCount() {
return mInputPortCount;
}
/**
* Returns the device's number of output ports.
*
* @return the number of output ports
*/
public int getOutputPortCount() {
return mOutputPortCount;
}
/**
* Returns information about the device's ports.
* The ports are in unspecified order.
*
* @return array of {@link PortInfo}
*/
public PortInfo[] getPorts() {
PortInfo[] ports = new PortInfo[mInputPortCount + mOutputPortCount];
int index = 0;
for (int i = 0; i < mInputPortCount; i++) {
ports[index++] = new PortInfo(PortInfo.TYPE_INPUT, i, mInputPortNames[i]);
}
for (int i = 0; i < mOutputPortCount; i++) {
ports[index++] = new PortInfo(PortInfo.TYPE_OUTPUT, i, mOutputPortNames[i]);
}
return ports;
}
/**
* Returns the {@link android.os.Bundle} containing the device's properties.
*
* @return the device's properties
*/
public Bundle getProperties() {
return mProperties;
}
/**
* Returns true if the device is private. Private devices are only visible and accessible
* to clients with the same UID as the application that is hosting the device.
*
* @return true if the device is private
*/
public boolean isPrivate() {
return mIsPrivate;
}
@Override
public boolean equals(Object o) {
if (o instanceof MidiDeviceInfo) {
return (((MidiDeviceInfo)o).mId == mId);
} else {
return false;
}
}
@Override
public int hashCode() {
return mId;
}
@Override
public String toString() {
// This is a hack to force the mProperties Bundle to unparcel so we can
// print all the names and values.
mProperties.getString(PROPERTY_NAME);
return ("MidiDeviceInfo[mType=" + mType +
",mInputPortCount=" + mInputPortCount +
",mOutputPortCount=" + mOutputPortCount +
",mProperties=" + mProperties +
",mIsPrivate=" + mIsPrivate);
}
public static final @android.annotation.NonNull Parcelable.Creator<MidiDeviceInfo> CREATOR =
new Parcelable.Creator<MidiDeviceInfo>() {
public MidiDeviceInfo createFromParcel(Parcel in) {
// Needs to be kept in sync with code in MidiDeviceInfo.cpp
int type = in.readInt();
int id = in.readInt();
int inputPortCount = in.readInt();
int outputPortCount = in.readInt();
String[] inputPortNames = in.createStringArray();
String[] outputPortNames = in.createStringArray();
boolean isPrivate = (in.readInt() == 1);
Bundle basicPropertiesIgnored = in.readBundle();
Bundle properties = in.readBundle();
return new MidiDeviceInfo(type, id, inputPortCount, outputPortCount,
inputPortNames, outputPortNames, properties, isPrivate);
}
public MidiDeviceInfo[] newArray(int size) {
return new MidiDeviceInfo[size];
}
};
public int describeContents() {
return 0;
}
private Bundle getBasicProperties(String[] keys) {
Bundle basicProperties = new Bundle();
for (String key : keys) {
Object val = mProperties.get(key);
if (val != null) {
if (val instanceof String) {
basicProperties.putString(key, (String) val);
} else if (val instanceof Integer) {
basicProperties.putInt(key, (Integer) val);
} else {
Log.w(TAG, "Unsupported property type: " + val.getClass().getName());
}
}
}
return basicProperties;
}
public void writeToParcel(Parcel parcel, int flags) {
// Needs to be kept in sync with code in MidiDeviceInfo.cpp
parcel.writeInt(mType);
parcel.writeInt(mId);
parcel.writeInt(mInputPortCount);
parcel.writeInt(mOutputPortCount);
parcel.writeStringArray(mInputPortNames);
parcel.writeStringArray(mOutputPortNames);
parcel.writeInt(mIsPrivate ? 1 : 0);
// "Basic" properties only contain properties of primitive types
// and thus can be read back by native code. "Extra" properties is
// a superset that contains all properties.
parcel.writeBundle(getBasicProperties(new String[] {
PROPERTY_NAME, PROPERTY_MANUFACTURER, PROPERTY_PRODUCT, PROPERTY_VERSION,
PROPERTY_SERIAL_NUMBER, PROPERTY_ALSA_CARD, PROPERTY_ALSA_DEVICE
}));
// Must be serialized last so native code can safely ignore it.
parcel.writeBundle(mProperties);
}
}