Merge "fix the build.  more string disambiguaiton."
diff --git a/api/current.xml b/api/current.xml
index 99c62a8..63215a0 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -245987,7 +245987,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index f55b746..f0758fd 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -59,6 +59,7 @@
 static bool gPreferSoftwareCodec;
 static bool gPlaybackAudio;
 static bool gWriteMP4;
+static bool gDisplayHistogram;
 static String8 gWriteMP4Filename;
 
 static int64_t getNowUs() {
@@ -68,6 +69,44 @@
     return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
 }
 
+static int CompareIncreasing(const int64_t *a, const int64_t *b) {
+    return (*a) < (*b) ? -1 : (*a) > (*b) ? 1 : 0;
+}
+
+static void displayDecodeHistogram(Vector<int64_t> *decodeTimesUs) {
+    printf("decode times:\n");
+
+    decodeTimesUs->sort(CompareIncreasing);
+
+    size_t n = decodeTimesUs->size();
+    int64_t minUs = decodeTimesUs->itemAt(0);
+    int64_t maxUs = decodeTimesUs->itemAt(n - 1);
+
+    printf("min decode time %lld us (%.2f secs)\n", minUs, minUs / 1E6);
+    printf("max decode time %lld us (%.2f secs)\n", maxUs, maxUs / 1E6);
+
+    size_t counts[100];
+    for (size_t i = 0; i < 100; ++i) {
+        counts[i] = 0;
+    }
+
+    for (size_t i = 0; i < n; ++i) {
+        int64_t x = decodeTimesUs->itemAt(i);
+
+        size_t slot = ((x - minUs) * 100) / (maxUs - minUs);
+        if (slot == 100) { slot = 99; }
+
+        ++counts[slot];
+    }
+
+    for (size_t i = 0; i < 100; ++i) {
+        int64_t slotUs = minUs + (i * (maxUs - minUs) / 100);
+
+        double fps = 1E6 / slotUs;
+        printf("[%.2f fps]: %d\n", fps, counts[i]);
+    }
+}
+
 static void playSource(OMXClient *client, sp<MediaSource> &source) {
     sp<MetaData> meta = source->getFormat();
 
@@ -201,6 +240,8 @@
     int64_t sumDecodeUs = 0;
     int64_t totalBytes = 0;
 
+    Vector<int64_t> decodeTimesUs;
+
     while (numIterationsLeft-- > 0) {
         long numFrames = 0;
 
@@ -224,9 +265,17 @@
                 break;
             }
 
-            if (buffer->range_length() > 0 && (n++ % 16) == 0) {
-                printf(".");
-                fflush(stdout);
+            if (buffer->range_length() > 0) {
+                if (gDisplayHistogram && n > 0) {
+                    // Ignore the first time since it includes some setup
+                    // cost.
+                    decodeTimesUs.push(delayDecodeUs);
+                }
+
+                if ((n++ % 16) == 0) {
+                    printf(".");
+                    fflush(stdout);
+                }
             }
 
             sumDecodeUs += delayDecodeUs;
@@ -266,6 +315,10 @@
                (double)sumDecodeUs / n);
 
         printf("decoded a total of %d frame(s).\n", n);
+
+        if (gDisplayHistogram) {
+            displayDecodeHistogram(&decodeTimesUs);
+        }
     } else if (!strncasecmp("audio/", mime, 6)) {
         // Frame count makes less sense for audio, as the output buffer
         // sizes may be different across decoders.
@@ -466,6 +519,8 @@
     fprintf(stderr, "       -o playback audio\n");
     fprintf(stderr, "       -w(rite) filename (write to .mp4 file)\n");
     fprintf(stderr, "       -k seek test\n");
+    fprintf(stderr, "       -x display a histogram of decoding times/fps "
+                    "(video only)\n");
 }
 
 int main(int argc, char **argv) {
@@ -482,12 +537,13 @@
     gPreferSoftwareCodec = false;
     gPlaybackAudio = false;
     gWriteMP4 = false;
+    gDisplayHistogram = false;
 
     sp<ALooper> looper;
     sp<ARTSPController> rtspController;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:ptsow:k")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:ptsow:kx")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -560,6 +616,12 @@
                 break;
             }
 
+            case 'x':
+            {
+                gDisplayHistogram = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index b8a1113..f8f8a29 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -99,6 +99,7 @@
     private final boolean mSecure;
 
     /** @deprecated Use {@link #getDefault(int)} instead. */
+    @Deprecated
     public SSLCertificateSocketFactory(int handshakeTimeoutMillis) {
         this(handshakeTimeoutMillis, null, true);
     }
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index 363a311..92be373 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -102,14 +102,15 @@
             }
         }
 
