From 533e072a592826df53b90491bcaa606dfddaf646 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Thu, 21 Jun 2012 19:43:59 +0200
Subject: NEWT: Add virtual on-screen keyboard visibility interface methods
 incl. Android implementation.

Note: Currently only w/ Android implementation.

Note: On Android there is no way to reliably be notified of the current keyboard state.
      It would be best, if your code does not rely on this information

Window adds:
  - setKeyboardVisible(boolean)
  - isKeyboardVisible() // unreliable on Android
---
 src/newt/classes/com/jogamp/newt/Window.java       | 35 ++++++++++++---
 .../classes/com/jogamp/newt/opengl/GLWindow.java   |  8 ++++
 src/newt/classes/jogamp/newt/WindowImpl.java       | 35 ++++++++++++++-
 .../jogamp/newt/driver/android/AndroidWindow.java  | 50 ++++++++++++++++++++++
 .../opengl/test/android/MovieCubeActivity0.java    |  8 +---
 .../opengl/test/android/NEWTGearsES2Activity.java  |  8 +---
 .../test/android/NEWTGearsES2ActivityLauncher.java |  2 +-
 7 files changed, 122 insertions(+), 24 deletions(-)

(limited to 'src')

diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java
index 3c5441bf7..136c19ff8 100644
--- a/src/newt/classes/com/jogamp/newt/Window.java
+++ b/src/newt/classes/com/jogamp/newt/Window.java
@@ -106,11 +106,11 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
     void destroy();
 
     /**
-     * <p>
      * <code>setVisible</code> makes the window and children visible if <code>visible</code> is true,
-     * otherwise the window and children becomes invisible.<br></p>
+     * otherwise the window and children becomes invisible.
      * <p>
-     * The <code>setVisible(true)</code> is responsible to actual create the native window.<br></p>
+     * The <code>setVisible(true)</code> is responsible to actual create the native window.
+     * </p>
      * <p>
      * Zero size semantics are respected, see {@link #setSize(int,int)}:<br>
      * <pre>
@@ -125,10 +125,11 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
      * }
      * </pre></p>
      * <p>
-     * In case this window is a child window and a parent {@link javax.media.nativewindow.NativeWindow} is being used,<br>
-     * the parent's {@link javax.media.nativewindow.NativeWindow} handle is retrieved via {@link javax.media.nativewindow.NativeWindow#getWindowHandle()}.<br>
-     * If this action fails, ie if the parent {@link javax.media.nativewindow.NativeWindow} is not valid yet,<br>
-     * no native window is created yet and <code>setVisible(true)</code> shall be repeated when it is.<br></p>
+     * In case this window is a child window and has a {@link javax.media.nativewindow.NativeWindow} parent,<br>
+     * <code>setVisible(true)</code> has no effect as long the parent's is not valid yet,
+     * i.e. {@link javax.media.nativewindow.NativeWindow#getWindowHandle()} returns <code>null</code>.<br>
+     * <code>setVisible(true)</code> shall be repeated when the parent becomes valid.
+     * </p>
      */
     void setVisible(boolean visible);
 
@@ -399,7 +400,27 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
     // KeyListener
     //
 
+    /**
+     * In case the platform supports or even requires a virtual on-screen keyboard,
+     * this method shows or hide it depending on whether <code>visible</code> is <code>true</code>
+     * or <code>false</code>.
+     * <p>
+     * One known platform where NEWT supports this feature is <code>Android</code>.
+     * </p>
+     */
+    void setKeyboardVisible(boolean visible);
 
