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

Commit 7c8aa44f authored by Jeff Brown's avatar Jeff Brown Committed by Android Git Automerger
Browse files

am 46b9ac0a: Native input dispatch rewrite work in progress.

Merge commit '46b9ac0a' into gingerbread

* commit '46b9ac0a':
  Native input dispatch rewrite work in progress.
parents 94f14aec 46b9ac0a
Loading
Loading
Loading
Loading
+35 −41
Original line number Diff line number Diff line
@@ -16,13 +16,11 @@

package android.os;

import java.util.ArrayList;

import android.util.AndroidRuntimeException;
import android.util.Config;
import android.util.Log;

import com.android.internal.os.RuntimeInit;
import java.util.ArrayList;

/**
 * Low-level class holding the list of messages to be dispatched by a
@@ -34,11 +32,18 @@ import com.android.internal.os.RuntimeInit;
 */
public class MessageQueue {
    Message mMessages;
    private final ArrayList mIdleHandlers = new ArrayList();
    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
    private boolean mQuiting = false;
    private int mObject = 0;    // used by native code
    boolean mQuitAllowed = true;

    @SuppressWarnings("unused")
    private int mPtr; // used by native code
    
    private native void nativeInit();
    private native void nativeDestroy();
    private native boolean nativePollOnce(int timeoutMillis);
    private native void nativeWake();

    /**
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
@@ -86,54 +91,38 @@ public class MessageQueue {
        }
    }
    
    // Add an input pipe to the set being selected over.  If token is
    // negative, remove 'handler's entry from the current set and forget
    // about it.
    void setInputToken(int token, int region, Handler handler) {
        if (token >= 0) nativeRegisterInputStream(token, region, handler);
        else nativeUnregisterInputStream(token);
    }

    MessageQueue() {
        nativeInit();
    }
    private native void nativeInit();

    /**
     * @param token fd of the readable end of the input stream
     * @param region fd of the ashmem region used for data transport alongside the 'token' fd
     * @param handler Handler from which to make input messages based on data read from the fd
     */
    private native void nativeRegisterInputStream(int token, int region, Handler handler);
    private native void nativeUnregisterInputStream(int token);
    private native void nativeSignal();
    
    /**
     * Wait until the designated time for new messages to arrive.
     *
     * @param when Timestamp in SystemClock.uptimeMillis() base of the next message in the queue.
     *    If 'when' is zero, the method will check for incoming messages without blocking.  If
     *    'when' is negative, the method will block forever waiting for the next message.
     * @return
     */
    private native int nativeWaitForNext(long when);
    @Override
    protected void finalize() throws Throwable {
        try {
            nativeDestroy();
        } finally {
            super.finalize();
        }
    }