-        return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain);
+        return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain, "RSA");
     }
 
     /**
      * Similar to doHandshakeAndValidateServerCertificates but exposed to JNI for use
      * by Chromium HTTPS stack to validate the cert chain.
-     * @param certChain The bytes for certificates in ASN.1 DER encoded certficates format.
+     * @param certChain The bytes for certificates in ASN.1 DER encoded certificates format.
      * @param domain The full website hostname and domain
+     * @param authType The authentication type for the cert chain
      * @return An SSL error object if there is an error and null otherwise
      */
     public static SslError verifyServerCertificates(
@@ -126,18 +127,19 @@
             serverCertificates[i] = new X509CertImpl(certChain[i]);
         }
 
-        return verifyServerDomainAndCertificates(serverCertificates, domain);
+        return verifyServerDomainAndCertificates(serverCertificates, domain, authType);
     }
 
     /**
      * Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates.
-     * Calls DomainNamevalidator to valide the domain, and TrustManager to valide the certs.
+     * Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.
      * @param chain the cert chain in X509 cert format.
      * @param domain The full website hostname and domain
+     * @param authType The authentication type for the cert chain
      * @return An SSL error object if there is an error and null otherwise
      */
     private static SslError verifyServerDomainAndCertificates(
-            X509Certificate[] chain, String domain)
+            X509Certificate[] chain, String domain, String authType)
             throws IOException {
         // check if the first certificate in the chain is for this site
         X509Certificate currCertificate = chain[0];
@@ -153,7 +155,7 @@
         }
 
         try {
-            SSLParametersImpl.getDefaultTrustManager().checkServerTrusted(chain, "RSA");
+            SSLParametersImpl.getDefaultTrustManager().checkServerTrusted(chain, authType);
             return null;  // No errors.
         } catch (CertificateException e) {
             if (HttpLog.LOGV) {
diff --git a/core/java/android/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java
index c29926c..30f25a2 100644
--- a/core/java/android/net/http/SslCertificate.java
+++ b/core/java/android/net/http/SslCertificate.java
@@ -112,6 +112,7 @@
      * @param validNotAfter The not-after date from the certificate validity period in ISO 8601 format
      * @deprecated Use {@link #SslCertificate(String, String, Date, Date)}
      */
+    @Deprecated
     public SslCertificate(
             String issuedTo, String issuedBy, String validNotBefore, String validNotAfter) {
         this(issuedTo, issuedBy, parseDate(validNotBefore), parseDate(validNotAfter));
@@ -157,6 +158,7 @@
      *
      * @deprecated Use {@link #getValidNotBeforeDate()}
      */
+    @Deprecated
     public String getValidNotBefore() {
         return formatDate(mValidNotBefore);
     }
@@ -175,6 +177,7 @@
      *
      * @deprecated Use {@link #getValidNotAfterDate()}
      */
+    @Deprecated
     public String getValidNotAfter() {
         return formatDate(mValidNotAfter);
     }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1fe2c5a..ddfcb06 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2396,14 +2396,6 @@
                 "selected_input_method_subtype";
 
         /**
-         * Setting to record the history of input method subtype, holding the pair of ID of IME
-         * and its last used subtype.
-         * @hide
-         */
-        public static final String INPUT_METHODS_SUBTYPE_HISTORY =
-                "input_methods_subtype_history";
-
-        /**
          * Whether the device has been provisioned (0 = false, 1 = true)
          */
         public static final String DEVICE_PROVISIONED = "device_provisioned";
diff --git a/core/java/android/util/EventLogTags.java b/core/java/android/util/EventLogTags.java
index 5cf5332..8c18417 100644
--- a/core/java/android/util/EventLogTags.java
+++ b/core/java/android/util/EventLogTags.java
@@ -29,6 +29,7 @@
  * @deprecated This class is no longer functional.
  * Use {@link android.util.EventLog} instead.
  */
+@Deprecated
 public class EventLogTags {
     public static class Description {
         public final int mTag;
diff --git a/core/tests/coretests/src/android/net/http/CookiesTest.java b/core/tests/coretests/src/android/net/http/CookiesTest.java
index c9eca03..e736bc9 100644
--- a/core/tests/coretests/src/android/net/http/CookiesTest.java
+++ b/core/tests/coretests/src/android/net/http/CookiesTest.java
@@ -19,15 +19,20 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.net.URISyntaxException;
+import java.util.List;
 import java.util.logging.Logger;
 import java.util.logging.SimpleFormatter;
 import java.util.logging.StreamHandler;
 import junit.framework.TestCase;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.params.ConnRoutePNames;
 import org.apache.http.impl.client.DefaultHttpClient;
 import tests.http.MockResponse;
 import tests.http.MockWebServer;
+import tests.http.RecordedRequest;
 
 public final class CookiesTest extends TestCase {
 
@@ -66,4 +71,38 @@
             logger.removeHandler(handler);
         }
     }
+
+    /**
+     * Test that cookies aren't case-sensitive with respect to hostname.
+     * http://b/3167208
+     */
+    public void testCookiesWithNonMatchingCase() throws Exception {
+        // use a proxy so we can manipulate the origin server's host name
+        server = new MockWebServer();
+        server.enqueue(new MockResponse()
+                .addHeader("Set-Cookie: a=first; Domain=my.t-mobile.com")
+                .addHeader("Set-Cookie: b=second; Domain=.T-mobile.com")
+                .addHeader("Set-Cookie: c=third; Domain=.t-mobile.com")
+                .setBody("This response sets some cookies."));
+        server.enqueue(new MockResponse()
+                .setBody("This response gets those cookies back."));
+        server.play();
+
+        HttpClient client = new DefaultHttpClient();
+        client.getParams().setParameter(
+                ConnRoutePNames.DEFAULT_PROXY, new HttpHost("localhost", server.getPort()));
+
+        HttpResponse getCookies = client.execute(new HttpGet("http://my.t-mobile.com/"));
+        getCookies.getEntity().consumeContent();
+        server.takeRequest();
+
+        HttpResponse sendCookies = client.execute(new HttpGet("http://my.t-mobile.com/"));
+        sendCookies.getEntity().consumeContent();
+        RecordedRequest sendCookiesRequest = server.takeRequest();
+        assertContains(sendCookiesRequest.getHeaders(), "Cookie: a=first; b=second; c=third");
+    }
+
+    private void assertContains(List<String> headers, String header) {
+        assertTrue(headers.toString(), headers.contains(header));
+    }
 }
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index e46dbb4..acb6f9f 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -257,9 +257,9 @@
 <p>
     The border is used to define the stretchable and static areas of 
     the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide 
-    black line(s) in the left and top part of the border. (You can have as 
-    many stretchable sections as you want.) The relative size of the stretchable 
-    sections stays the same, so the largest sections always remain the largest.
+    black line(s) in the left and top part of the border (the other border pixels should
+    be fully transparent or white). You can have as many stretchable sections as you want:
+    their relative size stays the same, so the largest sections always remain the largest.
 </p>
 <p>
     You can also define an optional drawable section of the image (effectively, 
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 11e6642..0f36345 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -84,34 +84,56 @@
 
         <dd>
           <ul>
+          
+            <li>A new toolchain (based on GCC 4.4.3), which generates better code, and can also now
+be used as a standalone cross-compiler, for people who want to build their stuff with
+<code>./configure &amp;&amp; make</code>. See
+docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided,
+but the 4.2.1 binaries were removed.</li>
+
+            <li>Support for prebuilt static and shared libraries (docs/PREBUILTS.html), module
+exports and imports to make sharing and reuse of third-party modules much easier
+(docs/IMPORT-MODULE.html explains why).</li>
+
+            <li>A C++ STL implementation (based on STLport) is now provided as a helper module. It
+can be used either as a static or shared library (details and usage exemple under
+sources/android/stlport/README). <strong>Note:</strong> For now, C++ Exceptions and RTTI are still
+not supported.</li>
+
+            <li>Improvements to the <code>cpufeatures</code> helper library to deal with buggy
+kernel that incorrectly report they run on an ARMv7 CPU (while the device really is an ARMv6). We
+recommend developers that use it to simply rebuild their applications to benefit from it, then
+upload to Market.</li>
+
             <li>Adds support for native activities, which allows you to write completely native
             applications.</li>
 
             <li>Adds an EGL library that lets you create and manage OpenGL ES textures and
             services.</li>
 
-            <li>Provides an interface that lets you write a native text-to-speech engine.</li>
-
             <li>Adds native support for the following:
 
               <ul>
-                <li>the input subsystem (such as the keyboard and touch screen)</li>
+                <li>Input subsystem (such as the keyboard and touch screen)</li>
 
-                <li>the window and surface subsystem.</li>
+                <li>Window and surface subsystem</li>
 
-                <li>audio APIs based on the OpenSL ES standard that support playback and recording
-                as well as control over platform audio effects.</li>
+                <li>Audio APIs based on the OpenSL ES standard that support playback and recording
+                as well as control over platform audio effects</li>
 
-                <li>event loop APIs to wait for things such as input and sensor events.</li>
+                <li>Event loop APIs to wait for things such as input and sensor events</li>
 
-                <li>accessing assets packaged in an <code>.apk</code> file.</li>
+                <li>Access to assets packaged in the <code>.apk</code></li>
 
-                <li>accessing sensor data (accelerometer, compass, gyroscope, etc).</li>
-
-                <li>provides sample applications, <code>native-plasma</code> and
-                <code>native-activity</code>, to demonstrate how to write a native activity.</li>
+                <li>Access to sensor data (accelerometer, compass, gyroscope, etc.)</li>
               </ul>
             </li>
+
+            <li>New sample applications, <code>native-plasma</code> and
+              <code>native-activity</code>, to demonstrate how to write a native activity.</li>
+            
+            <li>Plus many bugfixes and other small improvements; see docs/CHANGES.html for a more
+detailed list of changes.</li>
           </ul>
         </dd>
       </dl>
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index bb469e5..7bf07eb 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -154,6 +154,7 @@
     bool exceedsFileDurationLimit();
     bool isFileStreamable() const;
     void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
+    void writeCompositionMatrix(int32_t degrees);
 
     MPEG4Writer(const MPEG4Writer &);
     MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 6a25dc5..9da5f01 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -345,6 +345,17 @@
     return OK;
 }
 
+// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
+status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
+    LOGV("setParamVideoRotation: %d", degrees);
+    if (degrees < 0 || degrees % 90 != 0) {
+        LOGE("Unsupported video rotation angle: %d", degrees);
+        return BAD_VALUE;
+    }
+    mRotationDegrees = degrees % 360;
+    return OK;
+}
+
 status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
     LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
     if (timeUs <= 0) {
@@ -599,6 +610,11 @@
         if (safe_strtoi32(value.string(), &video_bitrate)) {
             return setParamVideoEncodingBitRate(video_bitrate);
         }
+    } else if (key == "video-param-rotation-angle-degrees") {
+        int32_t degrees;
+        if (safe_strtoi32(value.string(), &degrees)) {
+            return setParamVideoRotation(degrees);
+        }
     } else if (key == "video-param-i-frames-interval") {
         int32_t seconds;
         if (safe_strtoi32(value.string(), &seconds)) {
@@ -1255,6 +1271,9 @@
     if (mTrackEveryTimeDurationUs > 0) {
         (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
     }
+    if (mRotationDegrees != 0) {
+        (*meta)->setInt32(kKeyRotation, mRotationDegrees);
+    }
 }
 
 status_t StagefrightRecorder::startMPEG4Recording() {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index d11d7e0..36a15a8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -93,6 +93,7 @@
     int64_t mMaxFileSizeBytes;
     int64_t mMaxFileDurationUs;
     int64_t mTrackEveryTimeDurationUs;
+    int32_t mRotationDegrees;  // Clockwise
 
     bool mCaptureTimeLapse;
     int64_t mTimeBetweenTimeLapseFrameCaptureUs;
@@ -146,6 +147,7 @@
     status_t setParamVideoEncoderLevel(int32_t level);
     status_t setParamVideoCameraId(int32_t cameraId);
     status_t setParamVideoTimeScale(int32_t timeScale);
+    status_t setParamVideoRotation(int32_t degrees);
     status_t setParamTrackTimeStatus(int64_t timeDurationUs);
     status_t setParamInterleaveDuration(int32_t durationUs);
     status_t setParam64BitFileOffset(bool use64BitFileOffset);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index b3ed845..17a40b00 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -202,6 +202,7 @@
 
     // Simple validation on the codec specific data
     status_t checkCodecSpecificData() const;
+    int32_t mRotation;
 
     void updateTrackSizeEstimate();
     void addOneStscTableEntry(size_t chunkId, size_t sampleId);
@@ -520,6 +521,59 @@
     LOGD("Writer thread stopped");
 }
 
+/*
+ * MP4 file standard defines a composition matrix:
+ * | a  b  u |
+ * | c  d  v |
+ * | x  y  w |
+ *
+ * the element in the matrix is stored in the following
+ * order: {a, b, u, c, d, v, x, y, w},
+ * where a, b, c, d, x, and y is in 16.16 format, while
+ * u, v and w is in 2.30 format.
+ */
+void MPEG4Writer::writeCompositionMatrix(int degrees) {
+    LOGV("writeCompositionMatrix");
+    uint32_t a = 0x00010000;
+    uint32_t b = 0;
+    uint32_t c = 0;
+    uint32_t d = 0x00010000;
+    switch (degrees) {
+        case 0:
+            break;
+        case 90:
+            a = 0;
+            b = 0x00010000;
+            c = 0xFFFF0000;
+            d = 0;
+            break;
+        case 180:
+            a = 0xFFFF0000;
+            d = 0xFFFF0000;
+            break;
+        case 270:
+            a = 0;
+            b = 0xFFFF0000;
+            c = 0x00010000;
+            d = 0;
+            break;
+        default:
+            CHECK(!"Should never reach this unknown rotation");
+            break;
+    }
+
+    writeInt32(a);           // a
+    writeInt32(b);           // b
+    writeInt32(0);           // u
+    writeInt32(c);           // c
+    writeInt32(d);           // d
+    writeInt32(0);           // v
+    writeInt32(0);           // x
+    writeInt32(0);           // y
+    writeInt32(0x40000000);  // w
+}
+
+
 status_t MPEG4Writer::stop() {
     if (mFile == NULL) {
         return OK;
@@ -585,15 +639,7 @@
         writeInt16(0);             // reserved
         writeInt32(0);             // reserved
         writeInt32(0);             // reserved
-        writeInt32(0x10000);       // matrix
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0x10000);
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0x40000000);
+        writeCompositionMatrix(0); // matrix
         writeInt32(0);             // predefined
         writeInt32(0);             // predefined
         writeInt32(0);             // predefined
@@ -886,7 +932,8 @@
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
-      mReachedEOS(false) {
+      mReachedEOS(false),
+      mRotation(0) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
     const char *mime;
@@ -1179,6 +1226,11 @@
         startTimeUs = 0;
     }
 
+    int32_t rotationDegrees;
+    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
+        mRotation = rotationDegrees;
+    }
+
     mIsRealTimeRecording = true;
     {
         int32_t isNotRealTime;
@@ -2075,15 +2127,7 @@
         mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
         mOwner->writeInt16(0);             // reserved
 
-        mOwner->writeInt32(0x10000);       // matrix
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0x10000);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0x40000000);
+        mOwner->writeCompositionMatrix(mRotation);       // matrix
 
         if (mIsAudio) {
             mOwner->writeInt32(0);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index da5f204..d035eb5 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -116,7 +116,6 @@
     static final long TIME_TO_RECONNECT = 10*1000;
 
     private static final int NOT_A_SUBTYPE_ID = -1;
-    private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
     // If IME doesn't support the system locale, the default subtype will be the first defined one.
     private static final int DEFAULT_SUBTYPE_ID = 0;
 
@@ -367,7 +366,9 @@
                                     if (!doit) {
                                         return true;
                                     }
-                                    resetSelectedInputMethodAndSubtypeLocked("");
+                                    Settings.Secure.putString(mContext.getContentResolver(),
+                                            Settings.Secure.DEFAULT_INPUT_METHOD, "");
+                                    resetSelectedInputMethodSubtype();
                                     chooseNewDefaultIMELocked();
                                     return true;
                                 }
@@ -424,7 +425,9 @@
                                 changed = true;
                                 curIm = null;
                                 Slog.i(TAG, "Unsetting current input method");
-                                resetSelectedInputMethodAndSubtypeLocked("");
+                                Settings.Secure.putString(mContext.getContentResolver(),
+                                        Settings.Secure.DEFAULT_INPUT_METHOD, "");
+                                resetSelectedInputMethodSubtype();
                             }
                         }
                     }
@@ -507,7 +510,9 @@
                 Slog.i(TAG, "No default found, using " + defIm.getId());
             }
             if (defIm != null) {
-                setSelectSubtypeLocked(defIm, NOT_A_SUBTYPE_ID);
+                Settings.Secure.putString(mContext.getContentResolver(),
+                        Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId());
+                putSelectedInputMethodSubtype(defIm, NOT_A_SUBTYPE_ID);
             }
         }
 
