am d76b67c3: IME events are now dispatched to native applications.

Merge commit 'd76b67c340d1564abf8d14d976fdaf83bf2b3320' into gingerbread-plus-aosp

* commit 'd76b67c340d1564abf8d14d976fdaf83bf2b3320':
  IME events are now dispatched to native applications.
This commit is contained in:
Dianne Hackborn
2010-07-13 18:55:52 -07:00
committed by Android Git Automerger
19 changed files with 769 additions and 176 deletions

View File

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

View File

@@ -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);
}
}
@@ -420,6 +420,13 @@ public abstract class WallpaperService extends Service {
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**
* 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;

View File

@@ -118,6 +118,23 @@ public interface SurfaceHolder {
public void surfaceDestroyed(SurfaceHolder holder);
}
/**
* 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.

View File

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

View File

@@ -137,7 +137,7 @@ public final class ViewRoot extends Handler implements ViewParent,
int mViewVisibility;
boolean mAppVisible = true;
SurfaceHolder.Callback mSurfaceHolderCallback;
SurfaceHolder.Callback2 mSurfaceHolderCallback;
BaseSurfaceHolder mSurfaceHolder;
boolean mIsCreating;
boolean mDrawingAllowed;
@@ -1263,6 +1263,18 @@ public final class ViewRoot extends Handler implements ViewParent,
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) {

View File

@@ -478,7 +478,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

View File

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