Merge "Move MidiDeviceInfo to libamidi, its only user"
diff --git a/media/java/android/media/midi/MidiDeviceInfo.aidl b/media/java/android/media/midi/MidiDeviceInfo.aidl
index 5b2ac9b..a248204 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.aidl
+++ b/media/java/android/media/midi/MidiDeviceInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.media.midi;
 
-parcelable MidiDeviceInfo cpp_header "media/MidiDeviceInfo.h";
+parcelable MidiDeviceInfo cpp_header "MidiDeviceInfo.h";
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index 58317ed..8f3e12e 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/Android.bp
@@ -17,6 +17,7 @@
 
     srcs: [
         "amidi.cpp",
+        "MidiDeviceInfo.cpp",
         ":IMidiDeviceServer.aidl",
     ],
 
@@ -31,12 +32,14 @@
         "-fvisibility=hidden",
     ],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
     shared_libs: [
         "liblog",
         "libbinder",
         "libutils",
-        "libmedia",
-        "libmediandk",
         "libandroid_runtime",
     ],
 
diff --git a/media/native/midi/MidiDeviceInfo.cpp b/media/native/midi/MidiDeviceInfo.cpp
new file mode 100644
index 0000000..ac68d26
--- /dev/null
+++ b/media/native/midi/MidiDeviceInfo.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "MidiDeviceInfo"
+
+#include <MidiDeviceInfo.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+namespace android {
+namespace media {
+namespace midi {
+
+// The constant values need to be kept in sync with MidiDeviceInfo.java.
+// static
+const char* const MidiDeviceInfo::PROPERTY_NAME = "name";
+const char* const MidiDeviceInfo::PROPERTY_MANUFACTURER = "manufacturer";
+const char* const MidiDeviceInfo::PROPERTY_PRODUCT = "product";
+const char* const MidiDeviceInfo::PROPERTY_VERSION = "version";
+const char* const MidiDeviceInfo::PROPERTY_SERIAL_NUMBER = "serial_number";
+const char* const MidiDeviceInfo::PROPERTY_ALSA_CARD = "alsa_card";
+const char* const MidiDeviceInfo::PROPERTY_ALSA_DEVICE = "alsa_device";
+
+String16 MidiDeviceInfo::getProperty(const char* propertyName) {
+    String16 value;
+    if (mProperties.getString(String16(propertyName), &value)) {
+        return value;
+    } else {
+        return String16();
+    }
+}
+
+#define RETURN_IF_FAILED(calledOnce)                                     \
+    {                                                                    \
+        status_t returnStatus = calledOnce;                              \
+        if (returnStatus) {                                              \
+            ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
+            return returnStatus;                                         \
+         }                                                               \
+    }
+
+status_t MidiDeviceInfo::writeToParcel(Parcel* parcel) const {
+    // Needs to be kept in sync with code in MidiDeviceInfo.java
+    RETURN_IF_FAILED(parcel->writeInt32(mType));
+    RETURN_IF_FAILED(parcel->writeInt32(mId));
+    RETURN_IF_FAILED(parcel->writeInt32((int32_t)mInputPortNames.size()));
+    RETURN_IF_FAILED(parcel->writeInt32((int32_t)mOutputPortNames.size()));
+    RETURN_IF_FAILED(writeStringVector(parcel, mInputPortNames));
+    RETURN_IF_FAILED(writeStringVector(parcel, mOutputPortNames));
+    RETURN_IF_FAILED(parcel->writeInt32(mIsPrivate ? 1 : 0));
+    RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
+    // This corresponds to "extra" properties written by Java code
+    RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
+    return OK;
+}
+
+status_t MidiDeviceInfo::readFromParcel(const Parcel* parcel) {
+    // Needs to be kept in sync with code in MidiDeviceInfo.java
+    RETURN_IF_FAILED(parcel->readInt32(&mType));
+    RETURN_IF_FAILED(parcel->readInt32(&mId));
+    int32_t inputPortCount;
+    RETURN_IF_FAILED(parcel->readInt32(&inputPortCount));
+    int32_t outputPortCount;
+    RETURN_IF_FAILED(parcel->readInt32(&outputPortCount));
+    RETURN_IF_FAILED(readStringVector(parcel, &mInputPortNames, inputPortCount));
+    RETURN_IF_FAILED(readStringVector(parcel, &mOutputPortNames, outputPortCount));
+    int32_t isPrivate;
+    RETURN_IF_FAILED(parcel->readInt32(&isPrivate));
+    mIsPrivate = isPrivate == 1;
+    RETURN_IF_FAILED(mProperties.readFromParcel(parcel));
+    // Ignore "extra" properties as they may contain Java Parcelables
+    return OK;
+}
+
+status_t MidiDeviceInfo::readStringVector(
+        const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength) {
+    std::unique_ptr<std::vector<std::unique_ptr<String16>>> v;
+    status_t result = parcel->readString16Vector(&v);
+    if (result != OK) return result;
+    vectorPtr->clear();
+    if (v.get() != nullptr) {
+        for (const auto& iter : *v) {
+            if (iter.get() != nullptr) {
+                vectorPtr->push_back(*iter);
+            } else {
+                vectorPtr->push_back(String16());
+            }
+        }
+    } else {
+        vectorPtr->resize(defaultLength);
+    }
+    return OK;
+}
+
+status_t MidiDeviceInfo::writeStringVector(Parcel* parcel, const Vector<String16>& vector) const {
+    std::vector<String16> v;
+    for (size_t i = 0; i < vector.size(); ++i) {
+        v.push_back(vector[i]);
+    }
+    return parcel->writeString16Vector(v);
+}
+
+// Vector does not define operator==
+static inline bool areVectorsEqual(const Vector<String16>& lhs, const Vector<String16>& rhs) {
+    if (lhs.size() != rhs.size()) return false;
+    for (size_t i = 0; i < lhs.size(); ++i) {
+        if (lhs[i] != rhs[i]) return false;
+    }
+    return true;
+}
+
+bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
+    return (lhs.mType == rhs.mType && lhs.mId == rhs.mId &&
+            areVectorsEqual(lhs.mInputPortNames, rhs.mInputPortNames) &&
+            areVectorsEqual(lhs.mOutputPortNames, rhs.mOutputPortNames) &&
+            lhs.mProperties == rhs.mProperties &&
+            lhs.mIsPrivate == rhs.mIsPrivate);
+}
+
+}  // namespace midi
+}  // namespace media
+}  // namespace android
diff --git a/media/native/midi/MidiDeviceInfo.h b/media/native/midi/MidiDeviceInfo.h
new file mode 100644
index 0000000..5b4a241
--- /dev/null
+++ b/media/native/midi/MidiDeviceInfo.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_MEDIA_MIDI_DEVICE_INFO_H
+#define ANDROID_MEDIA_MIDI_DEVICE_INFO_H
+
+#include <binder/Parcelable.h>
+#include <binder/PersistableBundle.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace media {
+namespace midi {
+
+class MidiDeviceInfo : public Parcelable {
+public:
+    MidiDeviceInfo() = default;
+    virtual ~MidiDeviceInfo() = default;
+    MidiDeviceInfo(const MidiDeviceInfo& midiDeviceInfo) = default;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+    int getType() const { return mType; }
+    int getUid() const { return mId; }
+    bool isPrivate() const { return mIsPrivate; }
+    const Vector<String16>& getInputPortNames() const { return mInputPortNames; }
+    const Vector<String16>&  getOutputPortNames() const { return mOutputPortNames; }
+    String16 getProperty(const char* propertyName);
+
+    // The constants need to be kept in sync with MidiDeviceInfo.java
+    enum {
+        TYPE_USB = 1,
+        TYPE_VIRTUAL = 2,
+        TYPE_BLUETOOTH = 3,
+    };
+    static const char* const PROPERTY_NAME;
+    static const char* const PROPERTY_MANUFACTURER;
+    static const char* const PROPERTY_PRODUCT;
+    static const char* const PROPERTY_VERSION;
+    static const char* const PROPERTY_SERIAL_NUMBER;
+    static const char* const PROPERTY_ALSA_CARD;
+    static const char* const PROPERTY_ALSA_DEVICE;
+
+    friend bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs);
+    friend bool operator!=(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
+        return !(lhs == rhs);
+    }
+
+private:
+    status_t readStringVector(
+            const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength);
+    status_t writeStringVector(Parcel* parcel, const Vector<String16>& vector) const;
+
+    int32_t mType;
+    int32_t mId;
+    Vector<String16> mInputPortNames;
+    Vector<String16> mOutputPortNames;
+    os::PersistableBundle mProperties;
+    bool mIsPrivate;
+};
+
+}  // namespace midi
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_MIDI_DEVICE_INFO_H
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 1e9a194..e7c4d99 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -26,7 +26,7 @@
 #include <core_jni_helpers.h>
 
 #include "android/media/midi/BpMidiDeviceServer.h"
-#include "media/MidiDeviceInfo.h"
+#include "MidiDeviceInfo.h"
 
 #include "include/amidi/AMidi.h"
 #include "amidi_internal.h"