@@ -989,7 +994,7 @@
                     synchronized (mMethodMap) {
                         if (mCurMethod != null) {
                             try {
-                                setSelectSubtypeLocked(info, subtypeId);
+                                putSelectedInputMethodSubtype(info, subtypeId);
                                 if (mInputShown) {
                                     // If mInputShown is false, there is no IME button on the
                                     // system bar.
@@ -1009,13 +1014,13 @@
 
         final long ident = Binder.clearCallingIdentity();
         try {
+            mCurMethodId = id;
             // Set a subtype to this input method.
             // subtypeId the name of a subtype which will be set.
-            setSelectedInputMethodAndSubtypeLocked(info, subtypeId);
-            // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
-            // because mCurMethodId is stored as a history in
-            // setSelectedInputMethodAndSubtypeLocked().
-            mCurMethodId = id;
+            putSelectedInputMethodSubtype(info, subtypeId);
+
+            Settings.Secure.putString(mContext.getContentResolver(),
+                    Settings.Secure.DEFAULT_INPUT_METHOD, id);
 
             if (ActivityManagerNative.isSystemReady()) {
                 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -1482,7 +1487,9 @@
                 }
             }
             InputMethodInfo imi = enabled.get(i);
-            resetSelectedInputMethodAndSubtypeLocked(imi.getId());
+            Settings.Secure.putString(mContext.getContentResolver(),
+                    Settings.Secure.DEFAULT_INPUT_METHOD, imi.getId());
+            putSelectedInputMethodSubtype(imi, NOT_A_SUBTYPE_ID);
             return true;
         }
 
@@ -1786,8 +1793,11 @@
                 String selId = Settings.Secure.getString(mContext.getContentResolver(),
                         Settings.Secure.DEFAULT_INPUT_METHOD);
                 if (id.equals(selId)) {
-                    resetSelectedInputMethodAndSubtypeLocked(enabledInputMethodsList.size() > 0
-                            ? enabledInputMethodsList.get(0).first : "");
+                    Settings.Secure.putString(
+                            mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD,
+                            enabledInputMethodsList.size() > 0
+                                    ? enabledInputMethodsList.get(0).first : "");
+                    resetSelectedInputMethodSubtype();
                 }
                 // Previous state was enabled.
                 return true;
@@ -1799,54 +1809,22 @@
         }
     }
 
-    private void saveCurrentInputMethodAndSubtypeToHistory() {
-        String subtypeId = NOT_A_SUBTYPE_ID_STR;
-        if (mCurrentSubtype != null) {
-            subtypeId = String.valueOf(mCurrentSubtype.hashCode());
-        }
-        mSettings.addSubtypeToHistory(mCurMethodId, subtypeId);
+    private void resetSelectedInputMethodSubtype() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, NOT_A_SUBTYPE_ID);
     }
 
