diff options
author | Mike Lockwood <lockwood@android.com> | 2010-05-25 19:08:48 -0400 |
---|---|---|
committer | Mike Lockwood <lockwood@android.com> | 2010-06-01 22:12:44 -0400 |
commit | 755fd617258d3f1731b2829d681cab680db0fdd5 (patch) | |
tree | 386dd00b808f81308404f47347f31d73914825e9 /core/jni | |
parent | a393a85d2b2f319a29c52c354a8b5e44fc1621ed (diff) | |
download | frameworks_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.mk | 5 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 4 | ||||
-rw-r--r-- | core/jni/android_media_MtpClient.cpp | 227 | ||||
-rw-r--r-- | core/jni/android_media_MtpCursor.cpp | 131 |
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 |