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