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