Merge "Fix bugs in AllocationAdapter."
diff --git a/api/current.txt b/api/current.txt
index fc244d8..fa3130a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16782,6 +16782,9 @@
     method public void addF32(android.renderscript.Float3);
     method public void addF32(android.renderscript.Float4);
     method public void addF64(double);
+    method public void addF64(android.renderscript.Double2);
+    method public void addF64(android.renderscript.Double3);
+    method public void addF64(android.renderscript.Double4);
     method public void addI16(short);
     method public void addI16(android.renderscript.Short2);
     method public void addI16(android.renderscript.Short3);
@@ -16791,6 +16794,9 @@
     method public void addI32(android.renderscript.Int3);
     method public void addI32(android.renderscript.Int4);
     method public void addI64(long);
+    method public void addI64(android.renderscript.Long2);
+    method public void addI64(android.renderscript.Long3);
+    method public void addI64(android.renderscript.Long4);
     method public void addI8(byte);
     method public void addI8(android.renderscript.Byte2);
     method public void addI8(android.renderscript.Byte3);
@@ -16808,6 +16814,9 @@
     method public void addU32(android.renderscript.Long3);
     method public void addU32(android.renderscript.Long4);
     method public void addU64(long);
+    method public void addU64(android.renderscript.Long2);
+    method public void addU64(android.renderscript.Long3);
+    method public void addU64(android.renderscript.Long4);
     method public void addU8(short);
     method public void addU8(android.renderscript.Short2);
     method public void addU8(android.renderscript.Short3);
diff --git a/core/java/android/pim/EventRecurrence.java b/core/java/android/pim/EventRecurrence.java
index 56c4f7a..cde7dac 100644
--- a/core/java/android/pim/EventRecurrence.java
+++ b/core/java/android/pim/EventRecurrence.java
@@ -18,36 +18,18 @@
 
 import android.text.TextUtils;
 import android.text.format.Time;
+import android.util.Log;
+import android.util.TimeFormatException;
 
 import java.util.Calendar;
+import java.util.HashMap;
 
