Use a Native keyboard GUI instead of rockbox's internal one on android

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28407 a1c6a512-1295-4272-9138-f99709370657
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 4518241..c52cac2 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -17,7 +17,8 @@
       	</activity>
         <service android:name=".RockboxService"/>
 
-    </application>
+    <activity android:name="KeyboardActivity" android:launchMode="singleTop"></activity>
+</application>
 <uses-sdk android:minSdkVersion="4" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
 </manifest> 
diff --git a/android/res/layout/keyboardinput.xml b/android/res/layout/keyboardinput.xml
new file mode 100644
index 0000000..124eda8
--- /dev/null
+++ b/android/res/layout/keyboardinput.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<AbsoluteLayout android:id="@+id/AbsoluteLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"><EditText android:layout_height="wrap_content" android:text="Some Text" android:layout_width="fill_parent" android:id="@+id/KbdInput"></EditText>
+</AbsoluteLayout>
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 9320b26..b0d41f1 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -3,4 +3,7 @@
     
     <string name="app_name">Rockbox</string>
 <string name="notification">Rockbox</string>
+<string name="OK">OK</string>
+<string name="Cancel">Cancel</string>
+<string name="KbdInputTitle">Rockbox Keyboard Input</string>
 </resources>
diff --git a/android/src/org/rockbox/HostCallback.java b/android/src/org/rockbox/HostCallback.java
new file mode 100644
index 0000000..0e69b3f
--- /dev/null
+++ b/android/src/org/rockbox/HostCallback.java
@@ -0,0 +1,7 @@
+package org.rockbox;
+
+import android.content.Intent;
+
+public interface HostCallback {
+	public void onComplete(int resultCode, Intent data);
+}
diff --git a/android/src/org/rockbox/KeyboardActivity.java b/android/src/org/rockbox/KeyboardActivity.java
new file mode 100644
index 0000000..f32aae2
--- /dev/null
+++ b/android/src/org/rockbox/KeyboardActivity.java
@@ -0,0 +1,41 @@
+package org.rockbox;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.Editable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+
+public class KeyboardActivity extends Activity {
+	public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        LayoutInflater inflater=LayoutInflater.from(this);
+		View addView=inflater.inflate(R.layout.keyboardinput, null);
+		EditText input = (EditText) addView.findViewById(R.id.KbdInput);
+        input.setText(getIntent().getStringExtra("value"));
+        new AlertDialog.Builder(this)
+		.setTitle(R.string.KbdInputTitle)
+		.setView(addView)
+		.setIcon(R.drawable.icon)
+		.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
+			public void onClick(DialogInterface dialog, int whichButton) {
+				EditText input = (EditText)((Dialog)dialog).findViewById(R.id.KbdInput);
+				Editable s = input.getText();
+				getIntent().putExtra("value", s.toString());
+				setResult(RESULT_OK, getIntent());
+				finish();
+			}
+		})
+		.setNegativeButton(R.string.Cancel, new DialogInterface.OnClickListener() {
+			public void onClick(DialogInterface dialog, int whichButton) {
+				setResult(RESULT_CANCELED, getIntent());
+				finish();
+			}
+		})
+		.show();
+    }
+}
diff --git a/android/src/org/rockbox/RockboxActivity.java b/android/src/org/rockbox/RockboxActivity.java
index f775597..9eed3f4 100644
--- a/android/src/org/rockbox/RockboxActivity.java
+++ b/android/src/org/rockbox/RockboxActivity.java
@@ -24,7 +24,9 @@
 import android.app.Activity;
 import android.app.ProgressDialog;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
@@ -41,6 +43,7 @@
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
                        ,WindowManager.LayoutParams.FLAG_FULLSCREEN);
