summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-07-13 17:48:30 -0700
committerDianne Hackborn <hackbod@google.com>2010-07-13 18:36:46 -0700
commitd76b67c340d1564abf8d14d976fdaf83bf2b3320 (patch)
tree59c0fff396681a622480a84f4f9c74d188970a11 /core/java
parentfd03582995e0fce963dd0fa0669e3211b74c0dd7 (diff)
downloadframeworks_base-d76b67c340d1564abf8d14d976fdaf83bf2b3320.zip
frameworks_base-d76b67c340d1564abf8d14d976fdaf83bf2b3320.tar.gz
frameworks_base-d76b67c340d1564abf8d14d976fdaf83bf2b3320.tar.bz2
IME events are now dispatched to native applications.
And also: - APIs to show and hide the IME, and control its interaction with the app. - APIs to tell the app when its window resizes and needs to be redrawn. - API to tell the app the content rectangle of its window (to layout around the IME or status bar). There is still a problem with IME interaction -- we need a way for the app to deliver events to the IME before it handles them, so that for example the back key will close the IME instead of finishing the app. Change-Id: I37b75fc2ec533750ef36ca3aedd2f0cc0b5813cd
Diffstat (limited to 'core/java')
-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
7 files changed, 183 insertions, 37 deletions
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 fb45971..260bf7bc 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -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) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f40734b..11c09c1 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -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
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);