Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d76b67c3 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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
parent fd035829
Loading
Loading
Loading
Loading
+64 −2
Original line number Diff line number Diff line
@@ -26353,7 +26353,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"
@@ -26363,6 +26365,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"
@@ -26434,6 +26447,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"
@@ -142938,6 +142964,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"
@@ -179068,6 +179107,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"
@@ -187657,7 +187719,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"
+96 −5
Original line number Diff line number Diff line
@@ -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,11 +261,33 @@ 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) {
        try {
            mDispatchingUnhandledKey = true;
            View decor = getWindow().getDecorView();
            if (decor != null) {
                decor.dispatchKeyEvent(event);
            }
        } finally {
            mDispatchingUnhandledKey = false;
        }
    }
    
    void setWindowFlags(int flags, int mask) {
@@ -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);
    }
}
+33 −14
Original line number Diff line number Diff line
@@ -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;
+17 −0
Original line number Diff line number Diff line
@@ -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.
+22 −15
Original line number Diff line number Diff line
@@ -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;
            }
Loading