+        final Activity thisActivity = this;
         final Intent intent = new Intent(this, RockboxService.class);
         /* prepare a please wait dialog in case we need
          * to wait for unzipping libmisc.so
@@ -95,7 +98,8 @@
                 		loadingdialog.dismiss();
                 		if (rbservice.get_fb() == null)
                 		    throw new IllegalStateException("FB NULL");
-                        setContentView(rbservice.get_fb());
+                        rbservice.set_activity(thisActivity);
+                		setContentView(rbservice.get_fb());
                         rbservice.get_fb().invalidate();
                     }
                 });
@@ -111,6 +115,7 @@
     
     public void onResume()
     {
+    	
         super.onResume();
         if (isRockboxRunning())
         {
@@ -123,6 +128,7 @@
                 g.removeView(rbservice.get_fb());
                 setContentView(rbservice.get_fb());
             } finally {
+            	rbservice.set_activity(this);
                 rbservice.get_fb().resume();
             }
         }
@@ -135,6 +141,7 @@
     protected void onPause() 
     {
         super.onPause();
+        rbservice.set_activity(null);
         rbservice.get_fb().suspend();
     }
     
@@ -142,6 +149,7 @@
     protected void onStop() 
     {
         super.onStop();
+        rbservice.set_activity(null);
         rbservice.get_fb().suspend();
     }
     
@@ -149,6 +157,29 @@
     protected void onDestroy() 
     {
         super.onDestroy();
+        rbservice.set_activity(null);
         rbservice.get_fb().suspend();
     }
+    
+    private HostCallback hostcallback = null;
+    public void waitForActivity(Intent i, HostCallback callback)
+    {
+    	if (hostcallback !=  null)
+    	{
+    		LOG("Something has gone wrong");
+    	}
+    	hostcallback = callback;
+    	startActivityForResult(i, 0);
+    }
+
+    public void onActivityResult(int requestCode, int resultCode, Intent data)
+    {
+    	hostcallback.onComplete(resultCode, data);
+    	hostcallback = null;
+    }
+
+    private void LOG(CharSequence text)
+    {
+        Log.d("Rockbox", (String) text);
+    }
 }
diff --git a/android/src/org/rockbox/RockboxFramebuffer.java b/android/src/org/rockbox/RockboxFramebuffer.java
index e90eb86..20311a8 100644
--- a/android/src/org/rockbox/RockboxFramebuffer.java
+++ b/android/src/org/rockbox/RockboxFramebuffer.java
@@ -118,12 +118,11 @@
         setFocusableInTouchMode(true);
         setClickable(true);
         requestFocus();
-        /* make updates again, the underlying function will 
-         * send an event */
         set_lcd_active(1);
     }
 
     public native void set_lcd_active(int active);
     public native void touchHandler(boolean down, int x, int y);
     public native boolean buttonHandler(int keycode, boolean state);
+    
 }
diff --git a/android/src/org/rockbox/RockboxKeyboardInput.java b/android/src/org/rockbox/RockboxKeyboardInput.java
new file mode 100644
index 0000000..b037f6c
--- /dev/null
+++ b/android/src/org/rockbox/RockboxKeyboardInput.java
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Jonathan Gordon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+package org.rockbox;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.util.Log;
+
+public class RockboxKeyboardInput
+{
+	private BroadcastReceiver b;
+	private String result;
+	
+    public RockboxKeyboardInput()
+    {
+    	result = null;
+    }    
+
+    public void kbd_input(String text) 
+    {
+    	RockboxActivity a = (RockboxActivity) RockboxService.get_instance().get_activity();
+    	Intent kbd = new Intent(a, KeyboardActivity.class);
+    	kbd.putExtra("value", text);
+    	a.waitForActivity(kbd, new HostCallback(){
+
+			@Override
+			public void onComplete(int resultCode, Intent data) {
+				if (resultCode == Activity.RESULT_OK)
+				{
+					result = data.getStringExtra("value");
+				}
+				else {
+					result = "";
+				}
+			}
+		});
+    }
+	public String get_result()
+    {
+    	return result;
+    }
+	
+	public boolean is_usable()
+	{
+		return RockboxService.get_instance().get_activity() != null;
+	}
+    
+
+}
diff --git a/android/src/org/rockbox/RockboxService.java b/android/src/org/rockbox/RockboxService.java
index c403736..bbcdfec 100644
--- a/android/src/org/rockbox/RockboxService.java
+++ b/android/src/org/rockbox/RockboxService.java
@@ -35,6 +35,7 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import android.app.Activity;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -61,6 +62,7 @@
     /* locals needed for the c code and rockbox state */
     private RockboxFramebuffer fb = null;
     private boolean mRockboxRunning = false;
