Add settings option for running MTP server in PTP mode.

This can be used as a compatibility workaround for host operating systems
without MTP support.

Change-Id: If4f1856206056ca8e40c3ffbfa382f185c413598
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6d3ca276..57fa463 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1686,6 +1686,12 @@
         public static final String UNLOCK_SOUND = "unlock_sound";
 
         /**
+         * True if we should appear as a PTP device instead of MTP.
+         * @hide
+         */
+        public static final String USE_PTP_INTERFACE = "use_ptp_interface";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          * @hide
@@ -1745,7 +1751,8 @@
             DOCK_SOUNDS_ENABLED,
             LOCKSCREEN_SOUNDS_ENABLED,
             SHOW_WEB_SUGGESTIONS,
-            NOTIFICATION_LIGHT_PULSE
+            NOTIFICATION_LIGHT_PULSE,
+            USE_PTP_INTERFACE,
         };
 
         // Settings moved to Settings.Secure
diff --git a/media/java/android/media/MtpServer.java b/media/java/android/media/MtpServer.java
index dcf08e2..7f15276 100644
--- a/media/java/android/media/MtpServer.java
+++ b/media/java/android/media/MtpServer.java
@@ -59,6 +59,10 @@
         native_send_object_removed(handle);
     }
 
+    public void setPtpMode(boolean usePtp) {
+        native_set_ptp_mode(usePtp);
+    }
+
     // used by the JNI code
     private int mNativeContext;
 
@@ -68,4 +72,5 @@
     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);
+    private native final void native_set_ptp_mode(boolean usePtp);
 }
diff --git a/media/jni/android_media_MtpServer.cpp b/media/jni/android_media_MtpServer.cpp
index 3305136..3da3165 100644
--- a/media/jni/android_media_MtpServer.cpp
+++ b/media/jni/android_media_MtpServer.cpp
@@ -22,8 +22,11 @@
 #include <limits.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/ioctl.h>
 #include <utils/threads.h>
 
+#include <linux/usb/f_mtp.h>
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
@@ -56,34 +59,54 @@
     MtpServer*      mServer;
     String8         mStoragePath;
     jobject         mJavaServer;
+    int             mFd;
 
 public:
     MtpThread(MtpDatabase* database, const char* storagePath, jobject javaServer)
-        : mDatabase(database),
+        :   mDatabase(database),
             mServer(NULL),
             mStoragePath(storagePath),
-            mJavaServer(javaServer)
+            mJavaServer(javaServer),
+            mFd(-1)
     {
     }
 
+    void setPtpMode(bool usePtp) {
+        sMutex.lock();
+        if (mFd >= 0) {
+            ioctl(mFd, MTP_SET_INTERFACE_MODE,
+                    (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
+        } else {
+            int fd = open("/dev/mtp_usb", O_RDWR);
+            if (fd >= 0) {
+                ioctl(fd, MTP_SET_INTERFACE_MODE,
+                        (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
+                close(fd);
+            }
+        }
+        sMutex.unlock();
+    }
+
     virtual bool threadLoop() {
-        int fd = open("/dev/mtp_usb", O_RDWR);
-        printf("open returned %d\n", fd);
-        if (fd < 0) {
+        sMutex.lock();
+        mFd = open("/dev/mtp_usb", O_RDWR);
+        printf("open returned %d\n", mFd);
+        if (mFd < 0) {
             LOGE("could not open MTP driver\n");
+            sMutex.unlock();
             return false;
         }
 
-        sMutex.lock();
-        mServer = new MtpServer(fd, mDatabase, AID_SDCARD_RW, 0664, 0775);
+        mServer = new MtpServer(mFd, mDatabase, AID_SDCARD_RW, 0664, 0775);
         mServer->addStorage(mStoragePath);
         sMutex.unlock();
 
         LOGD("MtpThread mServer->run");
         mServer->run();
-        close(fd);
 
         sMutex.lock();
+        close(mFd);
+        mFd = -1;
         delete mServer;
         mServer = NULL;
 
@@ -184,6 +207,17 @@
 #endif
 }
 
+static void
+android_media_MtpServer_set_ptp_mode(JNIEnv *env, jobject thiz, jboolean usePtp)
+{
+#ifdef HAVE_ANDROID_OS
+    LOGD("set_ptp_mode\n");
+    MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
+    if (thread)
+        thread->setPtpMode(usePtp);
+ #endif
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -194,6 +228,7 @@
     {"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},
+    {"native_set_ptp_mode",         "(Z)V", (void *)android_media_MtpServer_set_ptp_mode},
 };
 
 static const char* const kClassPathName = "android/media/MtpServer";
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 8349fe6..fbeaf4f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -72,4 +72,6 @@
 
     <!-- Default for Settings.System.VIBRATE_IN_SILENT -->
     <bool name="def_vibrate_in_silent">true</bool>
+
+    <bool name="def_use_ptp_interface">false</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 7395233..a793106 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1047,6 +1047,9 @@
     
             loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT,
                     R.bool.def_vibrate_in_silent);
+
+            loadBooleanSetting(stmt, Settings.System.USE_PTP_INTERFACE,
+                    R.bool.def_use_ptp_interface);
         } finally {
             if (stmt != null) stmt.close();
         }