summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2010-05-25 19:08:48 -0400
committerMike Lockwood <lockwood@android.com>2010-06-01 22:12:44 -0400
commit755fd617258d3f1731b2829d681cab680db0fdd5 (patch)
tree386dd00b808f81308404f47347f31d73914825e9 /core/jni
parenta393a85d2b2f319a29c52c354a8b5e44fc1621ed (diff)
downloadframeworks_base-755fd617258d3f1731b2829d681cab680db0fdd5.zip
frameworks_base-755fd617258d3f1731b2829d681cab680db0fdd5.tar.gz
frameworks_base-755fd617258d3f1731b2829d681cab680db0fdd5.tar.bz2
Prototype Content Provider support for MTP/PTP devices.
At this point much of the plumbing is in place, but only a few simple queries are supported. This is enough to support a proof of concept sample program that navigates the file hierarchy of a digital camera connected via USB. Also removed obsolete ptptest host test program. Change-Id: I17644344b9f0ce1ecc302bc0478c1f3d44a1647f Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/Android.mk5
-rw-r--r--core/jni/AndroidRuntime.cpp4
-rw-r--r--core/jni/android_media_MtpClient.cpp227
-rw-r--r--core/jni/android_media_MtpCursor.cpp131
4 files changed, 367 insertions, 0 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 170a32f..2239bf4 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -106,6 +106,8 @@ LOCAL_SRC_FILES:= \
android_media_AudioSystem.cpp \
android_media_AudioTrack.cpp \
android_media_JetPlayer.cpp \
+ android_media_MtpClient.cpp \
+ android_media_MtpCursor.cpp \
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
@@ -138,6 +140,7 @@ LOCAL_C_INCLUDES += \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
$(LOCAL_PATH)/../../include/ui \
$(LOCAL_PATH)/../../include/utils \
+ $(LOCAL_PATH)/../../media/mtp \
external/skia/include/core \
external/skia/include/effects \
external/skia/include/images \
@@ -183,6 +186,8 @@ LOCAL_SHARED_LIBRARIES := \
libwpa_client \
libjpeg
+LOCAL_STATIC_LIBRARIES := libmtphost libusbhost
+
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_C_INCLUDES += \
external/dbus \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 76df9db..54505dc 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -124,6 +124,8 @@ extern int register_android_database_SQLiteProgram(JNIEnv* env);
extern int register_android_database_SQLiteQuery(JNIEnv* env);
extern int register_android_database_SQLiteStatement(JNIEnv* env);
extern int register_android_debug_JNITest(JNIEnv* env);
+extern int register_android_media_MtpClient(JNIEnv *env);
+extern int register_android_media_MtpCursor(JNIEnv *env);
extern int register_android_nio_utils(JNIEnv* env);
extern int register_android_pim_EventRecurrence(JNIEnv* env);
extern int register_android_text_format_Time(JNIEnv* env);
@@ -1268,6 +1270,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_media_AudioSystem),
REG_JNI(register_android_media_AudioTrack),
REG_JNI(register_android_media_JetPlayer),
+ REG_JNI(register_android_media_MtpClient),
+ REG_JNI(register_android_media_MtpCursor),
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
diff --git a/core/jni/android_media_MtpClient.cpp b/core/jni/android_media_MtpClient.cpp
new file mode 100644
index 0000000..0c04255
--- /dev/null
+++ b/core/jni/android_media_MtpClient.cpp
@@ -0,0 +1,227 @@
+/*
+ * 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 "MtpClientJNI"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utils/threads.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "MtpClient.h"
+#include "MtpDevice.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static jmethodID method_deviceAdded;
+static jmethodID method_deviceRemoved;
+static jfieldID field_context;
+
+class MyClient : public MtpClient {
+private:
+
+ enum {
+ kDeviceAdded = 1,
+ kDeviceRemoved,
+ };
+
+ virtual void deviceAdded(MtpDevice *device);
+ virtual void deviceRemoved(MtpDevice *device);
+
+ bool reportDeviceAdded(JNIEnv *env, MtpDevice *device);
+ bool reportDeviceRemoved(JNIEnv *env, MtpDevice *device);
+
+ JNIEnv* mEnv;
+ jobject mClient;
+ Mutex mEventLock;
+ Condition mEventCondition;
+ Mutex mAckLock;
+ Condition mAckCondition;
+ int mEvent;
+ MtpDevice* mEventDevice;
+
+public:
+ MyClient(JNIEnv *env, jobject client);
+ virtual ~MyClient();
+ void waitForEvent(JNIEnv *env);
+
+};
+
+MtpClient* get_client_from_object(JNIEnv* env, jobject javaClient)
+{
+ return (MtpClient*)env->GetIntField(javaClient, field_context);
+}
+
+
+MyClient::MyClient(JNIEnv *env, jobject client)
+ : mEnv(env),
+ mClient(env->NewGlobalRef(client)),
+ mEvent(0),
+ mEventDevice(NULL)
+{
+}
+
+MyClient::~MyClient() {
+ mEnv->DeleteGlobalRef(mClient);
+}
+
+
+void MyClient::deviceAdded(MtpDevice *device) {
+ LOGD("MyClient::deviceAdded\n");
+ mAckLock.lock();
+ mEventLock.lock();
+ mEvent = kDeviceAdded;
+ mEventDevice = device;
+ mEventCondition.signal();
+ mEventLock.unlock();
+ mAckCondition.wait(mAckLock);
+ mAckLock.unlock();
+}
+
+void MyClient::deviceRemoved(MtpDevice *device) {
+ LOGD("MyClient::deviceRemoved\n");
+ mAckLock.lock();
+ mEventLock.lock();
+ mEvent = kDeviceRemoved;
+ mEventDevice = device;
+ mEventCondition.signal();
+ mEventLock.unlock();
+ mAckCondition.wait(mAckLock);
+ mAckLock.unlock();
+}
+
+bool MyClient::reportDeviceAdded(JNIEnv *env, MtpDevice *device) {
+ const char* name = device->getDeviceName();
+ LOGD("MyClient::reportDeviceAdded %s\n", name);
+
+ env->CallVoidMethod(mClient, method_deviceAdded, device->getID());
+
+ return (!env->ExceptionCheck());
+}
+
+bool MyClient::reportDeviceRemoved(JNIEnv *env, MtpDevice *device) {
+ const char* name = device->getDeviceName();
+ LOGD("MyClient::reportDeviceRemoved %s\n", name);
+
+ env->CallVoidMethod(mClient, method_deviceRemoved, device->getID());
+
+ return (!env->ExceptionCheck());
+}
+
+void MyClient::waitForEvent(JNIEnv *env) {
+ mEventLock.lock();
+ mEventCondition.wait(mEventLock);
+ mEventLock.unlock();
+
+ switch (mEvent) {
+ case kDeviceAdded:
+ reportDeviceAdded(env, mEventDevice);
+ break;
+ case kDeviceRemoved:
+ reportDeviceRemoved(env, mEventDevice);
+ break;
+ }
+
+ mAckLock.lock();
+ mAckCondition.signal();
+ mAckLock.unlock();
+}
+
+
+// ----------------------------------------------------------------------------
+
+static bool ExceptionCheck(void* env)
+{
+ return ((JNIEnv *)env)->ExceptionCheck();
+}
+
+static void
+android_media_MtpClient_setup(JNIEnv *env, jobject thiz)
+{
+ LOGD("setup\n");
+ MyClient* client = new MyClient(env, thiz);
+ client->start();
+ env->SetIntField(thiz, field_context, (int)client);
+}
+
+static void
+android_media_MtpClient_finalize(JNIEnv *env, jobject thiz)
+{
+ LOGD("finalize\n");
+ MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
+ delete client;
+}
+
+static void
+android_media_MtpClient_wait_for_event(JNIEnv *env, jobject thiz)
+{
+ LOGD("wait_for_event\n");
+ MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
+ client->waitForEvent(env);
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"native_setup", "()V", (void *)android_media_MtpClient_setup},
+ {"native_finalize", "()V", (void *)android_media_MtpClient_finalize},
+ {"native_wait_for_event", "()V", (void *)android_media_MtpClient_wait_for_event},
+
+};
+
+static const char* const kClassPathName = "android/media/MtpClient";
+
+int register_android_media_MtpClient(JNIEnv *env)
+{
+ jclass clazz;
+
+ LOGD("register_android_media_MtpClient\n");
+
+ clazz = env->FindClass("android/media/MtpClient");
+ if (clazz == NULL) {
+ LOGE("Can't find android/media/MtpClient");
+ return -1;
+ }
+ method_deviceAdded = env->GetMethodID(clazz, "deviceAdded", "(I)V");
+ if (method_deviceAdded == NULL) {
+ LOGE("Can't find deviceAdded");
+ return -1;
+ }
+ method_deviceRemoved = env->GetMethodID(clazz, "deviceRemoved", "(I)V");
+ if (method_deviceRemoved == NULL) {
+ LOGE("Can't find deviceRemoved");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find MtpClient.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/MtpClient", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_media_MtpCursor.cpp b/core/jni/android_media_MtpCursor.cpp
new file mode 100644
index 0000000..7b0b7b7
--- /dev/null
+++ b/core/jni/android_media_MtpCursor.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 "MtpCursorJNI"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "binder/CursorWindow.h"
+
+#include "MtpClient.h"
+#include "MtpCursor.h"
+
+namespace android {
+
+static jfieldID field_context;
+
+// From android_database_CursorWindow.cpp
+CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
+
+// From android_media_MtpClient.cpp
+MtpClient * get_client_from_object(JNIEnv * env, jobject javaClient);
+
+// ----------------------------------------------------------------------------
+
+static bool ExceptionCheck(void* env)
+{
+ return ((JNIEnv *)env)->ExceptionCheck();
+}
+
+static void
+android_media_MtpCursor_setup(JNIEnv *env, jobject thiz, jobject javaClient,
+ jint queryType, jint deviceID, jint storageID, jint objectID, jintArray javaColumns)
+{
+ LOGD("android_media_MtpCursor_setup queryType: %d deviceID: %d storageID: %d objectID: %d\n",
+ queryType, deviceID, storageID, objectID);
+
+ int* columns = NULL;
+ int columnCount = 0;
+ if (javaColumns) {
+ columns = env->GetIntArrayElements(javaColumns, 0);
+ columnCount = env->GetArrayLength(javaColumns);
+ }
+
+ MtpClient* client = get_client_from_object(env, javaClient);
+ MtpCursor* cursor = new MtpCursor(client, queryType,
+ deviceID, storageID, objectID, columnCount, columns);
+
+ if (columns)
+ env->ReleaseIntArrayElements(javaColumns, columns, 0);
+ env->SetIntField(thiz, field_context, (int)cursor);
+}
+
+static void
+android_media_MtpCursor_finalize(JNIEnv *env, jobject thiz)
+{
+ LOGD("finalize\n");
+ MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context);
+ delete cursor;
+}
+
+static jint
+android_media_MtpCursor_fill_window(JNIEnv *env, jobject thiz, jobject javaWindow, jint startPos)
+{
+ CursorWindow* window = get_window_from_object(env, javaWindow);
+ if (!window) {
+ LOGE("Invalid CursorWindow");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Bad CursorWindow");
+ return 0;
+ }
+ MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context);
+
+ return cursor->fillWindow(window, startPos);
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"native_setup", "(Landroid/media/MtpClient;IIII[I)V",
+ (void *)android_media_MtpCursor_setup},
+ {"native_finalize", "()V", (void *)android_media_MtpCursor_finalize},
+ {"native_fill_window", "(Landroid/database/CursorWindow;I)I",
+ (void *)android_media_MtpCursor_fill_window},
+
+};
+
+static const char* const kClassPathName = "android/media/MtpCursor";
+
+int register_android_media_MtpCursor(JNIEnv *env)
+{
+ jclass clazz;
+
+ LOGD("register_android_media_MtpCursor\n");
+
+ clazz = env->FindClass("android/media/MtpCursor");
+ if (clazz == NULL) {
+ LOGE("Can't find android/media/MtpCursor");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find MtpCursor.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/MtpCursor", gMethods, NELEM(gMethods));
+}
+
+} // namespace android