diff options
50 files changed, 1510 insertions, 751 deletions
diff --git a/api/current.xml b/api/current.xml index f65b5ce270fc..c4cac831508a 100644 --- a/api/current.xml +++ b/api/current.xml @@ -145940,6 +145940,19 @@ visibility="public" > </method> +<method name="findPointerIndex" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="pointerId" type="int"> +</parameter> +</method> <method name="getAction" return="int" abstract="false" @@ -146031,7 +146044,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146059,7 +146072,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146087,7 +146100,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146115,7 +146128,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146153,6 +146166,19 @@ visibility="public" > </method> +<method name="getPointerId" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="index" type="int"> +</parameter> +</method> <method name="getPressure" return="float" abstract="false" @@ -146174,7 +146200,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getRawX" @@ -146220,7 +146246,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getX" @@ -146244,7 +146270,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getXPrecision" @@ -146279,7 +146305,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getYPrecision" @@ -146615,7 +146641,7 @@ visibility="public" > </field> -<field name="ACTION_POINTER_MASK" +<field name="ACTION_POINTER_ID_MASK" type="int" transient="false" volatile="false" @@ -146626,7 +146652,7 @@ visibility="public" > </field> -<field name="ACTION_POINTER_SHIFT" +<field name="ACTION_POINTER_ID_SHIFT" type="int" transient="false" volatile="false" diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index d8db8b3ed4a1..cd54958b7e38 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -114,8 +114,8 @@ int main(int argc, char **argv) { assert(success); sp<MetaData> enc_meta = new MetaData; - // enc_meta->setCString(kKeyMIMEType, "video/3gpp"); - enc_meta->setCString(kKeyMIMEType, "video/mp4v-es"); + enc_meta->setCString(kKeyMIMEType, "video/3gpp"); + // enc_meta->setCString(kKeyMIMEType, "video/mp4v-es"); enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyHeight, height); @@ -129,7 +129,8 @@ int main(int argc, char **argv) { MPEG4Writer writer("/sdcard/output.mp4"); writer.addSource(enc_meta, encoder); writer.start(); - sleep(120); + sleep(20); + printf("stopping now.\n"); writer.stop(); #else encoder->start(); diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 1d53eabc3d79..70aceebad0ae 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -693,39 +693,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/"); } - /* - * Menu. - */ - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Show search settings menu item if anyone handles the intent for it - Intent settingsIntent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS); - settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PackageManager pm = getContext().getPackageManager(); - ActivityInfo activityInfo = settingsIntent.resolveActivityInfo(pm, 0); - if (activityInfo != null) { - settingsIntent.setClassName(activityInfo.applicationInfo.packageName, - activityInfo.name); - CharSequence label = activityInfo.loadLabel(getContext().getPackageManager()); - menu.add(Menu.NONE, Menu.NONE, Menu.NONE, label) - .setIcon(android.R.drawable.ic_menu_preferences) - .setAlphabeticShortcut('P') - .setIntent(settingsIntent); - return true; - } - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - // The menu shows up above the IME, regardless of whether it is in front - // of the drop-down or not. This looks weird when there is no IME, so - // we make sure it is visible. - mSearchAutoComplete.ensureImeVisible(); - return super.onMenuOpened(featureId, menu); - } - /** * Listeners of various types */ diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java index 4a00e485f567..bd4e66e44ee9 100644 --- a/core/java/android/app/SuggestionsAdapter.java +++ b/core/java/android/app/SuggestionsAdapter.java @@ -658,7 +658,14 @@ class SuggestionsAdapter extends ResourceCursorAdapter { if (col == NONE) { return null; } - return cursor.getString(col); + try { + return cursor.getString(col); + } catch (Exception e) { + Log.e(LOG_TAG, + "unexpected error retrieving valid column from cursor, " + + "did the remote process die?", e); + return null; + } } } diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java index b95e4e1673b9..92bc8142dea2 100644 --- a/core/java/android/provider/Browser.java +++ b/core/java/android/provider/Browser.java @@ -107,7 +107,8 @@ public class Browser { public static final String[] HISTORY_PROJECTION = new String[] { BookmarkColumns._ID, BookmarkColumns.URL, BookmarkColumns.VISITS, BookmarkColumns.DATE, BookmarkColumns.BOOKMARK, BookmarkColumns.TITLE, - BookmarkColumns.FAVICON, BookmarkColumns.THUMBNAIL }; + BookmarkColumns.FAVICON, BookmarkColumns.THUMBNAIL, + BookmarkColumns.TOUCH_ICON }; /* these indices dependent on HISTORY_PROJECTION */ public static final int HISTORY_PROJECTION_ID_INDEX = 0; @@ -121,6 +122,10 @@ public class Browser { * @hide */ public static final int HISTORY_PROJECTION_THUMBNAIL_INDEX = 7; + /** + * @hide + */ + public static final int HISTORY_PROJECTION_TOUCH_ICON_INDEX = 8; /* columns needed to determine whether to truncate history */ public static final String[] TRUNCATE_HISTORY_PROJECTION = new String[] { @@ -521,6 +526,10 @@ public class Browser { * @hide */ public static final String THUMBNAIL = "thumbnail"; + /** + * @hide + */ + public static final String TOUCH_ICON = "touch_icon"; } public static class SearchColumns implements BaseColumns { diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index 75bd989da51a..489d936dab86 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -217,6 +217,13 @@ public final class Calendar { * <P>Type: INTEGER (boolean)</P> */ public static final String HIDDEN = "hidden"; + + /** + * The owner account for this calendar, based on the calendar feed. + * This will be different from the _SYNC_ACCOUNT for delegated calendars. + * <P>Type: String</P> + */ + public static final String OWNER_ACCOUNT = "ownerAccount"; } public interface AttendeesColumns { @@ -458,6 +465,14 @@ public final class Calendar { * <P>Type: INTEGER (long; millis since epoch)</P> */ public static final String LAST_DATE = "lastDate"; + + /** + * Whether the event has attendee information. True if the event + * has full attendee data, false if the event has information about + * self only. + * <P>Type: INTEGER (boolean)</P> + */ + public static final String HAS_ATTENDEE_DATA = "hasAttendeeData"; } /** diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index ae84e1e63309..d41d2d188ba6 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -19,6 +19,7 @@ package android.view; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.util.Log; /** * Object used to report movement (mouse, pen, finger, trackball) events. This @@ -26,6 +27,8 @@ import android.os.SystemClock; * it is being used for. */ public final class MotionEvent implements Parcelable { + static final boolean DEBUG_POINTERS = false; + /** * Bit mask of the parts of the action code that are the action itself. */ @@ -68,58 +71,67 @@ public final class MotionEvent implements Parcelable { /** * A non-primary pointer has gone down. The bits in - * {@link #ACTION_POINTER_MASK} indicate which pointer changed. + * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed. */ public static final int ACTION_POINTER_DOWN = 5; /** - * The primary pointer has gone done. + * Synonym for {@link #ACTION_POINTER_DOWN} with + * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone done. */ public static final int ACTION_POINTER_1_DOWN = ACTION_POINTER_DOWN | 0x0000; /** - * The secondary pointer has gone done. + * Synonym for {@link #ACTION_POINTER_DOWN} with + * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone done. */ public static final int ACTION_POINTER_2_DOWN = ACTION_POINTER_DOWN | 0x0100; /** - * The tertiary pointer has gone done. + * Synonym for {@link #ACTION_POINTER_DOWN} with + * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone done. */ public static final int ACTION_POINTER_3_DOWN = ACTION_POINTER_DOWN | 0x0200; /** * A non-primary pointer has gone up. The bits in - * {@link #ACTION_POINTER_MASK} indicate which pointer changed. + * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed. */ public static final int ACTION_POINTER_UP = 6; /** - * The primary pointer has gone up. + * Synonym for {@link #ACTION_POINTER_UP} with + * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone up. */ public static final int ACTION_POINTER_1_UP = ACTION_POINTER_UP | 0x0000; /** - * The secondary pointer has gone up. + * Synonym for {@link #ACTION_POINTER_UP} with + * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone up. */ public static final int ACTION_POINTER_2_UP = ACTION_POINTER_UP | 0x0100; /** - * The tertiary pointer has gone up. + * Synonym for {@link #ACTION_POINTER_UP} with + * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone up. */ public static final int ACTION_POINTER_3_UP = ACTION_POINTER_UP | 0x0200; /** * Bits in the action code that represent a pointer ID, used with * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Pointer IDs - * start at 0, with 0 being the primary (first) pointer in the motion. + * start at 0, with 0 being the primary (first) pointer in the motion. Note + * that this not <em>not</em> an index into the array of pointer values, + * which is compacted to only contain pointers that are down; the pointer + * ID for a particular index can be found with {@link #findPointerIndex}. */ - public static final int ACTION_POINTER_MASK = 0xff00; + public static final int ACTION_POINTER_ID_MASK = 0xff00; /** * Bit shift for the action bits holding the pointer identifier as - * defined by {@link #ACTION_POINTER_MASK}. + * defined by {@link #ACTION_POINTER_ID_MASK}. */ - public static final int ACTION_POINTER_SHIFT = 8; + public static final int ACTION_POINTER_ID_SHIFT = 8; private static final boolean TRACK_RECYCLED_LOCATION = false; @@ -144,18 +156,6 @@ public final class MotionEvent implements Parcelable { public static final int EDGE_RIGHT = 0x00000008; /** - * This is the part of the state data that holds the finger identifier - * for the sample. - */ - static private final int STATE_FINGER_ID_MASK = 0xff; - - /** - * Special value for STATE_FINGER_ID_MASK indicating that the finger - * is not down in that sample. - */ - static private final int STATE_FINGER_ID_NONE = 0xff; - - /** * Offset for the sample's X coordinate. * @hide */ @@ -212,8 +212,8 @@ public final class MotionEvent implements Parcelable { private int mNumPointers; private int mNumSamples; - // Array of (mNumSamples * mNumPointers) size of control data. - private int[] mStateSamples; + // Array of mNumPointers size of identifiers for each pointer of data. + private int[] mPointerIdentifiers; // Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data. private float[] mDataSamples; // Array of mNumSamples size of time stamps. @@ -224,7 +224,7 @@ public final class MotionEvent implements Parcelable { private boolean mRecycled; private MotionEvent() { - mStateSamples = new int[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES]; + mPointerIdentifiers = new int[BASE_AVAIL_POINTERS]; mDataSamples = new float[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES*NUM_SAMPLE_DATA]; mTimeSamples = new long[BASE_AVAIL_SAMPLES]; } @@ -256,16 +256,11 @@ public final class MotionEvent implements Parcelable { * @param action The kind of action being performed -- one of either * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or * {@link #ACTION_CANCEL}. - * @param x The X coordinate of this event. - * @param y The Y coordinate of this event. - * @param pressure The current pressure of this event. The pressure generally - * ranges from 0 (no pressure at all) to 1 (normal pressure), however - * values higher than 1 may be generated depending on the calibration of - * the input device. - * @param size A scaled value of the approximate size of the area being pressed when - * touched with the finger. The actual value in pixels corresponding to the finger - * touch is normalized with a device specific range of values - * and scaled to a value between 0 and 1. + * @param pointers The number of points that will be in this event. + * @param inPointerIds An array of <em>pointers</em> values providing + * an identifier for each pointer. + * @param inData An array of <em>pointers*NUM_SAMPLE_DATA</em> of initial + * data samples for the event. * @param metaState The state of any meta / modifier keys that were in effect when * the event was generated. * @param xPrecision The precision of the X coordinate being reported. @@ -279,7 +274,7 @@ public final class MotionEvent implements Parcelable { * @hide */ static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano, - int action, int pointers, float[] inData, int metaState, + int action, int pointers, int[] inPointerIds, float[] inData, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { MotionEvent ev = obtain(); ev.mDeviceId = deviceId; @@ -295,17 +290,25 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = pointers; ev.mNumSamples = 1; - float[] data = ev.mDataSamples; - System.arraycopy(inData, 0, data, 0, pointers * NUM_SAMPLE_DATA); - - int[] state = ev.mStateSamples; - while (pointers > 0) { - pointers--; - state[pointers] = pointers; - } - + System.arraycopy(inPointerIds, 0, ev.mPointerIdentifiers, 0, pointers); + System.arraycopy(inData, 0, ev.mDataSamples, 0, pointers * NUM_SAMPLE_DATA); ev.mTimeSamples[0] = eventTime; + if (DEBUG_POINTERS) { + StringBuilder sb = new StringBuilder(128); + sb.append("New:"); + for (int i=0; i<pointers; i++) { + sb.append(" #"); + sb.append(ev.mPointerIdentifiers[i]); + sb.append("("); + sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]); + sb.append(","); + sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]); + sb.append(")"); + } + Log.v("MotionEvent", sb.toString()); + } + return ev; } @@ -355,8 +358,8 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = 1; ev.mNumSamples = 1; - int[] state = ev.mStateSamples; - state[0] = 0; + int[] pointerIds = ev.mPointerIdentifiers; + pointerIds[0] = 0; float[] data = ev.mDataSamples; data[SAMPLE_X] = ev.mRawX = x; data[SAMPLE_Y] = ev.mRawY = y; @@ -415,8 +418,8 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = 1; ev.mNumSamples = 1; - int[] state = ev.mStateSamples; - state[0] = 0; + int[] pointerIds = ev.mPointerIdentifiers; + pointerIds[0] = 0; float[] data = ev.mDataSamples; data[SAMPLE_X] = ev.mRawX = x; data[SAMPLE_Y] = ev.mRawY = y; @@ -459,8 +462,8 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = 1; ev.mNumSamples = 1; - int[] state = ev.mStateSamples; - state[0] = 0; + int[] pointerIds = ev.mPointerIdentifiers; + pointerIds[0] = 0; float[] data = ev.mDataSamples; data[SAMPLE_X] = ev.mRawX = x; data[SAMPLE_Y] = ev.mRawY = y; @@ -508,21 +511,21 @@ public final class MotionEvent implements Parcelable { ev.mXPrecision = o.mXPrecision; ev.mYPrecision = o.mYPrecision; - final int NT = ev.mNumSamples = o.mNumSamples; - if (ev.mTimeSamples.length >= NT) { - System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NT); + final int NS = ev.mNumSamples = o.mNumSamples; + if (ev.mTimeSamples.length >= NS) { + System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NS); } else { ev.mTimeSamples = (long[])o.mTimeSamples.clone(); } - final int NS = (ev.mNumPointers=o.mNumPointers) * NT; - if (ev.mStateSamples.length >= NS) { - System.arraycopy(o.mStateSamples, 0, ev.mStateSamples, 0, NS); + final int NP = (ev.mNumPointers=o.mNumPointers); + if (ev.mPointerIdentifiers.length >= NP) { + System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP); } else { - ev.mStateSamples = (int[])o.mStateSamples.clone(); + ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone(); } - final int ND = NS * NUM_SAMPLE_DATA; + final int ND = NP * NS * NUM_SAMPLE_DATA; if (ev.mDataSamples.length >= ND) { System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND); } else { @@ -593,88 +596,131 @@ public final class MotionEvent implements Parcelable { } /** - * The number of pointers of data contained in this event. Always - * >= 1. - */ - public final int getPointerCount() { - return mNumPointers; - } - - /** - * {@link #getX(int)} for the first pointer (pointer 0). + * {@link #getX(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getX() { return mDataSamples[SAMPLE_X]; } /** - * {@link #getY(int)} for the first pointer (pointer 0). + * {@link #getY(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getY() { return mDataSamples[SAMPLE_Y]; } /** - * {@link #getPressure(int)} for the first pointer (pointer 0). + * {@link #getPressure(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getPressure() { return mDataSamples[SAMPLE_PRESSURE]; } /** - * {@link #getSize(int)} for the first pointer (pointer 0). + * {@link #getSize(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getSize() { return mDataSamples[SAMPLE_SIZE]; } /** - * Returns the X coordinate of this event for the given pointer. + * The number of pointers of data contained in this event. Always + * >= 1. + */ + public final int getPointerCount() { + return mNumPointers; + } + + /** + * Return the pointer identifier associated with a particular pointer + * data index is this event. The identifier tells you the actual pointer + * number associated with the data, accounting for individual pointers + * going up and down since the start of the current gesture. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. + */ + public final int getPointerId(int index) { + return mPointerIdentifiers[index]; + } + + /** + * Given a pointer identifier, find the index of its data in the event. + * + * @param pointerId The identifier of the pointer to be found. + * @return Returns either the index of the pointer (for use with + * {@link #getX(int) et al.), or -1 if there is no data available for + * that pointer identifier. + */ + public final int findPointerIndex(int pointerId) { + int i = mNumPointers; + while (i > 0) { + i--; + if (mPointerIdentifiers[i] == pointerId) { + return i; + } + } + return -1; + } + + /** + * Returns the X coordinate of this event for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). * Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getX(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_X]; + public final float getX(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X]; } /** - * Returns the Y coordinate of this event for the given pointer. + * Returns the Y coordinate of this event for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). * Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getY(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_Y]; + public final float getY(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_Y]; } /** - * Returns the current pressure of this event for the given pointer. + * Returns the current pressure of this event for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). * The pressure generally * ranges from 0 (no pressure at all) to 1 (normal pressure), however * values higher than 1 may be generated depending on the calibration of * the input device. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getPressure(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; + public final float getPressure(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; } /** - * Returns a scaled value of the approximate size for the given pointer, - * representing the area of the screen being pressed. - * The actual value in pixels corresponding to the + * Returns a scaled value of the approximate size for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). + * This represents some approximation of the area of the screen being + * pressed; the actual value in pixels corresponding to the * touch is normalized with the device specific range of values * and scaled to a value between 0 and 1. The value of size can be used to * determine fat touch events. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getSize(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_SIZE]; + public final float getSize(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_SIZE]; } /** @@ -758,99 +804,107 @@ public final class MotionEvent implements Parcelable { } /** - * {@link #getHistoricalX(int)} for the first pointer (pointer 0). + * {@link #getHistoricalX(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalX(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_X]; } /** - * {@link #getHistoricalY(int)} for the first pointer (pointer 0). + * {@link #getHistoricalY(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalY(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_Y]; } /** - * {@link #getHistoricalPressure(int)} for the first pointer (pointer 0). + * {@link #getHistoricalPressure(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalPressure(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_PRESSURE]; } /** - * {@link #getHistoricalSize(int)} for the first pointer (pointer 0). + * {@link #getHistoricalSize(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalSize(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_SIZE]; } /** - * Returns a historical X coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical X coordinate, as per {@link #getX(int)}, that + * occurred between this event and the previous event for the given pointer. + * Only applies to ACTION_MOVE events. * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getX */ - public final float getHistoricalX(int pointer, int pos) { + public final float getHistoricalX(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_X]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X]; } /** - * Returns a historical Y coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical Y coordinate, as per {@link #getY(int)}, that + * occurred between this event and the previous event for the given pointer. + * Only applies to ACTION_MOVE events. * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getY */ - public final float getHistoricalY(int pointer, int pos) { + public final float getHistoricalY(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_Y]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y]; } /** - * Returns a historical pressure coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical pressure coordinate, as per {@link #getPressure(int)}, + * that occurred between this event and the previous event for the given + * pointer. Only applies to ACTION_MOVE events. * + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} - * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * * @see #getHistorySize * @see #getPressure */ - public final float getHistoricalPressure(int pointer, int pos) { + public final float getHistoricalPressure(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; } /** - * Returns a historical size coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical size coordinate, as per {@link #getSize(int)}, that + * occurred between this event and the previous event for the given pointer. + * Only applies to ACTION_MOVE events. * + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} - * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * * @see #getHistorySize * @see #getSize */ - public final float getHistoricalSize(int pointer, int pos) { + public final float getHistoricalSize(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_SIZE]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE]; } /** @@ -938,7 +992,6 @@ public final class MotionEvent implements Parcelable { */ public final void addBatch(long eventTime, float x, float y, float pressure, float size, int metaState) { - int[] states = mStateSamples; float[] data = mDataSamples; long[] times = mTimeSamples; @@ -946,14 +999,8 @@ public final class MotionEvent implements Parcelable { final int NS = mNumSamples; final int NI = NP*NS; final int ND = NI * NUM_SAMPLE_DATA; - if (states.length < (NI+NP)) { - // The state and data arrays are sized together, since their - // size is always a fixed factor from each other. - final int NEW_NI = NP * (NS+BASE_AVAIL_SAMPLES); - int[] newState = new int[NEW_NI]; - System.arraycopy(states, 0, newState, 0, NI); - mStateSamples = states = newState; - final int NEW_ND = NEW_NI * NUM_SAMPLE_DATA; + if (data.length <= ND) { + final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA)); float[] newData = new float[NEW_ND]; System.arraycopy(data, 0, newData, 0, ND); mDataSamples = data = newData; @@ -996,7 +1043,6 @@ public final class MotionEvent implements Parcelable { * @hide */ public final void addBatch(long eventTime, float[] inData, int metaState) { - int[] states = mStateSamples; float[] data = mDataSamples; long[] times = mTimeSamples; @@ -1004,14 +1050,8 @@ public final class MotionEvent implements Parcelable { final int NS = mNumSamples; final int NI = NP*NS; final int ND = NI * NUM_SAMPLE_DATA; - if (states.length < (NI+NP)) { - // The state and data arrays are sized together, since their - // size is always a fixed factor from each other. - final int NEW_NI = NP * (NS+BASE_AVAIL_SAMPLES); - int[] newState = new int[NEW_NI]; - System.arraycopy(states, 0, newState, 0, NI); - mStateSamples = states = newState; - final int NEW_ND = NEW_NI * NUM_SAMPLE_DATA; + if (data.length <= ND) { + final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA)); float[] newData = new float[NEW_ND]; System.arraycopy(data, 0, newData, 0, ND); mDataSamples = data = newData; @@ -1034,6 +1074,21 @@ public final class MotionEvent implements Parcelable { mRawX = inData[SAMPLE_X]; mRawY = inData[SAMPLE_Y]; mMetaState |= metaState; + + if (DEBUG_POINTERS) { + StringBuilder sb = new StringBuilder(128); + sb.append("Add:"); + for (int i=0; i<mNumPointers; i++) { + sb.append(" #"); + sb.append(mPointerIdentifiers[i]); + sb.append("("); + sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]); + sb.append(","); + sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]); + sb.append(")"); + } + Log.v("MotionEvent", sb.toString()); + } } @Override @@ -1074,13 +1129,13 @@ public final class MotionEvent implements Parcelable { final int NI = NP*NS; if (NI > 0) { int i; - int[] state = mStateSamples; - for (i=0; i<NI; i++) { + int[] state = mPointerIdentifiers; + for (i=0; i<NP; i++) { out.writeInt(state[i]); } - final int NI4 = NI*NUM_SAMPLE_DATA; + final int ND = NI*NUM_SAMPLE_DATA; float[] history = mDataSamples; - for (i=0; i<NI4; i++) { + for (i=0; i<ND; i++) { out.writeFloat(history[i]); } long[] times = mTimeSamples; @@ -1107,19 +1162,19 @@ public final class MotionEvent implements Parcelable { mNumSamples = NS; final int NI = NP*NS; if (NI > 0) { - final int NI4 = NI*4; - int[] state = mStateSamples; - if (state.length < NI) { - mStateSamples = state = new int[NI]; + int[] ids = mPointerIdentifiers; + if (ids.length < NP) { + mPointerIdentifiers = ids = new int[NP]; } - for (int i=0; i<NI; i++) { - state[i] = in.readInt(); + for (int i=0; i<NP; i++) { + ids[i] = in.readInt(); } float[] history = mDataSamples; - if (history.length < NI4) { - mDataSamples = history = new float[NI4]; + final int ND = NI*NUM_SAMPLE_DATA; + if (history.length < ND) { + mDataSamples = history = new float[ND]; } - for (int i=0; i<NI4; i++) { + for (int i=0; i<ND; i++) { history[i] = in.readFloat(); } long[] times = mTimeSamples; diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java index 30da83ecd08e..db024b47023d 100644 --- a/core/java/android/view/RawInputEvent.java +++ b/core/java/android/view/RawInputEvent.java @@ -13,6 +13,8 @@ public class RawInputEvent { public static final int CLASS_ALPHAKEY = 0x00000002; public static final int CLASS_TOUCHSCREEN = 0x00000004; public static final int CLASS_TRACKBALL = 0x00000008; + public static final int CLASS_TOUCHSCREEN_MT = 0x00000010; + public static final int CLASS_DPAD = 0x00000020; // More special classes for QueuedEvent below. public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000; @@ -158,8 +160,21 @@ public class RawInputEvent { public static final int ABS_TOOL_WIDTH = 0x1c; public static final int ABS_VOLUME = 0x20; public static final int ABS_MISC = 0x28; + public static final int ABS_MT_TOUCH_MAJOR = 0x30; + public static final int ABS_MT_TOUCH_MINOR = 0x31; + public static final int ABS_MT_WIDTH_MAJOR = 0x32; + public static final int ABS_MT_WIDTH_MINOR = 0x33; + public static final int ABS_MT_ORIENTATION = 0x34; + public static final int ABS_MT_POSITION_X = 0x35; + public static final int ABS_MT_POSITION_Y = 0x36; + public static final int ABS_MT_TOOL_TYPE = 0x37; + public static final int ABS_MT_BLOB_ID = 0x38; public static final int ABS_MAX = 0x3f; + public static final int SYN_REPORT = 0; + public static final int SYN_CONFIG = 1; + public static final int SYN_MT_REPORT = 2; + public int deviceId; public int type; public int scancode; diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index e6ccd70ab74c..06581c16956d 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -615,6 +615,11 @@ class BrowserFrame extends Handler { mCallbackProxy.onReceivedIcon(icon); } + // Called by JNI when an apple-touch-icon attribute was found. + private void didReceiveTouchIconUrl(String url) { + mCallbackProxy.onReceivedTouchIconUrl(url); + } + /** * Request a new window from the client. * @return The BrowserFrame object stored in the new WebView. diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index ed77ce883e30..b2277cb4824e 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -104,6 +104,7 @@ class CallbackProxy extends Handler { private static final int ADD_MESSAGE_TO_CONSOLE = 129; private static final int GEOLOCATION_PERMISSIONS_SHOW_PROMPT = 130; private static final int GEOLOCATION_PERMISSIONS_HIDE_PROMPT = 131; + private static final int RECEIVED_TOUCH_ICON_URL = 132; // Message triggered by the client to resume execution private static final int NOTIFY = 200; @@ -244,6 +245,13 @@ class CallbackProxy extends Handler { } break; + case RECEIVED_TOUCH_ICON_URL: + if (mWebChromeClient != null) { + mWebChromeClient.onReceivedTouchIconUrl(mWebView, + (String) msg.obj); + } + break; + case RECEIVED_TITLE: if (mWebChromeClient != null) { mWebChromeClient.onReceivedTitle(mWebView, @@ -1054,6 +1062,21 @@ class CallbackProxy extends Handler { sendMessage(obtainMessage(RECEIVED_ICON, icon)); } + /* package */ void onReceivedTouchIconUrl(String url) { + // We should have a current item but we do not want to crash so check + // for null. + WebHistoryItem i = mBackForwardList.getCurrentItem(); + if (i != null) { + i.setTouchIconUrl(url); + } + // Do an unsynchronized quick check to avoid posting if no callback has + // been set. + if (mWebChromeClient == null) { + return; + } + sendMessage(obtainMessage(RECEIVED_TOUCH_ICON_URL, url)); + } + public void onReceivedTitle(String title) { // Do an unsynchronized quick check to avoid posting if no callback has // been set. diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java index 2d7376c8e6c7..21bcdf177217 100644 --- a/core/java/android/webkit/JWebCoreJavaBridge.java +++ b/core/java/android/webkit/JWebCoreJavaBridge.java @@ -186,6 +186,13 @@ final class JWebCoreJavaBridge extends Handler { } /** + * Returns the path of the plugin data directory + */ + private String getPluginSharedDataDirectory() { + return PluginManager.getInstance(null).getPluginSharedDataDirectory(); + } + + /** * setSharedTimer * @param timemillis The relative time when the timer should fire */ diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java index e4a44b9250dc..370d3d2c96d0 100644 --- a/core/java/android/webkit/PluginManager.java +++ b/core/java/android/webkit/PluginManager.java @@ -154,4 +154,8 @@ public class PluginManager { } return directories.toArray(new String[directories.size()]); } + + String getPluginSharedDataDirectory() { + return mContext.getDir("plugins", 0).getPath(); + } } diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index d52406de7920..c10bc97de103 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -45,6 +45,14 @@ public class WebChromeClient { public void onReceivedIcon(WebView view, Bitmap icon) {} /** + * Notify the host application of the url for an apple-touch-icon. + * @param view The WebView that initiated the callback. + * @param url The icon url. + * @hide pending council approval + */ + public void onReceivedTouchIconUrl(WebView view, String url) {} + + /** * A callback interface used by the host application to notify * the current page that its custom view has been dismissed. * diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java index fd26b9840176..abd82377d68c 100644 --- a/core/java/android/webkit/WebHistoryItem.java +++ b/core/java/android/webkit/WebHistoryItem.java @@ -39,6 +39,8 @@ public class WebHistoryItem implements Cloneable { private Bitmap mFavicon; // The pre-flattened data used for saving the state. private byte[] mFlattenedData; + // The apple-touch-icon url for use when adding the site to the home screen + private String mTouchIconUrl; /** * Basic constructor that assigns a unique id to the item. Called by JNI @@ -127,6 +129,14 @@ public class WebHistoryItem implements Cloneable { } /** + * Return the touch icon url. + * @hide + */ + public String getTouchIconUrl() { + return mTouchIconUrl; + } + + /** * Set the favicon. * @param icon A Bitmap containing the favicon for this history item. * Note: The VM ensures 32-bit atomic read/write operations so we don't have @@ -137,6 +147,14 @@ public class WebHistoryItem implements Cloneable { } /** + * Set the touch icon url. + * @hide + */ + /*package*/ void setTouchIconUrl(String url) { + mTouchIconUrl = url; + } + + /** * Get the pre-flattened data. * Note: The VM ensures 32-bit atomic read/write operations so we don't have * to synchronize this method. diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 3b81eed15391..444ef54d7bf5 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2003,6 +2003,15 @@ public class WebView extends AbsoluteLayout } /** + * Get the touch icon url for the apple-touch-icon <link> element. + * @hide + */ + public String getTouchIconUrl() { + WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); + return h != null ? h.getTouchIconUrl() : null; + } + + /** * Get the progress for the current page. * @return The progress for the current page between 0 and 100. */ diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java index a6fdf1f1dc88..c4f775995623 100644 --- a/graphics/java/android/renderscript/ProgramVertex.java +++ b/graphics/java/android/renderscript/ProgramVertex.java @@ -38,8 +38,8 @@ public class ProgramVertex extends BaseObj { mID = 0; } - public void bindAllocation(int slot, MatrixAllocation va) { - mRS.nProgramVertexBindAllocation(mID, slot, va.mAlloc.mID); + public void bindAllocation(MatrixAllocation va) { + mRS.nProgramVertexBindAllocation(mID, va.mAlloc.mID); } diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 5fb7f08f8717..0fb450ed0945 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -164,9 +164,8 @@ public class RenderScript { native void nProgramFragmentDestroy(int pgm); native void nProgramVertexDestroy(int pv); - native void nProgramVertexBindAllocation(int pv, int slot, int mID); + native void nProgramVertexBindAllocation(int pv, int mID); native void nProgramVertexBegin(int inID, int outID); - native void nProgramVertexSetType(int slot, int mID); native void nProgramVertexSetTextureMatrixEnable(boolean enable); native void nProgramVertexAddLight(int id); native int nProgramVertexCreate(); diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index 73380b8397d2..e2a8a275694b 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -909,19 +909,11 @@ nProgramVertexBegin(JNIEnv *_env, jobject _this, jint in, jint out) } static void -nProgramVertexBindAllocation(JNIEnv *_env, jobject _this, jint vpv, jint slot, jint a) +nProgramVertexBindAllocation(JNIEnv *_env, jobject _this, jint vpv, jint a) { RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nProgramVertexBindAllocation, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramVertex)vpv, slot, (RsAllocation)a); - rsProgramVertexBindAllocation((RsProgramFragment)vpv, slot, (RsAllocation)a); -} - -static void -nProgramVertexSetType(JNIEnv *_env, jobject _this, jint slot, jint t) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramVertexSetType, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramVertex)vpv, slot, (RsType)t); - rsProgramVertexSetType(slot, (RsType)t); + rsProgramVertexBindAllocation((RsProgramFragment)vpv, (RsAllocation)a); } static void @@ -1186,9 +1178,8 @@ static JNINativeMethod methods[] = { {"nProgramFragmentDestroy", "(I)V", (void*)nProgramFragmentDestroy }, {"nProgramVertexDestroy", "(I)V", (void*)nProgramVertexDestroy }, -{"nProgramVertexBindAllocation", "(III)V", (void*)nProgramVertexBindAllocation }, +{"nProgramVertexBindAllocation", "(II)V", (void*)nProgramVertexBindAllocation }, {"nProgramVertexBegin", "(II)V", (void*)nProgramVertexBegin }, -{"nProgramVertexSetType", "(II)V", (void*)nProgramVertexSetType }, {"nProgramVertexSetTextureMatrixEnable", "(Z)V", (void*)nProgramVertexSetTextureMatrixEnable }, {"nProgramVertexAddLight", "(I)V", (void*)nProgramVertexAddLight }, {"nProgramVertexCreate", "()I", (void*)nProgramVertexCreate }, diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h index e76fd4ceadd1..c6b7cb3fec3d 100644 --- a/include/media/stagefright/OMXDecoder.h +++ b/include/media/stagefright/OMXDecoder.h @@ -91,8 +91,10 @@ private: sp<IOMX> mOMX; IOMX::node_id mNode; char *mComponentName; + char *mMIME; bool mIsMP3; bool mIsAVC; + bool mIsEncoder; uint32_t mQuirks; MediaSource *mSource; @@ -132,6 +134,7 @@ private: OMXDecoder(OMXClient *client, IOMX::node_id node, const char *mime, const char *codec, + bool is_encoder, uint32_t quirks); void setPortStatus(OMX_U32 port_index, PortStatus status); @@ -148,6 +151,7 @@ private: OMX_COLOR_FORMATTYPE colorFormat); void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height); + void setVideoInputFormat(const char *mime, OMX_U32 width, OMX_U32 height); void setup(); void dumpPortDefinition(OMX_U32 port_index); diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index d62fd7d1af6a..bffba076ee86 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -55,7 +55,9 @@ public: CLASS_KEYBOARD = 0x00000001, CLASS_ALPHAKEY = 0x00000002, CLASS_TOUCHSCREEN = 0x00000004, - CLASS_TRACKBALL = 0x00000008 + CLASS_TRACKBALL = 0x00000008, + CLASS_TOUCHSCREEN_MT= 0x00000010, + CLASS_DPAD = 0x00000020 }; uint32_t getDeviceClasses(int32_t deviceId) const; @@ -122,6 +124,7 @@ private: }; device_t* getDevice(int32_t deviceId) const; + bool hasKeycode(device_t* device, int keycode) const; // Protect all internal state. mutable Mutex mLock; diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java index ef875fc0c40c..833bed047647 100644 --- a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java +++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java @@ -21,6 +21,7 @@ import android.renderscript.RenderScript; import android.renderscript.ScriptC; import android.renderscript.ProgramFragment; import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; import android.renderscript.Allocation; import android.renderscript.Sampler; import android.renderscript.ProgramVertex; @@ -79,7 +80,7 @@ class FallRS { mResources = res; initRS(); } - + public void destroy() { mScript.destroy(); mSampler.destroy(); @@ -126,7 +127,7 @@ class FallRS { } private void createMesh() { - + } private void createScriptStructures() { @@ -210,7 +211,7 @@ class FallRS { ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); pvb.setTextureMatrixEnable(true); mPvBackground = pvb.create(); - mPvBackground.bindAllocation(0, mPvOrthoAlloc); + mPvBackground.bindAllocation(mPvOrthoAlloc); mPvBackground.setName("PVBackground"); } } diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java index e598e0c46cbe..74f88c4fec74 100644 --- a/libs/rs/java/Film/src/com/android/film/FilmRS.java +++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java @@ -240,8 +240,8 @@ public class FilmRS { initState(); mPVA = new ProgramVertex.MatrixAllocation(mRS); - mPVBackground.bindAllocation(0, mPVA); - mPVImages.bindAllocation(0, mPVA); + mPVBackground.bindAllocation(mPVA); + mPVImages.bindAllocation(mPVA); mPVA.setupProjectionNormalized(320, 480); diff --git a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java index 4ff73656e8a4..8160a414ce09 100644 --- a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java +++ b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java @@ -265,7 +265,7 @@ class GrassRS { ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); pvb.setTextureMatrixEnable(true); mPvBackground = pvb.create(); - mPvBackground.bindAllocation(0, mPvOrthoAlloc); + mPvBackground.bindAllocation(mPvOrthoAlloc); mPvBackground.setName("PVBackground"); } } diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java index f6cf419b603a..32a8f3cfa542 100644 --- a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java +++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java @@ -168,7 +168,7 @@ public class RolloRS { ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); mPV = pvb.create(); mPV.setName("PV"); - mPV.bindAllocation(0, mPVAlloc); + mPV.bindAllocation(mPVAlloc); mPVOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS); mPVOrthoAlloc.setupOrthoWindow(mWidth, mHeight); @@ -176,7 +176,7 @@ public class RolloRS { pvb.setTextureMatrixEnable(true); mPVOrtho = pvb.create(); mPVOrtho.setName("PVOrtho"); - mPVOrtho.bindAllocation(0, mPVOrthoAlloc); + mPVOrtho.bindAllocation(mPVOrthoAlloc); mRS.contextBindProgramVertex(mPV); diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index e118acedfdfa..05a8c375a9fa 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -409,15 +409,9 @@ ProgramVertexCreate { ProgramVertexBindAllocation { param RsProgramVertex vpgm - param uint32_t slot param RsAllocation constants } -ProgramVertexSetType { - param uint32_t slot - param RsType constants - } - ProgramVertexSetTextureMatrixEnable { param bool enable } diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index ca277ef789b7..ecfbf83778ac 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -501,23 +501,25 @@ RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool g return texAlloc; } - void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data) { Allocation *a = static_cast<Allocation *>(va); a->data(data); + rsc->allocationCheck(a); } void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data) { Allocation *a = static_cast<Allocation *>(va); a->subData(xoff, count, data); + rsc->allocationCheck(a); } void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data) { Allocation *a = static_cast<Allocation *>(va); a->subData(xoff, yoff, w, h, data); + rsc->allocationCheck(a); } diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index e52b0e00b203..46bd892c5fb5 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -85,10 +85,15 @@ bool Context::runScript(Script *s, uint32_t launchID) bool Context::runRootScript() { +#if RS_LOG_TIMES + struct timespec beginTime; + clock_gettime(CLOCK_MONOTONIC, &beginTime); +#endif + rsAssert(mRootScript->mEnviroment.mIsRoot); - glColor4f(1,1,1,1); - glEnable(GL_LIGHT0); + //glColor4f(1,1,1,1); + //glEnable(GL_LIGHT0); glViewport(0, 0, mWidth, mHeight); glDepthMask(GL_TRUE); @@ -102,19 +107,34 @@ bool Context::runRootScript() glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT); - return runScript(mRootScript.get(), 0); +#if RS_LOG_TIMES + struct timespec startTime; + clock_gettime(CLOCK_MONOTONIC, &startTime); +#endif + bool ret = runScript(mRootScript.get(), 0); + +#if RS_LOG_TIMES + struct timespec endTime; + clock_gettime(CLOCK_MONOTONIC, &endTime); + + int t1 = ((unsigned long)startTime.tv_nsec - (unsigned long)beginTime.tv_nsec) / 1000 / 1000; + int t2 = ((unsigned long)endTime.tv_nsec - (unsigned long)startTime.tv_nsec) / 1000 / 1000; + LOGE("times %i, %i", t1, t2); +#endif + + return ret; } void Context::setupCheck() { if (mFragmentStore.get()) { - mFragmentStore->setupGL(); + mFragmentStore->setupGL(&mStateFragmentStore); } if (mFragment.get()) { - mFragment->setupGL(); + mFragment->setupGL(&mStateFragment); } if (mVertex.get()) { - mVertex->setupGL(); + mVertex->setupGL(&mStateVertex); } } @@ -245,7 +265,6 @@ void Context::setFragmentStore(ProgramFragmentStore *pfs) } else { mFragmentStore.set(pfs); } - mFragmentStore->setupGL(); } void Context::setFragment(ProgramFragment *pf) @@ -255,7 +274,13 @@ void Context::setFragment(ProgramFragment *pf) } else { mFragment.set(pf); } - mFragment->setupGL(); +} + +void Context::allocationCheck(const Allocation *a) +{ + mVertex->checkUpdatedAllocation(a); + mFragment->checkUpdatedAllocation(a); + mFragmentStore->checkUpdatedAllocation(a); } void Context::setVertex(ProgramVertex *pv) @@ -265,7 +290,6 @@ void Context::setVertex(ProgramVertex *pv) } else { mVertex.set(pv); } - mVertex->setupGL(); } void Context::assignName(ObjectBase *obj, const char *name, uint32_t len) diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index a00b8e8690f0..1f8352c0a607 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -45,7 +45,7 @@ namespace android { namespace renderscript { -class Context +class Context { public: Context(Device *, Surface *); @@ -86,6 +86,7 @@ public: const ProgramVertex * getVertex() {return mVertex.get();} void setupCheck(); + void allocationCheck(const Allocation *); void assignName(ObjectBase *obj, const char *name, uint32_t len); void removeName(ObjectBase *obj); diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 5a83fb7db000..6606daaaf488 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -34,12 +34,19 @@ Program::~Program() } -void Program::setAllocation(Allocation *alloc) +void Program::bindAllocation(Allocation *alloc) { mConstants.set(alloc); mDirty = true; } +void Program::checkUpdatedAllocation(const Allocation *alloc) +{ + if (mConstants.get() == alloc) { + mDirty = true; + } +} + void Program::setupGL() { diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index 913fdd279761..251072fb52b9 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -33,10 +33,12 @@ public: virtual ~Program(); - void setAllocation(Allocation *); + void bindAllocation(Allocation *); virtual void setupGL(); + void checkUpdatedAllocation(const Allocation *); + protected: // Components not listed in "in" will be passed though // unless overwritten by components in out. @@ -45,8 +47,7 @@ protected: ObjectBaseRef<Allocation> mConstants; - bool mDirty; - + mutable bool mDirty; }; diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index 628f93ec8d6d..ea507dc2fa42 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -39,8 +39,13 @@ ProgramFragment::~ProgramFragment() { } -void ProgramFragment::setupGL() +void ProgramFragment::setupGL(ProgramFragmentState *state) { + if ((state->mLast.get() == this) && !mDirty) { + return; + } + state->mLast.set(this); + for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) { glActiveTexture(GL_TEXTURE0 + ct); if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) { @@ -90,8 +95,8 @@ void ProgramFragment::setupGL() } } - glActiveTexture(GL_TEXTURE0); + mDirty = false; } @@ -104,6 +109,7 @@ void ProgramFragment::bindTexture(uint32_t slot, Allocation *a) //LOGE("bindtex %i %p", slot, a); mTextures[slot].set(a); + mDirty = true; } void ProgramFragment::bindSampler(uint32_t slot, Sampler *s) @@ -114,6 +120,7 @@ void ProgramFragment::bindSampler(uint32_t slot, Sampler *s) } mSamplers[slot].set(s); + mDirty = true; } void ProgramFragment::setType(uint32_t slot, const Element *e, uint32_t dim) @@ -190,7 +197,7 @@ void rsi_ProgramFragmentBindTexture(Context *rsc, RsProgramFragment vpf, uint32_ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf); pf->bindTexture(slot, static_cast<Allocation *>(a)); if (pf == rsc->getFragment()) { - pf->setupGL(); + //pf->setupGL(); } } @@ -200,7 +207,7 @@ void rsi_ProgramFragmentBindSampler(Context *rsc, RsProgramFragment vpf, uint32_ pf->bindSampler(slot, static_cast<Sampler *>(s)); if (pf == rsc->getFragment()) { - pf->setupGL(); + //pf->setupGL(); } } diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h index 896d8dd473c8..57fb6a55af4a 100644 --- a/libs/rs/rsProgramFragment.h +++ b/libs/rs/rsProgramFragment.h @@ -23,19 +23,19 @@ namespace android { namespace renderscript { +class ProgramFragmentState; class ProgramFragment : public Program { public: const static uint32_t MAX_TEXTURE = 2; - const static uint32_t MAX_CONSTANTS = 2; ProgramFragment(Element *in, Element *out); virtual ~ProgramFragment(); - virtual void setupGL(); + virtual void setupGL(ProgramFragmentState *); @@ -53,7 +53,7 @@ protected: // Texture lookups go though a sampler which in effect converts normalized // coordinates into type specific. Multiple samples may also be taken // and filtered. - // + // // Constants are strictly accessed by programetic loads. ObjectBaseRef<Allocation> mTextures[MAX_TEXTURE]; ObjectBaseRef<Sampler> mSamplers[MAX_TEXTURE]; @@ -61,21 +61,12 @@ protected: uint32_t mTextureDimensions[MAX_TEXTURE]; - ObjectBaseRef<Allocation> mConstants[MAX_CONSTANTS]; - ObjectBaseRef<Type> mConstantTypes[MAX_CONSTANTS]; - - // Hacks to create a program for now RsTexEnvMode mEnvModes[MAX_TEXTURE]; uint32_t mTextureEnableMask; - - - - - }; -class ProgramFragmentState +class ProgramFragmentState { public: ProgramFragmentState(); @@ -87,6 +78,8 @@ public: ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE]; ObjectBaseRef<ProgramFragment> mDefault; Vector<ProgramFragment *> mPrograms; + + ObjectBaseRef<ProgramFragment> mLast; }; diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp index 9ee270f2226e..27f401532886 100644 --- a/libs/rs/rsProgramFragmentStore.cpp +++ b/libs/rs/rsProgramFragmentStore.cpp @@ -48,8 +48,13 @@ ProgramFragmentStore::~ProgramFragmentStore() { } -void ProgramFragmentStore::setupGL() +void ProgramFragmentStore::setupGL(ProgramFragmentStoreState *state) { + if (state->mLast.get() == this) { + return; + } + state->mLast.set(this); + glColorMask(mColorRWriteEnable, mColorGWriteEnable, mColorBWriteEnable, @@ -123,7 +128,7 @@ void ProgramFragmentStore::setDepthMask(bool mask) void ProgramFragmentStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst) { mBlendEnable = true; - if ((src == RS_BLEND_SRC_ONE) && + if ((src == RS_BLEND_SRC_ONE) && (dst == RS_BLEND_DST_ZERO)) { mBlendEnable = false; } diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramFragmentStore.h index bd3a9f413e4e..0de5c3a335e3 100644 --- a/libs/rs/rsProgramFragmentStore.h +++ b/libs/rs/rsProgramFragmentStore.h @@ -23,18 +23,15 @@ namespace android { namespace renderscript { +class ProgramFragmentStoreState; class ProgramFragmentStore : public Program { public: - - - ProgramFragmentStore(Element *in, Element *out); virtual ~ProgramFragmentStore(); - virtual void setupGL(); - + virtual void setupGL(ProgramFragmentStoreState *); void setDepthFunc(RsDepthFunc); void setDepthMask(bool); @@ -55,21 +52,14 @@ protected: int32_t mBlendSrc; int32_t mBlendDst; - - bool mDepthTestEnable; bool mDepthWriteEnable; int32_t mDepthFunc; - - bool mStencilTestEnable; - - - }; -class ProgramFragmentStoreState +class ProgramFragmentStoreState { public: ProgramFragmentStoreState(); @@ -77,6 +67,9 @@ public: void init(Context *rsc, int32_t w, int32_t h); ObjectBaseRef<ProgramFragmentStore> mDefault; + ObjectBaseRef<ProgramFragmentStore> mLast; + + ProgramFragmentStore *mPFS; }; diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index 792135d4cfc6..c66e488a6c73 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -44,9 +44,14 @@ static void logMatrix(const char *txt, const float *f) LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[3], f[7], f[11], f[15]); } -void ProgramVertex::setupGL() +void ProgramVertex::setupGL(ProgramVertexState *state) { - const float *f = static_cast<const float *>(mConstants[0]->getPtr()); + if ((state->mLast.get() == this) && !mDirty) { + return; + } + state->mLast.set(this); + + const float *f = static_cast<const float *>(mConstants->getPtr()); glMatrixMode(GL_TEXTURE); if (mTextureMatrixEnable) { @@ -72,7 +77,7 @@ void ProgramVertex::setupGL() } else { glDisable(GL_LIGHTING); } - + if (!f) { LOGE("Must bind constants to vertex program"); } @@ -81,16 +86,8 @@ void ProgramVertex::setupGL() glLoadMatrixf(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]); -} - -void ProgramVertex::setConstantType(uint32_t slot, const Type *t) -{ - mConstantTypes[slot].set(t); -} -void ProgramVertex::bindAllocation(uint32_t slot, Allocation *a) -{ - mConstants[slot].set(a); + mDirty = false; } void ProgramVertex::addLight(const Light *l) @@ -103,20 +100,23 @@ void ProgramVertex::addLight(const Light *l) void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const { - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mConstants->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix)); + mDirty = true; } void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const { - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mConstants->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix)); + mDirty = true; } void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const { - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mConstants->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix)); + mDirty = true; } @@ -139,8 +139,8 @@ void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h) mDefaultAlloc.set(alloc); mDefault.set(pv); - pv->bindAllocation(0, alloc); - + pv->bindAllocation(alloc); + Matrix m; m.loadOrtho(0,w, h,0, -1,1); alloc->subData(RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0]); @@ -167,15 +167,10 @@ RsProgramVertex rsi_ProgramVertexCreate(Context *rsc) return pv; } -void rsi_ProgramVertexBindAllocation(Context *rsc, RsProgramVertex vpgm, uint32_t slot, RsAllocation constants) +void rsi_ProgramVertexBindAllocation(Context *rsc, RsProgramVertex vpgm, RsAllocation constants) { ProgramVertex *pv = static_cast<ProgramVertex *>(vpgm); - pv->bindAllocation(slot, static_cast<Allocation *>(constants)); -} - -void rsi_ProgramVertexSetType(Context *rsc, uint32_t slot, RsType constants) -{ - rsc->mStateVertex.mPV->setConstantType(slot, static_cast<const Type *>(constants)); + pv->bindAllocation(static_cast<Allocation *>(constants)); } void rsi_ProgramVertexSetTextureMatrixEnable(Context *rsc, bool enable) diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h index da5ed815514a..c9ce7aa6a674 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -23,21 +23,19 @@ namespace android { namespace renderscript { +class ProgramVertexState; class ProgramVertex : public Program { public: - const static uint32_t MAX_CONSTANTS = 2; const static uint32_t MAX_LIGHTS = 8; ProgramVertex(Element *in, Element *out); virtual ~ProgramVertex(); - virtual void setupGL(); + virtual void setupGL(ProgramVertexState *state); - void setConstantType(uint32_t slot, const Type *); - void bindAllocation(uint32_t slot, Allocation *); void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;} void addLight(const Light *); @@ -46,21 +44,15 @@ public: void setTextureMatrix(const rsc_Matrix *) const; protected: - bool mDirty; uint32_t mLightCount; - - ObjectBaseRef<Allocation> mConstants[MAX_CONSTANTS]; - ObjectBaseRef<const Type> mConstantTypes[MAX_CONSTANTS]; ObjectBaseRef<const Light> mLights[MAX_LIGHTS]; - // Hacks to create a program for now bool mTextureMatrixEnable; - }; -class ProgramVertexState +class ProgramVertexState { public: ProgramVertexState(); @@ -69,8 +61,9 @@ public: void init(Context *rsc, int32_t w, int32_t h); ObjectBaseRef<ProgramVertex> mDefault; + ObjectBaseRef<ProgramVertex> mLast; ObjectBaseRef<Allocation> mDefaultAlloc; - + ProgramVertex *mPV; diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h index b13e88fdbe91..f0e47506be2f 100644 --- a/libs/rs/rsUtils.h +++ b/libs/rs/rsUtils.h @@ -17,12 +17,13 @@ #ifndef ANDROID_RS_UTILS_H #define ANDROID_RS_UTILS_H -#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 #define LOG_TAG "rs" #include <utils/Log.h> #include <utils/Vector.h> #include <stdlib.h> #include <pthread.h> +#include <time.h> #include <EGL/egl.h> #include <math.h> @@ -38,6 +39,8 @@ namespace renderscript { #define rsAssert(v) while(0) #endif +#define RS_LOG_TIMES 0 + template<typename T> T rsMin(T in1, T in2) { diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 59c9476287f0..27334b7b85d8 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -16,6 +16,7 @@ //#define LOG_NDEBUG 0 #include <ui/EventHub.h> +#include <ui/KeycodeLabels.h> #include <hardware_legacy/power.h> #include <cutils/properties.h> @@ -58,6 +59,18 @@ #define SEQ_SHIFT 16 #define id_to_index(id) ((id&ID_MASK)+1) +#ifndef ABS_MT_TOUCH_MAJOR +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#endif + +#ifndef ABS_MT_POSITION_X +#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ +#endif + +#ifndef ABS_MT_POSITION_Y +#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ +#endif + namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; @@ -590,6 +603,8 @@ int EventHub::open_device(const char *deviceName) mFDs[mFDCount].events = POLLIN; // figure out the kinds of events the device reports + + // See if this is a keyboard, and classify it. uint8_t key_bitmask[(KEY_MAX+1)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); LOGV("Getting keys..."); @@ -601,15 +616,11 @@ int EventHub::open_device(const char *deviceName) for (int i=0; i<((BTN_MISC+7)/8); i++) { if (key_bitmask[i] != 0) { device->classes |= CLASS_KEYBOARD; - // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (test_bit(KEY_Q, key_bitmask)) { - device->classes |= CLASS_ALPHAKEY; - } break; } } if ((device->classes & CLASS_KEYBOARD) != 0) { - device->keyBitmask = new uint8_t[(KEY_MAX+1)/8]; + device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; if (device->keyBitmask != NULL) { memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); } else { @@ -619,6 +630,8 @@ int EventHub::open_device(const char *deviceName) } } } + + // See if this is a trackball. if (test_bit(BTN_MOUSE, key_bitmask)) { uint8_t rel_bitmask[(REL_MAX+1)/8]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); @@ -630,16 +643,22 @@ int EventHub::open_device(const char *deviceName) } } } - if (test_bit(BTN_TOUCH, key_bitmask)) { - uint8_t abs_bitmask[(ABS_MAX+1)/8]; - memset(abs_bitmask, 0, sizeof(abs_bitmask)); - LOGV("Getting absolute controllers..."); - if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) - { - if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { - device->classes |= CLASS_TOUCHSCREEN; - } - } + + uint8_t abs_bitmask[(ABS_MAX+1)/8]; + memset(abs_bitmask, 0, sizeof(abs_bitmask)); + LOGV("Getting absolute controllers..."); + ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask); + + // Is this a new modern multi-touch driver? + if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) + && test_bit(ABS_MT_POSITION_X, abs_bitmask) + && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { + device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT; + + // Is this an old style single-touch driver? + } else if (test_bit(BTN_TOUCH, key_bitmask) + && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { + device->classes |= CLASS_TOUCHSCREEN; } #ifdef EV_SW @@ -658,9 +677,6 @@ int EventHub::open_device(const char *deviceName) } #endif - LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", - deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); - if ((device->classes&CLASS_KEYBOARD) != 0) { char devname[101]; char tmpfn[101]; @@ -707,10 +723,27 @@ int EventHub::open_device(const char *deviceName) sprintf(propName, "hw.keyboards.%u.devname", publicID); property_set(propName, devname); - LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n", + // 'Q' key support = cheap test of whether this is an alpha-capable kbd + if (hasKeycode(device, kKeyCodeQ)) { + device->classes |= CLASS_ALPHAKEY; + } + + // See if this has a DPAD. + if (hasKeycode(device, kKeyCodeDpadUp) && + hasKeycode(device, kKeyCodeDpadDown) && + hasKeycode(device, kKeyCodeDpadLeft) && + hasKeycode(device, kKeyCodeDpadRight) && + hasKeycode(device, kKeyCodeDpadCenter)) { + device->classes |= CLASS_DPAD; + } + + LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n", publicID, device->id, devname, propName, keylayoutFilename); } + LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", + deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); + LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", deviceName, device, mFDCount, devid, device->classes); @@ -723,6 +756,25 @@ int EventHub::open_device(const char *deviceName) return 0; } +bool EventHub::hasKeycode(device_t* device, int keycode) const +{ + if (device->keyBitmask == NULL || device->layoutMap == NULL) { + return false; + } + + Vector<int32_t> scanCodes; + device->layoutMap->findScancodes(keycode, &scanCodes); + const size_t N = scanCodes.size(); + for (size_t i=0; i<N && i<=KEY_MAX; i++) { + int32_t sc = scanCodes.itemAt(i); + if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { + return true; + } + } + + return false; +} + int EventHub::close_device(const char *deviceName) { AutoMutex _l(mLock); diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp index a4710aafb495..c73909f0cd89 100644 --- a/libs/ui/Surface.cpp +++ b/libs/ui/Surface.cpp @@ -108,6 +108,9 @@ status_t SurfaceBuffer::unlock() status_t SurfaceBuffer::writeToParcel(Parcel* reply, android_native_buffer_t const* buffer) { + if (buffer == NULL) { + return BAD_VALUE; + } reply->writeInt32(buffer->width); reply->writeInt32(buffer->height); reply->writeInt32(buffer->stride); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 6bdf282179f3..b53bb2983380 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -342,7 +342,12 @@ void MPEG4Writer::Track::threadEntry() { ++offset; } - assert(offset + 3 < size); + // assert(offset + 3 < size); + if (offset + 3 >= size) { + // XXX assume the entire first chunk of data is the codec specific + // data. + offset = size; + } mCodecSpecificDataSize = offset; mCodecSpecificData = malloc(offset); diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp index 780cd2ea9b7b..3ea3d01f037b 100644 --- a/media/libstagefright/OMXDecoder.cpp +++ b/media/libstagefright/OMXDecoder.cpp @@ -76,9 +76,12 @@ static const CodecInfo kEncoderInfo[] = { { "audio/3gpp", "OMX.PV.amrencnb" }, { "audio/mp4a-latm", "OMX.PV.aacenc" }, { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" }, + { "video/mp4v-es", "OMX.TI.Video.encoder" }, { "video/mp4v-es", "OMX.PV.mpeg4enc" }, { "video/3gpp", "OMX.qcom.video.encoder.h263" }, + { "video/3gpp", "OMX.TI.Video.encoder" }, { "video/3gpp", "OMX.PV.h263enc" }, + { "video/avc", "OMX.TI.Video.encoder" }, { "video/avc", "OMX.PV.avcenc" }, }; @@ -158,7 +161,8 @@ OMXDecoder *OMXDecoder::Create( quirks |= kMeasuresTimeInMilliseconds; } - OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks); + OMXDecoder *decoder = new OMXDecoder( + client, node, mime, codec, createEncoder, quirks); uint32_t type; const void *data; @@ -166,7 +170,7 @@ OMXDecoder *OMXDecoder::Create( if (meta->findData(kKeyESDS, &type, &data, &size)) { ESDS esds((const char *)data, size); assert(esds.InitCheck() == OK); - + const void *codec_specific_data; size_t codec_specific_data_size; esds.getCodecSpecificInfo( @@ -211,13 +215,16 @@ OMXDecoder *OMXDecoder::Create( OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node, const char *mime, const char *codec, + bool is_encoder, uint32_t quirks) : mClient(client), mOMX(mClient->interface()), mNode(node), mComponentName(strdup(codec)), + mMIME(strdup(mime)), mIsMP3(!strcasecmp(mime, "audio/mpeg")), mIsAVC(!strcasecmp(mime, "video/avc")), + mIsEncoder(is_encoder), mQuirks(quirks), mSource(NULL), mCodecSpecificDataIterator(mCodecSpecificData.begin()), @@ -252,6 +259,9 @@ OMXDecoder::~OMXDecoder() { assert(err == OK); mNode = 0; + free(mMIME); + mMIME = NULL; + free(mComponentName); mComponentName = NULL; } @@ -512,6 +522,27 @@ status_t OMXDecoder::setVideoPortFormatType( // The following assertion is violated by TI's video decoder. // assert(format.nIndex == index); +#if 1 + LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d", + portIndex, + index, format.eCompressionFormat, format.eColorFormat); +#endif + + if (!strcmp("OMX.TI.Video.encoder", mComponentName)) { + if (portIndex == kPortIndexInput + && colorFormat == format.eColorFormat) { + // eCompressionFormat does not seem right. + found = true; + break; + } + if (portIndex == kPortIndexOutput + && compressionFormat == format.eCompressionFormat) { + // eColorFormat does not seem right. + found = true; + break; + } + } + if (format.eCompressionFormat == compressionFormat && format.eColorFormat == colorFormat) { found = true; @@ -525,6 +556,7 @@ status_t OMXDecoder::setVideoPortFormatType( return UNKNOWN_ERROR; } + LOGI("found a match."); status_t err = mOMX->set_parameter( mNode, OMX_IndexParamVideoPortFormat, &format, sizeof(format)); @@ -532,103 +564,51 @@ status_t OMXDecoder::setVideoPortFormatType( return err; } -#if 1 -void OMXDecoder::setVideoOutputFormat( +void OMXDecoder::setVideoInputFormat( const char *mime, OMX_U32 width, OMX_U32 height) { - LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height); - -#if 1 - // Enabling this code appears to be the right thing(tm), but,... - // the TI decoder then loses the ability to output YUV420 and only outputs - // YCbYCr (16bit) - if (!strcasecmp("video/avc", mime)) { - OMX_PARAM_COMPONENTROLETYPE role; - role.nSize = sizeof(role); - role.nVersion.s.nVersionMajor = 1; - role.nVersion.s.nVersionMinor = 1; - strncpy((char *)role.cRole, "video_decoder.avc", - OMX_MAX_STRINGNAME_SIZE - 1); - role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0'; - - status_t err = mOMX->set_parameter( - mNode, OMX_IndexParamStandardComponentRole, - &role, sizeof(role)); - assert(err == OK); - } -#endif + LOGI("setVideoInputFormat width=%ld, height=%ld", width, height); OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; - if (!strcasecmp("video/avc", mime)) { + if (!strcasecmp("video/avc", mMIME)) { compressionFormat = OMX_VIDEO_CodingAVC; - } else if (!strcasecmp("video/mp4v-es", mime)) { + } else if (!strcasecmp("video/mp4v-es", mMIME)) { compressionFormat = OMX_VIDEO_CodingMPEG4; - } else if (!strcasecmp("video/3gpp", mime)) { + } else if (!strcasecmp("video/3gpp", mMIME)) { compressionFormat = OMX_VIDEO_CodingH263; } else { + LOGE("Not a supported video mime type: %s", mime); assert(!"Should not be here. Not a supported video mime type."); } - setVideoPortFormatType( - kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused); - -#if 1 - { - OMX_VIDEO_PARAM_PORTFORMATTYPE format; - format.nSize = sizeof(format); - format.nVersion.s.nVersionMajor = 1; - format.nVersion.s.nVersionMinor = 1; - format.nPortIndex = kPortIndexOutput; - format.nIndex = 0; - - status_t err = mOMX->get_parameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - assert(err == OK); - - assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused); - - static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; + OMX_COLOR_FORMATTYPE colorFormat = + 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY; - assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar - || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar - || format.eColorFormat == OMX_COLOR_FormatCbYCrY - || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar); + setVideoPortFormatType( + kPortIndexInput, OMX_VIDEO_CodingUnused, + colorFormat); - err = mOMX->set_parameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - assert(err == OK); - } -#endif + setVideoPortFormatType( + kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused); OMX_PARAM_PORTDEFINITIONTYPE def; OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; - bool is_encoder = strstr(mComponentName, ".encoder.") != NULL; // XXX - def.nSize = sizeof(def); def.nVersion.s.nVersionMajor = 1; def.nVersion.s.nVersionMinor = 1; - def.nPortIndex = is_encoder ? kPortIndexOutput : kPortIndexInput; + def.nPortIndex = kPortIndexOutput; status_t err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); assert(err == NO_ERROR); -#if 1 - // XXX Need a (much) better heuristic to compute input buffer sizes. - const size_t X = 64 * 1024; - if (def.nBufferSize < X) { - def.nBufferSize = X; - } -#endif - assert(def.eDomain == OMX_PortDomainVideo); - + video_def->nFrameWidth = width; video_def->nFrameHeight = height; + video_def->eCompressionFormat = compressionFormat; video_def->eColorFormat = OMX_COLOR_FormatUnused; err = mOMX->set_parameter( @@ -640,96 +620,37 @@ void OMXDecoder::setVideoOutputFormat( def.nSize = sizeof(def); def.nVersion.s.nVersionMajor = 1; def.nVersion.s.nVersionMinor = 1; - def.nPortIndex = is_encoder ? kPortIndexInput : kPortIndexOutput; + def.nPortIndex = kPortIndexInput; err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); assert(err == NO_ERROR); + def.nBufferSize = (width * height * 2); // (width * height * 3) / 2; + LOGI("setting nBufferSize = %ld", def.nBufferSize); + assert(def.eDomain == OMX_PortDomainVideo); - -#if 0 - def.nBufferSize = - (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420 -#endif video_def->nFrameWidth = width; video_def->nFrameHeight = height; + video_def->eCompressionFormat = OMX_VIDEO_CodingUnused; + video_def->eColorFormat = colorFormat; err = mOMX->set_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); assert(err == NO_ERROR); } -#else -static void hexdump(const void *_data, size_t size) { - char line[256]; - char tmp[16]; - - const uint8_t *data = (const uint8_t *)_data; - size_t offset = 0; - while (offset < size) { - sprintf(line, "0x%04x ", offset); - - size_t n = size - offset; - if (n > 16) { - n = 16; - } - - for (size_t i = 0; i < 16; ++i) { - if (i == 8) { - strcat(line, " "); - } - - if (offset + i < size) { - sprintf(tmp, "%02x ", data[offset + i]); - strcat(line, tmp); - } else { - strcat(line, " "); - } - } - - strcat(line, " "); - - for (size_t i = 0; i < n; ++i) { - if (isprint(data[offset + i])) { - sprintf(tmp, "%c", data[offset + i]); - strcat(line, tmp); - } else { - strcat(line, "."); - } - } - - LOGI(line); - - offset += 16; - } -} - -static void DumpPortDefinitionType(const void *_param) { - OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param; - - LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output", - param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize); - - if (param->eDomain == OMX_PortDomainVideo) { - OMX_VIDEO_PORTDEFINITIONTYPE *video = ¶m->format.video; - LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d", - video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat); - } else { - hexdump(param, param->nSize); - } -} - void OMXDecoder::setVideoOutputFormat( const char *mime, OMX_U32 width, OMX_U32 height) { LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height); -#if 0 +#if 1 // Enabling this code appears to be the right thing(tm), but,... - // the decoder then loses the ability to output YUV420 and only outputs + // the TI decoder then loses the ability to output YUV420 and only outputs // YCbYCr (16bit) - { + if (!strcmp("OMX.TI.Video.Decoder", mComponentName) + && !strcasecmp("video/avc", mime)) { OMX_PARAM_COMPONENTROLETYPE role; role.nSize = sizeof(role); role.nVersion.s.nVersionMajor = 1; @@ -745,8 +666,20 @@ void OMXDecoder::setVideoOutputFormat( } #endif + OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; + if (!strcasecmp("video/avc", mime)) { + compressionFormat = OMX_VIDEO_CodingAVC; + } else if (!strcasecmp("video/mp4v-es", mime)) { + compressionFormat = OMX_VIDEO_CodingMPEG4; + } else if (!strcasecmp("video/3gpp", mime)) { + compressionFormat = OMX_VIDEO_CodingH263; + } else { + LOGE("Not a supported video mime type: %s", mime); + assert(!"Should not be here. Not a supported video mime type."); + } + setVideoPortFormatType( - kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused); + kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused); #if 1 { @@ -762,13 +695,14 @@ void OMXDecoder::setVideoOutputFormat( &format, sizeof(format)); assert(err == OK); - LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat"); - hexdump(&format, format.nSize); - assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused); + + static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; + assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar - || format.eColorFormat == OMX_COLOR_FormatCbYCrY); + || format.eColorFormat == OMX_COLOR_FormatCbYCrY + || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar); err = mOMX->set_parameter( mNode, OMX_IndexParamVideoPortFormat, @@ -777,60 +711,64 @@ void OMXDecoder::setVideoOutputFormat( } #endif - OMX_PORT_PARAM_TYPE ptype; - ptype.nSize = sizeof(ptype); - ptype.nVersion.s.nVersionMajor = 1; - ptype.nVersion.s.nVersionMinor = 1; - - status_t err = mOMX->get_parameter( - mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype)); - assert(err == OK); - - LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit"); - hexdump(&ptype, ptype.nSize); - OMX_PARAM_PORTDEFINITIONTYPE def; + OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; + def.nSize = sizeof(def); def.nVersion.s.nVersionMajor = 1; def.nVersion.s.nVersionMinor = 1; def.nPortIndex = kPortIndexInput; - err = mOMX->get_parameter( + status_t err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == OK); - LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition"); - DumpPortDefinitionType(&def); + assert(err == NO_ERROR); + +#if 1 + // XXX Need a (much) better heuristic to compute input buffer sizes. + const size_t X = 64 * 1024; + if (def.nBufferSize < X) { + def.nBufferSize = X; + } +#endif + + assert(def.eDomain == OMX_PortDomainVideo); - OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; video_def->nFrameWidth = width; video_def->nFrameHeight = height; + video_def->eColorFormat = OMX_COLOR_FormatUnused; + err = mOMX->set_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == OK); + assert(err == NO_ERROR); //////////////////////////////////////////////////////////////////////////// + def.nSize = sizeof(def); + def.nVersion.s.nVersionMajor = 1; + def.nVersion.s.nVersionMinor = 1; def.nPortIndex = kPortIndexOutput; err = mOMX->get_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == OK); + assert(err == NO_ERROR); + + assert(def.eDomain == OMX_PortDomainVideo); - LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition"); - DumpPortDefinitionType(&def); +#if 0 + def.nBufferSize = + (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420 +#endif video_def->nFrameWidth = width; video_def->nFrameHeight = height; err = mOMX->set_parameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - assert(err == OK); + assert(err == NO_ERROR); } -#endif - void OMXDecoder::setup() { const sp<MetaData> &meta = mSource->getFormat(); @@ -848,7 +786,11 @@ void OMXDecoder::setup() { success = success && meta->findInt32(kKeyHeight, &height); assert(success); - setVideoOutputFormat(mime, width, height); + if (mIsEncoder) { + setVideoInputFormat(mime, width, height); + } else { + setVideoOutputFormat(mime, width, height); + } } // dumpPortDefinition(0); @@ -1253,7 +1195,7 @@ void OMXDecoder::initiateShutdown() { if (mShutdownInitiated) { return; } - + if (mState == OMX_StateLoaded) { return; } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java index 4adb04ebb228..d8867d354b53 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java @@ -342,7 +342,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi File h263MemoryOut = new File(MEDIA_MEMORY_OUTPUT); Writer output = new BufferedWriter(new FileWriter(h263MemoryOut, true)); output.write("H263 Video Playback Only\n"); - getMemoryWriteToLog(output); for (int i = 0; i < NUM_STRESS_LOOP; i++) { mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263); getMemoryWriteToLog(output); @@ -363,7 +362,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi File h264MemoryOut = new File(MEDIA_MEMORY_OUTPUT); Writer output = new BufferedWriter(new FileWriter(h264MemoryOut, true)); output.write("H264 Video Playback only\n"); - getMemoryWriteToLog(output); for (int i = 0; i < NUM_STRESS_LOOP; i++) { mediaStressPlayback(MediaNames.VIDEO_H264_AMR); getMemoryWriteToLog(output); @@ -384,7 +382,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi File wmvMemoryOut = new File(MEDIA_MEMORY_OUTPUT); Writer output = new BufferedWriter(new FileWriter(wmvMemoryOut, true)); output.write("WMV video playback only\n"); - getMemoryWriteToLog(output); for (int i = 0; i < NUM_STRESS_LOOP; i++) { mediaStressPlayback(MediaNames.VIDEO_WMV); getMemoryWriteToLog(output); @@ -405,7 +402,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true)); output.write("H263 video record only\n"); - getMemoryWriteToLog(output); for (int i = 0; i < NUM_STRESS_LOOP; i++) { stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); @@ -427,7 +423,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true)); output.write("MPEG4 video record only\n"); - getMemoryWriteToLog(output); for (int i = 0; i < NUM_STRESS_LOOP; i++) { stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); @@ -450,7 +445,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT); Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true)); output.write("Audio and h263 video record\n"); - getMemoryWriteToLog(output); for (int i = 0; i < NUM_STRESS_LOOP; i++) { stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false); @@ -472,7 +466,6 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi File audioOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut, true)); output.write("Audio record only\n"); - getMemoryWriteToLog(output); for (int i = 0; i < NUM_STRESS_LOOP; i++) { stressAudioRecord(MediaNames.RECORDER_OUTPUT); getMemoryWriteToLog(output); diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.c index 7d0d320a3241..6be4876cc8df 100644 --- a/opengl/tests/angeles/app-linux.c +++ b/opengl/tests/angeles/app-linux.c @@ -132,6 +132,7 @@ static int initGraphics() }; EGLint numConfigs = -1; + EGLint n = 0; EGLint majorVersion; EGLint minorVersion; EGLConfig config; @@ -148,15 +149,43 @@ static int initGraphics() egl_error("eglInitialize"); eglGetConfigs(dpy, NULL, 0, &numConfigs); - egl_error("eglGetConfigs"); - fprintf(stderr,"num configs %d\n", numConfigs); + + // Get all the "potential match" configs... + EGLConfig* const configs = malloc(sizeof(EGLConfig)*numConfigs); + eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n); + config = configs[0]; + if (n > 1) { + // if there is more than one candidate, go through the list + // and pick one that matches our framebuffer format + int fbSzA = 0; // should not hardcode + int fbSzR = 5; // should not hardcode + int fbSzG = 6; // should not hardcode + int fbSzB = 5; // should not hardcode + int i; + for (i=0 ; i<n ; i++) { + EGLint r,g,b,a; + eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE, &r); + eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a); + if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) { + config = configs[i]; + break; + } + } + } + free(configs); + - eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); - egl_error("eglChooseConfig"); + //eglGetConfigs(dpy, NULL, 0, &numConfigs); + //egl_error("eglGetConfigs"); + //fprintf(stderr,"num configs %d\n", numConfigs); + //eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); + //egl_error("eglChooseConfig"); surface = eglCreateWindowSurface(dpy, config, android_createDisplaySurface(), NULL); - egl_error("eglMapWindowSurface"); + egl_error("eglCreateWindowSurface"); fprintf(stderr,"surface = %p\n", surface); diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk new file mode 100644 index 000000000000..a7d30c25f0f0 --- /dev/null +++ b/opengl/tests/fillrate/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + fillrate.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libEGL \ + libGLESv1_CM \ + libui + +LOCAL_MODULE:= test-opengl-fillrate + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp new file mode 100644 index 000000000000..c814e8d440bd --- /dev/null +++ b/opengl/tests/fillrate/fillrate.cpp @@ -0,0 +1,149 @@ +/* +** +** Copyright 2006, 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. +*/ + +#define LOG_TAG "fillrate" + +#include <stdlib.h> +#include <stdio.h> + +#include <EGL/egl.h> +#include <GLES/gl.h> +#include <GLES/glext.h> + +#include <utils/StopWatch.h> +#include <ui/FramebufferNativeWindow.h> + +using namespace android; + +int main(int argc, char** argv) +{ + EGLint configAttribs[] = { + EGL_DEPTH_SIZE, 0, + EGL_NONE + }; + + EGLint numConfigs = -1, n=0; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + EGLint w, h; + + EGLDisplay dpy; + + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(dpy, &majorVersion, &minorVersion); + + // Get all the "potential match" configs... + eglGetConfigs(dpy, NULL, 0, &numConfigs); + EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs); + eglChooseConfig(dpy, configAttribs, configs, numConfigs, &n); + config = configs[0]; + if (n > 1) { + // if there is more than one candidate, go through the list + // and pick one that matches our framebuffer format + int fbSzA = 0; // should not hardcode + int fbSzR = 5; // should not hardcode + int fbSzG = 6; // should not hardcode + int fbSzB = 5; // should not hardcode + int i; + for (i=0 ; i<n ; i++) { + EGLint r,g,b,a; + eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE, &r); + eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a); + if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) { + config = configs[i]; + break; + } + } + } + free(configs); + + surface = eglCreateWindowSurface(dpy, config, + android_createDisplaySurface(), NULL); + context = eglCreateContext(dpy, config, NULL, NULL); + eglMakeCurrent(dpy, surface, surface, context); + eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + + printf("w=%d, h=%d\n", w, h); + + glBindTexture(GL_TEXTURE_2D, 0); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_DITHER); + glDisable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glColor4f(1,1,1,1); + + uint32_t* t32 = (uint32_t*)malloc(512*512*4); + for (int y=0 ; y<512 ; y++) { + for (int x=0 ; x<512 ; x++) { + t32[x+y*512] = 0x10FFFFFF; + } + } + + const GLfloat vertices[4][2] = { + { 0, 0 }, + { 0, h }, + { w, h }, + { w, 0 } + }; + + const GLfloat texCoords[4][2] = { + { 0, 0 }, + { 0, 1 }, + { 1, 1 }, + { 1, 0 } + }; + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32); + + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, w, 0, h, 0, 1); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FIXED, 0, vertices); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + + glClearColor(1,0,0,0); + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + eglSwapBuffers(dpy, surface); + + for (int c=1 ; c<32 ; c++) { + glClear(GL_COLOR_BUFFER_BIT); + nsecs_t now = systemTime(); + for (int i=0 ; i<c ; i++) { + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + eglSwapBuffers(dpy, surface); + nsecs_t t = systemTime() - now; + printf("%lld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0); + } + return 0; +} diff --git a/opengl/tests/textures/textures.c b/opengl/tests/textures/textures.c index 214291b3b156..d877e740b409 100644 --- a/opengl/tests/textures/textures.c +++ b/opengl/tests/textures/textures.c @@ -31,7 +31,7 @@ int main(int argc, char** argv) EGL_NONE }; - EGLint numConfigs = -1; + EGLint numConfigs = -1, n=0; EGLint majorVersion; EGLint minorVersion; EGLConfig config; @@ -43,7 +43,36 @@ int main(int argc, char** argv) dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); - eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); + + // Get all the "potential match" configs... + eglGetConfigs(dpy, NULL, 0, &numConfigs); + EGLConfig* const configs = malloc(sizeof(EGLConfig)*numConfigs); + eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n); + config = configs[0]; + if (n > 1) { + // if there is more than one candidate, go through the list + // and pick one that matches our framebuffer format + int fbSzA = 0; // should not hardcode + int fbSzR = 5; // should not hardcode + int fbSzG = 6; // should not hardcode + int fbSzB = 5; // should not hardcode + int i; + for (i=0 ; i<n ; i++) { + EGLint r,g,b,a; + eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE, &r); + eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a); + if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) { + config = configs[i]; + break; + } + } + } + free(configs); + + + surface = eglCreateWindowSurface(dpy, config, android_createDisplaySurface(), NULL); context = eglCreateContext(dpy, config, NULL, NULL); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 835c683878cd..6a1f6f81cf1f 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -432,7 +432,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } finally { db.endTransaction(); } - upgradeVersion = 36; + upgradeVersion = 37; } if (upgradeVersion == 37) { diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index 0ac5740cd098..cb23c4558143 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -23,11 +23,13 @@ import android.view.Surface; import android.view.WindowManagerPolicy; public class InputDevice { + static final boolean DEBUG_POINTERS = false; + /** Amount that trackball needs to move in order to generate a key event. */ static final int TRACKBALL_MOVEMENT_THRESHOLD = 6; /** Maximum number of pointers we will track and report. */ - static final int MAX_POINTERS = 2; + static final int MAX_POINTERS = 10; final int id; final int classes; @@ -51,100 +53,316 @@ public class InputDevice { float yMoveScale; MotionEvent currentMove = null; boolean changed = false; - boolean mLastAnyDown = false; long mDownTime = 0; - final boolean[] mLastDown = new boolean[MAX_POINTERS]; - final boolean[] mDown = new boolean[MAX_POINTERS]; + + // The currently assigned pointer IDs, corresponding to the last data. + int[] mPointerIds = new int[MAX_POINTERS]; + + // This is the last generated pointer data, ordered to match + // mPointerIds. + int mLastNumPointers = 0; final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; - final int[] mCurData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; + + // This is the next set of pointer data being generated. It is not + // in any known order, and will be propagated in to mLastData + // as part of mapping it to the appropriate pointer IDs. + // Note that we have one extra sample of data here, to help clients + // avoid doing bounds checking. + int mNextNumPointers = 0; + final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS) + + MotionEvent.NUM_SAMPLE_DATA]; + + // Temporary data structures for doing the pointer ID mapping. + final int[] mLast2Next = new int[MAX_POINTERS]; + final int[] mNext2Last = new int[MAX_POINTERS]; + final long[] mNext2LastDistance = new long[MAX_POINTERS]; + + // Temporary data structure for generating the final motion data. final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; + // This is not used here, but can be used by callers for state tracking. + int mAddingPointerOffset = 0; + final boolean[] mDown = new boolean[MAX_POINTERS]; + MotionState(int mx, int my) { xPrecision = mx; yPrecision = my; xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f; yMoveScale = my != 0 ? (1.0f/my) : 1.0f; + for (int i=0; i<MAX_POINTERS; i++) { + mPointerIds[i] = i; + } } - MotionEvent generateAbsMotion(InputDevice device, long curTime, - long curTimeNano, Display display, int orientation, - int metaState) { + private boolean assignPointer(int nextIndex, boolean allowOverlap) { + final int lastNumPointers = mLastNumPointers; + final int[] next2Last = mNext2Last; + final long[] next2LastDistance = mNext2LastDistance; + final int[] last2Next = mLast2Next; + final int[] lastData = mLastData; + final int[] nextData = mNextData; + final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA; - final float[] scaled = mReportData; - final int[] cur = mCurData; + if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex=" + + nextIndex + " dataOff=" + id); + final int x1 = nextData[id + MotionEvent.SAMPLE_X]; + final int y1 = nextData[id + MotionEvent.SAMPLE_Y]; - boolean anyDown = false; - int firstDownChanged = -1; - int numPointers = 0; - for (int i=0; i<MAX_POINTERS; i++) { - boolean d = mDown[i]; - anyDown |= d; - if (d != mLastDown[i] && firstDownChanged < 0) { - firstDownChanged = i; - mLastDown[i] = mDown[i]; - d = true; + long bestDistance = -1; + int bestIndex = -1; + for (int j=0; j<lastNumPointers; j++) { + if (!allowOverlap && last2Next[j] < 0) { + continue; + } + final int jd = j * MotionEvent.NUM_SAMPLE_DATA; + final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1; + final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1; + final long distance = xd*(long)xd + yd*(long)yd; + if (j == 0 || distance < bestDistance) { + bestDistance = distance; + bestIndex = j; + } + } + + if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex + + " best old index=" + bestIndex + " (distance=" + + bestDistance + ")"); + next2Last[nextIndex] = bestIndex; + next2LastDistance[nextIndex] = bestDistance; + + if (bestIndex < 0) { + return true; + } + + if (last2Next[bestIndex] == -1) { + last2Next[bestIndex] = nextIndex; + return false; + } + + if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex + + " has multiple best new pointers!"); + + last2Next[bestIndex] = -2; + return true; + } + + private int updatePointerIdentifiers() { + final int[] lastData = mLastData; + final int[] nextData = mNextData; + final int nextNumPointers = mNextNumPointers; + final int lastNumPointers = mLastNumPointers; + + if (nextNumPointers == 1 && lastNumPointers == 1) { + System.arraycopy(nextData, 0, lastData, 0, + MotionEvent.NUM_SAMPLE_DATA); + return -1; + } + + // Clear our old state. + final int[] last2Next = mLast2Next; + for (int i=0; i<lastNumPointers; i++) { + last2Next[i] = -1; + } + + if (DEBUG_POINTERS) Log.v("InputDevice", + "Update pointers: lastNumPointers=" + lastNumPointers + + " nextNumPointers=" + nextNumPointers); + + // Figure out the closes new points to the previous points. + final int[] next2Last = mNext2Last; + final long[] next2LastDistance = mNext2LastDistance; + boolean conflicts = false; + for (int i=0; i<nextNumPointers; i++) { + conflicts |= assignPointer(i, true); + } + + // Resolve ambiguities in pointer mappings, when two or more + // new pointer locations find their best previous location is + // the same. + if (conflicts) { + if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts"); + + for (int i=0; i<lastNumPointers; i++) { + if (last2Next[i] != -2) { + continue; + } + + // Note that this algorithm is far from perfect. Ideally + // we should do something like the one described at + // http://portal.acm.org/citation.cfm?id=997856 + + if (DEBUG_POINTERS) Log.v("InputDevice", + "Resolving last index #" + i); + + int numFound; + do { + numFound = 0; + long worstDistance = 0; + int worstJ = -1; + for (int j=0; j<nextNumPointers; j++) { + if (next2Last[j] != i) { + continue; + } + numFound++; + if (worstDistance < next2LastDistance[j]) { + worstDistance = next2LastDistance[j]; + worstJ = j; + } + } + + if (worstJ >= 0) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Worst new pointer: " + worstJ + + " (distance=" + worstDistance + ")"); + if (assignPointer(worstJ, false)) { + // In this case there is no last pointer + // remaining for this new one! + next2Last[worstJ] = -1; + } + } + } while (numFound > 2); + } + } + + int retIndex = -1; + + if (lastNumPointers < nextNumPointers) { + // We have one or more new pointers that are down. Create a + // new pointer identifier for one of them. + if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer"); + int nextId = 0; + int i=0; + while (i < lastNumPointers) { + if (mPointerIds[i] > nextId) { + // Found a hole, insert the pointer here. + if (DEBUG_POINTERS) Log.v("InputDevice", + "Inserting new pointer at hole " + i); + System.arraycopy(mPointerIds, i, mPointerIds, + i+1, lastNumPointers-i); + System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA, + lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA, + (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA); + break; + } + i++; + nextId++; } - if (d) { - final int src = i * MotionEvent.NUM_SAMPLE_DATA; - final int dest = numPointers * MotionEvent.NUM_SAMPLE_DATA; - numPointers++; - scaled[dest + MotionEvent.SAMPLE_X] = cur[src + MotionEvent.SAMPLE_X]; - scaled[dest + MotionEvent.SAMPLE_Y] = cur[src + MotionEvent.SAMPLE_Y]; - scaled[dest + MotionEvent.SAMPLE_PRESSURE] = cur[src + MotionEvent.SAMPLE_PRESSURE]; - scaled[dest + MotionEvent.SAMPLE_SIZE] = cur[src + MotionEvent.SAMPLE_SIZE]; + if (DEBUG_POINTERS) Log.v("InputDevice", + "New pointer id " + nextId + " at index " + i); + + mLastNumPointers++; + retIndex = i; + mPointerIds[i] = nextId; + + // And assign this identifier to the first new pointer. + for (int j=0; j<nextNumPointers; j++) { + if (next2Last[j] < 0) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Assigning new id to new pointer index " + j); + next2Last[j] = i; + break; + } } } - if (numPointers <= 0) { + // Propagate all of the current data into the appropriate + // location in the old data to match the pointer ID that was + // assigned to it. + for (int i=0; i<nextNumPointers; i++) { + int lastIndex = next2Last[i]; + if (lastIndex >= 0) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Copying next pointer index " + i + + " to last index " + lastIndex); + System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA, + lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA, + MotionEvent.NUM_SAMPLE_DATA); + } + } + + if (lastNumPointers > nextNumPointers) { + // One or more pointers has gone up. Find the first one, + // and adjust accordingly. + if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer"); + for (int i=0; i<lastNumPointers; i++) { + if (last2Next[i] == -1) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Removing old pointer at index " + i); + retIndex = i; + break; + } + } + } + + return retIndex; + } + + void removeOldPointer(int index) { + final int lastNumPointers = mLastNumPointers; + if (index >= 0 && index < lastNumPointers) { + System.arraycopy(mPointerIds, index+1, mPointerIds, + index, lastNumPointers-index-1); + System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA, + mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA, + (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA); + mLastNumPointers--; + } + } + + MotionEvent generateAbsMotion(InputDevice device, long curTime, + long curTimeNano, Display display, int orientation, + int metaState) { + + if (mNextNumPointers <= 0 && mLastNumPointers <= 0) { return null; } + final int lastNumPointers = mLastNumPointers; + final int nextNumPointers = mNextNumPointers; + if (mNextNumPointers > MAX_POINTERS) { + Log.w("InputDevice", "Number of pointers " + mNextNumPointers + + " exceeded maximum of " + MAX_POINTERS); + mNextNumPointers = MAX_POINTERS; + } + + int upOrDownPointer = updatePointerIdentifiers(); + + final float[] reportData = mReportData; + final int[] rawData = mLastData; + + final int numPointers = mLastNumPointers; + + if (DEBUG_POINTERS) Log.v("InputDevice", "Processing " + + numPointers + " pointers (going from " + lastNumPointers + + " to " + nextNumPointers + ")"); + + for (int i=0; i<numPointers; i++) { + final int pos = i * MotionEvent.NUM_SAMPLE_DATA; + reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X]; + reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y]; + reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE]; + reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE]; + } + int action; int edgeFlags = 0; - if (anyDown != mLastAnyDown) { - final AbsoluteInfo absX = device.absX; - final AbsoluteInfo absY = device.absY; - if (anyDown && absX != null && absY != null) { - // We don't let downs start unless we are - // inside of the screen. There are two reasons for - // this: to avoid spurious touches when holding - // the edges of the device near the touchscreen, - // and to avoid reporting events if there are virtual - // keys on the touchscreen outside of the display - // area. - // Note that we are only looking at the first pointer, - // since what we are handling here is the first pointer - // going down, and this is the coordinate that will be - // used to dispatch the event. - if (cur[MotionEvent.SAMPLE_X] < absX.minValue - || cur[MotionEvent.SAMPLE_X] > absX.maxValue - || cur[MotionEvent.SAMPLE_Y] < absY.minValue - || cur[MotionEvent.SAMPLE_Y] > absY.maxValue) { - if (false) Log.v("InputDevice", "Rejecting (" - + cur[MotionEvent.SAMPLE_X] + "," - + cur[MotionEvent.SAMPLE_Y] + "): outside of (" - + absX.minValue + "," + absY.minValue - + ")-(" + absX.maxValue + "," - + absY.maxValue + ")"); - return null; + if (nextNumPointers != lastNumPointers) { + if (nextNumPointers > lastNumPointers) { + if (lastNumPointers == 0) { + action = MotionEvent.ACTION_DOWN; + mDownTime = curTime; + } else { + action = MotionEvent.ACTION_POINTER_DOWN + | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT); } - } - mLastAnyDown = anyDown; - if (anyDown) { - action = MotionEvent.ACTION_DOWN; - mDownTime = curTime; - } else { - action = MotionEvent.ACTION_UP; - } - currentMove = null; - } else if (firstDownChanged >= 0) { - if (mDown[firstDownChanged]) { - action = MotionEvent.ACTION_POINTER_DOWN - | (firstDownChanged << MotionEvent.ACTION_POINTER_SHIFT); } else { - action = MotionEvent.ACTION_POINTER_UP - | (firstDownChanged << MotionEvent.ACTION_POINTER_SHIFT); + if (numPointers == 1) { + action = MotionEvent.ACTION_UP; + } else { + action = MotionEvent.ACTION_POINTER_UP + | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT); + } } currentMove = null; } else { @@ -170,42 +388,42 @@ public class InputDevice { final int j = i * MotionEvent.NUM_SAMPLE_DATA; if (absX != null) { - scaled[j + MotionEvent.SAMPLE_X] = - ((scaled[j + MotionEvent.SAMPLE_X]-absX.minValue) + reportData[j + MotionEvent.SAMPLE_X] = + ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue) / absX.range) * w; } if (absY != null) { - scaled[j + MotionEvent.SAMPLE_Y] = - ((scaled[j + MotionEvent.SAMPLE_Y]-absY.minValue) + reportData[j + MotionEvent.SAMPLE_Y] = + ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue) / absY.range) * h; } if (absPressure != null) { - scaled[j + MotionEvent.SAMPLE_PRESSURE] = - ((scaled[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue) + reportData[j + MotionEvent.SAMPLE_PRESSURE] = + ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue) / (float)absPressure.range); } if (absSize != null) { - scaled[j + MotionEvent.SAMPLE_SIZE] = - ((scaled[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue) + reportData[j + MotionEvent.SAMPLE_SIZE] = + ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue) / (float)absSize.range); } switch (orientation) { case Surface.ROTATION_90: { - final float temp = scaled[MotionEvent.SAMPLE_X]; - scaled[j + MotionEvent.SAMPLE_X] = scaled[j + MotionEvent.SAMPLE_Y]; - scaled[j + MotionEvent.SAMPLE_Y] = w-temp; + final float temp = reportData[MotionEvent.SAMPLE_X]; + reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y]; + reportData[j + MotionEvent.SAMPLE_Y] = w-temp; break; } case Surface.ROTATION_180: { - scaled[j + MotionEvent.SAMPLE_X] = w-scaled[j + MotionEvent.SAMPLE_X]; - scaled[j + MotionEvent.SAMPLE_Y] = h-scaled[j + MotionEvent.SAMPLE_Y]; + reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X]; + reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y]; break; } case Surface.ROTATION_270: { - final float temp = scaled[i + MotionEvent.SAMPLE_X]; - scaled[j + MotionEvent.SAMPLE_X] = h-scaled[j + MotionEvent.SAMPLE_Y]; - scaled[j + MotionEvent.SAMPLE_Y] = temp; + final float temp = reportData[i + MotionEvent.SAMPLE_X]; + reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y]; + reportData[j + MotionEvent.SAMPLE_Y] = temp; break; } } @@ -214,24 +432,24 @@ public class InputDevice { // We only consider the first pointer when computing the edge // flags, since they are global to the event. if (action == MotionEvent.ACTION_DOWN) { - if (scaled[MotionEvent.SAMPLE_X] <= 0) { + if (reportData[MotionEvent.SAMPLE_X] <= 0) { edgeFlags |= MotionEvent.EDGE_LEFT; - } else if (scaled[MotionEvent.SAMPLE_X] >= dispW) { + } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) { edgeFlags |= MotionEvent.EDGE_RIGHT; } - if (scaled[MotionEvent.SAMPLE_Y] <= 0) { + if (reportData[MotionEvent.SAMPLE_Y] <= 0) { edgeFlags |= MotionEvent.EDGE_TOP; - } else if (scaled[MotionEvent.SAMPLE_Y] >= dispH) { + } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) { edgeFlags |= MotionEvent.EDGE_BOTTOM; } } if (currentMove != null) { if (false) Log.i("InputDevice", "Adding batch x=" - + scaled[MotionEvent.SAMPLE_X] - + " y=" + scaled[MotionEvent.SAMPLE_Y] + + reportData[MotionEvent.SAMPLE_X] + + " y=" + reportData[MotionEvent.SAMPLE_Y] + " to " + currentMove); - currentMove.addBatch(curTime, scaled, metaState); + currentMove.addBatch(curTime, reportData, metaState); if (WindowManagerPolicy.WATCH_POINTER) { Log.i("KeyInputQueue", "Updating: " + currentMove); } @@ -239,37 +457,53 @@ public class InputDevice { } MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, - curTimeNano, action, numPointers, scaled, metaState, - xPrecision, yPrecision, device.id, edgeFlags); + curTimeNano, action, numPointers, mPointerIds, reportData, + metaState, xPrecision, yPrecision, device.id, edgeFlags); if (action == MotionEvent.ACTION_MOVE) { currentMove = me; } + + if (nextNumPointers < lastNumPointers) { + removeOldPointer(upOrDownPointer); + } + return me; } + boolean hasMore() { + return mLastNumPointers != mNextNumPointers; + } + + void finish() { + mNextNumPointers = mAddingPointerOffset = 0; + mNextData[MotionEvent.SAMPLE_PRESSURE] = 0; + } + MotionEvent generateRelMotion(InputDevice device, long curTime, long curTimeNano, int orientation, int metaState) { final float[] scaled = mReportData; // For now we only support 1 pointer with relative motions. - scaled[MotionEvent.SAMPLE_X] = mCurData[MotionEvent.SAMPLE_X]; - scaled[MotionEvent.SAMPLE_Y] = mCurData[MotionEvent.SAMPLE_Y]; + scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X]; + scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y]; scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f; scaled[MotionEvent.SAMPLE_SIZE] = 0; int edgeFlags = 0; int action; - if (mDown[0] != mLastDown[0]) { - mCurData[MotionEvent.SAMPLE_X] = - mCurData[MotionEvent.SAMPLE_Y] = 0; - mLastDown[0] = mDown[0]; - if (mDown[0]) { + if (mNextNumPointers != mLastNumPointers) { + mNextData[MotionEvent.SAMPLE_X] = + mNextData[MotionEvent.SAMPLE_Y] = 0; + if (mNextNumPointers > 0 && mLastNumPointers == 0) { action = MotionEvent.ACTION_DOWN; mDownTime = curTime; - } else { + } else if (mNextNumPointers == 0) { action = MotionEvent.ACTION_UP; + } else { + action = MotionEvent.ACTION_MOVE; } + mLastNumPointers = mNextNumPointers; currentMove = null; } else { action = MotionEvent.ACTION_MOVE; @@ -310,7 +544,7 @@ public class InputDevice { } MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, - curTimeNano, action, 1, scaled, metaState, + curTimeNano, action, 1, mPointerIds, scaled, metaState, xPrecision, yPrecision, device.id, edgeFlags); if (action == MotionEvent.ACTION_MOVE) { currentMove = me; diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index e0ee7ed6698a..cfb3e35bec54 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -49,6 +49,7 @@ public abstract class KeyInputQueue { static final String TAG = "KeyInputQueue"; static final boolean DEBUG_VIRTUAL_KEYS = false; + static final boolean DEBUG_POINTERS = false; private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; @@ -326,6 +327,10 @@ public abstract class KeyInputQueue { config.navigation = Configuration.NAVIGATION_TRACKBALL; //Log.i("foo", "***** HAVE TRACKBALL!"); + } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) { + config.navigation + = Configuration.NAVIGATION_DPAD; + //Log.i("foo", "***** HAVE DPAD!"); } } } @@ -364,9 +369,9 @@ public abstract class KeyInputQueue { android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); - try { - RawInputEvent ev = new RawInputEvent(); - while (true) { + RawInputEvent ev = new RawInputEvent(); + while (true) { + try { InputDevice di; // block, doesn't release the monitor @@ -465,49 +470,81 @@ public abstract class KeyInputQueue { ? KeyEvent.FLAG_WOKE_HERE : 0)); } else if (ev.type == RawInputEvent.EV_KEY) { if (ev.scancode == RawInputEvent.BTN_TOUCH && - (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { + (classes&(RawInputEvent.CLASS_TOUCHSCREEN + |RawInputEvent.CLASS_TOUCHSCREEN_MT)) + == RawInputEvent.CLASS_TOUCHSCREEN) { di.mAbs.changed = true; di.mAbs.mDown[0] = ev.value != 0; } else if (ev.scancode == RawInputEvent.BTN_2 && - (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { + (classes&(RawInputEvent.CLASS_TOUCHSCREEN + |RawInputEvent.CLASS_TOUCHSCREEN_MT)) + == RawInputEvent.CLASS_TOUCHSCREEN) { di.mAbs.changed = true; di.mAbs.mDown[1] = ev.value != 0; } else if (ev.scancode == RawInputEvent.BTN_MOUSE && (classes&RawInputEvent.CLASS_TRACKBALL) != 0) { di.mRel.changed = true; - di.mRel.mDown[0] = ev.value != 0; + di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0; send = true; } } else if (ev.type == RawInputEvent.EV_ABS && + (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) { + if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_PRESSURE] = ev.value; + } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_X] = ev.value; + if (DEBUG_POINTERS) Log.v(TAG, "MT @" + + di.mAbs.mAddingPointerOffset + + " X:" + ev.value); + } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_Y] = ev.value; + if (DEBUG_POINTERS) Log.v(TAG, "MT @" + + di.mAbs.mAddingPointerOffset + + " Y:" + ev.value); + } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_SIZE] = ev.value; + } + + } else if (ev.type == RawInputEvent.EV_ABS && (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { // Finger 1 if (ev.scancode == RawInputEvent.ABS_X) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_X] = ev.value; + di.mAbs.mNextData[MotionEvent.SAMPLE_X] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_Y) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_Y] = ev.value; + di.mAbs.mNextData[MotionEvent.SAMPLE_Y] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_PRESSURE] = ev.value; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA + di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] = ev.value; + di.mAbs.mNextData[MotionEvent.NUM_SAMPLE_DATA + MotionEvent.SAMPLE_PRESSURE] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_SIZE] = ev.value; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA + di.mAbs.mNextData[MotionEvent.SAMPLE_SIZE] = ev.value; + di.mAbs.mNextData[MotionEvent.NUM_SAMPLE_DATA + MotionEvent.SAMPLE_SIZE] = ev.value; // Finger 2 } else if (ev.scancode == RawInputEvent.ABS_HAT0X) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA - + MotionEvent.SAMPLE_X] = ev.value; + di.mAbs.mNextData[(di.mAbs.mDown[0] ? + MotionEvent.NUM_SAMPLE_DATA : 0) + + MotionEvent.SAMPLE_X] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA - + MotionEvent.SAMPLE_Y] = ev.value; + di.mAbs.mNextData[(di.mAbs.mDown[0] ? + MotionEvent.NUM_SAMPLE_DATA : 0) + + MotionEvent.SAMPLE_Y] = ev.value; } } else if (ev.type == RawInputEvent.EV_REL && @@ -515,14 +552,40 @@ public abstract class KeyInputQueue { // Add this relative movement into our totals. if (ev.scancode == RawInputEvent.REL_X) { di.mRel.changed = true; - di.mRel.mCurData[MotionEvent.SAMPLE_X] += ev.value; + di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value; } else if (ev.scancode == RawInputEvent.REL_Y) { di.mRel.changed = true; - di.mRel.mCurData[MotionEvent.SAMPLE_Y] += ev.value; + di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value; } } - if (send || ev.type == RawInputEvent.EV_SYN) { + if (ev.type == RawInputEvent.EV_SYN + && ev.scancode == RawInputEvent.SYN_MT_REPORT + && di.mAbs != null) { + di.mAbs.changed = true; + if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) { + // If the value is <= 0, the pointer is not + // down, so keep it in the count. + + if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_PRESSURE] != 0) { + final int num = di.mAbs.mNextNumPointers+1; + di.mAbs.mNextNumPointers = num; + if (DEBUG_POINTERS) Log.v(TAG, + "MT_REPORT: now have " + num + " pointers"); + final int newOffset = (num <= InputDevice.MAX_POINTERS) + ? (num * MotionEvent.NUM_SAMPLE_DATA) + : (InputDevice.MAX_POINTERS * + MotionEvent.NUM_SAMPLE_DATA); + di.mAbs.mAddingPointerOffset = newOffset; + di.mAbs.mNextData[newOffset + + MotionEvent.SAMPLE_PRESSURE] = 0; + } else { + if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer"); + } + } + } else if (send || (ev.type == RawInputEvent.EV_SYN + && ev.scancode == RawInputEvent.SYN_REPORT)) { if (mDisplay != null) { if (!mHaveGlobalMetaState) { computeGlobalMetaStateLocked(); @@ -534,72 +597,21 @@ public abstract class KeyInputQueue { if (ms.changed) { ms.changed = false; - boolean doMotion = true; - - // Look for virtual buttons. - VirtualKey vk = mPressedVirtualKey; - if (vk != null) { - doMotion = false; - if (!ms.mDown[0]) { - mPressedVirtualKey = null; - ms.mLastDown[0] = ms.mDown[0]; - if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, - "Generate key up for: " + vk.scancode); - KeyEvent event = newKeyEvent(di, - di.mKeyDownTime, curTime, false, - vk.lastKeycode, - 0, vk.scancode, - KeyEvent.FLAG_VIRTUAL_HARD_KEY); - mHapticFeedbackCallback.virtualKeyFeedback(event); - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_KEYBOARD, - event); - } else if (isInsideDisplay(di)) { - // Whoops the pointer has moved into - // the display area! Cancel the - // virtual key and start a pointer - // motion. - mPressedVirtualKey = null; - if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, - "Cancel key up for: " + vk.scancode); - KeyEvent event = newKeyEvent(di, - di.mKeyDownTime, curTime, false, - vk.lastKeycode, - 0, vk.scancode, - KeyEvent.FLAG_CANCELED | - KeyEvent.FLAG_VIRTUAL_HARD_KEY); - mHapticFeedbackCallback.virtualKeyFeedback(event); - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_KEYBOARD, - event); - doMotion = true; - for (int i=InputDevice.MAX_POINTERS-1; i>=0; i--) { - ms.mLastDown[i] = false; - } - } + if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN + |RawInputEvent.CLASS_TOUCHSCREEN_MT)) + == RawInputEvent.CLASS_TOUCHSCREEN) { + ms.mNextNumPointers = 0; + if (ms.mDown[0]) ms.mNextNumPointers++; + if (ms.mDown[1]) ms.mNextNumPointers++; } - if (doMotion && ms.mDown[0] && !ms.mLastDown[0]) { - vk = findSoftButton(di); - if (vk != null) { - doMotion = false; - mPressedVirtualKey = vk; - vk.lastKeycode = scancodeToKeycode( - di.id, vk.scancode); - ms.mLastDown[0] = ms.mDown[0]; - di.mKeyDownTime = curTime; - if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, - "Generate key down for: " + vk.scancode - + " (keycode=" + vk.lastKeycode + ")"); - KeyEvent event = newKeyEvent(di, - di.mKeyDownTime, curTime, true, - vk.lastKeycode, 0, - vk.scancode, - KeyEvent.FLAG_VIRTUAL_HARD_KEY); - mHapticFeedbackCallback.virtualKeyFeedback(event); - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_KEYBOARD, - event); - } + + boolean doMotion = !monitorVirtualKey(di, + ev, curTime, curTimeNano); + + if (doMotion && ms.mNextNumPointers > 0 + && ms.mLastNumPointers == 0) { + doMotion = !generateVirtualKeyDown(di, + ev, curTime, curTimeNano); } if (doMotion) { @@ -607,22 +619,26 @@ public abstract class KeyInputQueue { // multiple events here, for example // if two fingers change up/down state // at the same time. - me = ms.generateAbsMotion(di, curTime, - curTimeNano, mDisplay, - mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Absolute: x=" - + di.mAbs.mCurData[MotionEvent.SAMPLE_X] - + " y=" - + di.mAbs.mCurData[MotionEvent.SAMPLE_Y] - + " ev=" + me); - if (me != null) { - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i(TAG, "Enqueueing: " + me); + do { + me = ms.generateAbsMotion(di, curTime, + curTimeNano, mDisplay, + mOrientation, mGlobalMetaState); + if (false) Log.v(TAG, "Absolute: x=" + + di.mAbs.mNextData[MotionEvent.SAMPLE_X] + + " y=" + + di.mAbs.mNextData[MotionEvent.SAMPLE_Y] + + " ev=" + me); + if (me != null) { + if (WindowManagerPolicy.WATCH_POINTER) { + Log.i(TAG, "Enqueueing: " + me); + } + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_TOUCHSCREEN, me); } - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_TOUCHSCREEN, me); - } + } while (ms.hasMore()); } + + ms.finish(); } ms = di.mRel; @@ -633,22 +649,24 @@ public abstract class KeyInputQueue { curTimeNano, mOrientation, mGlobalMetaState); if (false) Log.v(TAG, "Relative: x=" - + di.mRel.mCurData[MotionEvent.SAMPLE_X] + + di.mRel.mNextData[MotionEvent.SAMPLE_X] + " y=" - + di.mRel.mCurData[MotionEvent.SAMPLE_Y] + + di.mRel.mNextData[MotionEvent.SAMPLE_Y] + " ev=" + me); if (me != null) { addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_TRACKBALL, me); } + + ms.finish(); } } } } - } - } catch (RuntimeException exc) { - Log.e(TAG, "InputReaderThread uncaught exception", exc); + } catch (RuntimeException exc) { + Log.e(TAG, "InputReaderThread uncaught exception", exc); + } } } }; @@ -661,13 +679,13 @@ public abstract class KeyInputQueue { return true; } - if (absm.mCurData[MotionEvent.SAMPLE_X] >= absx.minValue - && absm.mCurData[MotionEvent.SAMPLE_X] <= absx.maxValue - && absm.mCurData[MotionEvent.SAMPLE_Y] >= absy.minValue - && absm.mCurData[MotionEvent.SAMPLE_Y] <= absy.maxValue) { + if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue + && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue + && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue + && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) { if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" - + absm.mCurData[MotionEvent.SAMPLE_X] - + "," + absm.mCurData[MotionEvent.SAMPLE_Y] + + absm.mNextData[MotionEvent.SAMPLE_X] + + "," + absm.mNextData[MotionEvent.SAMPLE_Y] + ") inside of display"); return true; } @@ -675,28 +693,24 @@ public abstract class KeyInputQueue { return false; } - private VirtualKey findSoftButton(InputDevice dev) { + private VirtualKey findVirtualKey(InputDevice dev) { final int N = mVirtualKeys.size(); if (N <= 0) { return null; } - if (isInsideDisplay(dev)) { - return null; - } - final InputDevice.MotionState absm = dev.mAbs; for (int i=0; i<N; i++) { VirtualKey sb = mVirtualKeys.get(i); sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight); if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test (" - + absm.mCurData[MotionEvent.SAMPLE_X] + "," - + absm.mCurData[MotionEvent.SAMPLE_Y] + ") in code " + + absm.mNextData[MotionEvent.SAMPLE_X] + "," + + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code " + sb.scancode + " - (" + sb.hitLeft + "," + sb.hitTop + ")-(" + sb.hitRight + "," + sb.hitBottom + ")"); - if (sb.checkHit(absm.mCurData[MotionEvent.SAMPLE_X], - absm.mCurData[MotionEvent.SAMPLE_Y])) { + if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X], + absm.mNextData[MotionEvent.SAMPLE_Y])) { if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!"); return sb; } @@ -705,6 +719,97 @@ public abstract class KeyInputQueue { return null; } + private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev, + long curTime, long curTimeNano) { + if (isInsideDisplay(di)) { + // Didn't consume event. + return false; + } + + + VirtualKey vk = findVirtualKey(di); + if (vk != null) { + final InputDevice.MotionState ms = di.mAbs; + mPressedVirtualKey = vk; + vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode); + ms.mLastNumPointers = ms.mNextNumPointers; + di.mKeyDownTime = curTime; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, + "Generate key down for: " + vk.scancode + + " (keycode=" + vk.lastKeycode + ")"); + KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true, + vk.lastKeycode, 0, vk.scancode, + KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, + event); + } + + // We always consume the event, even if we didn't + // generate a key event. There are two reasons for + // this: to avoid spurious touches when holding + // the edges of the device near the touchscreen, + // and to avoid reporting events if there are virtual + // keys on the touchscreen outside of the display + // area. + // Note that for all of this we are only looking at the + // first pointer, since what we are handling here is the + // first pointer going down, and this is the coordinate + // that will be used to dispatch the event. + if (false) { + final InputDevice.AbsoluteInfo absx = di.absX; + final InputDevice.AbsoluteInfo absy = di.absY; + final InputDevice.MotionState absm = di.mAbs; + Log.v(TAG, "Rejecting (" + + absm.mNextData[MotionEvent.SAMPLE_X] + "," + + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of (" + + absx.minValue + "," + absy.minValue + + ")-(" + absx.maxValue + "," + + absx.maxValue + ")"); + } + return true; + } + + private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev, + long curTime, long curTimeNano) { + VirtualKey vk = mPressedVirtualKey; + if (vk == null) { + return false; + } + + final InputDevice.MotionState ms = di.mAbs; + if (ms.mNextNumPointers <= 0) { + mPressedVirtualKey = null; + ms.mLastNumPointers = 0; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode); + KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false, + vk.lastKeycode, 0, vk.scancode, + KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, + event); + return true; + + } else if (isInsideDisplay(di)) { + // Whoops the pointer has moved into + // the display area! Cancel the + // virtual key and start a pointer + // motion. + mPressedVirtualKey = null; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Cancel key up for: " + vk.scancode); + KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false, + vk.lastKeycode, 0, vk.scancode, + KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, + event); + ms.mLastNumPointers = 0; + return false; + } + + return true; + } + /** * Returns a new meta state for the given keys and old state. */ @@ -851,8 +956,8 @@ public abstract class KeyInputQueue { if (ev.event == ev.inputDevice.mRel.currentMove) { if (false) Log.i(TAG, "Detach rel " + ev.event); ev.inputDevice.mRel.currentMove = null; - ev.inputDevice.mRel.mCurData[MotionEvent.SAMPLE_X] = 0; - ev.inputDevice.mRel.mCurData[MotionEvent.SAMPLE_Y] = 0; + ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0; + ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0; } recycleLocked(ev); } @@ -945,7 +1050,12 @@ public abstract class KeyInputQueue { InputDevice.AbsoluteInfo absY; InputDevice.AbsoluteInfo absPressure; InputDevice.AbsoluteInfo absSize; - if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { + if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) { + absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, "X"); + absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y, "Y"); + absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure"); + absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size"); + } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X"); absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y"); absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure"); diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index edba5b6dd653..ceb9c418fbe1 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -541,6 +541,17 @@ public class WindowManagerService extends IWindowManager.Stub mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(), Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale); + int max_events_per_sec = 35; + try { + max_events_per_sec = Integer.parseInt(SystemProperties + .get("windowsmgr.max_events_per_sec")); + if (max_events_per_sec < 1) { + max_events_per_sec = 35; + } + } catch (NumberFormatException e) { + } + mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec; + mQueue = new KeyQ(); mInputThread = new InputDispatcherThread(); @@ -4010,8 +4021,8 @@ public class WindowManagerService extends IWindowManager.Stub } } //end if target - // TODO remove once we settle on a value or make it app specific - if (action == MotionEvent.ACTION_DOWN) { + // Enable this for testing the "right" value + if (false && action == MotionEvent.ACTION_DOWN) { int max_events_per_sec = 35; try { max_events_per_sec = Integer.parseInt(SystemProperties |