+    private Activity current_activity = null; 
     
     private Notification notification;
     private static final Class<?>[] mStartForegroundSignature = 
@@ -113,6 +115,16 @@
     	fb = newfb;
         mRockboxRunning = true;
     }
+    
+    public Activity get_activity()
+    {
+    	return current_activity;
+    }
+    public void set_activity(Activity a)
+    {
+    	current_activity = a;
+    }
+    
 
     private void do_start(Intent intent)
     {
diff --git a/apps/SOURCES b/apps/SOURCES
index ad1003b..cb5e6ef 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -116,7 +116,11 @@
 #ifdef HAVE_LCD_BITMAP
 recorder/bmp.c
 recorder/icons.c
+#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
+hosted/keyboard.c
+#else
 recorder/keyboard.c
+#endif
 recorder/peakmeter.c
 #if defined(HAVE_ALBUMART) || defined(HAVE_JPEG)
 recorder/resize.c
diff --git a/apps/hosted/keyboard.c b/apps/hosted/keyboard.c
new file mode 100644
index 0000000..b395168
--- /dev/null
+++ b/apps/hosted/keyboard.c
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Jonathan Gordon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+
+#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
+#include <jni.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <system.h>
+
+extern JNIEnv *env_ptr;
+static jclass    RockboxKeyboardInput_class = NULL;
+static jobject   RockboxKeyboardInput_instance;
+static jmethodID kbd_inputfunc, kbd_result;
+
+static void kdb_init(void)
+{
+    JNIEnv e = *env_ptr;
+    jmethodID kbd_is_usable;
+    if (RockboxKeyboardInput_class == NULL)
+    {
+        /* get the class and its constructor */
+        RockboxKeyboardInput_class = e->FindClass(env_ptr, "org/rockbox/RockboxKeyboardInput");
+        jmethodID constructor = e->GetMethodID(env_ptr, RockboxKeyboardInput_class, "<init>", "()V");
+        RockboxKeyboardInput_instance = e->NewObject(env_ptr, RockboxKeyboardInput_class, constructor);
+        kbd_inputfunc = e->GetMethodID(env_ptr, RockboxKeyboardInput_class,
+                                    "kbd_input", "(Ljava/lang/String;)V");
+        kbd_result = e->GetMethodID(env_ptr, RockboxKeyboardInput_class,
+                                    "get_result", "()Ljava/lang/String;");
+    }
+    /* need to get it every time incase the activity died/restarted */
+    kbd_is_usable = e->GetMethodID(env_ptr, RockboxKeyboardInput_class,
+                                "is_usable", "()Z");
+    while (!e->CallBooleanMethod(env_ptr, RockboxKeyboardInput_instance, kbd_is_usable))
+        sleep(HZ/10);
+}
+
+int kbd_input(char* text, int buflen)
+{
+    JNIEnv e = *env_ptr;
+    jstring str = e->NewStringUTF(env_ptr, text);
+    jobject ret;
+    const char* retchars;
+    kdb_init();
+
+    e->CallVoidMethod(env_ptr, RockboxKeyboardInput_instance, kbd_inputfunc, str);
+
+    do {
+        sleep(HZ/10);
+        ret = e->CallObjectMethod(env_ptr, RockboxKeyboardInput_instance, kbd_result);
+    } while (!ret);
+    
+    e->ReleaseStringChars(env_ptr, str, NULL);
+    retchars = e->GetStringUTFChars(env_ptr, ret, 0);
+    if (retchars[0])
+        snprintf(text, buflen, retchars);
+    e->ReleaseStringUTFChars(env_ptr, ret, retchars);
+    
+    return retchars[0]?0:1; /* return 0 on success */
+}
+
+int load_kbd(unsigned char* filename)
+{
+    (void)filename;
+    return 1;
+}
+
+#endif