-    private void setSelectSubtypeLocked(InputMethodInfo imi, int subtypeId) {
-        saveCurrentInputMethodAndSubtypeToHistory();
-        if (imi == null || subtypeId < 0) {
-            mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
-            mCurrentSubtype = null;
+    private void putSelectedInputMethodSubtype(InputMethodInfo imi, int subtypeId) {
+        final ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
+        if (subtypeId >= 0 && subtypeId < subtypes.size()) {
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
+                    subtypes.get(subtypeId).hashCode());
+            mCurrentSubtype = subtypes.get(subtypeId);
         } else {
-            final ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
-            if (subtypeId < subtypes.size()) {
-                mSettings.putSelectedSubtype(subtypes.get(subtypeId).hashCode());
-                mCurrentSubtype = subtypes.get(subtypeId);
-            } else {
-                mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
-                mCurrentSubtype = null;
-            }
+            resetSelectedInputMethodSubtype();
+            mCurrentSubtype = null;
         }
-        
-    }
-
-    private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId) {
-        setSelectSubtypeLocked(imi, subtypeId);
-        mSettings.putSelectedInputMethod(imi.getId());
-    }
-
-    private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
-        InputMethodInfo imi = mMethodMap.get(newDefaultIme);
-        int lastSubtypeId = NOT_A_SUBTYPE_ID;
-        // newDefaultIme is empty when there is no candidate for the selected IME.
-        if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
-            String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
-            if (subtypeHashCode != null) {
-                try {
-                    lastSubtypeId = getSubtypeIdFromHashCode(
-                            imi, Integer.valueOf(subtypeHashCode));
-                } catch (NumberFormatException e) {
-                    Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
-                }
-            }
-        }
-        setSelectSubtypeLocked(imi, lastSubtypeId);
-        mSettings.putSelectedInputMethod(newDefaultIme);
     }
 
     private int getSelectedInputMethodSubtypeId(String id) {
@@ -1854,6 +1832,7 @@
         if (imi == null) {
             return NOT_A_SUBTYPE_ID;
         }
+        ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
         int subtypeId;
         try {
             subtypeId = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -1861,14 +1840,9 @@
         } catch (SettingNotFoundException e) {
             return NOT_A_SUBTYPE_ID;
         }
-        return getSubtypeIdFromHashCode(imi, subtypeId);
-    }
-
-    private int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) {
-        ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
         for (int i = 0; i < subtypes.size(); ++i) {
             InputMethodSubtype ims = subtypes.get(i);
-            if (subtypeHashCode == ims.hashCode()) {
+            if (subtypeId == ims.hashCode()) {
                 return i;
             }
         }
@@ -1948,10 +1922,10 @@
         // example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
         private static final char INPUT_METHOD_SEPARATER = ':';
         private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';';
-        private final TextUtils.SimpleStringSplitter mInputMethodSplitter =
+        private final TextUtils.SimpleStringSplitter mStringColonSplitter =
                 new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER);
 
-        private final TextUtils.SimpleStringSplitter mSubtypeSplitter =
+        private final TextUtils.SimpleStringSplitter mStringSemiColonSplitter =
                 new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER);
 
         private final ContentResolver mResolver;