    final Message next() {
        boolean tryIdle = true;
        // when we start out, we'll just touch the input pipes and then go from there
        long timeToNextEventMillis = 0;
        int timeToNextEventMillis = 0;

        while (true) {
            long now;
            Object[] idlers = null;

            nativeWaitForNext(timeToNextEventMillis);
            boolean dispatched = nativePollOnce(timeToNextEventMillis);

            // Try to retrieve the next message, returning if found.
            synchronized (this) {
                now = SystemClock.uptimeMillis();
                Message msg = pullNextLocked(now);
                if (msg != null) return msg;
                if (msg != null) {
                    return msg;
                }
                
                if (tryIdle && mIdleHandlers.size() > 0) {
                    idlers = mIdleHandlers.toArray();
                }
@@ -170,9 +159,14 @@ public class MessageQueue {
            synchronized (this) {
                // No messages, nobody to tell about it...  time to wait!
                if (mMessages != null) {
                    if (mMessages.when - now > 0) {
                    long longTimeToNextEventMillis = mMessages.when - now;
                    
                    if (longTimeToNextEventMillis > 0) {
                        Binder.flushPendingCommands();
                        timeToNextEventMillis = mMessages.when - now;
                        timeToNextEventMillis = (int) Math.min(longTimeToNextEventMillis,
                                Integer.MAX_VALUE);
                    } else {
                        timeToNextEventMillis = 0;
                    }
                } else {
                    Binder.flushPendingCommands();
@@ -230,7 +224,7 @@ public class MessageQueue {
                msg.next = prev.next;
                prev.next = msg;
            }
            nativeSignal();
            nativeWake();
        }
        return true;
    }
@@ -351,7 +345,7 @@ public class MessageQueue {
    void poke()
    {
        synchronized (this) {
            nativeSignal();
            nativeWake();
        }
    }
}
+49 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.service.wallpaper;

import com.android.internal.os.HandlerCaller;
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseInputHandler;
import com.android.internal.view.BaseSurfaceHolder;

import android.annotation.SdkConstant;
@@ -39,6 +40,10 @@ import android.util.Log;
import android.util.LogPrinter;
import android.view.Gravity;
import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.InputHandler;
import android.view.InputQueue;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
@@ -46,6 +51,7 @@ import android.view.ViewGroup;
import android.view.ViewRoot;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;

import java.util.ArrayList;

@@ -146,6 +152,7 @@ public abstract class WallpaperService extends Service {
        final WindowManager.LayoutParams mLayout
                = new WindowManager.LayoutParams();
        IWindowSession mSession;
        InputChannel mInputChannel;

        final Object mLock = new Object();
        boolean mOffsetMessageEnqueued;
@@ -205,6 +212,30 @@ public abstract class WallpaperService extends Service {
            
        };
        
        final InputHandler mInputHandler = new BaseInputHandler() {
            @Override
            public void handleTouch(MotionEvent event, Runnable finishedCallback) {
                try {
                    synchronized (mLock) {
                        if (event.getAction() == MotionEvent.ACTION_MOVE) {
                            if (mPendingMove != null) {
                                mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
                                mPendingMove.recycle();
                            }
                            mPendingMove = event;
                        } else {
                            mPendingMove = null;
                        }
                        Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
                                event);
                        mCaller.sendMessage(msg);
                    }
                } finally {
                    finishedCallback.run();
                }
            }
        };
        
        final BaseIWindow mWindow = new BaseIWindow() {
            @Override
            public boolean onDispatchPointer(MotionEvent event, long eventTime,
@@ -487,8 +518,15 @@ public abstract class WallpaperService extends Service {
                        mLayout.setTitle(WallpaperService.this.getClass().getName());
                        mLayout.windowAnimations =
                                com.android.internal.R.style.Animation_Wallpaper;
                        mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
                        mInputChannel = new InputChannel();
                        mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets,
                                mInputChannel);
                        mCreated = true;

                        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
                            InputQueue.registerInputChannel(mInputChannel, mInputHandler,
                                    Looper.myQueue());
                        }
                    }
                    
                    mSurfaceHolder.mSurfaceLock.lock();
@@ -587,6 +625,7 @@ public abstract class WallpaperService extends Service {
            mSurfaceHolder.setSizeFromLayout();
            mInitializing = true;
            mSession = ViewRoot.getWindowSession(getMainLooper());
            
            mWindow.setSession(mSession);
            
            IntentFilter filter = new IntentFilter();
@@ -730,6 +769,15 @@ public abstract class WallpaperService extends Service {
                try {
                    if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
                            + mSurfaceHolder.getSurface() + " of: " + this);
                    
                    if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
                        if (mInputChannel != null) {
                            InputQueue.unregisterInputChannel(mInputChannel);
                            mInputChannel.dispose();
                            mInputChannel = null;
                        }
                    }
                    
                    mSession.remove(mWindow);
                } catch (RemoteException e) {
                }
+4 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.view.InputChannel;
import android.view.IWindow;
import android.view.MotionEvent;
import android.view.WindowManager;
@@ -33,6 +34,9 @@ import android.view.Surface;
 */
interface IWindowSession {
    int add(IWindow window, in WindowManager.LayoutParams attrs,
            in int viewVisibility, out Rect outContentInsets,
            out InputChannel outInputChannel);
    int addWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs,
            in int viewVisibility, out Rect outContentInsets);
    void remove(IWindow window);
    
+20 −0
Original line number Diff line number Diff line
/* //device/java/android/android/view/InputChannel.aidl
**
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
** you may not use this file except in compliance with the License. 
** You may obtain a copy of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** Unless required by applicable law or agreed to in writing, software 
** distributed under the License is distributed on an "AS IS" BASIS, 
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
** See the License for the specific language governing permissions and 
** limitations under the License.
*/

package android.view;

parcelable InputChannel;
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.Slog;

/**
 * An input channel specifies the file descriptors used to send input events to
 * a window in another process.  It is Parcelable so that it can be transmitted
 * to the ViewRoot through a Binder transaction as part of registering the Window.
 * @hide
 */
public class InputChannel implements Parcelable {
    private static final String TAG = "InputChannel";
    
    public static final Parcelable.Creator<InputChannel> CREATOR
            = new Parcelable.Creator<InputChannel>() {
        public InputChannel createFromParcel(Parcel source) {
            InputChannel result = new InputChannel();
            result.readFromParcel(source);
            return result;
        }
        
        public InputChannel[] newArray(int size) {
            return new InputChannel[size];
        }
    };
    
    @SuppressWarnings("unused")
    private int mPtr; // used by native code
    
    private boolean mDisposeAfterWriteToParcel;
    
    private static native InputChannel[] nativeOpenInputChannelPair(String name);
    
    private native void nativeDispose(boolean finalized);
    private native void nativeTransferTo(InputChannel other);
    private native void nativeReadFromParcel(Parcel parcel);
    private native void nativeWriteToParcel(Parcel parcel);
    
    private native String nativeGetName();

    /**
     * Creates an uninitialized input channel.
     * It can be initialized by reading from a Parcel or by transferring the state of
     * another input channel into this one.
     */
    public InputChannel() {
    }
    
    @Override
    protected void finalize() throws Throwable {
        try {
            nativeDispose(true);
        } finally {
            super.finalize();
        }
    }
    
    /**
     * Creates a new input channel pair.  One channel should be provided to the input
     * dispatcher and the other to the application's input queue.
     * @param name The descriptive (non-unique) name of the channel pair.
     * @return A pair of input channels.  They are symmetric and indistinguishable.
     */
    public static InputChannel[] openInputChannelPair(String name) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }
        
        Slog.d(TAG, "Opening input channel pair '" + name + "'");
        return nativeOpenInputChannelPair(name);
    }
    
    /**
     * Gets the name of the input channel.
     * @return The input channel name.
     */
    public String getName() {
        String name = nativeGetName();
        return name != null ? name : "uninitialized";
    }

    /**
     * Disposes the input channel.
     * Explicitly releases the reference this object is holding on the input channel.
     * When all references are released, the input channel will be closed.
     */
    public void dispose() {
        nativeDispose(false);
    }
    
    /**
     * Transfers ownership of the internal state of the input channel to another
     * instance and invalidates this instance.  This is used to pass an input channel
     * as an out parameter in a binder call.
     * @param other The other input channel instance.
     */
    public void transferToBinderOutParameter(InputChannel outParameter) {
        if (outParameter == null) {
            throw new IllegalArgumentException("outParameter must not be null");
        }
        
        nativeTransferTo(outParameter);
        outParameter.mDisposeAfterWriteToParcel = true;
    }

    public int describeContents() {
        return Parcelable.CONTENTS_FILE_DESCRIPTOR;
    }
    
    public void readFromParcel(Parcel in) {
        if (in == null) {
            throw new IllegalArgumentException("in must not be null");
        }
        
        nativeReadFromParcel(in);
    }
    
    public void writeToParcel(Parcel out, int flags) {
        if (out == null) {
            throw new IllegalArgumentException("out must not be null");
        }
        
        nativeWriteToParcel(out);
        
        if (mDisposeAfterWriteToParcel) {
            dispose();
        }
    }
    
    @Override
    public String toString() {
        return getName();
    }
}
Loading