From 56c85244b9be0fc6f6c2baf5f9a53f2364d5ec5e Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 7 Mar 2014 13:29:08 -0800 Subject: MTP: Add support for battery level device property Bug: 7342482 Change-Id: I810e55fe9695e2206816f57334ad14f65e9c641d --- media/java/android/mtp/MtpDatabase.java | 43 ++++++++++ media/java/android/mtp/MtpServer.java | 6 ++ media/jni/android_mtp_MtpDatabase.cpp | 142 +++++++++++++++++++------------- media/jni/android_mtp_MtpServer.cpp | 14 ++++ 4 files changed, 147 insertions(+), 58 deletions(-) diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index cc464db..2ddbb7d 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -16,15 +16,19 @@ package android.mtp; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.ContentValues; import android.content.IContentProvider; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.media.MediaScanner; import android.net.Uri; +import android.os.BatteryManager; +import android.os.BatteryStats; import android.os.RemoteException; import android.provider.MediaStore; import android.provider.MediaStore.Audio; @@ -113,11 +117,35 @@ public class MtpDatabase { + Files.FileColumns.PARENT + "=?"; private final MediaScanner mMediaScanner; + private MtpServer mServer; + + // read from native code + private int mBatteryLevel; + private int mBatteryScale; static { System.loadLibrary("media_jni"); } + private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + mBatteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0); + int newLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + if (newLevel != mBatteryLevel) { + mBatteryLevel = newLevel; + if (mServer != null) { + // send device property changed event + mServer.sendDevicePropertyChanged( + MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL); + } + } + } + } + }; + public MtpDatabase(Context context, String volumeName, String storagePath, String[] subDirectories) { native_setup(); @@ -171,6 +199,18 @@ public class MtpDatabase { initDeviceProperties(context); } + public void setServer(MtpServer server) { + mServer = server; + + // register for battery notifications when we are connected + if (server != null) { + mContext.registerReceiver(mBatteryReceiver, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + } else { + mContext.unregisterReceiver(mBatteryReceiver); + } + } + @Override protected void finalize() throws Throwable { try { @@ -663,6 +703,7 @@ public class MtpDatabase { MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE, + MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL, }; } @@ -819,6 +860,8 @@ public class MtpDatabase { outStringValue[imageSize.length()] = 0; return MtpConstants.RESPONSE_OK; + // DEVICE_PROPERTY_BATTERY_LEVEL is implemented in the JNI code + default: return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED; } diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java index 266f78e..3814630 100644 --- a/media/java/android/mtp/MtpServer.java +++ b/media/java/android/mtp/MtpServer.java @@ -30,6 +30,7 @@ public class MtpServer implements Runnable { public MtpServer(MtpDatabase database, boolean usePtp) { native_setup(database, usePtp); + database.setServer(this); } public void start() { @@ -51,6 +52,10 @@ public class MtpServer implements Runnable { native_send_object_removed(handle); } + public void sendDevicePropertyChanged(int property) { + native_send_device_property_changed(property); + } + public void addStorage(MtpStorage storage) { native_add_storage(storage); } @@ -64,6 +69,7 @@ public class MtpServer implements Runnable { private native final void native_cleanup(); private native final void native_send_object_added(int handle); private native final void native_send_object_removed(int handle); + private native final void native_send_device_property_changed(int property); private native final void native_add_storage(MtpStorage storage); private native final void native_remove_storage(int storageId); } diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 6b0bd0d..ea75a18 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -68,6 +68,8 @@ static jmethodID method_sessionStarted; static jmethodID method_sessionEnded; static jfieldID field_context; +static jfieldID field_batteryLevel; +static jfieldID field_batteryScale; // MtpPropertyList fields static jfieldID field_mCount; @@ -527,68 +529,75 @@ MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle, MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) { - int type; + JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (!getDevicePropertyInfo(property, type)) - return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + if (property == MTP_DEVICE_PROPERTY_BATTERY_LEVEL) { + // special case - implemented here instead of Java + packet.putUInt8((uint8_t)env->GetIntField(mDatabase, field_batteryLevel)); + return MTP_RESPONSE_OK; + } else { + int type; + + if (!getDevicePropertyInfo(property, type)) + return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + + jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty, + (jint)property, mLongBuffer, mStringBuffer); + if (result != MTP_RESPONSE_OK) { + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return result; + } - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty, - (jint)property, mLongBuffer, mStringBuffer); - if (result != MTP_RESPONSE_OK) { - checkAndClearExceptionFromCallback(env, __FUNCTION__); - return result; - } + jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); + jlong longValue = longValues[0]; + env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); - jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); - jlong longValue = longValues[0]; - env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); + switch (type) { + case MTP_TYPE_INT8: + packet.putInt8(longValue); + break; + case MTP_TYPE_UINT8: + packet.putUInt8(longValue); + break; + case MTP_TYPE_INT16: + packet.putInt16(longValue); + break; + case MTP_TYPE_UINT16: + packet.putUInt16(longValue); + break; + case MTP_TYPE_INT32: + packet.putInt32(longValue); + break; + case MTP_TYPE_UINT32: + packet.putUInt32(longValue); + break; + case MTP_TYPE_INT64: + packet.putInt64(longValue); + break; + case MTP_TYPE_UINT64: + packet.putUInt64(longValue); + break; + case MTP_TYPE_INT128: + packet.putInt128(longValue); + break; + case MTP_TYPE_UINT128: + packet.putInt128(longValue); + break; + case MTP_TYPE_STR: + { + jchar* str = env->GetCharArrayElements(mStringBuffer, 0); + packet.putString(str); + env->ReleaseCharArrayElements(mStringBuffer, str, 0); + break; + } + default: + ALOGE("unsupported type in getDevicePropertyValue\n"); + return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT; + } - switch (type) { - case MTP_TYPE_INT8: - packet.putInt8(longValue); - break; - case MTP_TYPE_UINT8: - packet.putUInt8(longValue); - break; - case MTP_TYPE_INT16: - packet.putInt16(longValue); - break; - case MTP_TYPE_UINT16: - packet.putUInt16(longValue); - break; - case MTP_TYPE_INT32: - packet.putInt32(longValue); - break; - case MTP_TYPE_UINT32: - packet.putUInt32(longValue); - break; - case MTP_TYPE_INT64: - packet.putInt64(longValue); - break; - case MTP_TYPE_UINT64: - packet.putUInt64(longValue); - break; - case MTP_TYPE_INT128: - packet.putInt128(longValue); - break; - case MTP_TYPE_UINT128: - packet.putInt128(longValue); - break; - case MTP_TYPE_STR: - { - jchar* str = env->GetCharArrayElements(mStringBuffer, 0); - packet.putString(str); - env->ReleaseCharArrayElements(mStringBuffer, str, 0); - break; - } - default: - ALOGE("unsupported type in getDevicePropertyValue\n"); - return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT; + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return MTP_RESPONSE_OK; } - - checkAndClearExceptionFromCallback(env, __FUNCTION__); - return MTP_RESPONSE_OK; } MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property, @@ -923,6 +932,7 @@ static const PropertyTableEntry kDevicePropertyTable[] = { { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR }, { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR }, { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR }, + { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 }, }; bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) { @@ -1046,7 +1056,7 @@ MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: writable = true; // fall through - case MTP_DEVICE_PROPERTY_IMAGE_SIZE: + case MTP_DEVICE_PROPERTY_IMAGE_SIZE: { result = new MtpProperty(property, MTP_TYPE_STR, writable); // get current value @@ -1063,6 +1073,12 @@ MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { ALOGE("unable to read device property, response: %04X", ret); } break; + } + case MTP_DEVICE_PROPERTY_BATTERY_LEVEL: + result = new MtpProperty(property, MTP_TYPE_UINT8); + result->setFormRange(0, env->GetIntField(mDatabase, field_batteryScale), 1); + result->mCurrentValue.u.u8 = (uint8_t)env->GetIntField(mDatabase, field_batteryLevel); + break; } checkAndClearExceptionFromCallback(env, __FUNCTION__); @@ -1234,6 +1250,16 @@ int register_android_mtp_MtpDatabase(JNIEnv *env) ALOGE("Can't find MtpDatabase.mNativeContext"); return -1; } + field_batteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I"); + if (field_batteryLevel == NULL) { + ALOGE("Can't find MtpDatabase.mBatteryLevel"); + return -1; + } + field_batteryScale = env->GetFieldID(clazz, "mBatteryScale", "I"); + if (field_batteryScale == NULL) { + ALOGE("Can't find MtpDatabase.mBatteryScale"); + return -1; + } // now set up fields for MtpPropertyList class clazz = env->FindClass("android/mtp/MtpPropertyList"); diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp index 9d7f1c2..2f90dfe 100644 --- a/media/jni/android_mtp_MtpServer.cpp +++ b/media/jni/android_mtp_MtpServer.cpp @@ -118,6 +118,18 @@ android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle } static void +android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, jint property) +{ + Mutex::Autolock autoLock(sMutex); + + MtpServer* server = getMtpServer(env, thiz); + if (server) + server->sendDevicePropertyChanged(property); + else + ALOGE("server is null in send_object_removed"); +} + +static void android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage) { Mutex::Autolock autoLock(sMutex); @@ -174,6 +186,8 @@ static JNINativeMethod gMethods[] = { {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup}, {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, + {"native_send_device_property_changed", "(I)V", + (void *)android_mtp_MtpServer_send_device_property_changed}, {"native_add_storage", "(Landroid/mtp/MtpStorage;)V", (void *)android_mtp_MtpServer_add_storage}, {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage}, -- cgit v1.1