+    /** 
+     * Return <code>true</code> if the virtual on-screen keyboard is visible, otherwise <code>false</code>.
+     * <p>
+     * Currently on <code>Android</code>, the only supported platform right now,
+     * there is no way to reliably be notified of the current keyboard state.<br>
+     * It would be best, if your code does not rely on this information.
+     * </p>
+     * @see #setKeyboardVisible(boolean)
+     */
+    boolean isKeyboardVisible();
+    
     /**
      *
      * Appends the given {@link com.jogamp.newt.event.KeyListener} to the end of
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index f89193754..a3adf5090 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -790,6 +790,14 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC
         window.addWindowListener(index, l);
     }
 
+    public final void setKeyboardVisible(boolean visible) {
+        window.setKeyboardVisible(visible);
+    }
+    
+    public final boolean isKeyboardVisible() {
+        return window.isKeyboardVisible();
+    }
+    
     public final void addKeyListener(KeyListener l) {
         window.addKeyListener(l);
     }
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index 074f635e4..68a2430f7 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -303,6 +303,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                     setTitleImpl(title);
                     setPointerVisibleImpl(pointerVisible);
                     confinePointerImpl(pointerConfined);
+                    setKeyboardVisible(keyboardVisible);
                     if(waitForVisible(true, false)) {
                         if(isFullscreen()) {
                             synchronized(fullScreenAction) {
@@ -2182,6 +2183,36 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
         addKeyListener(-1, l);
     }
 
+    public final void setKeyboardVisible(boolean visible) {
+        if(isNativeValid()) {
+            // We don't skip the impl. if it seems that there is no state change,
+            // since we cannot assume the impl. reliably gives us it's current state. 
+            final boolean n = setKeyboardVisibleImpl(visible);
+            if(DEBUG_IMPLEMENTATION || DEBUG_KEY_EVENT) {
+                System.err.println("setKeyboardVisible(native): visible "+keyboardVisible+" -> "+visible +" -> "+n);
+            }
+            keyboardVisible = n;
+        } else {
+            keyboardVisible = visible; // earmark for creation
+        }
+    }
+    public final boolean isKeyboardVisible() {
+        return keyboardVisible;
+    }    
+    protected boolean setKeyboardVisibleImpl(boolean visible) {
+        return false; // nop
+    }
+    /** Triggered by implementation's WM events to update the virtual on-screen keyboard's visibility state. */
+    protected void keyboardVisibilityChanged(boolean visible) {
+        if(keyboardVisible != visible) {
+            if(DEBUG_IMPLEMENTATION || DEBUG_KEY_EVENT) {
+                System.err.println("keyboardVisibilityChanged: "+keyboardVisible+" -> "+visible);
+            }
+            keyboardVisible = visible;
+        }
+    }
+    protected boolean keyboardVisible = false;
+    
     public void addKeyListener(int index, KeyListener l) {
         if(l == null) {
             return;
@@ -2356,8 +2387,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
                 enqueueWindowEvent(false, evt);
             }
         }
