1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.midi; 18 19 import android.os.Bundle; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 23 import android.util.Log; 24 25 /** 26 * This class contains information to describe a MIDI device. 27 * For now we only have information that can be retrieved easily for USB devices, 28 * but we will probably expand this in the future. 29 * 30 * This class is just an immutable object to encapsulate the MIDI device description. 31 * Use the MidiDevice class to actually communicate with devices. 32 */ 33 public final class MidiDeviceInfo implements Parcelable { 34 35 private static final String TAG = "MidiDeviceInfo"; 36 37 /* 38 * Please note that constants and (un)marshalling code need to be kept in sync 39 * with the native implementation (MidiDeviceInfo.h|cpp) 40 */ 41 42 /** 43 * Constant representing USB MIDI devices for {@link #getType} 44 */ 45 public static final int TYPE_USB = 1; 46 47 /** 48 * Constant representing virtual (software based) MIDI devices for {@link #getType} 49 */ 50 public static final int TYPE_VIRTUAL = 2; 51 52 /** 53 * Constant representing Bluetooth MIDI devices for {@link #getType} 54 */ 55 public static final int TYPE_BLUETOOTH = 3; 56 57 /** 58 * Bundle key for the device's user visible name property. 59 * The value for this property is of type {@link java.lang.String}. 60 * Used with the {@link android.os.Bundle} returned by {@link #getProperties}. 61 * For USB devices, this is a concatenation of the manufacturer and product names. 62 */ 63 public static final String PROPERTY_NAME = "name"; 64 65 /** 66 * Bundle key for the device's manufacturer name property. 67 * The value for this property is of type {@link java.lang.String}. 68 * Used with the {@link android.os.Bundle} returned by {@link #getProperties}. 69 * Matches the USB device manufacturer name string for USB MIDI devices. 70 */ 71 public static final String PROPERTY_MANUFACTURER = "manufacturer"; 72 73 /** 74 * Bundle key for the device's product name property. 75 * The value for this property is of type {@link java.lang.String}. 76 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 77 * Matches the USB device product name string for USB MIDI devices. 78 */ 79 public static final String PROPERTY_PRODUCT = "product"; 80 81 /** 82 * Bundle key for the device's version property. 83 * The value for this property is of type {@link java.lang.String}. 84 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 85 * Matches the USB device version number for USB MIDI devices. 86 */ 87 public static final String PROPERTY_VERSION = "version"; 88 89 /** 90 * Bundle key for the device's serial number property. 91 * The value for this property is of type {@link java.lang.String}. 92 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 93 * Matches the USB device serial number for USB MIDI devices. 94 */ 95 public static final String PROPERTY_SERIAL_NUMBER = "serial_number"; 96 97 /** 98 * Bundle key for the device's corresponding USB device. 99 * The value for this property is of type {@link android.hardware.usb.UsbDevice}. 100 * Only set for USB MIDI devices. 101 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 102 */ 103 public static final String PROPERTY_USB_DEVICE = "usb_device"; 104 105 /** 106 * Bundle key for the device's corresponding Bluetooth device. 107 * The value for this property is of type {@link android.bluetooth.BluetoothDevice}. 108 * Only set for Bluetooth MIDI devices. 109 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 110 */ 111 public static final String PROPERTY_BLUETOOTH_DEVICE = "bluetooth_device"; 112 113 /** 114 * Bundle key for the device's ALSA card number. 115 * The value for this property is an integer. 116 * Only set for USB MIDI devices. 117 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 118 * 119 * @hide 120 */ 121 public static final String PROPERTY_ALSA_CARD = "alsa_card"; 122 123 /** 124 * Bundle key for the device's ALSA device number. 125 * The value for this property is an integer. 126 * Only set for USB MIDI devices. 127 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 128 * 129 * @hide 130 */ 131 public static final String PROPERTY_ALSA_DEVICE = "alsa_device"; 132 133 /** 134 * ServiceInfo for the service hosting the device implementation. 135 * The value for this property is of type {@link android.content.pm.ServiceInfo}. 136 * Only set for Virtual MIDI devices. 137 * Used with the {@link android.os.Bundle} returned by {@link #getProperties} 138 * 139 * @hide 140 */ 141 public static final String PROPERTY_SERVICE_INFO = "service_info"; 142 143 /** 144 * Contains information about an input or output port. 145 */ 146 public static final class PortInfo { 147 /** 148 * Port type for input ports 149 */ 150 public static final int TYPE_INPUT = 1; 151 152 /** 153 * Port type for output ports 154 */ 155 public static final int TYPE_OUTPUT = 2; 156 157 private final int mPortType; 158 private final int mPortNumber; 159 private final String mName; 160 PortInfo(int type, int portNumber, String name)161 PortInfo(int type, int portNumber, String name) { 162 mPortType = type; 163 mPortNumber = portNumber; 164 mName = (name == null ? "" : name); 165 } 166 167 /** 168 * Returns the port type of the port (either {@link #TYPE_INPUT} or {@link #TYPE_OUTPUT}) 169 * @return the port type 170 */ getType()171 public int getType() { 172 return mPortType; 173 } 174 175 /** 176 * Returns the port number of the port 177 * @return the port number 178 */ getPortNumber()179 public int getPortNumber() { 180 return mPortNumber; 181 } 182 183 /** 184 * Returns the name of the port, or empty string if the port has no name 185 * @return the port name 186 */ getName()187 public String getName() { 188 return mName; 189 } 190 } 191 192 private final int mType; // USB or virtual 193 private final int mId; // unique ID generated by MidiService. Accessed from native code. 194 private final int mInputPortCount; 195 private final int mOutputPortCount; 196 private final String[] mInputPortNames; 197 private final String[] mOutputPortNames; 198 private final Bundle mProperties; 199 private final boolean mIsPrivate; 200 201 /** 202 * MidiDeviceInfo should only be instantiated by MidiService implementation 203 * @hide 204 */ MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts, String[] inputPortNames, String[] outputPortNames, Bundle properties, boolean isPrivate)205 public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts, 206 String[] inputPortNames, String[] outputPortNames, Bundle properties, 207 boolean isPrivate) { 208 mType = type; 209 mId = id; 210 mInputPortCount = numInputPorts; 211 mOutputPortCount = numOutputPorts; 212 if (inputPortNames == null) { 213 mInputPortNames = new String[numInputPorts]; 214 } else { 215 mInputPortNames = inputPortNames; 216 } 217 if (outputPortNames == null) { 218 mOutputPortNames = new String[numOutputPorts]; 219 } else { 220 mOutputPortNames = outputPortNames; 221 } 222 mProperties = properties; 223 mIsPrivate = isPrivate; 224 } 225 226 /** 227 * Returns the type of the device. 228 * 229 * @return the device's type 230 */ getType()231 public int getType() { 232 return mType; 233 } 234 235 /** 236 * Returns the ID of the device. 237 * This ID is generated by the MIDI service and is not persistent across device unplugs. 238 * 239 * @return the device's ID 240 */ getId()241 public int getId() { 242 return mId; 243 } 244 245 /** 246 * Returns the device's number of input ports. 247 * 248 * @return the number of input ports 249 */ getInputPortCount()250 public int getInputPortCount() { 251 return mInputPortCount; 252 } 253 254 /** 255 * Returns the device's number of output ports. 256 * 257 * @return the number of output ports 258 */ getOutputPortCount()259 public int getOutputPortCount() { 260 return mOutputPortCount; 261 } 262 263 /** 264 * Returns information about the device's ports. 265 * The ports are in unspecified order. 266 * 267 * @return array of {@link PortInfo} 268 */ getPorts()269 public PortInfo[] getPorts() { 270 PortInfo[] ports = new PortInfo[mInputPortCount + mOutputPortCount]; 271 272 int index = 0; 273 for (int i = 0; i < mInputPortCount; i++) { 274 ports[index++] = new PortInfo(PortInfo.TYPE_INPUT, i, mInputPortNames[i]); 275 } 276 for (int i = 0; i < mOutputPortCount; i++) { 277 ports[index++] = new PortInfo(PortInfo.TYPE_OUTPUT, i, mOutputPortNames[i]); 278 } 279 280 return ports; 281 } 282 283 /** 284 * Returns the {@link android.os.Bundle} containing the device's properties. 285 * 286 * @return the device's properties 287 */ getProperties()288 public Bundle getProperties() { 289 return mProperties; 290 } 291 292 /** 293 * Returns true if the device is private. Private devices are only visible and accessible 294 * to clients with the same UID as the application that is hosting the device. 295 * 296 * @return true if the device is private 297 */ isPrivate()298 public boolean isPrivate() { 299 return mIsPrivate; 300 } 301 302 @Override equals(Object o)303 public boolean equals(Object o) { 304 if (o instanceof MidiDeviceInfo) { 305 return (((MidiDeviceInfo)o).mId == mId); 306 } else { 307 return false; 308 } 309 } 310 311 @Override hashCode()312 public int hashCode() { 313 return mId; 314 } 315 316 @Override toString()317 public String toString() { 318 // This is a hack to force the mProperties Bundle to unparcel so we can 319 // print all the names and values. 320 mProperties.getString(PROPERTY_NAME); 321 return ("MidiDeviceInfo[mType=" + mType + 322 ",mInputPortCount=" + mInputPortCount + 323 ",mOutputPortCount=" + mOutputPortCount + 324 ",mProperties=" + mProperties + 325 ",mIsPrivate=" + mIsPrivate); 326 } 327 328 public static final @android.annotation.NonNull Parcelable.Creator<MidiDeviceInfo> CREATOR = 329 new Parcelable.Creator<MidiDeviceInfo>() { 330 public MidiDeviceInfo createFromParcel(Parcel in) { 331 // Needs to be kept in sync with code in MidiDeviceInfo.cpp 332 int type = in.readInt(); 333 int id = in.readInt(); 334 int inputPortCount = in.readInt(); 335 int outputPortCount = in.readInt(); 336 String[] inputPortNames = in.createStringArray(); 337 String[] outputPortNames = in.createStringArray(); 338 boolean isPrivate = (in.readInt() == 1); 339 Bundle basicPropertiesIgnored = in.readBundle(); 340 Bundle properties = in.readBundle(); 341 return new MidiDeviceInfo(type, id, inputPortCount, outputPortCount, 342 inputPortNames, outputPortNames, properties, isPrivate); 343 } 344 345 public MidiDeviceInfo[] newArray(int size) { 346 return new MidiDeviceInfo[size]; 347 } 348 }; 349 describeContents()350 public int describeContents() { 351 return 0; 352 } 353 getBasicProperties(String[] keys)354 private Bundle getBasicProperties(String[] keys) { 355 Bundle basicProperties = new Bundle(); 356 for (String key : keys) { 357 Object val = mProperties.get(key); 358 if (val != null) { 359 if (val instanceof String) { 360 basicProperties.putString(key, (String) val); 361 } else if (val instanceof Integer) { 362 basicProperties.putInt(key, (Integer) val); 363 } else { 364 Log.w(TAG, "Unsupported property type: " + val.getClass().getName()); 365 } 366 } 367 } 368 return basicProperties; 369 } 370 writeToParcel(Parcel parcel, int flags)371 public void writeToParcel(Parcel parcel, int flags) { 372 // Needs to be kept in sync with code in MidiDeviceInfo.cpp 373 parcel.writeInt(mType); 374 parcel.writeInt(mId); 375 parcel.writeInt(mInputPortCount); 376 parcel.writeInt(mOutputPortCount); 377 parcel.writeStringArray(mInputPortNames); 378 parcel.writeStringArray(mOutputPortNames); 379 parcel.writeInt(mIsPrivate ? 1 : 0); 380 // "Basic" properties only contain properties of primitive types 381 // and thus can be read back by native code. "Extra" properties is 382 // a superset that contains all properties. 383 parcel.writeBundle(getBasicProperties(new String[] { 384 PROPERTY_NAME, PROPERTY_MANUFACTURER, PROPERTY_PRODUCT, PROPERTY_VERSION, 385 PROPERTY_SERIAL_NUMBER, PROPERTY_ALSA_CARD, PROPERTY_ALSA_DEVICE 386 })); 387 // Must be serialized last so native code can safely ignore it. 388 parcel.writeBundle(mProperties); 389 } 390 } 391