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:
@@ -26365,7 +26365,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"
|
||||
@@ -26375,6 +26377,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"
|
||||
@@ -26446,6 +26459,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"
|
||||
@@ -142950,6 +142976,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"
|
||||
@@ -179080,6 +179119,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"
|
||||
@@ -187669,7 +187731,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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
mPendingKeys.add(keyEvent);
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
KeyEvent* getNextEvent() {
|
||||
KeyEvent* event = NULL;
|
||||
|
||||
mLock.lock();
|
||||
if (mPendingKeys.size() > 0) {
|
||||
event = mPendingKeys[0];
|
||||
mPendingKeys.removeAt(0);
|
||||
if (mDispatchingKeys.size() > 0) {
|
||||
KeyEvent* kevent = mDispatchingKeys[0];
|
||||
*outEvent = kevent;
|
||||
mDispatchingKeys.removeAt(0);
|
||||
mDeliveringKeys.add(kevent);
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
return event;
|
||||
if (*outEvent != NULL) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int mWorkWrite;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Mutex mLock;
|
||||
Vector<KeyEvent*> mPendingKeys;
|
||||
};
|
||||
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();
|
||||
|
||||
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,10 +650,41 @@ 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -467,6 +692,7 @@ onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface
|
||||
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,
|
||||
|
||||
@@ -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
|
||||
//<2F>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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
return queue->getEvent(outEvent);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled) {
|
||||
queue->finishEvent(event, handled != 0);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -146,6 +146,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
|
||||
@@ -169,6 +184,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
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
@@ -104,6 +110,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.
|
||||
@@ -116,6 +142,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.
|
||||
*/
|
||||
|
||||
@@ -104,7 +104,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;
|
||||
@@ -248,7 +248,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeSurface(SurfaceHolder.Callback callback) {
|
||||
public void takeSurface(SurfaceHolder.Callback2 callback) {
|
||||
mTakeSurfaceCallback = callback;
|
||||
}
|
||||
|
||||
@@ -2038,7 +2038,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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user