MTP: Add support for sending events to the host when objects are added and removed
Change-Id: Ia1d5232b919c644c670ff9ca651eca92b3f9ad42
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/media/java/android/media/MtpServer.java b/media/java/android/media/MtpServer.java
index 766a86a..b0945a5 100644
--- a/media/java/android/media/MtpServer.java
+++ b/media/java/android/media/MtpServer.java
@@ -47,6 +47,14 @@
native_stop();
}
+ public void sendObjectAdded(int handle) {
+ native_send_object_added(handle);
+ }
+
+ public void sendObjectRemoved(int handle) {
+ native_send_object_removed(handle);
+ }
+
// used by the JNI code
private int mNativeContext;
@@ -54,4 +62,6 @@
private native final void native_finalize();
private native final void native_start();
private native final void native_stop();
+ private native final void native_send_object_added(int handle);
+ private native final void native_send_object_removed(int handle);
}
diff --git a/media/jni/android_media_MtpServer.cpp b/media/jni/android_media_MtpServer.cpp
index 17e85f8..0883527 100644
--- a/media/jni/android_media_MtpServer.cpp
+++ b/media/jni/android_media_MtpServer.cpp
@@ -50,12 +50,14 @@
class MtpThread : public Thread {
private:
MtpDatabase* mDatabase;
+ MtpServer* mServer;
String8 mStoragePath;
bool mDone;
+ Mutex mMutex;
public:
MtpThread(MtpDatabase* database, const char* storagePath)
- : mDatabase(database), mStoragePath(storagePath), mDone(false)
+ : mDatabase(database), mServer(NULL), mStoragePath(storagePath), mDone(false)
{
}
@@ -67,14 +69,19 @@
return false;
}
- MtpServer* server = new MtpServer(fd, mDatabase, AID_SDCARD_RW, 0664, 0775);
- server->addStorage(mStoragePath);
+ mMutex.lock();
+ mServer = new MtpServer(fd, mDatabase, AID_SDCARD_RW, 0664, 0775);
+ mServer->addStorage(mStoragePath);
+ mMutex.unlock();
- // temporary
- LOGD("MtpThread server->run");
- server->run();
+ LOGD("MtpThread mServer->run");
+ mServer->run();
close(fd);
- delete server;
+
+ mMutex.lock();
+ delete mServer;
+ mServer = NULL;
+ mMutex.unlock();
bool done = mDone;
if (done)
@@ -84,6 +91,24 @@
}
void setDone() { mDone = true; }
+
+ void sendObjectAdded(MtpObjectHandle handle) {
+ mMutex.lock();
+ if (mServer)
+ mServer->sendObjectAdded(handle);
+ else
+ LOGE("sendObjectAdded called while disconnected\n");
+ mMutex.unlock();
+ }
+
+ void sendObjectRemoved(MtpObjectHandle handle) {
+ mMutex.lock();
+ if (mServer)
+ mServer->sendObjectRemoved(handle);
+ else
+ LOGE("sendObjectRemoved called while disconnected\n");
+ mMutex.unlock();
+ }
};
static void
@@ -126,14 +151,38 @@
}
}
+static void
+android_media_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
+{
+ LOGD("send_object_added %d\n", handle);
+ MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+ if (thread)
+ thread->sendObjectAdded(handle);
+ else
+ LOGE("sendObjectAdded called while disconnected\n");
+}
+
+static void
+android_media_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
+{
+ LOGD("send_object_removed %d\n", handle);
+ MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+ if (thread)
+ thread->sendObjectRemoved(handle);
+ else
+ LOGE("sendObjectRemoved called while disconnected\n");
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"native_setup", "(Landroid/media/MtpDatabase;Ljava/lang/String;)V",
+ {"native_setup", "(Landroid/media/MtpDatabase;Ljava/lang/String;)V",
(void *)android_media_MtpServer_setup},
- {"native_finalize", "()V", (void *)android_media_MtpServer_finalize},
- {"native_start", "()V", (void *)android_media_MtpServer_start},
- {"native_stop", "()V", (void *)android_media_MtpServer_stop},
+ {"native_finalize", "()V", (void *)android_media_MtpServer_finalize},
+ {"native_start", "()V", (void *)android_media_MtpServer_start},
+ {"native_stop", "()V", (void *)android_media_MtpServer_stop},
+ {"native_send_object_added", "(I)V", (void *)android_media_MtpServer_send_object_added},
+ {"native_send_object_removed", "(I)V", (void *)android_media_MtpServer_send_object_removed},
};
static const char* const kClassPathName = "android/media/MtpServer";
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 174ea36..4659709 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -23,6 +23,7 @@
MtpDataPacket.cpp \
MtpDebug.cpp \
MtpDevice.cpp \
+ MtpEventPacket.cpp \
MtpDeviceInfo.cpp \
MtpObjectInfo.cpp \
MtpPacket.cpp \
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
new file mode 100644
index 0000000..651761e
--- /dev/null
+++ b/media/mtp/MtpEventPacket.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 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 "MtpEventPacket"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <f_mtp.h>
+
+#include "MtpEventPacket.h"
+
+namespace android {
+
+MtpEventPacket::MtpEventPacket()
+ : MtpPacket(512)
+{
+}
+
+MtpEventPacket::~MtpEventPacket() {
+}
+
+#ifdef MTP_DEVICE
+int MtpEventPacket::write(int fd) {
+ struct mtp_event event;
+
+ putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
+ putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_EVENT);
+
+ event.data = mBuffer;
+ event.length = mPacketSize;
+ int ret = ::ioctl(fd, MTP_SEND_EVENT, (unsigned long)&event);
+ return (ret < 0 ? ret : 0);
+}
+#endif
+
+#ifdef MTP_HOST
+ // read our buffer from the given endpoint
+int MtpEventPacket::read(struct usb_endpoint *ep) {
+ int ret = transfer(ep, mBuffer, mBufferSize);
+ if (ret >= 0)
+ mPacketSize = ret;
+ else
+ mPacketSize = 0;
+ return ret;
+}
+#endif
+
+} // namespace android
+
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
new file mode 100644
index 0000000..30ae869
--- /dev/null
+++ b/media/mtp/MtpEventPacket.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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 _MTP_EVENT_PACKET_H
+#define _MTP_EVENT_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+namespace android {
+
+class MtpEventPacket : public MtpPacket {
+
+public:
+ MtpEventPacket();
+ virtual ~MtpEventPacket();
+
+#ifdef MTP_DEVICE
+ // write our data to the given file descriptor
+ int write(int fd);
+#endif
+
+#ifdef MTP_HOST
+ // read our buffer from the given endpoint
+ int read(struct usb_endpoint *ep);
+#endif
+
+ inline MtpEventCode getEventCode() const { return getContainerCode(); }
+ inline void setEventCode(MtpEventCode code)
+ { return setContainerCode(code); }
+};
+
+}; // namespace android
+
+#endif // _MTP_EVENT_PACKET_H
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index e8f09fa..fda5f8f 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -73,6 +73,11 @@
// MTP_OPERATION_SKIP,
};
+static const MtpEventCode kSupportedEventCodes[] = {
+ MTP_EVENT_OBJECT_ADDED,
+ MTP_EVENT_OBJECT_REMOVED,
+};
+
static const MtpObjectProperty kSupportedObjectProperties[] = {
MTP_PROPERTY_STORAGE_ID,
MTP_PROPERTY_OBJECT_FORMAT,
@@ -239,6 +244,24 @@
return NULL;
}
+void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
+ LOGD("sendObjectAdded %d\n", handle);
+ mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
+ mEvent.setTransactionID(mRequest.getTransactionID());
+ mEvent.setParameter(1, handle);
+ int ret = mEvent.write(mFD);
+ LOGD("mEvent.write returned %d\n", ret);
+}
+
+void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
+ LOGD("sendObjectRemoved %d\n", handle);
+ mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
+ mEvent.setTransactionID(mRequest.getTransactionID());
+ mEvent.setParameter(1, handle);
+ int ret = mEvent.write(mFD);
+ LOGD("mEvent.write returned %d\n", ret);
+}
+
void MtpServer::initObjectProperties() {
mObjectProperties.push(new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT16));
mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16));
@@ -326,7 +349,8 @@
mData.putUInt16(0); //Functional Mode
mData.putAUInt16(kSupportedOperationCodes,
sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
- mData.putEmptyArray(); // Events Supported
+ mData.putAUInt16(kSupportedEventCodes,
+ sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
mData.putEmptyArray(); // Device Properties Supported
mData.putEmptyArray(); // Capture Formats
mData.putAUInt16(kSupportedPlaybackFormats,
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 37b1cbe..aff973a 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -20,6 +20,7 @@
#include "MtpRequestPacket.h"
#include "MtpDataPacket.h"
#include "MtpResponsePacket.h"
+#include "MtpEventPacket.h"
#include "mtp.h"
#include "MtpUtils.h"
@@ -52,6 +53,7 @@
MtpRequestPacket mRequest;
MtpDataPacket mData;
MtpResponsePacket mResponse;
+ MtpEventPacket mEvent;
MtpStorageList mStorages;
@@ -77,6 +79,9 @@
MtpProperty* getObjectProperty(MtpPropertyCode propCode);
MtpProperty* getDeviceProperty(MtpPropertyCode propCode);
+ void sendObjectAdded(MtpObjectHandle handle);
+ void sendObjectRemoved(MtpObjectHandle handle);
+
private:
void initObjectProperties();
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
index ec0f867..2a895a7 100644
--- a/media/mtp/MtpTypes.h
+++ b/media/mtp/MtpTypes.h
@@ -28,6 +28,7 @@
typedef uint16_t MtpOperationCode;
typedef uint16_t MtpResponseCode;
+typedef uint16_t MtpEventCode;
typedef uint32_t MtpSessionID;
typedef uint32_t MtpStorageID;
typedef uint32_t MtpTransactionID;
diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h
index c1c9aef..426c6b5 100644
--- a/media/mtp/f_mtp.h
+++ b/media/mtp/f_mtp.h
@@ -32,6 +32,13 @@
size_t length;
};
+struct mtp_event {
+ /* size of the event */
+ size_t length;
+ /* event data to send */
+ void *data;
+};
+
/* Sends the specified file range to the host */
#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
/* Receives data from the host and writes it to a file.
@@ -40,5 +47,7 @@
#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
/* Sets the driver mode to either MTP or PTP */
#define MTP_SET_INTERFACE_MODE _IOW('M', 2, int)
+/* Sends an event to the host via the interrupt endpoint */
+#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event)
#endif /* __LINUX_USB_F_MTP_H */