-    }    
-
+    }
+    
     /** Triggered by implementation's WM events to update the visibility state. */
     protected void visibleChanged(boolean defer, boolean visible) {
         if(this.visible != visible) {
diff --git a/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java b/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java
index 63d5f7003..73192a07f 100644
--- a/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java
+++ b/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java
@@ -48,10 +48,14 @@ import jogamp.opengl.egl.EGLGraphicsConfigurationFactory;
 
 import android.content.Context;
 import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ResultReceiver;
 import android.util.Log;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceHolder.Callback2;
+import android.view.inputmethod.InputMethodManager;
 import android.view.SurfaceView;
 import android.view.View;
 
@@ -316,6 +320,52 @@ public class AndroidWindow extends jogamp.newt.WindowImpl implements Callback2 {
         // nop ..        
     }
     
+    //----------------------------------------------------------------------
+    // Virtual On-Screen Keyboard / SoftInput 
+    //
+    
+    private class KeyboardVisibleReceiver extends ResultReceiver {
+        public KeyboardVisibleReceiver() {
+            super(null);
+        }
+        
+        @Override 
+        public void onReceiveResult(int r, Bundle data) {
+            boolean v = false;
+        
+            switch(r) {
+                case InputMethodManager.RESULT_UNCHANGED_SHOWN:
+                case InputMethodManager.RESULT_SHOWN:
+                    v = true;
+                    break;
+                case InputMethodManager.RESULT_HIDDEN:
+                case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
+                    v = false;
+                    break;            
+            }
+            Log.d(MD.TAG, "keyboardVisible: "+v);
+            keyboardVisibilityChanged(v);
+        }
+    }
+    private KeyboardVisibleReceiver keyboardVisibleReceiver = new KeyboardVisibleReceiver();
+    
+    protected final boolean setKeyboardVisibleImpl(boolean visible) {
+        if(null != androidView) {
+            final InputMethodManager imm = (InputMethodManager) getAndroidView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+            final IBinder winid = getAndroidView().getWindowToken();
+            if(visible) {
+                // Show soft-keyboard:
+                imm.showSoftInput(androidView, 0, keyboardVisibleReceiver);
+            } else {
+                // hide keyboard :
+                imm.hideSoftInputFromWindow(winid, 0, keyboardVisibleReceiver);
+            }
+            return visible;
+        } else {
+            return false; // nop
+        }
+    }
+    
     //----------------------------------------------------------------------
     // Surface Callbacks 
     //
diff --git a/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java b/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java
index 59e78936d..a30262ee3 100644
--- a/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java
+++ b/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java
@@ -34,7 +34,6 @@ import java.util.Arrays;
 import javax.media.opengl.GLCapabilities;
 import javax.media.opengl.GLProfile;
 
-import jogamp.newt.driver.android.AndroidWindow;
 import jogamp.newt.driver.android.NewtBaseActivity;
 
 import com.jogamp.common.util.IOUtil;
@@ -46,10 +45,8 @@ import com.jogamp.newt.opengl.GLWindow;
 import com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube;
 import com.jogamp.opengl.util.Animator;
 
-import android.content.Context;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.inputmethod.InputMethodManager;
 
 public class MovieCubeActivity0 extends NewtBaseActivity {
    static String TAG = "MovieCubeActivity0";
@@ -58,10 +55,7 @@ public class MovieCubeActivity0 extends NewtBaseActivity {
         @Override
         public void mousePressed(MouseEvent e) {
            if(e.getPressure()>2f) {
-               final AndroidWindow win = (AndroidWindow)e.getSource();           
-               InputMethodManager mgr = (InputMethodManager) win.getAndroidView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-               mgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); // shows keyboard ..
-               win.getAndroidView().requestFocus();
+               ((com.jogamp.newt.Window) e.getSource()).setKeyboardVisible(true);
            }
         }
    };
diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java
index 592ecf5d6..4468868f6 100644
--- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java
+++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java
@@ -30,7 +30,6 @@ package com.jogamp.opengl.test.android;
 import javax.media.opengl.GLCapabilities;
 import javax.media.opengl.GLProfile;
 
-import jogamp.newt.driver.android.AndroidWindow;
 import jogamp.newt.driver.android.NewtBaseActivity;
 
 import com.jogamp.newt.ScreenMode;
@@ -42,10 +41,8 @@ import com.jogamp.newt.opengl.GLWindow;
 import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
 import com.jogamp.opengl.util.Animator;
 
-import android.content.Context;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.inputmethod.InputMethodManager;
 
 public class NEWTGearsES2Activity extends NewtBaseActivity {
    static String TAG = "NEWTGearsES2Activity";
@@ -65,10 +62,7 @@ public class NEWTGearsES2Activity extends NewtBaseActivity {
         @Override
         public void mousePressed(MouseEvent e) {
            if(e.getPressure()>2f) { // show Keyboard
-               final AndroidWindow win = (AndroidWindow)e.getSource();           
-               InputMethodManager mgr = (InputMethodManager) win.getAndroidView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-               mgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); // shows keyboard ..
-               win.getAndroidView().requestFocus();
+               ((com.jogamp.newt.Window) e.getSource()).setKeyboardVisible(true);
            }
         }
        });
diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2ActivityLauncher.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2ActivityLauncher.java
index 0454d543c..907be5092 100644
--- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2ActivityLauncher.java
+++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2ActivityLauncher.java
@@ -59,7 +59,7 @@ public class NEWTGearsES2ActivityLauncher extends LauncherUtil.BaseActivityLaunc
        // properties.setProperty("newt.debug", "all");
        // props.setProperty("newt.debug.Window", "true");
        // props.setProperty("newt.debug.Window.MouseEvent", "true");
-       // props.setProperty("newt.debug.Window.KeyEvent", "true");
+       props.setProperty("newt.debug.Window.KeyEvent", "true");
     }
     
     @Override
-- 
cgit v1.2.3