-public class EventRecurrence
-{
-    /**
-     * Thrown when a recurrence string provided can not be parsed according
-     * to RFC2445.
-     */
-    public static class InvalidFormatException extends RuntimeException
-    {
-        InvalidFormatException(String s) {
-            super(s);
-        }
-    }
+/**
+ * Event recurrence utility functions.
+ */
+public class EventRecurrence {
+    private static String TAG = "EventRecur";
 
-    public EventRecurrence()
-    {
-        wkst = MO;
-    }
-    
-    /**
-     * Parse an iCalendar/RFC2445 recur type according to Section 4.3.10.
-     */
-    public native void parse(String recur);
-
-    public void setStartDate(Time date) {
-        startDate = date;
-    }
-    
     public static final int SECONDLY = 1;
     public static final int MINUTELY = 2;
     public static final int HOURLY = 3;
@@ -64,13 +46,15 @@
     public static final int FR = 0x00200000;
     public static final int SA = 0x00400000;
 
-    public Time      startDate;
-    public int       freq;
+    public Time      startDate;     // set by setStartDate(), not parse()
+
+    public int       freq;          // SECONDLY, MINUTELY, etc.
     public String    until;
     public int       count;
     public int       interval;
-    public int       wkst;
+    public int       wkst;          // SU, MO, TU, etc.
 
+    /* lists with zero entries may be null references */
     public int[]     bysecond;
     public int       bysecondCount;
     public int[]     byminute;
@@ -79,7 +63,7 @@
     public int       byhourCount;
     public int[]     byday;
     public int[]     bydayNum;
-    public int       bydayCount;   
+    public int       bydayCount;
     public int[]     bymonthday;
     public int       bymonthdayCount;
     public int[]     byyearday;
@@ -91,6 +75,134 @@
     public int[]     bysetpos;
     public int       bysetposCount;
 
+    /** maps a part string to a parser object */
+    private static HashMap<String,PartParser> sParsePartMap;
+    static {
+        sParsePartMap = new HashMap<String,PartParser>();
+        sParsePartMap.put("FREQ", new ParseFreq());
+        sParsePartMap.put("UNTIL", new ParseUntil());
+        sParsePartMap.put("COUNT", new ParseCount());
+        sParsePartMap.put("INTERVAL", new ParseInterval());
+        sParsePartMap.put("BYSECOND", new ParseBySecond());
+        sParsePartMap.put("BYMINUTE", new ParseByMinute());
+        sParsePartMap.put("BYHOUR", new ParseByHour());
+        sParsePartMap.put("BYDAY", new ParseByDay());
+        sParsePartMap.put("BYMONTHDAY", new ParseByMonthDay());
+        sParsePartMap.put("BYYEARDAY", new ParseByYearDay());
+        sParsePartMap.put("BYWEEKNO", new ParseByWeekNo());
+        sParsePartMap.put("BYMONTH", new ParseByMonth());
+        sParsePartMap.put("BYSETPOS", new ParseBySetPos());
+        sParsePartMap.put("WKST", new ParseWkst());
+    }
+
+    /* values for bit vector that keeps track of what we have already seen */
+    private static final int PARSED_FREQ = 1 << 0;
+    private static final int PARSED_UNTIL = 1 << 1;
+    private static final int PARSED_COUNT = 1 << 2;
+    private static final int PARSED_INTERVAL = 1 << 3;
+    private static final int PARSED_BYSECOND = 1 << 4;
+    private static final int PARSED_BYMINUTE = 1 << 5;
+    private static final int PARSED_BYHOUR = 1 << 6;
+    private static final int PARSED_BYDAY = 1 << 7;
+    private static final int PARSED_BYMONTHDAY = 1 << 8;
+    private static final int PARSED_BYYEARDAY = 1 << 9;
+    private static final int PARSED_BYWEEKNO = 1 << 10;
+    private static final int PARSED_BYMONTH = 1 << 11;
+    private static final int PARSED_BYSETPOS = 1 << 12;
+    private static final int PARSED_WKST = 1 << 13;
+
+    /** maps a FREQ value to an integer constant */
+    private static final HashMap<String,Integer> sParseFreqMap = new HashMap<String,Integer>();
+    static {
+        sParseFreqMap.put("SECONDLY", SECONDLY);
+        sParseFreqMap.put("MINUTELY", MINUTELY);
+        sParseFreqMap.put("HOURLY", HOURLY);
+        sParseFreqMap.put("DAILY", DAILY);
+        sParseFreqMap.put("WEEKLY", WEEKLY);
+        sParseFreqMap.put("MONTHLY", MONTHLY);
+        sParseFreqMap.put("YEARLY", YEARLY);
+    }
+
+    /** maps a two-character weekday string to an integer constant */
+    private static final HashMap<String,Integer> sParseWeekdayMap = new HashMap<String,Integer>();
+    static {
+        sParseWeekdayMap.put("SU", SU);
+        sParseWeekdayMap.put("MO", MO);
+        sParseWeekdayMap.put("TU", TU);
+        sParseWeekdayMap.put("WE", WE);
+        sParseWeekdayMap.put("TH", TH);
+        sParseWeekdayMap.put("FR", FR);
+        sParseWeekdayMap.put("SA", SA);
+    }
+
+    /** If set, allow lower-case recurrence rule strings.  Minor performance impact. */
+    private static final boolean ALLOW_LOWER_CASE = false;
+
+    /** If set, validate the value of UNTIL parts.  Minor performance impact. */
+    private static final boolean VALIDATE_UNTIL = false;
+
+    /** If set, require that only one of {UNTIL,COUNT} is present.  Breaks compat w/ old parser. */
+    private static final boolean ONLY_ONE_UNTIL_COUNT = false;
+
+
+    /**
+     * Thrown when a recurrence string provided can not be parsed according
+     * to RFC2445.
+     */
+    public static class InvalidFormatException extends RuntimeException {
+        InvalidFormatException(String s) {
+            super(s);
+        }
+    }
+
+    /**
+     * Parse an iCalendar/RFC2445 recur type according to Section 4.3.10.  The string is
+     * parsed twice, by the old and new parsers, and the results are compared.
+     * <p>
+     * TODO: this will go away, and what is now parse2() will simply become parse().
+     */
+    public void parse(String recur) {
+        InvalidFormatException newExcep = null;
+        try {
+            parse2(recur);
+        } catch (InvalidFormatException ife) {
+            newExcep = ife;
+        }
+
+        boolean oldThrew = false;
+        try {
+            EventRecurrence check = new EventRecurrence();
+            check.parseNative(recur);
+            if (newExcep == null) {
+                // Neither threw, check to see if results match.
+                if (!equals(check)) {
+                    throw new InvalidFormatException("Recurrence rule parse does not match [" +
+                            recur + "]");
+                }
+            }
+        } catch (InvalidFormatException ife) {
+            oldThrew = true;
+            if (newExcep == null) {
+                // Old threw, but new didn't.  Log a warning, but don't throw.
+                Log.d(TAG, "NOTE: old parser rejected [" + recur + "]: " + ife.getMessage());
+            }
+        }
+
+        if (newExcep != null) {
+            if (!oldThrew) {
+                // New threw, but old didn't.  Log a warning and throw the exception.
+                Log.d(TAG, "NOTE: new parser rejected [" + recur + "]: " + newExcep.getMessage());
+            }
+            throw newExcep;
+        }
+    }
+
+    native void parseNative(String recur);
+
+    public void setStartDate(Time date) {
+        startDate = date;
+    }
+
     /**
      * Converts one of the Calendar.SUNDAY constants to the SU, MO, etc.
      * constants.  btw, I think we should switch to those here too, to
@@ -118,7 +230,7 @@
                 throw new RuntimeException("bad day of week: " + day);
         }
     }
-    
+
     public static int timeDay2Day(int day)
     {
         switch (day)
@@ -191,16 +303,16 @@
                 throw new RuntimeException("bad day of week: " + day);
         }
     }
-    
+
     /**
      * Converts one of the internal day constants (SU, MO, etc.) to the
      * two-letter string representing that constant.
-     * 
-     * @throws IllegalArgumentException Thrown if the day argument is not one of
-     * the defined day constants.
-     * 
+     *
      * @param day one the internal constants SU, MO, etc.
      * @return the two-letter string for the day ("SU", "MO", etc.)
+     *
+     * @throws IllegalArgumentException Thrown if the day argument is not one of
+     * the defined day constants.
      */
     private static String day2String(int day) {
         switch (day) {
@@ -283,7 +395,7 @@
             s.append(";UNTIL=");
             s.append(until);
         }
-        
+
         if (this.count != 0) {
             s.append(";COUNT=");
             s.append(this.count);
@@ -323,36 +435,484 @@
 
         return s.toString();
     }
-    
+
     public boolean repeatsOnEveryWeekDay() {
         if (this.freq != WEEKLY) {
-            return false; 
+            return false;
         }
-        
+
         int count = this.bydayCount;
         if (count != 5) {
             return false;
         }
-        
+
         for (int i = 0 ; i < count ; i++) {
             int day = byday[i];
             if (day == SU || day == SA) {
                 return false;
             }
         }
-        
+
         return true;
     }
-    
+
     public boolean repeatsMonthlyOnDayCount() {
         if (this.freq != MONTHLY) {
             return false;
         }
-        
+
         if (bydayCount != 1 || bymonthdayCount != 0) {
             return false;
         }
-        
+
         return true;
     }
+
+    /**
+     * Determines whether two integer arrays contain identical elements.
+     * <p>
+     * The native implementation over-allocated the arrays (and may have stuff left over from
+     * a previous run), so we can't just check the arrays -- the separately-maintained count
+     * field also matters.  We assume that a null array will have a count of zero, and that the
+     * array can hold as many elements as the associated count indicates.
+     * <p>
+     * TODO: replace this with Arrays.equals() when the old parser goes away.
+     */
+    private static boolean arraysEqual(int[] array1, int count1, int[] array2, int count2) {
+        if (count1 != count2) {
+            return false;
+        }
+
+        for (int i = 0; i < count1; i++) {
+            if (array1[i] != array2[i])
+                return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof EventRecurrence)) {
+            return false;
+        }
+
+        EventRecurrence er = (EventRecurrence) obj;
+        return  (startDate == null ?
+                        er.startDate == null : Time.compare(startDate, er.startDate) == 0) &&
+                freq == er.freq &&
+                (until == null ? er.until == null : until.equals(er.until)) &&
+                count == er.count &&
+                interval == er.interval &&
+                wkst == er.wkst &&
+                arraysEqual(bysecond, bysecondCount, er.bysecond, er.bysecondCount) &&
+                arraysEqual(byminute, byminuteCount, er.byminute, er.byminuteCount) &&
+                arraysEqual(byhour, byhourCount, er.byhour, er.byhourCount) &&
+                arraysEqual(byday, bydayCount, er.byday, er.bydayCount) &&
+                arraysEqual(bydayNum, bydayCount, er.bydayNum, er.bydayCount) &&
+                arraysEqual(bymonthday, bymonthdayCount, er.bymonthday, er.bymonthdayCount) &&
+                arraysEqual(byyearday, byyeardayCount, er.byyearday, er.byyeardayCount) &&
+                arraysEqual(byweekno, byweeknoCount, er.byweekno, er.byweeknoCount) &&
+                arraysEqual(bymonth, bymonthCount, er.bymonth, er.bymonthCount) &&
+                arraysEqual(bysetpos, bysetposCount, er.bysetpos, er.bysetposCount);
+    }
+
+    @Override public int hashCode() {
+        // We overrode equals, so we must override hashCode().  Nobody seems to need this though.
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Resets parser-modified fields to their initial state.  Does not alter startDate.
+     * <p>
+     * The original parser always set all of the "count" fields, "wkst", and "until",
+     * essentially allowing the same object to be used multiple times by calling parse().
+     * It's unclear whether this behavior was intentional.  For now, be paranoid and
+     * preserve the existing behavior by resetting the fields.
+     * <p>
+     * We don't need to touch the integer arrays; they will either be ignored or
+     * overwritten.  The "startDate" field is not set by the parser, so we ignore it here.
+     */
+    private void resetFields() {
+        until = null;
+        freq = count = interval = bysecondCount = byminuteCount = byhourCount =
+            bydayCount = bymonthdayCount = byyeardayCount = byweeknoCount = bymonthCount =
+            bysetposCount = 0;
+    }
+
+    /**
+     * Parses an rfc2445 recurrence rule string into its component pieces.  Attempting to parse
+     * malformed input will result in an EventRecurrence.InvalidFormatException.
+     *
+     * @param recur The recurrence rule to parse (in un-folded form).
+     */
+    void parse2(String recur) {
+        /*
+         * From RFC 2445 section 4.3.10:
+         *
+         * recur = "FREQ"=freq *(
+         *       ; either UNTIL or COUNT may appear in a 'recur',
+         *       ; but UNTIL and COUNT MUST NOT occur in the same 'recur'
+         *
+         *       ( ";" "UNTIL" "=" enddate ) /
+         *       ( ";" "COUNT" "=" 1*DIGIT ) /
+         *
+         *       ; the rest of these keywords are optional,
+         *       ; but MUST NOT occur more than once
+         *
+         *       ( ";" "INTERVAL" "=" 1*DIGIT )          /
+         *       ( ";" "BYSECOND" "=" byseclist )        /
+         *       ( ";" "BYMINUTE" "=" byminlist )        /
+         *       ( ";" "BYHOUR" "=" byhrlist )           /
+         *       ( ";" "BYDAY" "=" bywdaylist )          /
+         *       ( ";" "BYMONTHDAY" "=" bymodaylist )    /
+         *       ( ";" "BYYEARDAY" "=" byyrdaylist )     /
+         *       ( ";" "BYWEEKNO" "=" bywknolist )       /
+         *       ( ";" "BYMONTH" "=" bymolist )          /
+         *       ( ";" "BYSETPOS" "=" bysplist )         /
+         *       ( ";" "WKST" "=" weekday )              /
+         *       ( ";" x-name "=" text )
+         *       )
+         *
+         * Examples:
+         *   FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
+         *   FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8
+         *
+         * Strategy:
+         * (1) Split the string at ';' boundaries to get an array of rule "parts".
+         * (2) For each part, find substrings for left/right sides of '=' (name/value).
+         * (3) Call a <name>-specific parsing function to parse the <value> into an
+         *     output field.
+         *
+         * By keeping track of which names we've seen in a bit vector, we can verify the
+         * constraints indicated above (FREQ appears first, none of them appear more than once --
+         * though x-[name] would require special treatment), and we have either UNTIL or COUNT
+         * but not both.
+         *
+         * In general, RFC 2445 property names (e.g. "FREQ") and enumerations ("TU") must
+         * be handled in a case-insensitive fashion, but case may be significant for other
+         * properties.  We don't have any case-sensitive values in RRULE, except possibly
+         * for the custom "X-" properties, but we ignore those anyway.  Thus, we can trivially
+         * convert the entire string to upper case and then use simple comparisons.
+         *
+         * Differences from previous version:
+         * - allows lower-case property and enumeration values [optional]
+         * - enforces that FREQ appears first
+         * - enforces that only one of UNTIL and COUNT may be specified
+         * - allows (but ignores) X-* parts
+         * - improved validation on various values (e.g. UNTIL timestamps)
+         * - error messages are more specific
+         */
+
+        /* TODO: replace with "if (freq != 0) throw" if nothing requires this */
+        resetFields();
+
+        int parseFlags = 0;
+        String[] parts;
+        if (ALLOW_LOWER_CASE) {
+            parts = recur.toUpperCase().split(";");
+        } else {
+            parts = recur.split(";");
+        }
+        for (String part : parts) {
+            int equalIndex = part.indexOf('=');
+            if (equalIndex <= 0) {
+                /* no '=' or no LHS */
+                throw new InvalidFormatException("Missing LHS in " + part);
+            }
+
+            String lhs = part.substring(0, equalIndex);
+            String rhs = part.substring(equalIndex + 1);
+            if (rhs.length() == 0) {
+                throw new InvalidFormatException("Missing RHS in " + part);
+            }
+
+            /*
+             * In lieu of a "switch" statement that allows string arguments, we use a
+             * map from strings to parsing functions.
+             */
+            PartParser parser = sParsePartMap.get(lhs);
+            if (parser == null) {
+                if (lhs.startsWith("X-")) {
+                    //Log.d(TAG, "Ignoring custom part " + lhs);
+                    continue;
+                }
+                throw new InvalidFormatException("Couldn't find parser for " + lhs);
+            } else {
+                int flag = parser.parsePart(rhs, this);
+                if ((parseFlags & flag) != 0) {
+                    throw new InvalidFormatException("Part " + lhs + " was specified twice");
+                }
+                if (parseFlags == 0 && flag != PARSED_FREQ) {
+                    throw new InvalidFormatException("FREQ must be specified first");
+                }
+                parseFlags |= flag;
+            }
+        }
+
+        // If not specified, week starts on Monday.
+        if ((parseFlags & PARSED_WKST) == 0) {
+            wkst = MO;
+        }
+
+        // FREQ is mandatory.
+        if ((parseFlags & PARSED_FREQ) == 0) {
+            throw new InvalidFormatException("Must specify a FREQ value");
+        }
+
+        // Can't have both UNTIL and COUNT.
+        if ((parseFlags & (PARSED_UNTIL | PARSED_COUNT)) == (PARSED_UNTIL | PARSED_COUNT)) {
+            if (ONLY_ONE_UNTIL_COUNT) {
+                throw new InvalidFormatException("Must not specify both UNTIL and COUNT: " + recur);
+            } else {
+                Log.w(TAG, "Warning: rrule has both UNTIL and COUNT: " + recur);
+            }
+        }
+    }
+
+    /**
+     * Base class for the RRULE part parsers.
+     */
+    abstract static class PartParser {
+        /**
+         * Parses a single part.
+         *
+         * @param value The right-hand-side of the part.
+         * @param er The EventRecurrence into which the result is stored.
+         * @return A bit value indicating which part was parsed.
+         */
+        public abstract int parsePart(String value, EventRecurrence er);
+
+        /**
+         * Parses an integer, with range-checking.
+         *
+         * @param str The string to parse.
+         * @param minVal Minimum allowed value.
+         * @param maxVal Maximum allowed value.
+         * @param allowZero Is 0 allowed?
+         * @return The parsed value.
+         */
+        public static int parseIntRange(String str, int minVal, int maxVal, boolean allowZero) {
+            try {
+                if (str.charAt(0) == '+') {
+                    // Integer.parseInt does not allow a leading '+', so skip it manually.
+                    str = str.substring(1);
+                }
+                int val = Integer.parseInt(str);
+                if (val < minVal || val > maxVal || (val == 0 && !allowZero)) {
+                    throw new InvalidFormatException("Integer value out of range: " + str);
+                }
+                return val;
+            } catch (NumberFormatException nfe) {
+                throw new InvalidFormatException("Invalid integer value: " + str);
+            }
+        }
+
+        /**
+         * Parses a comma-separated list of integers, with range-checking.
+         *
+         * @param listStr The string to parse.
+         * @param minVal Minimum allowed value.
+         * @param maxVal Maximum allowed value.
+         * @param allowZero Is 0 allowed?
+         * @return A new array with values, sized to hold the exact number of elements.
+         */
+        public static int[] parseNumberList(String listStr, int minVal, int maxVal,
+                boolean allowZero) {
+            int[] values;
+
+            if (listStr.indexOf(",") < 0) {
+                // Common case: only one entry, skip split() overhead.
+                values = new int[1];
+                values[0] = parseIntRange(listStr, minVal, maxVal, allowZero);
+            } else {
+                String[] valueStrs = listStr.split(",");
+                int len = valueStrs.length;
+                values = new int[len];
+                for (int i = 0; i < len; i++) {
+                    values[i] = parseIntRange(valueStrs[i], minVal, maxVal, allowZero);
+                }
+            }
+            return values;
+        }
+   }
+
+    /** parses FREQ={SECONDLY,MINUTELY,...} */
+    private static class ParseFreq extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            Integer freq = sParseFreqMap.get(value);
+            if (freq == null) {
+                throw new InvalidFormatException("Invalid FREQ value: " + value);
+            }
+            er.freq = freq;
+            return PARSED_FREQ;
+        }
+    }
+    /** parses UNTIL=enddate, e.g. "19970829T021400" */
+    private static class ParseUntil extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            if (VALIDATE_UNTIL) {
+                try {
+                    // Parse the time to validate it.  The result isn't retained.
+                    Time until = new Time();
+                    until.parse(value);
+                } catch (TimeFormatException tfe) {
+                    throw new InvalidFormatException("Invalid UNTIL value: " + value);
+                }
+            }
+            er.until = value;
+            return PARSED_UNTIL;
+        }
+    }
+    /** parses COUNT=[non-negative-integer] */
+    private static class ParseCount extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            er.count = parseIntRange(value, 0, Integer.MAX_VALUE, true);
+            return PARSED_COUNT;
+        }
+    }
+    /** parses INTERVAL=[non-negative-integer] */
+    private static class ParseInterval extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            er.interval = parseIntRange(value, 1, Integer.MAX_VALUE, false);
+            return PARSED_INTERVAL;
+        }
+    }
+    /** parses BYSECOND=byseclist */
+    private static class ParseBySecond extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] bysecond = parseNumberList(value, 0, 59, true);
+            er.bysecond = bysecond;
+            er.bysecondCount = bysecond.length;
+            return PARSED_BYSECOND;
+        }
+    }
+    /** parses BYMINUTE=byminlist */
+    private static class ParseByMinute extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] byminute = parseNumberList(value, 0, 59, true);
+            er.byminute = byminute;
+            er.byminuteCount = byminute.length;
+            return PARSED_BYMINUTE;
+        }
+    }
+    /** parses BYHOUR=byhrlist */
+    private static class ParseByHour extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] byhour = parseNumberList(value, 0, 23, true);
+            er.byhour = byhour;
+            er.byhourCount = byhour.length;
+            return PARSED_BYHOUR;
+        }
+    }
+    /** parses BYDAY=bywdaylist, e.g. "1SU,-1SU" */
+    private static class ParseByDay extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] byday;
+            int[] bydayNum;
+            int bydayCount;
+
+            if (value.indexOf(",") < 0) {
+                /* only one entry, skip split() overhead */
+                bydayCount = 1;
+                byday = new int[1];
+                bydayNum = new int[1];
+                parseWday(value, byday, bydayNum, 0);
+            } else {
+                String[] wdays = value.split(",");
+                int len = wdays.length;
+                bydayCount = len;
+                byday = new int[len];
+                bydayNum = new int[len];
+                for (int i = 0; i < len; i++) {
+                    parseWday(wdays[i], byday, bydayNum, i);
+                }
+            }
+            er.byday = byday;
+            er.bydayNum = bydayNum;
+            er.bydayCount = bydayCount;
+            return PARSED_BYDAY;
+        }
+
+        /** parses [int]weekday, putting the pieces into parallel array entries */
+        private static void parseWday(String str, int[] byday, int[] bydayNum, int index) {
+            int wdayStrStart = str.length() - 2;
+            String wdayStr;
+
+            if (wdayStrStart > 0) {
+                /* number is included; parse it out and advance to weekday */
+                String numPart = str.substring(0, wdayStrStart);
+                int num = parseIntRange(numPart, -53, 53, false);
+                bydayNum[index] = num;
+                wdayStr = str.substring(wdayStrStart);
+            } else {
+                /* just the weekday string */
+                wdayStr = str;
+            }
+            Integer wday = sParseWeekdayMap.get(wdayStr);
+            if (wday == null) {
+                throw new InvalidFormatException("Invalid BYDAY value: " + str);
+            }
+            byday[index] = wday;
+        }
+    }
+    /** parses BYMONTHDAY=bymodaylist */
+    private static class ParseByMonthDay extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] bymonthday = parseNumberList(value, -31, 31, false);
+            er.bymonthday = bymonthday;
+            er.bymonthdayCount = bymonthday.length;
+            return PARSED_BYMONTHDAY;
+        }
+    }
+    /** parses BYYEARDAY=byyrdaylist */
+    private static class ParseByYearDay extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] byyearday = parseNumberList(value, -366, 366, false);
+            er.byyearday = byyearday;
+            er.byyeardayCount = byyearday.length;
+            return PARSED_BYYEARDAY;
+        }
+    }
+    /** parses BYWEEKNO=bywknolist */
+    private static class ParseByWeekNo extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] byweekno = parseNumberList(value, -53, 53, false);
+            er.byweekno = byweekno;
+            er.byweeknoCount = byweekno.length;
+            return PARSED_BYWEEKNO;
+        }
+    }
+    /** parses BYMONTH=bymolist */
+    private static class ParseByMonth extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] bymonth = parseNumberList(value, 1, 12, false);
+            er.bymonth = bymonth;
+            er.bymonthCount = bymonth.length;
+            return PARSED_BYMONTH;
+        }
+    }
+    /** parses BYSETPOS=bysplist */
+    private static class ParseBySetPos extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            int[] bysetpos = parseNumberList(value, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
+            er.bysetpos = bysetpos;
+            er.bysetposCount = bysetpos.length;
+            return PARSED_BYSETPOS;
+        }
+    }
+    /** parses WKST={SU,MO,...} */
+    private static class ParseWkst extends PartParser {
+        @Override public int parsePart(String value, EventRecurrence er) {
+            Integer wkst = sParseWeekdayMap.get(value);
+            if (wkst == null) {
+                throw new InvalidFormatException("Invalid WKST value: " + value);
+            }
+            er.wkst = wkst;
+            return PARSED_WKST;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index cc09927..27e4191 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -184,12 +184,12 @@
 
     private class MenuAdapter extends BaseAdapter {
         public int getCount() {
-            ArrayList<MenuItemImpl> items = mMenu.getVisibleItems();
+            ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
             return items.size() - mItemIndexOffset;
         }
 
         public MenuItemImpl getItem(int position) {
-            ArrayList<MenuItemImpl> items = mMenu.getVisibleItems();
+            ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
             return items.get(position + mItemIndexOffset);
         }
 
diff --git a/core/jni/android_pim_EventRecurrence.cpp b/core/jni/android_pim_EventRecurrence.cpp
index 44e898d..3e11569 100644
--- a/core/jni/android_pim_EventRecurrence.cpp
+++ b/core/jni/android_pim_EventRecurrence.cpp
@@ -147,7 +147,7 @@
  */

 static JNINativeMethod METHODS[] = {

     /* name, signature, funcPtr */

-    { "parse", "(Ljava/lang/String;)V", (void*)EventRecurrence_parse }

+    { "parseNative", "(Ljava/lang/String;)V", (void*)EventRecurrence_parse }

 };

 

 static const char*const CLASS_NAME = "android/pim/EventRecurrence";

diff --git a/core/tests/coretests/src/android/pim/EventRecurrenceTest.java b/core/tests/coretests/src/android/pim/EventRecurrenceTest.java
new file mode 100644
index 0000000..05000f1
--- /dev/null
+++ b/core/tests/coretests/src/android/pim/EventRecurrenceTest.java
@@ -0,0 +1,753 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.pim;
+
+import android.pim.EventRecurrence.InvalidFormatException;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * Test android.pim.EventRecurrence.
+ *
+ * adb shell am instrument -w -e class android.pim.EventRecurrenceTest \
+ *   com.android.frameworks.coretests/android.test.InstrumentationTestRunner
+ */
+public class EventRecurrenceTest extends TestCase {
+
+    @SmallTest
+    public void test0() throws Exception {
+        verifyRecurType("FREQ=SECONDLY",
+                /* int freq */         EventRecurrence.SECONDLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test1() throws Exception {
+        verifyRecurType("FREQ=MINUTELY",
+                /* int freq */         EventRecurrence.MINUTELY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test2() throws Exception {
+        verifyRecurType("FREQ=HOURLY",
+                /* int freq */         EventRecurrence.HOURLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test3() throws Exception {
+        verifyRecurType("FREQ=DAILY",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test4() throws Exception {
+        verifyRecurType("FREQ=WEEKLY",
+                /* int freq */         EventRecurrence.WEEKLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test5() throws Exception {
+        verifyRecurType("FREQ=MONTHLY",
+                /* int freq */         EventRecurrence.MONTHLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test6() throws Exception {
+        verifyRecurType("FREQ=YEARLY",
+                /* int freq */         EventRecurrence.YEARLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test7() throws Exception {
+        // with an until
+        verifyRecurType("FREQ=DAILY;UNTIL=112233T223344Z",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     "112233T223344Z",
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test8() throws Exception {
+        // with a count
+        verifyRecurType("FREQ=DAILY;COUNT=334",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        334,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test9() throws Exception {
+        // with a count
+        verifyRecurType("FREQ=DAILY;INTERVAL=5000",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     5000,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @SmallTest
+    public void test10() throws Exception {
+        // verifyRecurType all of the BY* ones with one element
+        verifyRecurType("FREQ=DAILY"
+                + ";BYSECOND=0"
+                + ";BYMINUTE=1"
+                + ";BYHOUR=2"
+                + ";BYMONTHDAY=30"
+                + ";BYYEARDAY=300"
+                + ";BYWEEKNO=53"
+                + ";BYMONTH=12"
+                + ";BYSETPOS=-15"
+                + ";WKST=SU",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   new int[]{0},
+                /* int[] byminute */   new int[]{1},
+                /* int[] byhour */     new int[]{2},
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ new int[]{30},
+                /* int[] byyearday */  new int[]{300},
+                /* int[] byweekno */   new int[]{53},
+                /* int[] bymonth */    new int[]{12},
+                /* int[] bysetpos */   new int[]{-15},
+                /* int wkst */         EventRecurrence.SU
+        );
+    }
+
+    @SmallTest
+    public void test11() throws Exception {
+        // verifyRecurType all of the BY* ones with one element
+        verifyRecurType("FREQ=DAILY"
+                + ";BYSECOND=0,30,59"
+                + ";BYMINUTE=0,41,59"
+                + ";BYHOUR=0,4,23"
+                + ";BYMONTHDAY=-31,-1,1,31"
+                + ";BYYEARDAY=-366,-1,1,366"
+                + ";BYWEEKNO=-53,-1,1,53"
+                + ";BYMONTH=1,12"
+                + ";BYSETPOS=1,2,3,4,500,10000"
+                + ";WKST=SU",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   new int[]{0, 30, 59},
+                /* int[] byminute */   new int[]{0, 41, 59},
+                /* int[] byhour */     new int[]{0, 4, 23},
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ new int[]{-31, -1, 1, 31},
+                /* int[] byyearday */  new int[]{-366, -1, 1, 366},
+                /* int[] byweekno */   new int[]{-53, -1, 1, 53},
+                /* int[] bymonth */    new int[]{1, 12},
+                /* int[] bysetpos */   new int[]{1, 2, 3, 4, 500, 10000},
+                /* int wkst */         EventRecurrence.SU
+        );
+    }
+
+    private static class Check {
+        Check(String k, int... v) {
+            key = k;
+            values = v;
+        }
+
+        String key;
+        int[] values;
+    }
+
+    // this is a negative verifyRecurType case to verifyRecurType the range of the numbers accepted
+    @SmallTest
+    public void test12() throws Exception {
+        Check[] checks = new Check[]{
+                new Check("BYSECOND", -100, -1, 60, 100),
+                new Check("BYMINUTE", -100, -1, 60, 100),
+                new Check("BYHOUR", -100, -1, 24, 100),
+                new Check("BYMONTHDAY", -100, -32, 0, 32, 100),
+                new Check("BYYEARDAY", -400, -367, 0, 367, 400),
+                new Check("BYWEEKNO", -100, -54, 0, 54, 100),
+                new Check("BYMONTH", -100, -5, 0, 13, 100)
+        };
+
+        for (Check ck : checks) {
+            for (int n : ck.values) {
+                String recur = "FREQ=DAILY;" + ck.key + "=" + n;
+                try {
+                    EventRecurrence er = new EventRecurrence();
+                    er.parse(recur);
+                    fail("Negative verifyRecurType failed. "
+                            + " parse failed to throw an exception for '"
+                            + recur + "'");
+                } catch (EventRecurrence.InvalidFormatException e) {
+                    // expected
+                }
+            }
+        }
+    }
+
+    // verifyRecurType BYDAY
+    @SmallTest
+    public void test13() throws Exception {
+        verifyRecurType("FREQ=DAILY;BYDAY=1SU,-2MO,+33TU,WE,TH,FR,SA",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      new int[] {
+                        EventRecurrence.SU,
+                        EventRecurrence.MO,
+                        EventRecurrence.TU,
+                        EventRecurrence.WE,
+                        EventRecurrence.TH,
+                        EventRecurrence.FR,
+                        EventRecurrence.SA
+                },
+                /* int[] bydayNum */   new int[]{1, -2, 33, 0, 0, 0, 0},
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    @Suppress
+    // Repro bug #2331761 - this should fail because of the last comma into BYDAY
+    public void test14() throws Exception {
+        verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;BYDAY=MO,TU,WE,",
+                /* int freq */         EventRecurrence.WEEKLY,
+                /* String until */     "20100129T130000Z",
+                /* int count */        0,
+                /* int interval */     1,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      new int[] {
+                        EventRecurrence.MO,
+                        EventRecurrence.TU,
+                        EventRecurrence.WE,
+                },
+                /* int[] bydayNum */   new int[]{0, 0, 0},
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    // This test should pass
+    public void test15() throws Exception {
+        verifyRecurType("FREQ=WEEKLY;WKST=MO;UNTIL=20100129T130000Z;INTERVAL=1;"
+                + "BYDAY=MO,TU,WE,TH,FR,SA,SU",
+                /* int freq */         EventRecurrence.WEEKLY,
+                /* String until */     "20100129T130000Z",
+                /* int count */        0,
+                /* int interval */     1,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      new int[] {
+                        EventRecurrence.MO,
+                        EventRecurrence.TU,
+                        EventRecurrence.WE,
+                        EventRecurrence.TH,
+                        EventRecurrence.FR,
+                        EventRecurrence.SA,
+                        EventRecurrence.SU
+                },
+                /* int[] bydayNum */   new int[]{0, 0, 0, 0, 0, 0, 0},
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    // Sample coming from RFC2445
+    public void test16() throws Exception {
+        verifyRecurType("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1",
+                /* int freq */         EventRecurrence.MONTHLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      new int[] {
+                        EventRecurrence.MO,
+                        EventRecurrence.TU,
+                        EventRecurrence.WE,
+                        EventRecurrence.TH,
+                        EventRecurrence.FR
+                },
+                /* int[] bydayNum */   new int[] {0, 0, 0, 0, 0},
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   new int[] { -1 },
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    // Sample coming from RFC2445
+    public void test17() throws Exception {
+        verifyRecurType("FREQ=DAILY;COUNT=10;INTERVAL=2",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        10,
+                /* int interval */     2,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    // Sample coming from RFC2445
+    public void test18() throws Exception {
+        verifyRecurType("FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10",
+                /* int freq */         EventRecurrence.YEARLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      new int[] {
+                        EventRecurrence.SU
+                },
+                /* int[] bydayNum */   new int[] { -1 },
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    new int[] { 10 },
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    // Sample coming from bug #1640517
+    public void test19() throws Exception {
+        verifyRecurType("FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
+                /* int freq */         EventRecurrence.YEARLY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      new int[] {
+                        EventRecurrence.TH
+                },
+                /* int[] bydayNum */   new int[] { 0 },
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    new int[] { 3 },
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    // for your copying pleasure
+    public void fakeTestXX() throws Exception {
+        verifyRecurType("FREQ=DAILY;",
+                /* int freq */         EventRecurrence.DAILY,
+                /* String until */     null,
+                /* int count */        0,
+                /* int interval */     0,
+                /* int[] bysecond */   null,
+                /* int[] byminute */   null,
+                /* int[] byhour */     null,
+                /* int[] byday */      null,
+                /* int[] bydayNum */   null,
+                /* int[] bymonthday */ null,
+                /* int[] byyearday */  null,
+                /* int[] byweekno */   null,
+                /* int[] bymonth */    null,
+                /* int[] bysetpos */   null,
+                /* int wkst */         EventRecurrence.MO
+        );
+    }
+
+    private static void cmp(int vlen, int[] v, int[] correct, String name) {
+        if ((correct == null && v != null)
+                || (correct != null && v == null)) {
+            throw new RuntimeException("One is null, one isn't for " + name
+                    + ": correct=" + Arrays.toString(correct)
+                    + " actual=" + Arrays.toString(v));
+        }
+        if ((correct == null && vlen != 0)
+                || (vlen != (correct == null ? 0 : correct.length))) {
+            throw new RuntimeException("Reported length mismatch for " + name
+                    + ": correct=" + ((correct == null) ? "null" : correct.length)
+                    + " actual=" + vlen);
+        }
+        if (correct == null) {
+            return;
+        }
+        if (v.length < correct.length) {
+            throw new RuntimeException("Array length mismatch for " + name
+                    + ": correct=" + Arrays.toString(correct)
+                    + " actual=" + Arrays.toString(v));
+        }
+        for (int i = 0; i < correct.length; i++) {
+            if (v[i] != correct[i]) {
+                throw new RuntimeException("Array value mismatch for " + name
+                        + ": correct=" + Arrays.toString(correct)
+                        + " actual=" + Arrays.toString(v));
+            }
+        }
+    }
+
+    private static boolean eq(String a, String b) {
+        if ((a == null && b != null) || (a != null && b == null)) {
+            return false;
+        } else {
+            return a == b || a.equals(b);
+        }
+    }
+
+    private static void verifyRecurType(String recur,
+            int freq, String until, int count, int interval,
+            int[] bysecond, int[] byminute, int[] byhour,
+            int[] byday, int[] bydayNum, int[] bymonthday,
+            int[] byyearday, int[] byweekno, int[] bymonth,
+            int[] bysetpos, int wkst) {
+        EventRecurrence eventRecurrence = new EventRecurrence();
+        eventRecurrence.parse(recur);
+        if (eventRecurrence.freq != freq
+                || !eq(eventRecurrence.until, until)
+                || eventRecurrence.count != count
+                || eventRecurrence.interval != interval
+                || eventRecurrence.wkst != wkst) {
+            System.out.println("Error... got:");
+            print(eventRecurrence);
+            System.out.println("expected:");
+            System.out.println("{");
+            System.out.println("    freq=" + freq);
+            System.out.println("    until=" + until);
+            System.out.println("    count=" + count);
+            System.out.println("    interval=" + interval);
+            System.out.println("    wkst=" + wkst);
+            System.out.println("    bysecond=" + Arrays.toString(bysecond));
+            System.out.println("    byminute=" + Arrays.toString(byminute));
+            System.out.println("    byhour=" + Arrays.toString(byhour));
+            System.out.println("    byday=" + Arrays.toString(byday));
+            System.out.println("    bydayNum=" + Arrays.toString(bydayNum));
+            System.out.println("    bymonthday=" + Arrays.toString(bymonthday));
+            System.out.println("    byyearday=" + Arrays.toString(byyearday));
+            System.out.println("    byweekno=" + Arrays.toString(byweekno));
+            System.out.println("    bymonth=" + Arrays.toString(bymonth));
+            System.out.println("    bysetpos=" + Arrays.toString(bysetpos));
+            System.out.println("}");
+            throw new RuntimeException("Mismatch in fields");
+        }
+        cmp(eventRecurrence.bysecondCount, eventRecurrence.bysecond, bysecond, "bysecond");
+        cmp(eventRecurrence.byminuteCount, eventRecurrence.byminute, byminute, "byminute");
+        cmp(eventRecurrence.byhourCount, eventRecurrence.byhour, byhour, "byhour");
+        cmp(eventRecurrence.bydayCount, eventRecurrence.byday, byday, "byday");
+        cmp(eventRecurrence.bydayCount, eventRecurrence.bydayNum, bydayNum, "bydayNum");
+        cmp(eventRecurrence.bymonthdayCount, eventRecurrence.bymonthday, bymonthday, "bymonthday");
+        cmp(eventRecurrence.byyeardayCount, eventRecurrence.byyearday, byyearday, "byyearday");
+        cmp(eventRecurrence.byweeknoCount, eventRecurrence.byweekno, byweekno, "byweekno");
+        cmp(eventRecurrence.bymonthCount, eventRecurrence.bymonth, bymonth, "bymonth");
+        cmp(eventRecurrence.bysetposCount, eventRecurrence.bysetpos, bysetpos, "bysetpos");
+    }
+
+    private static void print(EventRecurrence er) {
+        System.out.println("{");
+        System.out.println("    freq=" + er.freq);
+        System.out.println("    until=" + er.until);
+        System.out.println("    count=" + er.count);
+        System.out.println("    interval=" + er.interval);
+        System.out.println("    wkst=" + er.wkst);
+        System.out.println("    bysecond=" + Arrays.toString(er.bysecond));
+        System.out.println("    bysecondCount=" + er.bysecondCount);
+        System.out.println("    byminute=" + Arrays.toString(er.byminute));
+        System.out.println("    byminuteCount=" + er.byminuteCount);
+        System.out.println("    byhour=" + Arrays.toString(er.byhour));
+        System.out.println("    byhourCount=" + er.byhourCount);
+        System.out.println("    byday=" + Arrays.toString(er.byday));
+        System.out.println("    bydayNum=" + Arrays.toString(er.bydayNum));
+        System.out.println("    bydayCount=" + er.bydayCount);
+        System.out.println("    bymonthday=" + Arrays.toString(er.bymonthday));
+        System.out.println("    bymonthdayCount=" + er.bymonthdayCount);
+        System.out.println("    byyearday=" + Arrays.toString(er.byyearday));
+        System.out.println("    byyeardayCount=" + er.byyeardayCount);
+        System.out.println("    byweekno=" + Arrays.toString(er.byweekno));
+        System.out.println("    byweeknoCount=" + er.byweeknoCount);
+        System.out.println("    bymonth=" + Arrays.toString(er.bymonth));
+        System.out.println("    bymonthCount=" + er.bymonthCount);
+        System.out.println("    bysetpos=" + Arrays.toString(er.bysetpos));
+        System.out.println("    bysetposCount=" + er.bysetposCount);
+        System.out.println("}");
+    }
+
+
+    /** A list of valid rules.  The parser must accept these. */
+    private static final String[] GOOD_RRULES = {
+        /* extracted wholesale from from RFC 2445 section 4.8.5.4 */
+        "FREQ=DAILY;COUNT=10",
+        "FREQ=DAILY;UNTIL=19971224T000000Z",
+        "FREQ=DAILY;INTERVAL=2",
+        "FREQ=DAILY;INTERVAL=10;COUNT=5",
+        "FREQ=YEARLY;UNTIL=20000131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA",
+        "FREQ=DAILY;UNTIL=20000131T090000Z;BYMONTH=1",
+        "FREQ=WEEKLY;COUNT=10",
+        "FREQ=WEEKLY;UNTIL=19971224T000000Z",
+        "FREQ=WEEKLY;INTERVAL=2;WKST=SU",
+        "FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH",
+        "FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH",
+        "FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR",
+        "FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH",
+        "FREQ=MONTHLY;COUNT=10;BYDAY=1FR",
+        "FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR",
+        "FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU",
+        "FREQ=MONTHLY;COUNT=6;BYDAY=-2MO",
+        "FREQ=MONTHLY;BYMONTHDAY=-3",
+        "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15",
+        "FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1",
+        "FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15",
+        "FREQ=MONTHLY;INTERVAL=2;BYDAY=TU",
+        "FREQ=YEARLY;COUNT=10;BYMONTH=6,7",
+        "FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3",
+        "FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200",
+        "FREQ=YEARLY;BYDAY=20MO",
+        "FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO",
+        "FREQ=YEARLY;BYMONTH=3;BYDAY=TH",
+        "FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8",
+        "FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13",
+        "FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13",
+        "FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8",
+        "FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3",
+        "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2",
+        "FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z",
+        "FREQ=MINUTELY;INTERVAL=15;COUNT=6",
+        "FREQ=MINUTELY;INTERVAL=90;COUNT=4",
+        "FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40",
+        "FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16",
+        "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO",
+        "FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU",
+        /* a few more */
+        "FREQ=SECONDLY;BYSECOND=0,15,59",
+        "FREQ=MINUTELY;BYMINUTE=0,15,59",
+        "FREQ=HOURLY;BYHOUR=+0,+15,+23",
+        "FREQ=DAILY;X-WHATEVER=blah",                       // fails on old parser
+        //"freq=daily;wkst=su",                               // fails on old parser
+    };
+
+    /** The parser must reject these. */
+    private static final String[] BAD_RRULES = {
+        "INTERVAL=4;FREQ=YEARLY",                           // FREQ must come first
+        "FREQ=MONTHLY;FREQ=MONTHLY",                        // can't specify twice
+        "FREQ=MONTHLY;COUNT=1;COUNT=1",                     // can't specify twice
+        "FREQ=SECONDLY;BYSECOND=60",                        // range
+        "FREQ=MINUTELY;BYMINUTE=-1",                        // range
+        "FREQ=HOURLY;BYHOUR=24",                            // range
+        "FREQ=YEARLY;BYMONTHDAY=0",                         // zero not valid
+        //"FREQ=YEARLY;COUNT=1;UNTIL=12345",                  // can't have both COUNT and UNTIL
+        //"FREQ=DAILY;UNTIL=19970829T021400e",                // invalid date
+    };
+
+    /**
+     * Simple test of good/bad rules.
+     */
+    @SmallTest
+    public void testBasicParse() {
+        for (String rule : GOOD_RRULES) {
+            EventRecurrence recur = new EventRecurrence();
+            recur.parse(rule);
+        }
+
+        for (String rule : BAD_RRULES) {
+            EventRecurrence recur = new EventRecurrence();
+            boolean didThrow = false;
+
+            try {
+                recur.parse(rule);
+            } catch (InvalidFormatException ife) {
+                didThrow = true;
+            }
+
+            assertTrue("Expected throw on " + rule, didThrow);
+        }
+    }
+}
diff --git a/docs/html/guide/topics/usb/adk.jd b/docs/html/guide/topics/usb/adk.jd
index e4e1215..0e35637 100644
--- a/docs/html/guide/topics/usb/adk.jd
+++ b/docs/html/guide/topics/usb/adk.jd
@@ -55,7 +55,6 @@
       </ol>
 
 
-
       <h2>See also</h2>
 
       <ol>
@@ -66,6 +65,12 @@
       <h2>Where to buy</h2>
 
       <ol>
+      <li><a href="http://shop.moderndevice.com/products/freeduino-usb-host-board">
+        Modern Device</a></li>
+
+      <li><a href="http://www.seeedstudio.com/depot/seeeduino-adk-main-board-p-846.html">
+        Seeed Studio</a></li>
+
         <li><a href=
         "http://www.rt-net.jp/shop/index.php?main_page=product_info&cPath=3_4&products_id=1">
         RT Corp</a></li>
@@ -77,8 +82,6 @@
         <li><a href="https://store.diydrones.com/ProductDetails.asp?ProductCode=BR-PhoneDrone">
         DIY Drones</a></li>
 
-    <li><a href="http://shop.moderndevice.com/products/freeduino-usb-host-board">
-        Modern Device</a></li>
       </ol>
     </div>
   </div>
@@ -106,15 +109,22 @@
   development boards:</p>
 
   <ul>
+    <li><a href="http://shop.moderndevice.com/products/freeduino-usb-host-board">Modern
+    Device</a> provides an Arduino-compatible board that supports the ADK firmware.</li>
+
+    <li><a href="http://www.seeedstudio.com/depot/seeeduino-adk-main-board-p-846.html">
+    Seeed Studio</a> provides an Arduino-compatible board that supports the ADK firmware.</li>
+
     <li><a href="http://www.rt-net.jp/shop/index.php?main_page=product_info&cPath=3_4&products_id=1">
     RT Corp</a> provides an Arduino-compatible board based on the Android ADK board design.</li>
+
     <li><a href="http://www.microchip.com/android">Microchip</a> provides a A PIC based USB
     microcontroller board.</li>
+
     <li><a href="https://store.diydrones.com/ProductDetails.asp?ProductCode=BR-PhoneDrone">DIY
     Drones</a> provides an Arduino-compatible board geared towards RC (radio controlled) and UAV
     (unmanned aerial vehicle) enthusiasts.</li>
-    <li><a href="http://shop.moderndevice.com/products/freeduino-usb-host-board">Modern
-        Device</a> provides an Arduino-compatible board that supports the ADK firmware.</li>
+
   </ul>
 
   <p>We expect more hardware distributers to create a variety of kits, so please stay tuned for
@@ -125,7 +135,7 @@
   accessory that is based on the <a href="http://www.arduino.cc/">Arduino open source electronics
   prototyping platform</a>, the accessory's hardware design files, code that implements the
   accessory's firmware, and the Android application that interacts with the accessory. The hardware
-  design files and firmware code are contained in the <a href=
+  design files and firmware code are contained in the <a href=ctive 
   "https://dl-ssl.google.com/android/adk/adk_release_0512.zip">ADK package download</a>.</p>
   <p>The main hardware and software components of the ADK include:</p>
 
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 5750c81..d02c13d 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -175,7 +175,8 @@
       <span style="display:none" class="zh-TW"></span>
     </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r5c</a>
+      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r5c <span
+       class="new">new!</span></a>
         </li>
       <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
     </ul>
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index fac7144..2739a4b8 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -165,6 +165,22 @@
         addF32(v.w);
     }
 
+    public void addF64(Double2 v) {
+        addF64(v.x);
+        addF64(v.y);
+    }
+    public void addF64(Double3 v) {
+        addF64(v.x);
+        addF64(v.y);
+        addF64(v.z);
+    }
+    public void addF64(Double4 v) {
+        addF64(v.x);
+        addF64(v.y);
+        addF64(v.z);
+        addF64(v.w);
+    }
+
     public void addI8(Byte2 v) {
         addI8(v.x);
         addI8(v.y);
@@ -261,6 +277,38 @@
         addU32(v.w);
     }
 
+    public void addI64(Long2 v) {
+        addI64(v.x);
+        addI64(v.y);
+    }
+    public void addI64(Long3 v) {
+        addI64(v.x);
+        addI64(v.y);
+        addI64(v.z);
+    }
+    public void addI64(Long4 v) {
+        addI64(v.x);
+        addI64(v.y);
+        addI64(v.z);
+        addI64(v.w);
+    }
+
+    public void addU64(Long2 v) {
+        addU64(v.x);
+        addU64(v.y);
+    }
+    public void addU64(Long3 v) {
+        addU64(v.x);
+        addU64(v.y);
+        addU64(v.z);
+    }
+    public void addU64(Long4 v) {
+        addU64(v.x);
+        addU64(v.y);
+        addU64(v.z);
+        addU64(v.w);
+    }
+
     public void addMatrix(Matrix4f v) {
         for (int i=0; i < v.mMat.length; i++) {
             addF32(v.mMat[i]);
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index f6cefa6..f219639 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -173,11 +173,11 @@
     }
 
     virtual EGLint getSurfaceWidth() {
-        return 64;
+        return 512;
     }
 
     virtual EGLint getSurfaceHeight() {
-        return 64;
+        return 512;
     }
 
     void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
@@ -526,18 +526,19 @@
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    glViewport(0, 0, texWidth, texHeight);
     drawTexture();
 
     EXPECT_TRUE(checkPixel( 0,  0, 255, 127, 255, 255));
     EXPECT_TRUE(checkPixel(63,  0,   0, 133,   0, 255));
-    EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
-    EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(63, 65,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
 
-    EXPECT_TRUE(checkPixel(22, 44, 247,  70, 255, 255));
-    EXPECT_TRUE(checkPixel(45, 52, 209,  32, 235, 255));
-    EXPECT_TRUE(checkPixel(52, 51, 100, 255,  73, 255));
+    EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(52, 51,  98, 255,  73, 255));
     EXPECT_TRUE(checkPixel( 7, 31, 155,   0, 118, 255));
-    EXPECT_TRUE(checkPixel(31,  9, 148,  71, 110, 255));
+    EXPECT_TRUE(checkPixel(31,  9, 107,  24,  87, 255));
     EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
     EXPECT_TRUE(checkPixel(36, 22, 155,  29,   0, 255));
 }
@@ -570,6 +571,7 @@
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    glViewport(0, 0, texWidth, texHeight);
     drawTexture();
 
     EXPECT_TRUE(checkPixel( 0,  0,   0, 133,   0, 255));
@@ -628,6 +630,7 @@
         glClearColor(0.2, 0.2, 0.2, 0.2);
         glClear(GL_COLOR_BUFFER_BIT);
 
+        glViewport(0, 0, 64, 64);
         drawTexture();
 
         EXPECT_TRUE(checkPixel( 0,  0,  82, 255,  35, 255));
@@ -675,28 +678,29 @@
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    glViewport(0, 0, texWidth, texHeight);
     drawTexture();
 
     EXPECT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
     EXPECT_TRUE(checkPixel(63,  0, 231, 231, 231, 231));
-    EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231));
-    EXPECT_TRUE(checkPixel( 0, 63,  35,  35,  35,  35));
+    EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231));
+    EXPECT_TRUE(checkPixel( 0, 65,  35,  35,  35,  35));
 
     EXPECT_TRUE(checkPixel(15, 10,  35, 231, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 63,  35, 231, 231,  35));
-    EXPECT_TRUE(checkPixel(19, 40,  87, 179,  35,  35));
+    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(19, 40,  35, 231,  35,  35));
     EXPECT_TRUE(checkPixel(38, 30, 231,  35,  35,  35));
     EXPECT_TRUE(checkPixel(42, 54,  35,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(37, 33,  35, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(37, 33, 228,  38,  38,  38));
     EXPECT_TRUE(checkPixel(31,  8, 231,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(36, 47, 231,  35, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 63,  35, 231, 231,  35));
-    EXPECT_TRUE(checkPixel(48,  3, 231, 231,  35,  35));
+    EXPECT_TRUE(checkPixel(36, 47, 228,  35, 231, 231));
+    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(48,  3, 228, 228,  38,  35));
     EXPECT_TRUE(checkPixel(54, 50,  35, 231, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 25, 191, 191, 231, 231));
-    EXPECT_TRUE(checkPixel(10,  9,  93,  93, 231, 231));
+    EXPECT_TRUE(checkPixel(24, 25,  41,  41, 231, 231));
+    EXPECT_TRUE(checkPixel(10,  9,  38,  38, 231, 231));
     EXPECT_TRUE(checkPixel(29,  4,  35,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(56, 31,  35, 231, 231,  35));
+    EXPECT_TRUE(checkPixel(56, 31,  38, 228, 231,  35));
     EXPECT_TRUE(checkPixel(58, 55,  35,  35, 231, 231));
 }
 
@@ -730,6 +734,7 @@
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    glViewport(0, 0, texWidth, texHeight);
     drawTexture();
 
     EXPECT_TRUE(checkPixel( 0,  0, 231, 231, 231, 231));
@@ -803,6 +808,7 @@
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    glViewport(0, 0, texWidth, texHeight);
     drawTexture();
 
     EXPECT_TRUE(checkPixel( 0,  0, 153, 153, 153, 153));
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 58f6699..ea9911c 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -47,10 +47,6 @@
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
 static const int64_t kInitialDelayTimeUs     = 700000LL;
 
-// Using longer adjustment period to suppress fluctuations in
-// the audio encoding paths
-static const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL;  // 10 minutes
-
 class MPEG4Writer::Track {
 public:
     Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
@@ -88,8 +84,6 @@
     int64_t mTrackDurationUs;
     int64_t mMaxChunkDurationUs;
 
-    // For realtime applications, we need to adjust the media clock
-    // for video track based on the audio media clock
     bool mIsRealTimeRecording;
     int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
@@ -175,28 +169,9 @@
     int64_t mPreviousTrackTimeUs;
     int64_t mTrackEveryTimeDurationUs;
 
-    // Has the media time adjustment for video started?
-    bool    mIsMediaTimeAdjustmentOn;
-    // The time stamp when previous media time adjustment period starts
-    int64_t mPrevMediaTimeAdjustTimestampUs;
-    // Number of vidoe frames whose time stamp may be adjusted
-    int64_t mMediaTimeAdjustNumFrames;
-    // The sample number when previous meida time adjustmnet period starts
-    int64_t mPrevMediaTimeAdjustSample;
-    // The total accumulated drift time within a period of
-    // kVideoMediaTimeAdjustPeriodTimeUs.
-    int64_t mTotalDriftTimeToAdjustUs;
-    // The total accumalated drift time since the start of the recording
-    // excluding the current time adjustment period
-    int64_t mPrevTotalAccumDriftTimeUs;
-
     // Update the audio track's drift information.
     void updateDriftTime(const sp<MetaData>& meta);
 
-    // Adjust the time stamp of the video track according to
-    // the drift time information from the audio track.
-    void adjustMediaTime(int64_t *timestampUs);
-
     static void *ThreadWrapper(void *me);
     status_t threadEntry();
 
@@ -1512,12 +1487,7 @@
     mNumSttsTableEntries = 0;
     mNumCttsTableEntries = 0;
     mMdatSizeBytes = 0;
-    mIsMediaTimeAdjustmentOn = false;
-    mPrevMediaTimeAdjustTimestampUs = 0;
-    mMediaTimeAdjustNumFrames = 0;
-    mPrevMediaTimeAdjustSample = 0;
-    mTotalDriftTimeToAdjustUs = 0;
-    mPrevTotalAccumDriftTimeUs = 0;
+
     mMaxChunkDurationUs = 0;
     mHasNegativeCttsDeltaDuration = false;
 
@@ -1816,128 +1786,6 @@
 }
 
 /*
-* The video track's media time adjustment for real-time applications
-* is described as follows:
-*
-* First, the media time adjustment is done for every period of
-* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs
-* is currently a fixed value chosen heuristically. The value of
-* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small
-* for two considerations: on one hand, a relatively large value
-* helps reduce large fluctuation of drift time in the audio encoding
-* path; while on the other hand, a relatively small value helps keep
-* restoring synchronization in audio/video more frequently. Note for the
-* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is
-* no media time adjustment for the video track.
-*
-* Second, the total accumulated audio track time drift found
-* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed
-* over a stream of incoming video frames. The number of video frames
-* affected is determined based on the number of recorded video frames
-* within the past kVideoMediaTimeAdjustPeriodTimeUs period.
-* We choose to distribute the drift time over only a portion
-* (rather than all) of the total number of recorded video frames
-* in order to make sure that the video track media time adjustment is
-* completed for the current period before the next video track media
-* time adjustment period starts. Currently, the portion chosen is a
-* half (0.5).
-*
-* Last, various additional checks are performed to ensure that
-* the actual audio encoding path does not have too much drift.
-* In particular, 1) we want to limit the average incremental time
-* adjustment for each video frame to be less than a threshold
-* for a single period of kVideoMediaTimeAdjustPeriodTimeUs.
-* Currently, the threshold is set to 5 ms. If the average incremental
-* media time adjustment for a video frame is larger than the
-* threshold, the audio encoding path has too much time drift.
-* 2) We also want to limit the total time drift in the audio
-* encoding path to be less than a threshold for a period of
-* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold
-* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of
-* the audio encoding path is larger than the threshold, the audio
-* encoding path has too much time drift. We treat the large time
-* drift of the audio encoding path as errors, since there is no
-* way to keep audio/video in synchronization for real-time
-* applications if the time drift is too large unless we drop some
-* video frames, which has its own problems that we don't want
-* to get into for the time being.
-*/
-void MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) {
-    if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >=
-        kVideoMediaTimeAdjustPeriodTimeUs) {
-
-        LOGV("New media time adjustment period at %lld us", *timestampUs);
-        mIsMediaTimeAdjustmentOn = true;
-        mMediaTimeAdjustNumFrames =
-                (mNumSamples - mPrevMediaTimeAdjustSample) >> 1;
-
-        mPrevMediaTimeAdjustTimestampUs = *timestampUs;
-        mPrevMediaTimeAdjustSample = mNumSamples;
-        int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs();
-        mTotalDriftTimeToAdjustUs =
-                totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs;
-
-        mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs;
-
-        // Check on incremental adjusted time per frame
-        int64_t adjustTimePerFrameUs =
-                mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames;
-
-        if (adjustTimePerFrameUs < 0) {
-            adjustTimePerFrameUs = -adjustTimePerFrameUs;
-        }
-        if (adjustTimePerFrameUs >= 5000) {
-            LOGE("Adjusted time per video frame is %lld us",
-                adjustTimePerFrameUs);
-            CHECK(!"Video frame time adjustment is too large!");
-        }
-
-        // Check on total accumulated time drift within a period of
-        // kVideoMediaTimeAdjustPeriodTimeUs.
-        int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000)
-                / kVideoMediaTimeAdjustPeriodTimeUs;
-
-        if (driftPercentage < 0) {
-            driftPercentage = -driftPercentage;
-        }
-        if (driftPercentage > 5) {
-            LOGE("Audio track has time drift %lld us over %lld us",
-                mTotalDriftTimeToAdjustUs,
-                kVideoMediaTimeAdjustPeriodTimeUs);
-
-            CHECK(!"The audio track media time drifts too much!");
-        }
-
-    }
-
-    if (mIsMediaTimeAdjustmentOn) {
-        if (mNumSamples - mPrevMediaTimeAdjustSample <=
-            mMediaTimeAdjustNumFrames) {
-
-            // Do media time incremental adjustment
-            int64_t incrementalAdjustTimeUs =
-                        (mTotalDriftTimeToAdjustUs *
-                            (mNumSamples - mPrevMediaTimeAdjustSample))
-                                / mMediaTimeAdjustNumFrames;
-
-            *timestampUs +=
-                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs);
-
-            LOGV("Incremental video frame media time adjustment: %lld us",
-                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs));
-        } else {
-            // Within the remaining adjustment period,
-            // no incremental adjustment is needed.
-            *timestampUs +=
-                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs);
-
-            LOGV("Fixed video frame media time adjustment: %lld us",
-                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs));
-        }
-    }
-}
-
-/*
  * Updates the drift time from the audio track so that
  * the video track can get the updated drift time information
  * from the file writer. The fluctuation of the drift time of the audio
@@ -2080,32 +1928,6 @@
 
         int32_t isSync = false;
         meta_data->findInt32(kKeyIsSyncFrame, &isSync);
-
-        /*
-         * The original timestamp found in the data buffer will be modified as below:
-         *
-         * There is a playback offset into this track if the track's start time
-         * is not the same as the movie start time, which will be recorded in edst
-         * box of the output file. The playback offset is to make sure that the
-         * starting time of the audio/video tracks are synchronized. Although the
-         * track's media timestamp may be subject to various modifications
-         * as outlined below, the track's playback offset time remains unchanged
-         * once the first data buffer of the track is received.
-         *
-         * The media time stamp will be calculated by subtracting the playback offset
-         * (and potential pause durations) from the original timestamp in the buffer.
-         *
-         * If this track is a video track for a real-time recording application with
-         * both audio and video tracks, its media timestamp will subject to further
-         * modification based on the media clock of the audio track. This modification
-         * is needed for the purpose of maintaining good audio/video synchronization.
-         *
-         * If the recording session is paused and resumed multiple times, the track
-         * media timestamp will be modified as if the  recording session had never been
-         * paused at all during playback of the recorded output file. In other words,
-         * the output file will have no memory of pause/resume durations.
-         *
-         */
         CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -2146,31 +1968,13 @@
                 timestampUs, cttsDeltaTimeUs);
         }
 
-        // Media time adjustment for real-time applications
         if (mIsRealTimeRecording) {
             if (mIsAudio) {
                 updateDriftTime(meta_data);
-            } else {
-                adjustMediaTime(&timestampUs);
             }
         }
 
         CHECK(timestampUs >= 0);
-        if (mNumSamples > 1) {
-            if (timestampUs <= lastTimestampUs) {
-                LOGW("Frame arrives too late!");
-                // Don't drop the late frame, since dropping a frame may cause
-                // problems later during playback
-
-                // The idea here is to avoid having two or more samples with the
-                // same timestamp in the output file.
-                if (mTimeScale >= 1000000LL) {
-                    timestampUs = lastTimestampUs + 1;
-                } else {
-                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
-                }
-            }
-        }
 
         LOGV("%s media time stamp: %lld and previous paused duration %lld",
                 mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index 545e6d4..504d470 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -86,7 +86,11 @@
 
         mPluginByComponentName.add(name8, plugin);
     }
-    CHECK_EQ(err, OMX_ErrorNoMore);
+
+    if (err != OMX_ErrorNoMore) {
+        LOGE("OMX plugin failed w/ error 0x%08x after registering %d "
+             "components", err, mPluginByComponentName.size());
+    }
 }
 
 void OMXMaster::clearPlugins() {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 541bf22..e77998e 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2011 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.
@@ -65,6 +65,7 @@
         unitTests = new ArrayList<UnitTest>();
 
         unitTests.add(new UT_primitives(this, mRes, mCtx));
+        unitTests.add(new UT_vector(this, mRes, mCtx));
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
         unitTests.add(new UT_rstime(this, mRes, mCtx));
         unitTests.add(new UT_rstypes(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
new file mode 100644
index 0000000..748701d
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_vector extends UnitTest {
+    private Resources mRes;
+
+    protected UT_vector(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Vector", ctx);
+        mRes = res;
+    }
+
+    private boolean initializeGlobals(ScriptC_vector s) {
+        Float2 F2 = s.get_f2();
+        if (F2.x != 1.0f || F2.y != 2.0f) {
+            return false;
+        }
+        F2.x = 2.99f;
+        F2.y = 3.99f;
+        s.set_f2(F2);
+
+        Float3 F3 = s.get_f3();
+        if (F3.x != 1.0f || F3.y != 2.0f || F3.z != 3.0f) {
+            return false;
+        }
+        F3.x = 2.99f;
+        F3.y = 3.99f;
+        F3.z = 4.99f;
+        s.set_f3(F3);
+
+        Float4 F4 = s.get_f4();
+        if (F4.x != 1.0f || F4.y != 2.0f || F4.z != 3.0f || F4.w != 4.0f) {
+            return false;
+        }
+        F4.x = 2.99f;
+        F4.y = 3.99f;
+        F4.z = 4.99f;
+        F4.w = 5.99f;
+        s.set_f4(F4);
+
+        Double2 D2 = s.get_d2();
+        if (D2.x != 1.0 || D2.y != 2.0) {
+            return false;
+        }
+        D2.x = 2.99;
+        D2.y = 3.99;
+        s.set_d2(D2);
+
+        Double3 D3 = s.get_d3();
+        if (D3.x != 1.0 || D3.y != 2.0 || D3.z != 3.0) {
+            return false;
+        }
+        D3.x = 2.99;
+        D3.y = 3.99;
+        D3.z = 4.99;
+        s.set_d3(D3);
+
+        Double4 D4 = s.get_d4();
+        if (D4.x != 1.0 || D4.y != 2.0 || D4.z != 3.0 || D4.w != 4.0) {
+            return false;
+        }
+        D4.x = 2.99;
+        D4.y = 3.99;
+        D4.z = 4.99;
+        D4.w = 5.99;
+        s.set_d4(D4);
+
+        Byte2 B2 = s.get_i8_2();
+        if (B2.x != 1 || B2.y != 2) {
+            return false;
+        }
+        B2.x = 2;
+        B2.y = 3;
+        s.set_i8_2(B2);
+
+        Byte3 B3 = s.get_i8_3();
+        if (B3.x != 1 || B3.y != 2 || B3.z != 3) {
+            return false;
+        }
+        B3.x = 2;
+        B3.y = 3;
+        B3.z = 4;
+        s.set_i8_3(B3);
+
+        Byte4 B4 = s.get_i8_4();
+        if (B4.x != 1 || B4.y != 2 || B4.z != 3 || B4.w != 4) {
+            return false;
+        }
+        B4.x = 2;
+        B4.y = 3;
+        B4.z = 4;
+        B4.w = 5;
+        s.set_i8_4(B4);
+
+        Short2 S2 = s.get_u8_2();
+        if (S2.x != 1 || S2.y != 2) {
+            return false;
+        }
+        S2.x = 2;
+        S2.y = 3;
+        s.set_u8_2(S2);
+
+        Short3 S3 = s.get_u8_3();
+        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
+            return false;
+        }
+        S3.x = 2;
+        S3.y = 3;
+        S3.z = 4;
+        s.set_u8_3(S3);
+
+        Short4 S4 = s.get_u8_4();
+        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
+            return false;
+        }
+        S4.x = 2;
+        S4.y = 3;
+        S4.z = 4;
+        S4.w = 5;
+        s.set_u8_4(S4);
+
+        S2 = s.get_i16_2();
+        if (S2.x != 1 || S2.y != 2) {
+            return false;
+        }
+        S2.x = 2;
+        S2.y = 3;
+        s.set_i16_2(S2);
+
+        S3 = s.get_i16_3();
+        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
+            return false;
+        }
+        S3.x = 2;
+        S3.y = 3;
+        S3.z = 4;
+        s.set_i16_3(S3);
+
+        S4 = s.get_i16_4();
+        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
+            return false;
+        }
+        S4.x = 2;
+        S4.y = 3;
+        S4.z = 4;
+        S4.w = 5;
+        s.set_i16_4(S4);
+
+        Int2 I2 = s.get_u16_2();
+        if (I2.x != 1 || I2.y != 2) {
+            return false;
+        }
+        I2.x = 2;
+        I2.y = 3;
+        s.set_u16_2(I2);
+
+        Int3 I3 = s.get_u16_3();
+        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
+            return false;
+        }
+        I3.x = 2;
+        I3.y = 3;
+        I3.z = 4;
+        s.set_u16_3(I3);
+
+        Int4 I4 = s.get_u16_4();
+        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
+            return false;
+        }
+        I4.x = 2;
+        I4.y = 3;
+        I4.z = 4;
+        I4.w = 5;
+        s.set_u16_4(I4);
+
+        I2 = s.get_i32_2();
+        if (I2.x != 1 || I2.y != 2) {
+            return false;
+        }
+        I2.x = 2;
+        I2.y = 3;
+        s.set_i32_2(I2);
+
+        I3 = s.get_i32_3();
+        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
+            return false;
+        }
+        I3.x = 2;
+        I3.y = 3;
+        I3.z = 4;
+        s.set_i32_3(I3);
+
+        I4 = s.get_i32_4();
+        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
+            return false;
+        }
+        I4.x = 2;
+        I4.y = 3;
+        I4.z = 4;
+        I4.w = 5;
+        s.set_i32_4(I4);
+
+        Long2 L2 = s.get_u32_2();
+        if (L2.x != 1 || L2.y != 2) {
+            return false;
+        }
+        L2.x = 2;
+        L2.y = 3;
+        s.set_u32_2(L2);
+
+        Long3 L3 = s.get_u32_3();
+        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
+            return false;
+        }
+        L3.x = 2;
+        L3.y = 3;
+        L3.z = 4;
+        s.set_u32_3(L3);
+
+        Long4 L4 = s.get_u32_4();
+        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
+            return false;
+        }
+        L4.x = 2;
+        L4.y = 3;
+        L4.z = 4;
+        L4.w = 5;
+        s.set_u32_4(L4);
+
+        L2 = s.get_i64_2();
+        if (L2.x != 1 || L2.y != 2) {
+            return false;
+        }
+        L2.x = 2;
+        L2.y = 3;
+        s.set_i64_2(L2);
+
+        L3 = s.get_i64_3();
+        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
+            return false;
+        }
+        L3.x = 2;
+        L3.y = 3;
+        L3.z = 4;
+        s.set_i64_3(L3);
+
+        L4 = s.get_i64_4();
+        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
+            return false;
+        }
+        L4.x = 2;
+        L4.y = 3;
+        L4.z = 4;
+        L4.w = 5;
+        s.set_i64_4(L4);
+
+        L2 = s.get_u64_2();
+        if (L2.x != 1 || L2.y != 2) {
+            return false;
+        }
+        L2.x = 2;
+        L2.y = 3;
+        s.set_u64_2(L2);
+
+        L3 = s.get_u64_3();
+        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
+            return false;
+        }
+        L3.x = 2;
+        L3.y = 3;
+        L3.z = 4;
+        s.set_u64_3(L3);
+
+        L4 = s.get_u64_4();
+        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
+            return false;
+        }
+        L4.x = 2;
+        L4.y = 3;
+        L4.z = 4;
+        L4.w = 5;
+        s.set_u64_4(L4);
+
+        return true;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_vector s = new ScriptC_vector(pRS, mRes, R.raw.vector);
+        pRS.setMessageHandler(mRsMessage);
+        if (!initializeGlobals(s)) {
+            result = -1;
+        } else {
+            s.invoke_vector_test();
+            pRS.finish();
+            waitForMessage();
+        }
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/vector.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/vector.rs
new file mode 100644
index 0000000..0430a2f
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/vector.rs
@@ -0,0 +1,198 @@
+#include "shared.rsh"
+
+// Testing vector types
+float2 f2 = { 1.0f, 2.0f };
+float3 f3 = { 1.0f, 2.0f, 3.0f };
+float4 f4 = { 1.0f, 2.0f, 3.0f, 4.0f };
+
+double2 d2 = { 1.0, 2.0 };
+double3 d3 = { 1.0, 2.0, 3.0 };
+double4 d4 = { 1.0, 2.0, 3.0, 4.0 };
+
+char2 i8_2 = { 1, 2 };
+char3 i8_3 = { 1, 2, 3 };
+char4 i8_4 = { 1, 2, 3, 4 };
+
+uchar2 u8_2 = { 1, 2 };
+uchar3 u8_3 = { 1, 2, 3 };
+uchar4 u8_4 = { 1, 2, 3, 4 };
+
+short2 i16_2 = { 1, 2 };
+short3 i16_3 = { 1, 2, 3 };
+short4 i16_4 = { 1, 2, 3, 4 };
+
+ushort2 u16_2 = { 1, 2 };
+ushort3 u16_3 = { 1, 2, 3 };
+ushort4 u16_4 = { 1, 2, 3, 4 };
+
+int2 i32_2 = { 1, 2 };
+int3 i32_3 = { 1, 2, 3 };
+int4 i32_4 = { 1, 2, 3, 4 };
+
+uint2 u32_2 = { 1, 2 };
+uint3 u32_3 = { 1, 2, 3 };
+uint4 u32_4 = { 1, 2, 3, 4 };
+
+long2 i64_2 = { 1, 2 };
+long3 i64_3 = { 1, 2, 3 };
+long4 i64_4 = { 1, 2, 3, 4 };
+
+ulong2 u64_2 = { 1, 2 };
+ulong3 u64_3 = { 1, 2, 3 };
+ulong4 u64_4 = { 1, 2, 3, 4 };
+
+static bool test_vector_types() {
+    bool failed = false;
+
+    rsDebug("Testing F32", 0);
+    _RS_ASSERT(f2.x == 2.99f);
+    _RS_ASSERT(f2.y == 3.99f);
+
+    _RS_ASSERT(f3.x == 2.99f);
+    _RS_ASSERT(f3.y == 3.99f);
+    _RS_ASSERT(f3.z == 4.99f);
+
+    _RS_ASSERT(f4.x == 2.99f);
+    _RS_ASSERT(f4.y == 3.99f);
+    _RS_ASSERT(f4.z == 4.99f);
+    _RS_ASSERT(f4.w == 5.99f);
+
+    rsDebug("Testing F64", 0);
+    _RS_ASSERT(d2.x == 2.99);
+    _RS_ASSERT(d2.y == 3.99);
+
+    _RS_ASSERT(d3.x == 2.99);
+    _RS_ASSERT(d3.y == 3.99);
+    _RS_ASSERT(d3.z == 4.99);
+
+    _RS_ASSERT(d4.x == 2.99);
+    _RS_ASSERT(d4.y == 3.99);
+    _RS_ASSERT(d4.z == 4.99);
+    _RS_ASSERT(d4.w == 5.99);
+
+    rsDebug("Testing I8", 0);
+    _RS_ASSERT(i8_2.x == 2);
+    _RS_ASSERT(i8_2.y == 3);
+
+    _RS_ASSERT(i8_3.x == 2);
+    _RS_ASSERT(i8_3.y == 3);
+    _RS_ASSERT(i8_3.z == 4);
+
+    _RS_ASSERT(i8_4.x == 2);
+    _RS_ASSERT(i8_4.y == 3);
+    _RS_ASSERT(i8_4.z == 4);
+    _RS_ASSERT(i8_4.w == 5);
+
+    rsDebug("Testing U8", 0);
+    _RS_ASSERT(u8_2.x == 2);
+    _RS_ASSERT(u8_2.y == 3);
+
+    _RS_ASSERT(u8_3.x == 2);
+    _RS_ASSERT(u8_3.y == 3);
+    _RS_ASSERT(u8_3.z == 4);
+
+    _RS_ASSERT(u8_4.x == 2);
+    _RS_ASSERT(u8_4.y == 3);
+    _RS_ASSERT(u8_4.z == 4);
+    _RS_ASSERT(u8_4.w == 5);
+
+    rsDebug("Testing I16", 0);
+    _RS_ASSERT(i16_2.x == 2);
+    _RS_ASSERT(i16_2.y == 3);
+
+    _RS_ASSERT(i16_3.x == 2);
+    _RS_ASSERT(i16_3.y == 3);
+    _RS_ASSERT(i16_3.z == 4);
+
+    _RS_ASSERT(i16_4.x == 2);
+    _RS_ASSERT(i16_4.y == 3);
+    _RS_ASSERT(i16_4.z == 4);
+    _RS_ASSERT(i16_4.w == 5);
+
+    rsDebug("Testing U16", 0);
+    _RS_ASSERT(u16_2.x == 2);
+    _RS_ASSERT(u16_2.y == 3);
+
+    _RS_ASSERT(u16_3.x == 2);
+    _RS_ASSERT(u16_3.y == 3);
+    _RS_ASSERT(u16_3.z == 4);
+
+    _RS_ASSERT(u16_4.x == 2);
+    _RS_ASSERT(u16_4.y == 3);
+    _RS_ASSERT(u16_4.z == 4);
+    _RS_ASSERT(u16_4.w == 5);
+
+    rsDebug("Testing I32", 0);
+    _RS_ASSERT(i32_2.x == 2);
+    _RS_ASSERT(i32_2.y == 3);
+
+    _RS_ASSERT(i32_3.x == 2);
+    _RS_ASSERT(i32_3.y == 3);
+    _RS_ASSERT(i32_3.z == 4);
+
+    _RS_ASSERT(i32_4.x == 2);
+    _RS_ASSERT(i32_4.y == 3);
+    _RS_ASSERT(i32_4.z == 4);
+    _RS_ASSERT(i32_4.w == 5);
+
+    rsDebug("Testing U32", 0);
+    _RS_ASSERT(u32_2.x == 2);
+    _RS_ASSERT(u32_2.y == 3);
+
+    _RS_ASSERT(u32_3.x == 2);
+    _RS_ASSERT(u32_3.y == 3);
+    _RS_ASSERT(u32_3.z == 4);
+
+    _RS_ASSERT(u32_4.x == 2);
+    _RS_ASSERT(u32_4.y == 3);
+    _RS_ASSERT(u32_4.z == 4);
+    _RS_ASSERT(u32_4.w == 5);
+
+    rsDebug("Testing I64", 0);
+    _RS_ASSERT(i64_2.x == 2);
+    _RS_ASSERT(i64_2.y == 3);
+
+    _RS_ASSERT(i64_3.x == 2);
+    _RS_ASSERT(i64_3.y == 3);
+    _RS_ASSERT(i64_3.z == 4);
+
+    _RS_ASSERT(i64_4.x == 2);
+    _RS_ASSERT(i64_4.y == 3);
+    _RS_ASSERT(i64_4.z == 4);
+    _RS_ASSERT(i64_4.w == 5);
+
+    rsDebug("Testing U64", 0);
+    _RS_ASSERT(u64_2.x == 2);
+    _RS_ASSERT(u64_2.y == 3);
+
+    _RS_ASSERT(u64_3.x == 2);
+    _RS_ASSERT(u64_3.y == 3);
+    _RS_ASSERT(u64_3.z == 4);
+
+    _RS_ASSERT(u64_4.x == 2);
+    _RS_ASSERT(u64_4.y == 3);
+    _RS_ASSERT(u64_4.z == 4);
+    _RS_ASSERT(u64_4.w == 5);
+
+    if (failed) {
+        rsDebug("test_vector FAILED", 0);
+    }
+    else {
+        rsDebug("test_vector PASSED", 0);
+    }
+
+    return failed;
+}
+
+void vector_test() {
+    bool failed = false;
+    failed |= test_vector_types();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+