@@ -2014,16 +1988,16 @@
             if (TextUtils.isEmpty(enabledInputMethodsStr)) {
                 return imsList;
             }
-            mInputMethodSplitter.setString(enabledInputMethodsStr);
-            while (mInputMethodSplitter.hasNext()) {
-                String nextImsStr = mInputMethodSplitter.next();
-                mSubtypeSplitter.setString(nextImsStr);
-                if (mSubtypeSplitter.hasNext()) {
+            mStringColonSplitter.setString(enabledInputMethodsStr);
+            while (mStringColonSplitter.hasNext()) {
+                String nextImsStr = mStringColonSplitter.next();
+                mStringSemiColonSplitter.setString(nextImsStr);
+                if (mStringSemiColonSplitter.hasNext()) {
                     ArrayList<String> subtypeHashes = new ArrayList<String>();
                     // The first element is ime id.
-                    String imeId = mSubtypeSplitter.next();
-                    while (mSubtypeSplitter.hasNext()) {
-                        subtypeHashes.add(mSubtypeSplitter.next());
+                    String imeId = mStringSemiColonSplitter.next();
+                    while (mStringSemiColonSplitter.hasNext()) {
+                        subtypeHashes.add(mStringSemiColonSplitter.next());
                     }
                     imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
                 }
@@ -2109,161 +2083,8 @@
         private String getEnabledInputMethodsStr() {
             mEnabledInputMethodsStrCache = Settings.Secure.getString(
                     mResolver, Settings.Secure.ENABLED_INPUT_METHODS);
-            if (DEBUG) {
-                Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache);
-            }
             return mEnabledInputMethodsStrCache;
         }
-
-        private void saveSubtypeHistory(
-                List<Pair<String, String>> savedImes, String newImeId, String newSubtypeId) {
-            StringBuilder builder = new StringBuilder();
-            boolean isImeAdded = false;
-            if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeId)) {
-                builder.append(newImeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
-                        newSubtypeId);
-                isImeAdded = true;
-            }
-            for (Pair<String, String> ime: savedImes) {
-                String imeId = ime.first;
-                String subtypeId = ime.second;
-                if (TextUtils.isEmpty(subtypeId)) {
-                    subtypeId = NOT_A_SUBTYPE_ID_STR;
-                }
-                if (isImeAdded) {
-                    builder.append(INPUT_METHOD_SEPARATER);
-                } else {
-                    isImeAdded = true;
-                }
-                builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
-                        subtypeId);
-            }
-            // Remove the last INPUT_METHOD_SEPARATER
-            putSubtypeHistoryStr(builder.toString());
-        }
-
-        public void addSubtypeToHistory(String imeId, String subtypeId) {
-            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
-            for (Pair<String, String> ime: subtypeHistory) {
-                if (ime.first.equals(imeId)) {
-                    if (DEBUG) {
-                        Slog.v(TAG, "Subtype found in the history: " + imeId
-                                + ime.second);
-                    }
-                    // We should break here
-                    subtypeHistory.remove(ime);
-                    break;
-                }
-            }
-            saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
-        }
-
-        private void putSubtypeHistoryStr(String str) {
-            if (DEBUG) {
-                Slog.d(TAG, "putSubtypeHistoryStr: " + str);
-            }
-            Settings.Secure.putString(
-                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
-        }
-
-        public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
-            // Gets the first one from the history
-            return getLastSubtypeForInputMethodLockedInternal(null);
-        }
-
-        public String getLastSubtypeForInputMethodLocked(String imeId) {
-            Pair<String, String> ime = getLastSubtypeForInputMethodLockedInternal(imeId);
-            if (ime != null) {
-                return ime.second;
-            } else {
-                return null;
-            }
-        }
-
-        private Pair<String, String> getLastSubtypeForInputMethodLockedInternal(String imeId) {
-            List<Pair<String, ArrayList<String>>> enabledImes =
-                    getEnabledInputMethodsAndSubtypeListLocked();
-            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
-            for (Pair<String, String> imeAndSubtype: subtypeHistory) {
-                final String imeInTheHistory = imeAndSubtype.first;
-                // If imeId is empty, returns the first IME and subtype in the history
-                if (TextUtils.isEmpty(imeId) || imeInTheHistory.equals(imeId)) {
-                    final String subtypeInTheHistory = imeAndSubtype.second;
-                    final String subtypeHashCode = getEnabledSubtypeForInputMethodAndSubtypeLocked(
-                            enabledImes, imeInTheHistory, subtypeInTheHistory);
-                    if (!TextUtils.isEmpty(subtypeHashCode)) {
-                        if (DEBUG) {
-                            Slog.d(TAG, "Enabled subtype found in the history:" + subtypeHashCode);
-                        }
-                        return new Pair<String, String>(imeInTheHistory, subtypeHashCode);
-                    }
-                }
-            }
-            if (DEBUG) {
-                Slog.d(TAG, "No enabled IME found in the history");
-            }
-            return null;
-        }
-
-        private String getEnabledSubtypeForInputMethodAndSubtypeLocked(List<Pair<String,
-                ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) {
-            for (Pair<String, ArrayList<String>> enabledIme: enabledImes) {
-                if (enabledIme.first.equals(imeId)) {
-                    for (String s: enabledIme.second) {
-                        if (s.equals(subtypeHashCode)) {
-                            // If both imeId and subtypeId are enabled, return subtypeId.
-                            return s;
-                        }
-                    }
-                    // If imeId was enabled but subtypeId was disabled.
-                    return NOT_A_SUBTYPE_ID_STR;
-                }
-            }
-            // If both imeId and subtypeId are disabled, return null
-            return null;
-        }
-
-        private List<Pair<String, String>> loadInputMethodAndSubtypeHistoryLocked() {
-            ArrayList<Pair<String, String>> imsList = new ArrayList<Pair<String, String>>();
-            final String subtypeHistoryStr = getSubtypeHistoryStr();
-            if (TextUtils.isEmpty(subtypeHistoryStr)) {
-                return imsList;
-            }
-            mInputMethodSplitter.setString(subtypeHistoryStr);
-            while (mInputMethodSplitter.hasNext()) {
-                String nextImsStr = mInputMethodSplitter.next();
-                mSubtypeSplitter.setString(nextImsStr);
-                if (mSubtypeSplitter.hasNext()) {
-                    String subtypeId = NOT_A_SUBTYPE_ID_STR;
-                    // The first element is ime id.
-                    String imeId = mSubtypeSplitter.next();
-                    while (mSubtypeSplitter.hasNext()) {
-                        subtypeId = mSubtypeSplitter.next();
-                        break;
-                    }
-                    imsList.add(new Pair<String, String>(imeId, subtypeId));
-                }
-            }
-            return imsList;
-        }
-
-        private String getSubtypeHistoryStr() {
-            if (DEBUG) {
-                Slog.d(TAG, "getSubtypeHistoryStr: " + Settings.Secure.getString(
-                        mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY));
-            }
-            return Settings.Secure.getString(
-                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY);
-        }
-
-        public void putSelectedInputMethod(String imeId) {
-            Settings.Secure.putString(mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, imeId);
-        }
-
-        public void putSelectedSubtype(int subtypeId) {
-            Settings.Secure.putInt(
-                    mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, subtypeId);
-        }
     }
 
     // ----------------------------------------------------------------------
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
index ebdf9c2..6c33a21 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
@@ -240,13 +240,18 @@
 
     /**
      * Checks if the file is a test.
-     * Currently we run .html and .xhtml tests.
+     * Currently we run .html, .xhtml and .php tests.
+     *
+     * @warning You MUST also call isTestDir() on the parent directory before
+     * assuming that a file is a test.
      *
      * @param testName
      * @return if the file is a test
      */
     public static boolean isTestFile(String testName) {
-        return testName.endsWith(".html") || testName.endsWith(".xhtml");
+        return testName.endsWith(".html")
+            || testName.endsWith(".xhtml")
+            || testName.endsWith(".php");
     }
 
     /**