summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-07-13 19:50:36 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2010-07-13 19:50:36 -0700
commit2388ad9eef109fa7f63c196c819c83f0376f0645 (patch)
tree19c965b6d7efb893604fc448cebc9380ebb60fb6
parentfc6d300f408959b11f86623ea7a0ce547ded3563 (diff)
parentf8d9379bd834573feca085284970cf686993c330 (diff)
downloadframeworks_base-2388ad9eef109fa7f63c196c819c83f0376f0645.zip
frameworks_base-2388ad9eef109fa7f63c196c819c83f0376f0645.tar.gz
frameworks_base-2388ad9eef109fa7f63c196c819c83f0376f0645.tar.bz2
am f8d9379b: am d76b67c3: IME events are now dispatched to native applications.
Merge commit 'f8d9379bd834573feca085284970cf686993c330' * commit 'f8d9379bd834573feca085284970cf686993c330': IME events are now dispatched to native applications.
-rw-r--r--api/current.xml66
-rw-r--r--core/java/android/app/NativeActivity.java101
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java47
-rw-r--r--core/java/android/view/SurfaceHolder.java17
-rw-r--r--core/java/android/view/SurfaceView.java37
-rw-r--r--core/java/android/view/ViewRoot.java14
-rw-r--r--core/java/android/view/Window.java2
-rw-r--r--core/java/com/android/internal/view/RootViewSurfaceTaker.java2
-rw-r--r--core/jni/android_app_NativeActivity.cpp337
-rw-r--r--include/android_runtime/android_app_NativeActivity.h60
-rw-r--r--include/ui/Input.h4
-rw-r--r--include/ui/InputTransport.h26
-rw-r--r--libs/ui/InputTransport.cpp19
-rw-r--r--native/android/input.cpp62
-rw-r--r--native/android/native_activity.cpp8
-rw-r--r--native/glue/threaded_app/threaded_app.c61
-rw-r--r--native/include/android/native_activity.h42
-rw-r--r--native/include/android_glue/threaded_app.h32
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java6
19 files changed, 768 insertions, 175 deletions
diff --git a/api/current.xml b/api/current.xml
index 086a87a..9486ca6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -28906,7 +28906,9 @@
>
<implements name="android.view.InputQueue.Callback">
</implements>
-<implements name="android.view.SurfaceHolder.Callback">
+<implements name="android.view.SurfaceHolder.Callback2">
+</implements>
+<implements name="android.view.ViewTreeObserver.OnGlobalLayoutListener">
</implements>
<constructor name="NativeActivity"
type="android.app.NativeActivity"
@@ -28916,6 +28918,17 @@
visibility="public"
>
</constructor>
+<method name="onGlobalLayout"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onInputQueueCreated"
return="void"
abstract="false"
@@ -28987,6 +29000,19 @@
<parameter name="holder" type="android.view.SurfaceHolder">
</parameter>
</method>
+<method name="surfaceRedrawNeeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
<field name="META_DATA_LIB_NAME"
type="java.lang.String"
transient="false"
@@ -147148,6 +147174,19 @@
<parameter name="holder" type="android.view.SurfaceHolder">
</parameter>
</method>
+<method name="onSurfaceRedrawNeeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
<method name="onTouchEvent"
return="void"
abstract="false"
@@ -183229,6 +183268,29 @@
</parameter>
</method>
</interface>
+<interface name="SurfaceHolder.Callback2"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.view.SurfaceHolder.Callback">
+</implements>
+<method name="surfaceRedrawNeeded"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
+</interface>
<class name="SurfaceView"
extends="android.view.View"
abstract="false"
@@ -191868,7 +191930,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.view.SurfaceHolder.Callback">
+<parameter name="callback" type="android.view.SurfaceHolder.Callback2">
</parameter>
</method>
<method name="togglePanel"
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index d72dda7..ccc9ae3 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -2,6 +2,7 @@ package android.app;
import dalvik.system.PathClassLoader;
+import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -11,12 +12,16 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.Looper;
import android.os.MessageQueue;
+import android.util.AttributeSet;
import android.view.InputChannel;
import android.view.InputQueue;
import android.view.KeyEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
+import android.view.WindowManager;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.inputmethod.InputMethodManager;
import java.io.File;
@@ -24,15 +29,26 @@ import java.io.File;
* Convenience for implementing an activity that will be implemented
* purely in native code. That is, a game (or game-like thing).
*/
-public class NativeActivity extends Activity implements SurfaceHolder.Callback,
- InputQueue.Callback {
+public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
+ InputQueue.Callback, OnGlobalLayoutListener {
public static final String META_DATA_LIB_NAME = "android.app.lib_name";
+ private NativeContentView mNativeContentView;
+ private InputMethodManager mIMM;
+
private int mNativeHandle;
private InputQueue mCurInputQueue;
private SurfaceHolder mCurSurfaceHolder;
+ final int[] mLocation = new int[2];
+ int mLastContentX;
+ int mLastContentY;
+ int mLastContentWidth;
+ int mLastContentHeight;
+
+ private boolean mDispatchingUnhandledKey;
+
private boolean mDestroyed;
private native int loadNativeCode(String path, MessageQueue queue,
@@ -49,18 +65,44 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
private native void onSurfaceCreatedNative(int handle, Surface surface);
private native void onSurfaceChangedNative(int handle, Surface surface,
int format, int width, int height);
+ private native void onSurfaceRedrawNeededNative(int handle, Surface surface);
private native void onSurfaceDestroyedNative(int handle);
private native void onInputChannelCreatedNative(int handle, InputChannel channel);
private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
+ private native void onContentRectChangedNative(int handle, int x, int y, int w, int h);
+ private native void dispatchKeyEventNative(int handle, KeyEvent event);
+
+ static class NativeContentView extends View {
+ NativeActivity mActivity;
+
+ public NativeContentView(Context context) {
+ super(context);
+ }
+
+ public NativeContentView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
String libname = "main";
ActivityInfo ai;
+ mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+
getWindow().takeSurface(this);
getWindow().takeInputQueue(this);
getWindow().setFormat(PixelFormat.RGB_565);
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
+ | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+ mNativeContentView = new NativeContentView(this);
+ mNativeContentView.mActivity = this;
+ setContentView(mNativeContentView);
+ mNativeContentView.requestFocus();
+ mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
try {
ai = getPackageManager().getActivityInfo(
@@ -165,6 +207,18 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
}
}
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (mDispatchingUnhandledKey) {
+ return super.dispatchKeyEvent(event);
+ } else {
+ // Key events from the IME do not go through the input channel;
+ // we need to intercept them here to hand to the application.
+ dispatchKeyEventNative(mNativeHandle, event);
+ return true;
+ }
+ }
+
public void surfaceCreated(SurfaceHolder holder) {
if (!mDestroyed) {
mCurSurfaceHolder = holder;
@@ -179,6 +233,13 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
}
}
+ public void surfaceRedrawNeeded(SurfaceHolder holder) {
+ if (!mDestroyed) {
+ mCurSurfaceHolder = holder;
+ onSurfaceRedrawNeededNative(mNativeHandle, holder.getSurface());
+ }
+ }
+
public void surfaceDestroyed(SurfaceHolder holder) {
mCurSurfaceHolder = null;
if (!mDestroyed) {
@@ -200,10 +261,32 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
}
}
+ public void onGlobalLayout() {
+ mNativeContentView.getLocationInWindow(mLocation);
+ int w = mNativeContentView.getWidth();
+ int h = mNativeContentView.getHeight();
+ if (mLocation[0] != mLastContentX || mLocation[1] != mLastContentY
+ || w != mLastContentWidth || h != mLastContentHeight) {
+ mLastContentX = mLocation[0];
+ mLastContentY = mLocation[1];
+ mLastContentWidth = w;
+ mLastContentHeight = h;
+ if (!mDestroyed) {
+ onContentRectChangedNative(mNativeHandle, mLastContentX,
+ mLastContentY, mLastContentWidth, mLastContentHeight);
+ }
+ }
+ }
+
void dispatchUnhandledKeyEvent(KeyEvent event) {
- View decor = getWindow().getDecorView();
- if (decor != null) {
- decor.dispatchKeyEvent(event);
+ try {
+ mDispatchingUnhandledKey = true;
+ View decor = getWindow().getDecorView();
+ if (decor != null) {
+ decor.dispatchKeyEvent(event);
+ }
+ } finally {
+ mDispatchingUnhandledKey = false;
}
}
@@ -214,4 +297,12 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
void setWindowFormat(int format) {
getWindow().setFormat(format);
}
+
+ void showIme(int mode) {
+ mIMM.showSoftInput(mNativeContentView, mode);
+ }
+
+ void hideIme(int mode) {
+ mIMM.hideSoftInputFromWindow(mNativeContentView.getWindowToken(), mode);
+ }
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 6f12f19..2d120e8 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -336,7 +336,7 @@ public abstract class WallpaperService extends Service {
? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
: (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
if (mCreated) {
- updateSurface(false, false);
+ updateSurface(false, false, false);
}
}
@@ -421,6 +421,13 @@ public abstract class WallpaperService extends Service {
}
/**
+ * Convenience for {@link SurfaceHolder.Callback#surfaceRedrawNeeded
+ * SurfaceHolder.Callback.surfaceRedrawNeeded()}.
+ */
+ public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
+ }
+
+ /**
* Convenience for {@link SurfaceHolder.Callback#surfaceCreated
* SurfaceHolder.Callback.surfaceCreated()}.
*/
@@ -450,7 +457,7 @@ public abstract class WallpaperService extends Service {
}
}
- void updateSurface(boolean forceRelayout, boolean forceReport) {
+ void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
if (mDestroyed) {
Log.w(TAG, "Ignoring updateSurface: destroyed");
}
@@ -467,7 +474,7 @@ public abstract class WallpaperService extends Service {
final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged
- || typeChanged || flagsChanged) {
+ || typeChanged || flagsChanged || redrawNeeded) {
if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged);
@@ -555,6 +562,10 @@ public abstract class WallpaperService extends Service {
}
}
}
+
+ redrawNeeded |= creating
+ || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0;
+
if (forceReport || creating || surfaceCreating
|| formatChanged || sizeChanged) {
if (DEBUG) {
@@ -578,10 +589,24 @@ public abstract class WallpaperService extends Service {
}
}
}
+
+ if (redrawNeeded) {
+ onSurfaceRedrawNeeded(mSurfaceHolder);
+ SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ if (c instanceof SurfaceHolder.Callback2) {
+ ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+ mSurfaceHolder);
+ }
+ }
+ }
+ }
+
} finally {
mIsCreating = false;
mSurfaceCreated = true;
- if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ if (redrawNeeded) {
mSession.finishDrawing(mWindow);
}
}
@@ -618,7 +643,7 @@ public abstract class WallpaperService extends Service {
onCreate(mSurfaceHolder);
mInitializing = false;
- updateSurface(false, false);
+ updateSurface(false, false, false);
}
void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
@@ -647,7 +672,7 @@ public abstract class WallpaperService extends Service {
// If becoming visible, in preview mode the surface
// may have been destroyed so now we need to make
// sure it is re-created.
- updateSurface(false, false);
+ updateSurface(false, false, false);
}
onVisibilityChanged(visible);
}
@@ -852,7 +877,7 @@ public abstract class WallpaperService extends Service {
return;
}
case MSG_UPDATE_SURFACE:
- mEngine.updateSurface(true, false);
+ mEngine.updateSurface(true, false, false);
break;
case MSG_VISIBILITY_CHANGED:
if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
@@ -868,14 +893,8 @@ public abstract class WallpaperService extends Service {
} break;
case MSG_WINDOW_RESIZED: {
final boolean reportDraw = message.arg1 != 0;
- mEngine.updateSurface(true, false);
+ mEngine.updateSurface(true, false, reportDraw);
mEngine.doOffsetsChanged();
- if (reportDraw) {
- try {
- mEngine.mSession.finishDrawing(mEngine.mWindow);
- } catch (RemoteException e) {
- }
- }
} break;
case MSG_TOUCH_EVENT: {
MotionEvent ev = (MotionEvent)message.obj;
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 34e4638..0d38f7b 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -119,6 +119,23 @@ public interface SurfaceHolder {
}
/**
+ * Additional callbacks that can be received for {@link Callback}.
+ */
+ public interface Callback2 extends Callback {
+ /**
+ * Called when the application needs to redraw the content of its
+ * surface, after it is resized or for some other reason. By not
+ * returning here until the redraw is complete, you can ensure that
+ * the user will not see your surface in a bad state (at its new
+ * size before it has been correctly drawn that way). This will
+ * typically be preceeded by a call to {@link #surfaceChanged}.
+ *
+ * @param holder The SurfaceHolder whose surface has changed.
+ */
+ public void surfaceRedrawNeeded(SurfaceHolder holder);
+ }
+
+ /**
* Add a Callback interface for this holder. There can several Callback
* interfaces associated to a holder.
*
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index e4d1ae1..c469bcc 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -123,7 +123,7 @@ public class SurfaceView extends View {
handleGetNewSurface();
} break;
case UPDATE_WINDOW_MSG: {
- updateWindow(false);
+ updateWindow(false, false);
} break;
}
}
@@ -132,7 +132,7 @@ public class SurfaceView extends View {
final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
= new ViewTreeObserver.OnScrollChangedListener() {
public void onScrollChanged() {
- updateWindow(false);
+ updateWindow(false, false);
}
};
@@ -210,7 +210,7 @@ public class SurfaceView extends View {
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
- updateWindow(false);
+ updateWindow(false, false);
}
@Override
@@ -218,7 +218,7 @@ public class SurfaceView extends View {
super.setVisibility(visibility);
mViewVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
- updateWindow(false);
+ updateWindow(false, false);
}
/**
@@ -232,7 +232,7 @@ public class SurfaceView extends View {
*/
protected void showSurface() {
if (mSession != null) {
- updateWindow(true);
+ updateWindow(true, false);
}
}
@@ -265,7 +265,7 @@ public class SurfaceView extends View {
protected void onDetachedFromWindow() {
getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener);
mRequestedVisible = false;
- updateWindow(false);
+ updateWindow(false, false);
mHaveFrame = false;
if (mWindow != null) {
try {
@@ -290,7 +290,7 @@ public class SurfaceView extends View {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- updateWindow(false);
+ updateWindow(false, false);
}
@Override
@@ -343,7 +343,7 @@ public class SurfaceView extends View {
}
// reposition ourselves where the surface is
mHaveFrame = true;
- updateWindow(false);
+ updateWindow(false, false);
super.dispatchDraw(canvas);
}
@@ -397,7 +397,7 @@ public class SurfaceView extends View {
mWindowType = type;
}
- private void updateWindow(boolean force) {
+ private void updateWindow(boolean force, boolean redrawNeeded) {
if (!mHaveFrame) {
return;
}
@@ -425,7 +425,7 @@ public class SurfaceView extends View {
final boolean typeChanged = mType != mRequestedType;
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]
- || mUpdateWindowNeeded || mReportDrawNeeded) {
+ || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
@@ -524,6 +524,8 @@ public class SurfaceView extends View {
}
try {
+ redrawNeeded |= creating | reportDrawNeeded;
+
if (visible) {
mDestroyReportNeeded = true;
@@ -541,8 +543,13 @@ public class SurfaceView extends View {
}
if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) {
+ }
+ if (redrawNeeded) {
for (SurfaceHolder.Callback c : callbacks) {
- c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
+ if (c instanceof SurfaceHolder.Callback2) {
+ ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+ mSurfaceHolder);
+ }
}
}
} else {
@@ -550,7 +557,7 @@ public class SurfaceView extends View {
}
} finally {
mIsCreating = false;
- if (creating || reportDrawNeeded) {
+ if (redrawNeeded) {
mSession.finishDrawing(mWindow);
}
}
@@ -580,7 +587,7 @@ public class SurfaceView extends View {
void handleGetNewSurface() {
mNewSurfaceNeeded = true;
- updateWindow(false);
+ updateWindow(false, false);
}
/**
@@ -696,7 +703,7 @@ public class SurfaceView extends View {
mRequestedFormat = format;
if (mWindow != null) {
- updateWindow(false);
+ updateWindow(false, false);
}
}
@@ -713,7 +720,7 @@ public class SurfaceView extends View {
case SURFACE_TYPE_PUSH_BUFFERS:
mRequestedType = type;
if (mWindow != null) {
- updateWindow(false);
+ updateWindow(false, false);
}
break;
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 329226e..a89e7f6 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -130,7 +130,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
int mViewVisibility;
boolean mAppVisible = true;
- SurfaceHolder.Callback mSurfaceHolderCallback;
+ SurfaceHolder.Callback2 mSurfaceHolderCallback;
BaseSurfaceHolder mSurfaceHolder;
boolean mIsCreating;
boolean mDrawingAllowed;
@@ -1152,6 +1152,18 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
Log.v("ViewRoot", "FINISHED DRAWING: " + mWindowAttributes.getTitle());
}
mReportNextDraw = false;
+ if (mSurfaceHolder != null && mSurface.isValid()) {
+ mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
+ SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ if (c instanceof SurfaceHolder.Callback2) {
+ ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+ mSurfaceHolder);
+ }
+ }
+ }
+ }
try {
sWindowSession.finishDrawing(mWindow);
} catch (RemoteException e) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9b31b9c..be681cc 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -485,7 +485,7 @@ public abstract class Window {
* to operate (such as for receiving input events). The given SurfaceHolder
* callback will be used to tell you about state changes to the surface.
*/
- public abstract void takeSurface(SurfaceHolder.Callback callback);
+ public abstract void takeSurface(SurfaceHolder.Callback2 callback);
/**
* Take ownership of this window's InputQueue. The window will no
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index 7ff8d4c..9c1b558 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -5,7 +5,7 @@ import android.view.SurfaceHolder;
/** hahahah */
public interface RootViewSurfaceTaker {
- SurfaceHolder.Callback willYouTakeTheSurface();
+ SurfaceHolder.Callback2 willYouTakeTheSurface();
void setSurfaceType(int type);
void setSurfaceFormat(int format);
void setSurfaceKeepScreenOn(boolean keepOn);
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 54a9c2a..acbf854 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -19,6 +19,7 @@
#include <poll.h>
#include <dlfcn.h>
+#include <fcntl.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
@@ -33,6 +34,9 @@
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
+//#define LOG_TRACE(...)
+#define LOG_TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+
namespace android
{
@@ -42,6 +46,8 @@ static struct {
jmethodID dispatchUnhandledKeyEvent;
jmethodID setWindowFlags;
jmethodID setWindowFormat;
+ jmethodID showIme;
+ jmethodID hideIme;
} gNativeActivityClassInfo;
// ------------------------------------------------------------------------
@@ -56,6 +62,8 @@ enum {
CMD_DEF_KEY = 1,
CMD_SET_WINDOW_FORMAT,
CMD_SET_WINDOW_FLAGS,
+ CMD_SHOW_SOFT_INPUT,
+ CMD_HIDE_SOFT_INPUT,
};
static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
@@ -64,6 +72,8 @@ static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
work.arg1 = arg1;
work.arg2 = arg2;
+ LOG_TRACE("write_work: cmd=%d", cmd);
+
restart:
int res = write(fd, &work, sizeof(work));
if (res < 0 && errno == EINTR) {
@@ -88,43 +98,177 @@ static bool read_work(int fd, ActivityWork* outWork) {
// ------------------------------------------------------------------------
-/*
- * Specialized input queue that allows unhandled key events to be dispatched
- * back to the native activity's Java framework code.
- */
-struct MyInputQueue : AInputQueue {
- explicit MyInputQueue(const android::sp<android::InputChannel>& channel, int workWrite)
- : AInputQueue(channel), mWorkWrite(workWrite) {
+} // namespace android
+
+using namespace android;
+
+AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) :
+ mWorkWrite(workWrite), mConsumer(channel) {
+ int msgpipe[2];
+ if (pipe(msgpipe)) {
+ LOGW("could not create pipe: %s", strerror(errno));
+ mDispatchKeyRead = mDispatchKeyWrite = -1;
+ } else {
+ mDispatchKeyRead = msgpipe[0];
+ mDispatchKeyWrite = msgpipe[1];
+ int result = fcntl(mDispatchKeyRead, F_SETFL, O_NONBLOCK);
+ SLOGW_IF(result != 0, "Could not make AInputQueue read pipe "
+ "non-blocking: %s", strerror(errno));
+ result = fcntl(mDispatchKeyWrite, F_SETFL, O_NONBLOCK);
+ SLOGW_IF(result != 0, "Could not make AInputQueue write pipe "
+ "non-blocking: %s", strerror(errno));
}
+}
+
+AInputQueue::~AInputQueue() {
+ close(mDispatchKeyRead);
+ close(mDispatchKeyWrite);
+}
+
+void AInputQueue::attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data) {
+ mPollLoop = static_cast<android::PollLoop*>(looper);
+ mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
+ POLLIN, callback, data);
+ mPollLoop->setLooperCallback(mDispatchKeyRead,
+ POLLIN, callback, data);
+}
+
+void AInputQueue::detachLooper() {
+ mPollLoop->removeCallback(mConsumer.getChannel()->getReceivePipeFd());
+ mPollLoop->removeCallback(mDispatchKeyRead);
+}
+
+int32_t AInputQueue::hasEvents() {
+ struct pollfd pfd[2];
+
+ pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd();
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+ pfd[1].fd = mDispatchKeyRead;
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
- virtual void doDefaultKey(android::KeyEvent* keyEvent) {
+ int nfd = poll(pfd, 2, 0);
+ if (nfd <= 0) return 0;
+ return (pfd[0].revents == POLLIN || pfd[1].revents == POLLIN) ? 1 : -1;
+}
+
+int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
+ *outEvent = NULL;
+
+ char byteread;
+ ssize_t nRead = read(mDispatchKeyRead, &byteread, 1);
+ if (nRead == 1) {
mLock.lock();
- LOGI("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
- if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
- write_work(mWorkWrite, CMD_DEF_KEY);
+ if (mDispatchingKeys.size() > 0) {
+ KeyEvent* kevent = mDispatchingKeys[0];
+ *outEvent = kevent;
+ mDispatchingKeys.removeAt(0);
+ mDeliveringKeys.add(kevent);
}
- mPendingKeys.add(keyEvent);
mLock.unlock();
+ if (*outEvent != NULL) {
+ return 0;
+ }
}
- KeyEvent* getNextEvent() {
- KeyEvent* event = NULL;
-
- mLock.lock();
- if (mPendingKeys.size() > 0) {
- event = mPendingKeys[0];
- mPendingKeys.removeAt(0);
+ int32_t res = mConsumer.receiveDispatchSignal();
+ if (res != android::OK) {
+ LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
+ mConsumer.getChannel()->getName().string(), res);
+ return -1;
+ }
+
+ InputEvent* myEvent = NULL;
+ res = mConsumer.consume(&mInputEventFactory, &myEvent);
+ if (res != android::OK) {
+ LOGW("channel '%s' ~ Failed to consume input event. status=%d",
+ mConsumer.getChannel()->getName().string(), res);
+ mConsumer.sendFinishedSignal();
+ return -1;
+ }
+
+ *outEvent = myEvent;
+ return 0;
+}
+
+void AInputQueue::finishEvent(AInputEvent* event, bool handled) {
+ bool needFinished = true;
+
+ if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
+ && ((KeyEvent*)event)->hasDefaultAction()) {
+ // The app didn't handle this, but it may have a default action
+ // associated with it. We need to hand this back to Java to be
+ // executed.
+ doDefaultKey((KeyEvent*)event);
+ needFinished = false;
+ }
+
+ const size_t N = mDeliveringKeys.size();
+ for (size_t i=0; i<N; i++) {
+ if (mDeliveringKeys[i] == event) {
+ delete event;
+ mDeliveringKeys.removeAt(i);
+ needFinished = false;
+ break;
}
- mLock.unlock();
-
- return event;
}
- int mWorkWrite;
+ if (needFinished) {
+ int32_t res = mConsumer.sendFinishedSignal();
+ if (res != android::OK) {
+ LOGW("Failed to send finished signal on channel '%s'. status=%d",
+ mConsumer.getChannel()->getName().string(), res);
+ }
+ }
+}
+
+void AInputQueue::dispatchEvent(android::KeyEvent* event) {
+ mLock.lock();
+ LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
+ mDispatchKeyWrite);
+ mDispatchingKeys.add(event);
+ mLock.unlock();
- Mutex mLock;
- Vector<KeyEvent*> mPendingKeys;
-};
+restart:
+ char dummy = 0;
+ int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy));
+ if (res < 0 && errno == EINTR) {
+ goto restart;
+ }
+
+ if (res == sizeof(dummy)) return;
+
+ if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno));
+ else LOGW("Truncated writing to dispatch fd: %d", res);
+}
+
+KeyEvent* AInputQueue::consumeUnhandledEvent() {
+ KeyEvent* event = NULL;
+
+ mLock.lock();
+ if (mPendingKeys.size() > 0) {
+ event = mPendingKeys[0];
+ mPendingKeys.removeAt(0);
+ }
+ mLock.unlock();
+
+ LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
+
+ return event;
+}
+
+void AInputQueue::doDefaultKey(KeyEvent* keyEvent) {
+ mLock.lock();
+ LOG_TRACE("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
+ if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
+ write_work(mWorkWrite, CMD_DEF_KEY);
+ }
+ mPendingKeys.add(keyEvent);
+ mLock.unlock();
+}
+
+namespace android {
// ------------------------------------------------------------------------
@@ -133,8 +277,8 @@ struct MyInputQueue : AInputQueue {
*/
struct NativeCode : public ANativeActivity {
NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
- memset((ANativeActivity*)this, sizeof(ANativeActivity), 0);
- memset(&callbacks, sizeof(callbacks), 0);
+ memset((ANativeActivity*)this, 0, sizeof(ANativeActivity));
+ memset(&callbacks, 0, sizeof(callbacks));
dlhandle = _dlhandle;
createActivityFunc = _createFunc;
nativeWindow = NULL;
@@ -188,7 +332,7 @@ struct NativeCode : public ANativeActivity {
sp<InputChannel> ic =
android_view_InputChannel_getInputChannel(env, _channel);
if (ic != NULL) {
- nativeInputQueue = new MyInputQueue(ic, mainWorkWrite);
+ nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
if (nativeInputQueue->getConsumer().initialize() != android::OK) {
delete nativeInputQueue;
nativeInputQueue = NULL;
@@ -210,8 +354,11 @@ struct NativeCode : public ANativeActivity {
String8 externalDataPath;
sp<ANativeWindow> nativeWindow;
+ int32_t lastWindowWidth;
+ int32_t lastWindowHeight;
+
jobject inputChannel;
- struct MyInputQueue* nativeInputQueue;
+ struct AInputQueue* nativeInputQueue;
// These are used to wake up the main thread to process work.
int mainWorkRead;
@@ -231,6 +378,18 @@ void android_NativeActivity_setWindowFlags(
write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
}
+void android_NativeActivity_showSoftInput(
+ ANativeActivity* activity, int32_t flags) {
+ NativeCode* code = static_cast<NativeCode*>(activity);
+ write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags);
+}
+
+void android_NativeActivity_hideSoftInput(
+ ANativeActivity* activity, int32_t flags) {
+ NativeCode* code = static_cast<NativeCode*>(activity);
+ write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags);
+}
+
// ------------------------------------------------------------------------
/*
@@ -246,10 +405,13 @@ static bool mainWorkCallback(int fd, int events, void* data) {
if (!read_work(code->mainWorkRead, &work)) {
return true;
}
+
+ LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
+
switch (work.cmd) {
case CMD_DEF_KEY: {
KeyEvent* keyEvent;
- while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
+ while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) {
jobject inputEventObj = android_view_KeyEvent_fromNative(
code->env, keyEvent);
code->env->CallVoidMethod(code->clazz,
@@ -269,6 +431,14 @@ static bool mainWorkCallback(int fd, int events, void* data) {
code->env->CallVoidMethod(code->clazz,
gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
} break;
+ case CMD_SHOW_SOFT_INPUT: {
+ code->env->CallVoidMethod(code->clazz,
+ gNativeActivityClassInfo.showIme, work.arg1);
+ } break;
+ case CMD_HIDE_SOFT_INPUT: {
+ code->env->CallVoidMethod(code->clazz,
+ gNativeActivityClassInfo.hideIme, work.arg1);
+ } break;
default:
LOGW("Unknown work command: %d", work.cmd);
break;
@@ -283,6 +453,8 @@ static jint
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue,
jstring internalDataDir, jstring externalDataDir, int sdkVersion)
{
+ LOG_TRACE("loadNativeCode_native");
+
const char* pathStr = env->GetStringUTFChars(path, NULL);
NativeCode* code = NULL;
@@ -314,6 +486,12 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
}
code->mainWorkRead = msgpipe[0];
code->mainWorkWrite = msgpipe[1];
+ int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK);
+ SLOGW_IF(result != 0, "Could not make main work read pipe "
+ "non-blocking: %s", strerror(errno));
+ result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
+ SLOGW_IF(result != 0, "Could not make main work write pipe "
+ "non-blocking: %s", strerror(errno));
code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
code->ANativeActivity::callbacks = &code->callbacks;
@@ -346,6 +524,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
static void
unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
{
+ LOG_TRACE("unloadNativeCode_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
delete code;
@@ -355,6 +534,7 @@ unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
static void
onStart_native(JNIEnv* env, jobject clazz, jint handle)
{
+ LOG_TRACE("onStart_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onStart != NULL) {
@@ -366,6 +546,7 @@ onStart_native(JNIEnv* env, jobject clazz, jint handle)
static void
onResume_native(JNIEnv* env, jobject clazz, jint handle)
{
+ LOG_TRACE("onResume_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onResume != NULL) {
@@ -377,6 +558,7 @@ onResume_native(JNIEnv* env, jobject clazz, jint handle)
static void
onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
{
+ LOG_TRACE("onSaveInstanceState_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onSaveInstanceState != NULL) {
@@ -389,6 +571,7 @@ onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
static void
onPause_native(JNIEnv* env, jobject clazz, jint handle)
{
+ LOG_TRACE("onPause_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onPause != NULL) {
@@ -400,6 +583,7 @@ onPause_native(JNIEnv* env, jobject clazz, jint handle)
static void
onStop_native(JNIEnv* env, jobject clazz, jint handle)
{
+ LOG_TRACE("onStop_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onStop != NULL) {
@@ -411,6 +595,7 @@ onStop_native(JNIEnv* env, jobject clazz, jint handle)
static void
onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
{
+ LOG_TRACE("onLowMemory_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onLowMemory != NULL) {
@@ -422,6 +607,7 @@ onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
static void
onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
{
+ LOG_TRACE("onWindowFocusChanged_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onWindowFocusChanged != NULL) {
@@ -433,6 +619,7 @@ onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean fo
static void
onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
{
+ LOG_TRACE("onSurfaceCreated_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
code->setSurface(surface);
@@ -443,10 +630,17 @@ onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface
}
}
+static int32_t getWindowProp(ANativeWindow* window, int what) {
+ int value;
+ int res = window->query(window, what, &value);
+ return res < 0 ? res : value;
+}
+
static void
onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
jint format, jint width, jint height)
{
+ LOG_TRACE("onSurfaceChanged_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
@@ -456,17 +650,49 @@ onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface
code->callbacks.onNativeWindowDestroyed(code,
oldNativeWindow.get());
}
- if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
- code->callbacks.onNativeWindowCreated(code,
- code->nativeWindow.get());
+ if (code->nativeWindow != NULL) {
+ if (code->callbacks.onNativeWindowCreated != NULL) {
+ code->callbacks.onNativeWindowCreated(code,
+ code->nativeWindow.get());
+ }
+ code->lastWindowWidth = getWindowProp(code->nativeWindow.get(),
+ NATIVE_WINDOW_WIDTH);
+ code->lastWindowHeight = getWindowProp(code->nativeWindow.get(),
+ NATIVE_WINDOW_HEIGHT);
+ }
+ } else {
+ // Maybe it resized?
+ int32_t newWidth = getWindowProp(code->nativeWindow.get(),
+ NATIVE_WINDOW_WIDTH);
+ int32_t newHeight = getWindowProp(code->nativeWindow.get(),
+ NATIVE_WINDOW_HEIGHT);
+ if (newWidth != code->lastWindowWidth
+ || newHeight != code->lastWindowHeight) {
+ if (code->callbacks.onNativeWindowResized != NULL) {
+ code->callbacks.onNativeWindowResized(code,
+ code->nativeWindow.get());
+ }
}
}
}
}
static void
+onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle)
+{
+ LOG_TRACE("onSurfaceRedrawNeeded_native");
+ if (handle != 0) {
+ NativeCode* code = (NativeCode*)handle;
+ if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
+ code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get());
+ }
+ }
+}
+
+static void
onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
{
+ LOG_TRACE("onSurfaceDestroyed_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
@@ -480,6 +706,7 @@ onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surfa
static void
onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
{
+ LOG_TRACE("onInputChannelCreated_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
status_t err = code->setInputChannel(channel);
@@ -498,6 +725,7 @@ onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject ch
static void
onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
{
+ LOG_TRACE("onInputChannelDestroyed_native");
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->nativeInputQueue != NULL
@@ -509,6 +737,38 @@ onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject
}
}
+static void
+onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle,
+ jint x, jint y, jint w, jint h)
+{
+ LOG_TRACE("onContentRectChanged_native");
+ if (handle != 0) {
+ NativeCode* code = (NativeCode*)handle;
+ if (code->callbacks.onContentRectChanged != NULL) {
+ ARect rect;
+ rect.left = x;
+ rect.top = y;
+ rect.right = x+w;
+ rect.bottom = y+h;
+ code->callbacks.onContentRectChanged(code, &rect);
+ }
+ }
+}
+
+static void
+dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventObj)
+{
+ LOG_TRACE("dispatchKeyEvent_native");
+ if (handle != 0) {
+ NativeCode* code = (NativeCode*)handle;
+ if (code->nativeInputQueue != NULL) {
+ KeyEvent* event = new KeyEvent();
+ android_view_KeyEvent_toNative(env, eventObj, INPUT_EVENT_NATURE_KEY, event);
+ code->nativeInputQueue->dispatchEvent(event);
+ }
+ }
+}
+
static const JNINativeMethod g_methods[] = {
{ "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;I)I",
(void*)loadNativeCode_native },
@@ -522,9 +782,12 @@ static const JNINativeMethod g_methods[] = {
{ "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
{ "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
{ "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
+ { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native },
{ "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
{ "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
{ "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
+ { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native },
+ { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native },
};
static const char* const kNativeActivityPathName = "android/app/NativeActivity";
@@ -554,6 +817,12 @@ int register_android_app_NativeActivity(JNIEnv* env)
GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
gNativeActivityClassInfo.clazz,
"setWindowFormat", "(I)V");
+ GET_METHOD_ID(gNativeActivityClassInfo.showIme,
+ gNativeActivityClassInfo.clazz,
+ "showIme", "(I)V");
+ GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
+ gNativeActivityClassInfo.clazz,
+ "hideIme", "(I)V");
return AndroidRuntime::registerNativeMethods(
env, kNativeActivityPathName,
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index f808328..d7a9a2c 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -17,6 +17,8 @@
#ifndef _ANDROID_APP_NATIVEACTIVITY_H
#define _ANDROID_APP_NATIVEACTIVITY_H
+#include <ui/InputTransport.h>
+
#include <android/native_activity.h>
#include "jni.h"
@@ -29,7 +31,65 @@ extern void android_NativeActivity_setWindowFormat(
extern void android_NativeActivity_setWindowFlags(
ANativeActivity* activity, int32_t values, int32_t mask);
+extern void android_NativeActivity_showSoftInput(
+ ANativeActivity* activity, int32_t flags);
+
+extern void android_NativeActivity_hideSoftInput(
+ ANativeActivity* activity, int32_t flags);
} // namespace android
+
+/*
+ * NDK input queue API.
+ */
+struct AInputQueue {
+public:
+ /* Creates a consumer associated with an input channel. */
+ explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite);
+
+ /* Destroys the consumer and releases its input channel. */
+ ~AInputQueue();
+
+ void attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data);
+
+ void detachLooper();
+
+ int32_t hasEvents();
+
+ int32_t getEvent(AInputEvent** outEvent);
+
+ void finishEvent(AInputEvent* event, bool handled);
+
+
+ // ----------------------------------------------------------
+
+ inline android::InputConsumer& getConsumer() { return mConsumer; }
+
+ void dispatchEvent(android::KeyEvent* event);
+
+ android::KeyEvent* consumeUnhandledEvent();
+
+ int mWorkWrite;
+
+private:
+ void doDefaultKey(android::KeyEvent* keyEvent);
+
+ android::InputConsumer mConsumer;
+ android::PreallocatedInputEventFactory mInputEventFactory;
+ android::sp<android::PollLoop> mPollLoop;
+
+ int mDispatchKeyRead;
+ int mDispatchKeyWrite;
+
+ // This is only touched by the event reader thread. It is the current
+ // key events that came out of the mDispatchingKeys list and are now
+ //Êdelivered to the app.
+ android::Vector<android::KeyEvent*> mDeliveringKeys;
+
+ android::Mutex mLock;
+ android::Vector<android::KeyEvent*> mPendingKeys;
+ android::Vector<android::KeyEvent*> mDispatchingKeys;
+};
+
#endif // _ANDROID_APP_NATIVEACTIVITY_H
diff --git a/include/ui/Input.h b/include/ui/Input.h
index a2e0ba06..a7d23d4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -43,7 +43,9 @@ enum {
/*
* Declare a concrete type for the NDK's input event forward declaration.
*/
-struct AInputEvent { };
+struct AInputEvent {
+ virtual ~AInputEvent() { }
+};
namespace android {
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 11714d5..226d1d5 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -331,30 +331,4 @@ private:
} // namespace android
-/*
- * NDK input queue API.
- */
-struct AInputQueue {
-public:
- /* Creates a consumer associated with an input channel. */
- explicit AInputQueue(const android::sp<android::InputChannel>& channel);
-
- /* Destroys the consumer and releases its input channel. */
- virtual ~AInputQueue();
-
- inline android::InputConsumer& getConsumer() { return mConsumer; }
-
- android::status_t consume(android::InputEvent** event);
-
- void setPollLoop(const android::sp<android::PollLoop>& pollLoop) { mPollLoop = pollLoop; }
- const android::sp<android::PollLoop> getPollLoop() const { return mPollLoop; }
-
- virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
-
-private:
- android::InputConsumer mConsumer;
- android::PreallocatedInputEventFactory mInputEventFactory;
- android::sp<android::PollLoop> mPollLoop;
-};
-
#endif // _UI_INPUT_TRANSPORT_H
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 25def3c..fc83e31 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -690,22 +690,3 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
}
} // namespace android
-
-// --- AInputQueue ---
-
-using android::InputEvent;
-using android::InputChannel;
-using android::InputConsumer;
-using android::sp;
-using android::status_t;
-
-AInputQueue::AInputQueue(const sp<InputChannel>& channel) :
- mConsumer(channel) {
-}
-
-AInputQueue::~AInputQueue() {
-}
-
-status_t AInputQueue::consume(InputEvent** event) {
- return mConsumer.consume(&mInputEventFactory, event);
-}
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 89d53e2..a4dde51 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -22,6 +22,8 @@
#include <ui/InputTransport.h>
#include <utils/PollLoop.h>
+#include <android_runtime/android_app_NativeActivity.h>
+
#include <poll.h>
using android::InputEvent;
@@ -187,65 +189,21 @@ float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_i
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
ALooper_callbackFunc* callback, void* data) {
- queue->setPollLoop(static_cast<android::PollLoop*>(looper));
- ALooper_addFd(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
- POLLIN, callback, data);
+ queue->attachLooper(looper, callback, data);
}
void AInputQueue_detachLooper(AInputQueue* queue) {
- queue->getPollLoop()->removeCallback(
- queue->getConsumer().getChannel()->getReceivePipeFd());
+ queue->detachLooper();
}
int AInputQueue_hasEvents(AInputQueue* queue) {
- struct pollfd pfd;
-
- pfd.fd = queue->getConsumer().getChannel()->getReceivePipeFd();
- pfd.events = POLLIN;
- pfd.revents = 0;
-
- int nfd = poll(&pfd, 1, 0);
- if (nfd <= 0) return nfd;
- return pfd.revents == POLLIN ? 1 : -1;
+ return queue->hasEvents();
}
int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent) {
- *outEvent = NULL;
-
- int32_t res = queue->getConsumer().receiveDispatchSignal();
- if (res != android::OK) {
- LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
- queue->getConsumer().getChannel()->getName().string(), res);
- return -1;
- }
-
- InputEvent* myEvent = NULL;
- res = queue->consume(&myEvent);
- if (res != android::OK) {
- LOGW("channel '%s' ~ Failed to consume input event. status=%d",
- queue->getConsumer().getChannel()->getName().string(), res);
- queue->getConsumer().sendFinishedSignal();
- return -1;
- }
-
- *outEvent = myEvent;
- return 0;
-}
-
-void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event,
- int handled) {
- if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
- && ((KeyEvent*)event)->hasDefaultAction()) {
- // The app didn't handle this, but it may have a default action
- // associated with it. We need to hand this back to Java to be
- // executed.
- queue->doDefaultKey((KeyEvent*)event);
- return;
- }
-
- int32_t res = queue->getConsumer().sendFinishedSignal();
- if (res != android::OK) {
- LOGW("Failed to send finished signal on channel '%s'. status=%d",
- queue->getConsumer().getChannel()->getName().string(), res);
- }
+ return queue->getEvent(outEvent);
+}
+
+void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled) {
+ queue->finishEvent(event, handled != 0);
}
diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp
index 509cc33..0c6823a 100644
--- a/native/android/native_activity.cpp
+++ b/native/android/native_activity.cpp
@@ -29,3 +29,11 @@ void ANativeActivity_setWindowFlags(ANativeActivity* activity,
uint32_t addFlags, uint32_t removeFlags) {
android_NativeActivity_setWindowFlags(activity, addFlags, addFlags|removeFlags);
}
+
+void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags) {
+ android_NativeActivity_showSoftInput(activity, flags);
+}
+
+void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags) {
+ android_NativeActivity_hideSoftInput(activity, flags);
+}
diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c
index 2411e93..452c735 100644
--- a/native/glue/threaded_app/threaded_app.c
+++ b/native/glue/threaded_app/threaded_app.c
@@ -18,6 +18,7 @@
#include <jni.h>
#include <errno.h>
+#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
@@ -75,6 +76,19 @@ int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd) {
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
+
+ case APP_CMD_WINDOW_REDRAW_NEEDED:
+ LOGI("APP_CMD_WINDOW_REDRAW_NEEDED\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->redrawNeeded = 0;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_CONTENT_RECT_CHANGED:
+ LOGI("APP_CMD_CONTENT_RECT_CHANGED\n");
+ android_app->contentRect = android_app->pendingContentRect;
+ break;
case APP_CMD_DESTROY:
LOGI("APP_CMD_DESTROY\n");
@@ -133,6 +147,12 @@ static struct android_app* android_app_create(ANativeActivity* activity) {
}
android_app->msgread = msgpipe[0];
android_app->msgwrite = msgpipe[1];
+ int result = fcntl(android_app->msgread, F_SETFL, O_NONBLOCK);
+ if (result != 0) LOGW("Could not make message read pipe "
+ "non-blocking: %s", strerror(errno));
+ result = fcntl(android_app->msgwrite, F_SETFL, O_NONBLOCK);
+ if (result != 0) LOGW("Could not make message write pipe "
+ "non-blocking: %s", strerror(errno));
pthread_attr_t attr;
pthread_attr_init(&attr);
@@ -184,6 +204,23 @@ static void android_app_set_activity_state(struct android_app* android_app, int8
pthread_mutex_unlock(&android_app->mutex);
}
+static void android_app_wait_redraw(struct android_app* android_app) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->redrawNeeded = 1;
+ android_app_write_cmd(android_app, APP_CMD_WINDOW_REDRAW_NEEDED);
+ while (android_app->redrawNeeded) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_content_rect(struct android_app* android_app, const ARect* rect) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->pendingContentRect = *rect;
+ android_app_write_cmd(android_app, APP_CMD_CONTENT_RECT_CHANGED);
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
static void android_app_free(struct android_app* android_app) {
pthread_mutex_lock(&android_app->mutex);
android_app_write_cmd(android_app, APP_CMD_DESTROY);
@@ -231,6 +268,8 @@ static void onStop(ANativeActivity* activity) {
static void onLowMemory(ANativeActivity* activity) {
LOGI("LowMemory: %p\n", activity);
+ android_app_write_cmd((struct android_app*)activity->instance,
+ APP_CMD_LOW_MEMORY);
}
static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
@@ -244,6 +283,23 @@ static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* wind
android_app_set_window((struct android_app*)activity->instance, window);
}
+static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowResized: %p -- %p\n", activity, window);
+ android_app_write_cmd((struct android_app*)activity->instance,
+ APP_CMD_WINDOW_RESIZED);
+}
+
+static void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowRedrawNeeded: %p -- %p\n", activity, window);
+ android_app_wait_redraw((struct android_app*)activity->instance);
+}
+
+static void onContentRectChanged(ANativeActivity* activity, const ARect* rect) {
+ LOGI("ContentRectChanged: %p -- (%d,%d)-(%d,%d)\n", activity, rect->left,
+ rect->top, rect->right, rect->bottom);
+ android_app_set_content_rect((struct android_app*)activity->instance, rect);
+}
+
static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
android_app_set_window((struct android_app*)activity->instance, NULL);
@@ -268,12 +324,15 @@ void ANativeActivity_onCreate(ANativeActivity* activity,
activity->callbacks->onSaveInstanceState = onSaveInstanceState;
activity->callbacks->onPause = onPause;
activity->callbacks->onStop = onStop;
- activity->callbacks->onLowMemory = onLowMemory;
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+ activity->callbacks->onNativeWindowResized = onNativeWindowResized;
+ activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+ activity->callbacks->onContentRectChanged = onContentRectChanged;
+ activity->callbacks->onLowMemory = onLowMemory;
activity->instance = android_app_create(activity);
}
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index d0ff052..ea6f05f 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -147,6 +147,21 @@ typedef struct ANativeActivityCallbacks {
void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window);
/**
+ * The drawing window for this native activity has been resized. You should
+ * retrieve the new size from the window and ensure that your rendering in
+ * it now matches.
+ */
+ void (*onNativeWindowResized)(ANativeActivity* activity, ANativeWindow* window);
+
+ /**
+ * The drawing window for this native activity needs to be redrawn. To avoid
+ * transient artifacts during screen changes (such resizing after rotation),
+ * applications should not return from this function until they have finished
+ * drawing their window in its current state.
+ */
+ void (*onNativeWindowRedrawNeeded)(ANativeActivity* activity, ANativeWindow* window);
+
+ /**
* The drawing window for this native activity is going to be destroyed.
* You MUST ensure that you do not touch the window object after returning
* from this function: in the common case of drawing to the window from
@@ -170,6 +185,11 @@ typedef struct ANativeActivityCallbacks {
void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue);
/**
+ * The rectangle in the window in which content should be placed has changed.
+ */
+ void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect);
+
+ /**
* The system is running low on memory. Use this callback to release
* resources you do not need, to help the system avoid killing more
* important processes.
@@ -197,6 +217,28 @@ void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format);
void ANativeActivity_setWindowFlags(ANativeActivity* activity,
uint32_t addFlags, uint32_t removeFlags);
+/**
+ * Flags for ANativeActivity_showSoftInput; see the Java InputMethodManager
+ * API for documentation.
+ */
+enum {
+ ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001,
+ ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002,
+};
+
+void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags);
+
+/**
+ * Flags for ANativeActivity_hideSoftInput; see the Java InputMethodManager
+ * API for documentation.
+ */
+enum {
+ ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001,
+ ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002,
+};
+
+void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags);
+
#ifdef __cplusplus
};
#endif
diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h
index adfdbea..2b58e9c 100644
--- a/native/include/android_glue/threaded_app.h
+++ b/native/include/android_glue/threaded_app.h
@@ -48,6 +48,10 @@ struct android_app {
// When non-NULL, this is the window surface that the app can draw in.
ANativeWindow* window;
+ // Current content rectangle of the window; this is the area where the
+ // window's content should be placed to be seen by the user.
+ ARect contentRect;
+
// Current state of the app's activity. May be either APP_CMD_START,
// APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
int activityState;
@@ -69,8 +73,10 @@ struct android_app {
int running;
int destroyed;
+ int redrawNeeded;
AInputQueue* pendingInputQueue;
ANativeWindow* pendingWindow;
+ ARect pendingContentRect;
};
enum {
@@ -105,6 +111,26 @@ enum {
APP_CMD_WINDOW_CHANGED,
/**
+ * Command from main thread: the current ANativeWindow has been resized.
+ * Please redraw with its new size.
+ */
+ APP_CMD_WINDOW_RESIZED,
+
+ /**
+ * Command from main thread: the system needs that the current ANativeWindow
+ * be redrawn. You should redraw the window before handing this to
+ * android_app_exec_cmd() in order to avoid transient drawing glitches.
+ */
+ APP_CMD_WINDOW_REDRAW_NEEDED,
+
+ /**
+ * Command from main thread: the content area of the window has changed,
+ * such as from the soft input window being shown or hidden. You can
+ * find the new content rect in android_app::contentRect.
+ */
+ APP_CMD_CONTENT_RECT_CHANGED,
+
+ /**
* Command from main thread: the app's activity window has gained
* input focus.
*/
@@ -117,6 +143,12 @@ enum {
APP_CMD_LOST_FOCUS,
/**
+ * Command from main thread: the system is running low on memory.
+ * Try to reduce your memory use.
+ */
+ APP_CMD_LOW_MEMORY,
+
+ /**
* Command from main thread: the app's activity has been started.
*/
APP_CMD_START,
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 879679f..8321473 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -109,7 +109,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// mDecor itself, or a child of mDecor where the contents go.
private ViewGroup mContentParent;
- SurfaceHolder.Callback mTakeSurfaceCallback;
+ SurfaceHolder.Callback2 mTakeSurfaceCallback;
BaseSurfaceHolder mSurfaceHolder;
InputQueue.Callback mTakeInputQueueCallback;
@@ -255,7 +255,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
@Override
- public void takeSurface(SurfaceHolder.Callback callback) {
+ public void takeSurface(SurfaceHolder.Callback2 callback) {
mTakeSurfaceCallback = callback;
}
@@ -2085,7 +2085,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- public android.view.SurfaceHolder.Callback willYouTakeTheSurface() {
+ public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
return mFeatureId < 0 ? mTakeSurfaceCallback : null;
}