MTP: Add support for battery level device property

Bug: 7342482

Change-Id: I810e55fe9695e2206816f57334ad14f65e9c641d
This commit is contained in:
Mike Lockwood
2014-03-07 13:29:08 -08:00
parent daeb393618
commit 56c85244b9
4 changed files with 149 additions and 60 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
if (!getDevicePropertyInfo(property, type))
return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
JNIEnv* env = AndroidRuntime::getJNIEnv();
jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
(jint)property, mLongBuffer, mStringBuffer);
if (result != MTP_RESPONSE_OK) {
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;
}
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;
}
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return result;
return MTP_RESPONSE_OK;
}
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;
}
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");

View File

@ -117,6 +117,18 @@ android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle
ALOGE("server is null in send_object_removed");
}
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)
{
@ -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},