am 705a3ee: AI 147793: cleanup broken links and delete all innacurate in

Merge commit '705a3ee3975877460c124d98eda12ae16dadd1a6' into donut

* commit '705a3ee3975877460c124d98eda12ae16dadd1a6':
  AI 147793: cleanup broken links and delete all innacurate info in apidemo pages
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/apps/Fallback/res/values-es-rUS/strings.xml b/apps/Fallback/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..0ce5751
--- /dev/null
+++ b/apps/Fallback/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"Acción no admitida"</string>
+    <string name="error">"Esa acción no se admite actualmente."</string>
+</resources>
diff --git a/apps/SdkSetup/src/com/android/sdksetup/DefaultActivity.java b/apps/SdkSetup/src/com/android/sdksetup/DefaultActivity.java
index db6385c..56f43a4 100644
--- a/apps/SdkSetup/src/com/android/sdksetup/DefaultActivity.java
+++ b/apps/SdkSetup/src/com/android/sdksetup/DefaultActivity.java
@@ -38,9 +38,7 @@
 
         // Enable the GPS.
         // Not needed since this SDK will contain the Settings app.
-        LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
         Settings.Secure.putString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, LocationManager.GPS_PROVIDER);
-        locationManager.updateProviders();
         
         // enable install from non market
         Settings.Secure.putInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 1);
diff --git a/cmds/monkey/src/com/android/commands/monkey/Monkey.java b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
index 00fb40c..5e9f07c 100644
--- a/cmds/monkey/src/com/android/commands/monkey/Monkey.java
+++ b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
@@ -130,7 +130,8 @@
     
     float[] mFactors = new float[MonkeySourceRandom.FACTORZ_COUNT];    
     MonkeyEventSource mEventSource;
-
+    private MonkeyNetworkMonitor mNetworkMonitor = new MonkeyNetworkMonitor();
+    
     /**
      * Monitor operations happening in the system.
      */
@@ -222,14 +223,14 @@
             return 1;
         }
     }
-    
+  
     /**
      * Run the procrank tool to insert system status information into the debug report.
      */
     private void reportProcRank() {
       commandLineReport("procrank", "procrank");
     }
-    
+  
     /**
      * Run "cat /data/anr/traces.txt".  Wait about 5 seconds first, to let the asynchronous
      * report writing complete.
@@ -362,7 +363,7 @@
         
         if (mScriptFileName != null) {
             // script mode, ignore other options
-            mEventSource = new MonkeySourceScript(mScriptFileName);
+            mEventSource = new MonkeySourceScript(mScriptFileName, mThrottle);
             mEventSource.setVerbose(mVerbose);
         } else {
             // random source by default
@@ -401,7 +402,9 @@
             signalPersistentProcesses();
         }
         
+        mNetworkMonitor.start();
         int crashedAtCycle = runMonkeyCycles();
+        mNetworkMonitor.stop();
 
         synchronized (this) {
             if (mRequestAnrTraces) {
@@ -423,6 +426,7 @@
         
         try {
             mAm.setActivityWatcher(null);
+            mNetworkMonitor.unregister(mAm);
         } catch (RemoteException e) {
             // just in case this was latent (after mCount cycles), make sure
             // we report it
@@ -442,6 +446,9 @@
             System.out.print(" flips=");
             System.out.println(mDroppedFlipEvents);
         }
+        
+        // report network stats
+        mNetworkMonitor.dump();
 
         if (crashedAtCycle < mCount - 1) {
             System.err.println("** System appears to have crashed at event "
@@ -602,6 +609,7 @@
 
         try {
             mAm.setActivityWatcher(new ActivityWatcher());
+            mNetworkMonitor.register(mAm);
         } catch (RemoteException e) {
             System.err.println("** Failed talking with activity manager!");
             return false;
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
index 7176073..d926be8 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
@@ -51,6 +51,14 @@
     }
     
     /**
+     * @return true if it is safe to throttle after this event, and false otherwise.
+     */
+    public boolean isThrottlable() {
+        return true;
+    }
+    
+    
+    /**
      * a method for injecting event
      * @param iwm wires to current window manager
      * @param iam wires to current activity manager
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyEventQueue.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyEventQueue.java
new file mode 100644
index 0000000..dfe389a
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyEventQueue.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 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.commands.monkey;
+
+import java.util.LinkedList;
+
+/**
+ * class for keeping a monkey event queue
+ */
+@SuppressWarnings("serial")
+public class MonkeyEventQueue extends LinkedList<MonkeyEvent> {   
+
+    private long mThrottle;
+    
+    public MonkeyEventQueue(long throttle) {
+        super();
+        mThrottle = throttle;
+    }
+    
+    @Override
+    public void addLast(MonkeyEvent e) {
+        super.add(e);
+        if (e.isThrottlable()) {
+            super.add(new MonkeyThrottleEvent(mThrottle));
+        }
+    }
+}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java
index c1e0ffc..877ebb5 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java
@@ -92,6 +92,11 @@
     }
 
     @Override
+    public boolean isThrottlable() {
+        return (getAction() == KeyEvent.ACTION_UP);
+    }
+    
+    @Override
     public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
         if (verbose > 1) {
             String note;
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyMotionEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyMotionEvent.java
index 2657061..81c64b4 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyMotionEvent.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyMotionEvent.java
@@ -20,6 +20,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.view.IWindowManager;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 
 
@@ -124,6 +125,11 @@
     }
 
     @Override
+    public boolean isThrottlable() {
+        return (getAction() == KeyEvent.ACTION_UP);
+    }
+    
+    @Override
     public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
         
         String note;
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyNetworkMonitor.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyNetworkMonitor.java
new file mode 100644
index 0000000..e8d9812
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyNetworkMonitor.java
@@ -0,0 +1,105 @@
+/**
+** Copyright 2007, 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.commands.monkey;
+
+import android.app.IActivityManager;
+import android.app.IIntentReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+
+/**
+ * Class for monitoring network connectivity during monkey runs.
+ */
+public class MonkeyNetworkMonitor extends IIntentReceiver.Stub {
+    private static final boolean LDEBUG = false;
+    private final IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+    private long mCollectionStartTime; // time we started collecting data
+    private long mEventTime; // time of last event (connect, disconnect, etc.)
+    private int mLastNetworkType = -1; // unknown
+    private long mWifiElapsedTime = 0;  // accumulated time spent on wifi since start()
+    private long mMobileElapsedTime = 0; // accumulated time spent on mobile since start()
+    private long mElapsedTime = 0; // amount of time spent between start() and stop()
+    
+    public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+            boolean ordered) throws RemoteException {
+        NetworkInfo ni = (NetworkInfo) intent.getParcelableExtra(
+                ConnectivityManager.EXTRA_NETWORK_INFO);
+        if (LDEBUG) System.out.println("Network state changed: " 
+                + "type=" + ni.getType() + ", state="  + ni.getState());
+        updateNetworkStats();
+        if (NetworkInfo.State.CONNECTED == ni.getState()) {
+            if (LDEBUG) System.out.println("Network connected");
+            mLastNetworkType = ni.getType();
+        } else if (NetworkInfo.State.DISCONNECTED == ni.getState()) {
+            if (LDEBUG) System.out.println("Network not connected");
+            mLastNetworkType = -1; // unknown since we're disconnected
+        }
+        mEventTime = SystemClock.elapsedRealtime();
+    }
+
+    private void updateNetworkStats() {
+        long timeNow = SystemClock.elapsedRealtime();
+        long delta = timeNow - mEventTime;
+        switch (mLastNetworkType) {
+            case ConnectivityManager.TYPE_MOBILE:
+                if (LDEBUG) System.out.println("Adding to mobile: " + delta);
+                mMobileElapsedTime += delta;
+                break;
+            case ConnectivityManager.TYPE_WIFI:
+                if (LDEBUG) System.out.println("Adding to wifi: " + delta);
+                mWifiElapsedTime += delta;
+                break;
+            default:
+                if (LDEBUG) System.out.println("Unaccounted for: " + delta);
+                break;
+        }
+        mElapsedTime = timeNow - mCollectionStartTime;
+    }
+
+    public void start() {
+        mWifiElapsedTime = 0;
+        mMobileElapsedTime = 0;
+        mElapsedTime = 0;
+        mEventTime = mCollectionStartTime = SystemClock.elapsedRealtime();
+    }
+
+    public void register(IActivityManager am) throws RemoteException {
+        if (LDEBUG) System.out.println("registering Receiver");
+        am.registerReceiver(null, this, filter, null); 
+    }
+    
+    public void unregister(IActivityManager am) throws RemoteException {
+        if (LDEBUG) System.out.println("unregistering Receiver");
+        am.unregisterReceiver(this);
+    }
+    
+    public void stop() {
+        updateNetworkStats();
+    }
+    
+    public void dump() {
+        System.out.println("## Network stats: elapsed time=" + mElapsedTime + "ms (" 
+                + mMobileElapsedTime + "ms mobile, "
+                + mWifiElapsedTime + "ms wifi, "
+                + (mElapsedTime - mMobileElapsedTime - mWifiElapsedTime) + "ms not connected)");
+    }
+ }
\ No newline at end of file
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
index 902d8e8..5f9c10f 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
@@ -31,7 +31,7 @@
 /**
  * monkey event queue
  */
-public class MonkeySourceRandom implements MonkeyEventSource{    
+public class MonkeySourceRandom implements MonkeyEventSource {    
     /** Key events that move around the UI. */
     private static final int[] NAV_KEYS = {
         KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
@@ -168,7 +168,7 @@
     private float[] mFactors = new float[FACTORZ_COUNT];
     private ArrayList<ComponentName> mMainApps;
     private int mEventCount = 0;  //total number of events generated so far
-    private LinkedList<MonkeyEvent> mQ = new LinkedList<MonkeyEvent>();
+    private MonkeyEventQueue mQ;
     private Random mRandom;    
     private int mVerbose = 0;
     private long mThrottle = 0;
@@ -203,7 +203,7 @@
         mRandom = new SecureRandom();
         mRandom.setSeed((seed == 0) ? -1 : seed);
         mMainApps = MainApps;
-        mThrottle = throttle;
+        mQ = new MonkeyEventQueue(throttle);
     }
 
     /**
@@ -336,7 +336,6 @@
                 downAt, MotionEvent.ACTION_UP, x, y, 0);        
         e.setIntermediateNote(false);        
         mQ.addLast(e);
-        addThrottle();
     }
   
     /**
@@ -387,7 +386,6 @@
             e.setIntermediateNote(false);        
             mQ.addLast(e);
         }        
-        addThrottle();
     }
     
     /** 
@@ -420,13 +418,11 @@
             MonkeyActivityEvent e = new MonkeyActivityEvent(mMainApps.get(
                     mRandom.nextInt(mMainApps.size())));
             mQ.addLast(e);
-            addThrottle();
             return;
         } else if (cls < mFactors[FACTOR_FLIP]) {
             MonkeyFlipEvent e = new MonkeyFlipEvent(mKeyboardOpen);
             mKeyboardOpen = !mKeyboardOpen;
             mQ.addLast(e);
-            addThrottle();
             return;
         } else {
             lastKey = 1 + mRandom.nextInt(KeyEvent.getMaxKeyCode() - 1);
@@ -437,8 +433,6 @@
         
         e = new MonkeyKeyEvent(KeyEvent.ACTION_UP, lastKey);
         mQ.addLast(e);
-        
-        addThrottle();
     }
     
     public boolean validate() {
@@ -472,8 +466,4 @@
         mQ.removeFirst();        
         return e;
     }
-    
-    private void addThrottle() {
-        mQ.addLast(new MonkeyThrottleEvent(MonkeyEvent.EVENT_TYPE_THROTTLE, mThrottle));
-    }
 }
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java
index aadda9f..869af2c 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java
@@ -35,18 +35,19 @@
  *      type= raw events
  *      count= 10
  *      speed= 1.0
+ *      start data >>
  *      captureDispatchPointer(5109520,5109520,0,230.75429,458.1814,0.20784314,
  *          0.06666667,0,0.0,0.0,65539,0)
  *      captureDispatchKey(5113146,5113146,0,20,0,0,0,0)
  *      captureDispatchFlip(true)
  *      ...
  */
-public class MonkeySourceScript implements MonkeyEventSource{    
+public class MonkeySourceScript implements MonkeyEventSource {    
     private int mEventCountInScript = 0;  //total number of events in the file
     private int mVerbose = 0;
     private double mSpeed = 1.0;
     private String mScriptFileName; 
-    private LinkedList<MonkeyEvent> mQ = new LinkedList<MonkeyEvent>();
+    private MonkeyEventQueue mQ;
     
     private static final String HEADER_TYPE = "type=";
     private static final String HEADER_COUNT = "count=";
@@ -80,12 +81,14 @@
     // a line at the end of the header
     private static final String STARTING_DATA_LINE = "start data >>";    
     private boolean mFileOpened = false;    
+    
     FileInputStream mFStream;
     DataInputStream mInputStream;
     BufferedReader mBufferReader;
     
-    public MonkeySourceScript(String filename) {
+    public MonkeySourceScript(String filename, long throttle) {
         mScriptFileName = filename;
+        mQ = new MonkeyEventQueue(throttle);
     }
     
     /**
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyThrottleEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyThrottleEvent.java
index 3d7d48a..0b4e6b6 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyThrottleEvent.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyThrottleEvent.java
@@ -16,11 +16,10 @@
 
 package com.android.commands.monkey;
 
+import java.util.List;
+
 import android.app.IActivityManager;
-import android.os.RemoteException;
-import android.os.SystemClock;
 import android.view.IWindowManager;
-import android.view.MotionEvent;
 
 
 /**
@@ -29,8 +28,8 @@
 public class MonkeyThrottleEvent extends MonkeyEvent {
     private long mThrottle; 
         
-    public MonkeyThrottleEvent(int type, long throttle) {
-        super(type);
+    public MonkeyThrottleEvent(long throttle) {
+        super(MonkeyEvent.EVENT_TYPE_THROTTLE);
         mThrottle = throttle;
     }  
 
diff --git a/docs/copyright-templates/asm.txt b/docs/copyright-templates/asm.txt
new file mode 100644
index 0000000..95a9022
--- /dev/null
+++ b/docs/copyright-templates/asm.txt
@@ -0,0 +1,13 @@
+; Copyright (C) 2009 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.
diff --git a/docs/copyright-templates/bash.txt b/docs/copyright-templates/bash.txt
new file mode 100644
index 0000000..ecf510e
--- /dev/null
+++ b/docs/copyright-templates/bash.txt
@@ -0,0 +1,15 @@
+#!/bin/bash
+#
+# Copyright (C) 2009 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.
diff --git a/docs/copyright-templates/bsd/c.txt b/docs/copyright-templates/bsd/c.txt
new file mode 100644
index 0000000..c574b4a
--- /dev/null
+++ b/docs/copyright-templates/bsd/c.txt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff --git a/docs/copyright-templates/c.txt b/docs/copyright-templates/c.txt
new file mode 100644
index 0000000..7cd7083
--- /dev/null
+++ b/docs/copyright-templates/c.txt
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2009 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.
+ */
diff --git a/docs/copyright-templates/java.txt b/docs/copyright-templates/java.txt
new file mode 100644
index 0000000..7cd7083
--- /dev/null
+++ b/docs/copyright-templates/java.txt
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2009 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.
+ */
diff --git a/docs/copyright-templates/make.txt b/docs/copyright-templates/make.txt
new file mode 100644
index 0000000..e4b376e
--- /dev/null
+++ b/docs/copyright-templates/make.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2009 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.
diff --git a/docs/copyright-templates/plain.txt b/docs/copyright-templates/plain.txt
new file mode 100644
index 0000000..4549ecb
--- /dev/null
+++ b/docs/copyright-templates/plain.txt
@@ -0,0 +1,13 @@
+Copyright (C) 2009 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.
diff --git a/docs/copyright-templates/sh.txt b/docs/copyright-templates/sh.txt
new file mode 100644
index 0000000..e53137d
--- /dev/null
+++ b/docs/copyright-templates/sh.txt
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# Copyright (C) 2009 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.
diff --git a/docs/copyright-templates/xml.txt b/docs/copyright-templates/xml.txt
new file mode 100644
index 0000000..2a9d2b6
--- /dev/null
+++ b/docs/copyright-templates/xml.txt
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
diff --git a/docs/howto_SDK_git_cygwin.txt b/docs/howto_SDK_git_cygwin.txt
new file mode 100644
index 0000000..078062b
--- /dev/null
+++ b/docs/howto_SDK_git_cygwin.txt
@@ -0,0 +1,168 @@
+Copyright (C) 2009 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.
+
+
+Subject: How to get the android source code using Cygwin and Git
+Date:    2009/04/27
+
+
+
+Table of content:
+  1- Goals and Requirements
+  2- Getting the code, the simple way
+  3- SSH issues
+  4- Advanced Tricks
+
+
+-------------------------
+1- Goals and Requirements
+-------------------------
+
+This document explains how to checkout the Android source from the git
+repositories under Windows.
+
+As stated in development/docs/howto_build_SDK.txt, one can't build the whole
+Android source code under Windows. You can only build a the SDK tools for
+Windows.
+
+There are a number of caveats in checking out the code from Git under Windows. 
+This document tries to explain them.
+
+First you will need to meet the following requirements:
+- You must have Cygwin installed.
+  See http://www.cygwin.com/
+
+- You must install Cyginw using the "Unix / Binary" mode.
+  If you don't do that, git will fail to properly compute some SHA1 keys.
+
+- You need the "git" and "curl" packages to checkout the code.
+  If you plan to contribute, you might want to get "gitk" also.
+
+  Note: if you want to build the SDK, check the howto_build_SDK.txt file
+  for a list of extra required packages.
+
+
+-----------------------------------
+2- Getting the code, the simple way
+-----------------------------------
+
+Out of the box, "repo" and "git" will work just fine under Cygwin:
+
+  $ repo init -u git://android.git.kernel.org/platform/manifest.git
+  $ repo sync
+
+And you're done. You can build as explained in howto_build_SDK.txt and ignore
+the rest of this document.
+
+
+-------------
+3- SSH issues
+-------------
+
+If you maintain your own private repository using an SSH server, you might get
+some "mux/ssh" errors. In this case try this:
+
+  $ repo init -u ssh://my.private.ssh.repo/platform/manifest.git
+  $ export GIT_SSH=ssh
+  $ repo sync
+
+
+------------------
+4- Advanced Tricks
+------------------
+
+There are two remaining issues with the default repo/git options:
+
+A- If you plan on contributing, you will notice that even after a fresh "repo
+sync" some projects are marked as having modified files. This happens on the
+"bionic" and the "external/iptables" project. The issue is that they have files
+which have the same name yet differ only by their case-sensitivity. Since the
+Windows filesystem is not case-sensitive, this confuses Git.
+
+Solution: we can simply ignore these projects as they are not needed to build
+the Windows SDK.
+
+To do this you just need to create a file .repo/local_manifest.xml that
+provides a list of projects to ignore:
+
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest>
+  <remove-project name="platform/bionic" />
+  <remove-project name="platform/external/iptables" />
+</manifest>
+
+
+B- The other issue is that by default repo maintains around 100+ git projects. 
+However most of these are not needed to build the Windows SDK. We can easily
+reduce this list to around 70 projects, which will make your repo syncs a lot
+faster.
+
+Solution: Simply ignore all projects bionic, bootable/*, hardware/* and most
+external projects. For external, we still need a handful of projects for the
+SDK -- things like the emulator or sqlite can be quite useful :-)
+
+Here's a script that takes care of all these details. It performs the repo
+init, creates the appropriate local_manifest.xml and does a repo sync as
+needed:
+
+------------
+#!/bin/bash
+
+set -e  # fail on errors
+
+URL=git://android.git.kernel.org/platform/manifest.git
+BRANCH=donut
+
+# repo init if there's no .repo directory
+if [[ ! -d .repo ]]; then
+    repo init -u $URL -b $BRANCH
+fi
+
+# create a local_manifest to exclude projects not useful to the Windows SDK
+L=.repo/local_manifest.xml
+if [[ ! -f $L ]]; then
+    M=.repo/manifest.xml
+
+    cat > $L <<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest>
+EOF
+
+    for i in $(sed -sn '/external\/\(apache\|expat\|g\|libpng\|pr\|qemu\|sqlite\|tag\|zlib\)/d;/\(bionic\|bootable\|cts\|external\|hardware\).* name/s/^.*name="\([^"]\+\)".*/\1/p' $M) ; do
+        echo "Ignore project $i"
+        echo "  <remove-project name=\"$i\" />" >> $L
+    done
+
+    cat >> $L <<EOF2
+</manifest>
+EOF2
+fi
+
+[[ $URL != ${URL/ssh/} ]] && export GIT_SSH=ssh
+repo sync
+------------
+
+
+Simply extract this to a "my_sync.sh" file and try the following:
+  $ mkdir android_src
+  $ cd android_src
+  $ chmod +x mysync.sh
+  $ ./mysync.sh
+
+
+-end-
+
+
+
+
diff --git a/emulator/qtools/coverage.cpp b/emulator/qtools/coverage.cpp
index fb1fe52..790f721 100644
--- a/emulator/qtools/coverage.cpp
+++ b/emulator/qtools/coverage.cpp
@@ -137,7 +137,7 @@
             continue;
         if (strcmp(psym->name, ".plt") == 0)
             continue;
-        char *ksym = " ";
+        const char *ksym = " ";
         if (psym->region->flags & region_type::kIsKernelRegion)
             ksym = "k";
         printf("%s %s %s\n", ksym, psym->name, psym->region->path);
diff --git a/emulator/qtools/post_trace.cpp b/emulator/qtools/post_trace.cpp
index 99525fb..becfc2b 100644
--- a/emulator/qtools/post_trace.cpp
+++ b/emulator/qtools/post_trace.cpp
@@ -137,7 +137,7 @@
   double insn_per_sec = 0;
   if (elapsed_secs != 0)
     insn_per_sec = num_dynamic_insn / elapsed_secs;
-  char *suffix = "";
+  const char *suffix = "";
   if (insn_per_sec >= 1000000) {
     insn_per_sec /= 1000000.0;
     suffix = "M";
diff --git a/emulator/qtools/profile_pid.cpp b/emulator/qtools/profile_pid.cpp
index aa37847..589abe9 100644
--- a/emulator/qtools/profile_pid.cpp
+++ b/emulator/qtools/profile_pid.cpp
@@ -76,7 +76,7 @@
     sum_time += pstate->cpu_time;
     double per = 100.0 * pstate->cpu_time / total_time;
     double sum_per = 100.0 * sum_time / total_time;
-    char *print_flags = "";
+    const char *print_flags = "";
     if ((pstate->flags & ProcessState::kCalledExec) == 0)
       print_flags = "T";
     if (pstate->name == NULL)
diff --git a/emulator/qtools/profile_trace.cpp b/emulator/qtools/profile_trace.cpp
index 9d14a03..0b056cc 100644
--- a/emulator/qtools/profile_trace.cpp
+++ b/emulator/qtools/profile_trace.cpp
@@ -118,7 +118,7 @@
         double per = 100.0 * sym->elapsed / total;
         double sum_per = 100.0 * sum / total;
         double secs = 1.0 * sym->elapsed / kMHz;
-        char *ksym = " ";
+        const char *ksym = " ";
         if (sym->region->flags & region_type::kIsKernelRegion)
             ksym = "k";
         printf("%12.2f %11lld %6.2f %6.2f  %s %s\n",
diff --git a/emulator/qtools/q2dm.cpp b/emulator/qtools/q2dm.cpp
index 7f987dc..74dbaeb 100644
--- a/emulator/qtools/q2dm.cpp
+++ b/emulator/qtools/q2dm.cpp
@@ -208,7 +208,7 @@
         if (pStack == NULL) {
             pStack = new CallStackType(event.pid, kNumStackFrames, trace);
             stacks[event.pid] = pStack;
-            char *name = trace->GetProcessName(event.pid);
+            const char *name = trace->GetProcessName(event.pid);
             dmtrace->addThread(event.pid, name);
         }
 
@@ -267,7 +267,6 @@
         }
     }
 
-
     dmtrace->close();
     delete dmtrace;
     delete trace;
diff --git a/emulator/qtools/read_addr.cpp b/emulator/qtools/read_addr.cpp
index 38fc62a..1c8c20f 100644
--- a/emulator/qtools/read_addr.cpp
+++ b/emulator/qtools/read_addr.cpp
@@ -20,7 +20,7 @@
 
     if (trace->ReadAddr(&time, &addr, &flags))
       break;
-    char *op = "ld";
+    const char *op = "ld";
     if (flags == 1)
         op = "st";
     printf("%lld 0x%08x %s\n", time, addr, op);
diff --git a/emulator/qtools/trace_reader.cpp b/emulator/qtools/trace_reader.cpp
index b38c0b4..d2af64f 100644
--- a/emulator/qtools/trace_reader.cpp
+++ b/emulator/qtools/trace_reader.cpp
@@ -131,7 +131,7 @@
     delete decoder_;
 }
 
-void BBReader::Open(char *filename)
+void BBReader::Open(const char *filename)
 {
     // Initialize the class variables
     memset(&nextrec_, 0, sizeof(TimeRec));
@@ -268,7 +268,7 @@
     delete decoder_;
 }
 
-void InsnReader::Open(char *filename)
+void InsnReader::Open(const char *filename)
 {
     prev_time_ = 0;
     time_diff_ = 0;
@@ -310,7 +310,7 @@
 }
 
 // Returns true if there is an error opening the file
-bool AddrReader::Open(char *filename, char *suffix)
+bool AddrReader::Open(const char *filename, const char *suffix)
 {
     struct stat stat_buf;
 
@@ -367,7 +367,7 @@
     delete decoder_;
 }
 
-void ExcReader::Open(char *filename)
+void ExcReader::Open(const char *filename)
 {
     prev_time_ = 0;
     prev_recnum_ = 0;
@@ -421,7 +421,7 @@
     delete decoder_;
 }
 
-void PidReader::Open(char *filename)
+void PidReader::Open(const char *filename)
 {
     prev_time_ = 0;
 
@@ -561,7 +561,7 @@
     delete decoder_;
 }
 
-bool MethodReader::Open(char *filename)
+bool MethodReader::Open(const char *filename)
 {
     struct stat stat_buf;
 
@@ -686,8 +686,8 @@
     delete[] static_filename_;
 }
 
-void TraceReaderBase::ReadTraceHeader(FILE *fstream, char *filename,
-                                      char *tracename, TraceHeader *header)
+void TraceReaderBase::ReadTraceHeader(FILE *fstream, const char *filename,
+                                      const char *tracename, TraceHeader *header)
 {
     int rval = fread(header, sizeof(TraceHeader), 1, fstream);
     if (rval != 1) {
@@ -721,7 +721,7 @@
 }
 
 
-void TraceReaderBase::Open(char *filename)
+void TraceReaderBase::Open(const char *filename)
 {
     char *fname;
     FILE *fstream;
@@ -840,7 +840,7 @@
     }
 }
 
-void TraceReaderBase::ParseDexList(char *filename)
+void TraceReaderBase::ParseDexList(const char *filename)
 {
     struct stat stat_buf;
     static const int kBufSize = 4096;
diff --git a/emulator/qtools/trace_reader.h b/emulator/qtools/trace_reader.h
index 4123014..f73f17a 100644
--- a/emulator/qtools/trace_reader.h
+++ b/emulator/qtools/trace_reader.h
@@ -165,7 +165,7 @@
         uint32_t        flags;
         int             argc;
         char            **argv;
-        char            *name;
+        const char      *name;
         int             nregions;        // num regions in use
         int             max_regions;     // max regions allocated
         region_type     **regions;
@@ -189,7 +189,7 @@
     ProcessState        *GetCurrentProcess()            { return current_; }
     ProcessState        *GetProcesses(int *num_procs);
     ProcessState        *GetNextProcess();
-    char                *GetProcessName(int pid);
+    const char          *GetProcessName(int pid);
     void                SetRoot(const char *root)       { root_ = root; }
     void                SetDemangle(bool demangle)      { demangle_ = demangle; }
     bool                ReadMethodSymbol(MethodRec *method_record,
@@ -276,11 +276,14 @@
     hash_entry_type *ptr;
     for (ptr = hash_->GetFirst(); ptr; ptr = hash_->GetNext()) {
         region_type *region = ptr->value;
-        int nsymbols = region->nsymbols;
-        for (int ii = 0; ii < nsymbols; ii++) {
-            delete[] region->symbols[ii].name;
+        // If the symbols are not shared with another region, then delete them.
+        if ((region->flags & region_type::kSharedSymbols) == 0) {
+            int nsymbols = region->nsymbols;
+            for (int ii = 0; ii < nsymbols; ii++) {
+                delete[] region->symbols[ii].name;
+            }
+            delete[] region->symbols;
         }
-        delete[] region->symbols;
         delete[] region->path;
 
         // Do not delete the region itself here.  Each region
@@ -422,7 +425,7 @@
 }
 
 template<class T>
-char* TraceReader<T>::GetProcessName(int pid)
+const char* TraceReader<T>::GetProcessName(int pid)
 {
     if (pid < 0 || pid >= kNumPids || processes_[pid] == NULL)
         return "(unknown)";
@@ -1165,8 +1168,6 @@
                 } else {
                     region->nsymbols = existing_region->nsymbols;
                     region->symbols = existing_region->symbols;
-                    region->path = existing_region->path;
-                    delete[] event->path;
                     region->flags |= region_type::kSharedSymbols;
                 }
 
diff --git a/emulator/qtools/trace_reader_base.h b/emulator/qtools/trace_reader_base.h
index 281d085..416c3d1 100644
--- a/emulator/qtools/trace_reader_base.h
+++ b/emulator/qtools/trace_reader_base.h
@@ -83,7 +83,7 @@
 
     friend class BBReader;
 
-    void                Open(char *filename);
+    void                Open(const char *filename);
     void                Close();
     void                WriteHeader(TraceHeader *header);
     inline bool         ReadBB(BBEvent *event);
@@ -120,10 +120,10 @@
 
   private:
     int          FindNumInsns(uint64_t bb_num, uint64_t bb_start_time);
-    void         ReadTraceHeader(FILE *fstream, char *filename,
-                                char *tracename, TraceHeader *header);
+    void         ReadTraceHeader(FILE *fstream, const char *filename,
+                                const char *tracename, TraceHeader *header);
     PidEvent     *FindMmapDexFileEvent();
-    void         ParseDexList(char *filename);
+    void         ParseDexList(const char *filename);
 
     char         *static_filename_;
     FILE         *static_fstream_;
@@ -159,7 +159,7 @@
   public:
     explicit BBReader(TraceReaderBase *trace);
     ~BBReader();
-    void     Open(char *filename);
+    void     Open(const char *filename);
     void     Close();
     bool     ReadBB(BBEvent *event);
 
@@ -193,7 +193,7 @@
     InsnReader();
     ~InsnReader();
 
-    void        Open(char *filename);
+    void        Open(const char *filename);
     void        Close();
     uint64_t    ReadInsnTime(uint64_t min_time);
 
@@ -209,7 +209,7 @@
     AddrReader();
     ~AddrReader();
 
-    bool        Open(char *filename, char *suffix);
+    bool        Open(const char *filename, const char *suffix);
     void        Close();
     bool        ReadAddr(uint64_t *time, uint32_t *addr);
 
@@ -225,7 +225,7 @@
     ExcReader();
     ~ExcReader();
 
-    void        Open(char *filename);
+    void        Open(const char *filename);
     void        Close();
     bool        ReadExc(uint64_t *time, uint32_t *current_pc,
                         uint64_t *recnum, uint32_t *target_pc,
@@ -243,7 +243,7 @@
     PidReader();
     ~PidReader();
 
-    void        Open(char *filename);
+    void        Open(const char *filename);
     void        Close();
     bool        ReadPidEvent(struct PidEvent *event);
     void        Dispose(struct PidEvent *event);
@@ -258,7 +258,7 @@
     MethodReader();
     ~MethodReader();
 
-    bool        Open(char *filename);
+    bool        Open(const char *filename);
     void        Close();
     bool        ReadMethod(MethodRec *method_record);
 
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index a53718e..d353d31 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -1104,6 +1104,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".view.Animation3" android:label="Views/Animation/Interpolators">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".view.LayoutAnimation1" android:label="Views/Layout Animation/1. Grid Fade">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/res/layout/animation_3.xml b/samples/ApiDemos/res/layout/animation_3.xml
new file mode 100644
index 0000000..4d1474c
--- /dev/null
+++ b/samples/ApiDemos/res/layout/animation_3.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:padding="10dip"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:clipToPadding="false">
+
+    <TextView
+        android:id="@+id/target"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="26sp"
+        android:text="@string/animation_3_text"/>
+
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dip"
+        android:layout_marginBottom="5dip"
+        android:text="@string/animation_2_instructions" />
+
+    <Spinner
+        android:id="@+id/spinner"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
+
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index 0cafe14..29bbcec 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -476,6 +476,7 @@
     <string name="animation_2_text_3">a chance to be better.</string>
     <string name="animation_2_text_4">— Albert Camus</string>
     <string name="animation_2_instructions">Select an animation:</string>
+    <string name="animation_3_text">Interpolators</string>
     <string name="autocomplete_1_instructions">Type in the text field for auto-completion.</string>
     <string name="autocomplete_1_country">Country:</string>
     <string name="autocomplete_1_focus">Give me Focus</string>
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/StaticTriangleRenderer.java b/samples/ApiDemos/src/com/example/android/apis/graphics/StaticTriangleRenderer.java
new file mode 100644
index 0000000..c492e3f
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/StaticTriangleRenderer.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2008 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.example.android.apis.graphics;
+
+import static android.opengl.GLES10.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLU;
+import android.opengl.GLUtils;
+import android.os.SystemClock;
+
+import com.example.android.apis.R;
+
+/**
+ * A GLSurfaceView.Renderer that uses the Android-specific
+ * android.opengl.GLESXXX static OpenGL ES APIs. The static APIs
+ * expose more of the OpenGL ES features than the
+ * javax.microedition.khronos.opengles APIs, and also
+ * provide a programming model that is closer to the C OpenGL ES APIs, which
+ * may make it easier to reuse code and documentation written for the
+ * C OpenGL ES APIs.
+ *
+ */
+public class StaticTriangleRenderer implements GLSurfaceView.Renderer{
+
+    public StaticTriangleRenderer(Context context) {
+        mContext = context;
+        mTriangle = new Triangle();
+    }
+
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        /*
+         * By default, OpenGL enables features that improve quality
+         * but reduce performance. One might want to tweak that
+         * especially on software renderer.
+         */
+        glDisable(GL_DITHER);
+
+        /*
+         * Some one-time OpenGL initialization can be made here
+         * probably based on features of this particular context
+         */
+        glHint(GL_PERSPECTIVE_CORRECTION_HINT,
+                GL_FASTEST);
+
+        glClearColor(.5f, .5f, .5f, 1);
+        glShadeModel(GL_SMOOTH);
+        glEnable(GL_DEPTH_TEST);
+        glEnable(GL_TEXTURE_2D);
+
+        /*
+         * Create our texture. This has to be done each time the
+         * surface is created.
+         */
+
+        int[] textures = new int[1];
+        glGenTextures(1, textures, 0);
+
+        mTextureID = textures[0];
+        glBindTexture(GL_TEXTURE_2D, mTextureID);
+
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                GL_NEAREST);
+        glTexParameterf(GL_TEXTURE_2D,
+                GL_TEXTURE_MAG_FILTER,
+                GL_LINEAR);
+
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+                GL_CLAMP_TO_EDGE);
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+                GL_CLAMP_TO_EDGE);
+
+        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
+                GL_REPLACE);
+
+        InputStream is = mContext.getResources()
+                .openRawResource(R.drawable.robot);
+        Bitmap bitmap;
+        try {
+            bitmap = BitmapFactory.decodeStream(is);
+        } finally {
+            try {
+                is.close();
+            } catch(IOException e) {
+                // Ignore.
+            }
+        }
+
+        GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
+        bitmap.recycle();
+    }
+
+    public void onDrawFrame(GL10 gl) {
+        /*
+         * By default, OpenGL enables features that improve quality
+         * but reduce performance. One might want to tweak that
+         * especially on software renderer.
+         */
+        glDisable(GL_DITHER);
+
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
+                GL_MODULATE);
+
+        /*
+         * Usually, the first thing one might want to do is to clear
+         * the screen. The most efficient way of doing this is to use
+         * glClear().
+         */
+
+        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+        /*
+         * Now we're ready to draw some 3D objects
+         */
+
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+
+        GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, mTextureID);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+                GL_REPEAT);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+                GL_REPEAT);
+
+        long time = SystemClock.uptimeMillis() % 4000L;
+        float angle = 0.090f * ((int) time);
+
+        glRotatef(angle, 0, 0, 1.0f);
+
+        mTriangle.draw(gl);
+    }
+
+    public void onSurfaceChanged(GL10 gl, int w, int h) {
+        glViewport(0, 0, w, h);
+
+        /*
+        * Set our projection matrix. This doesn't have to be done
+        * each time we draw, but usually a new projection needs to
+        * be set when the viewport is resized.
+        */
+
+        float ratio = (float) w / h;
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+        glFrustumf(-ratio, ratio, -1, 1, 3, 7);
+    }
+
+    private Context mContext;
+    private Triangle mTriangle;
+    private int mTextureID;
+
+    static class Triangle {
+        public Triangle() {
+
+            // Buffers to be passed to gl*Pointer() functions
+            // must be direct, i.e., they must be placed on the
+            // native heap where the garbage collector cannot
+            // move them.
+            //
+            // Buffers with multi-byte datatypes (e.g., short, int, float)
+            // must have their byte order set to native order
+
+            ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
+            vbb.order(ByteOrder.nativeOrder());
+            mFVertexBuffer = vbb.asFloatBuffer();
+
+            ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);
+            tbb.order(ByteOrder.nativeOrder());
+            mTexBuffer = tbb.asFloatBuffer();
+
+            ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
+            ibb.order(ByteOrder.nativeOrder());
+            mIndexBuffer = ibb.asShortBuffer();
+
+            // A unit-sided equilateral triangle centered on the origin.
+            float[] coords = {
+                    // X, Y, Z
+                    -0.5f, -0.25f, 0,
+                     0.5f, -0.25f, 0,
+                     0.0f,  0.559016994f, 0
+            };
+
+            for (int i = 0; i < VERTS; i++) {
+                for(int j = 0; j < 3; j++) {
+                    mFVertexBuffer.put(coords[i*3+j] * 2.0f);
+                }
+            }
+
+            for (int i = 0; i < VERTS; i++) {
+                for(int j = 0; j < 2; j++) {
+                    mTexBuffer.put(coords[i*3+j] * 2.0f + 0.5f);
+                }
+            }
+
+            for(int i = 0; i < VERTS; i++) {
+                mIndexBuffer.put((short) i);
+            }
+
+            mFVertexBuffer.position(0);
+            mTexBuffer.position(0);
+            mIndexBuffer.position(0);
+        }
+
+        public void draw(GL10 gl) {
+            glFrontFace(GL_CCW);
+            glVertexPointer(3, GL_FLOAT, 0, mFVertexBuffer);
+            glEnable(GL_TEXTURE_2D);
+            glTexCoordPointer(2, GL_FLOAT, 0, mTexBuffer);
+            glDrawElements(GL_TRIANGLE_STRIP, VERTS,
+                    GL_UNSIGNED_SHORT, mIndexBuffer);
+        }
+
+        private final static int VERTS = 3;
+
+        private FloatBuffer mFVertexBuffer;
+        private FloatBuffer mTexBuffer;
+        private ShortBuffer mIndexBuffer;
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleActivity.java b/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleActivity.java
index e5b06f4..7d7cd4a 100644
--- a/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleActivity.java
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleActivity.java
@@ -27,7 +27,7 @@
         super.onCreate(savedInstanceState);
         mGLView = new GLSurfaceView(this);
         mGLView.setEGLConfigChooser(false);
-        mGLView.setRenderer(new TriangleRenderer(this));
+        mGLView.setRenderer(new StaticTriangleRenderer(this));
         setContentView(mGLView);
     }
 
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Animation3.java b/samples/ApiDemos/src/com/example/android/apis/view/Animation3.java
new file mode 100644
index 0000000..11fc9ed
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Animation3.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 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.example.android.apis.view;
+
+// Need the following import to get access to the app resources, since this
+// class is in a sub-package.
+import com.example.android.apis.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Animation;
+import android.view.animation.TranslateAnimation;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+
+public class Animation3 extends Activity implements AdapterView.OnItemSelectedListener {
+    private static final String[] INTERPOLATORS = {
+            "Accelerate", "Decelerate", "Accelerate/Decelerate",
+            "Anticipate", "Overshoot", "Anticipate/Overshoot",
+            "Bounce"
+    };
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.animation_3);
+
+        Spinner s = (Spinner) findViewById(R.id.spinner);
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_spinner_item, INTERPOLATORS);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        s.setAdapter(adapter);
+        s.setOnItemSelectedListener(this);
+    }
+
+    public void onItemSelected(AdapterView parent, View v, int position, long id) {
+        final View target = findViewById(R.id.target);
+        final View targetParent = (View) target.getParent();
+
+        Animation a = new TranslateAnimation(0.0f,
+                targetParent.getWidth() - target.getWidth() - targetParent.getPaddingLeft() -
+                targetParent.getPaddingRight(), 0.0f, 0.0f);
+        a.setDuration(1000);
+        a.setStartOffset(300);
+        a.setRepeatMode(Animation.RESTART);
+        a.setRepeatCount(Animation.INFINITE);
+
+        switch (position) {
+            case 0:
+                a.setInterpolator(AnimationUtils.loadInterpolator(this,
+                        android.R.anim.accelerate_interpolator));
+                break;
+            case 1:
+                a.setInterpolator(AnimationUtils.loadInterpolator(this,
+                        android.R.anim.decelerate_interpolator));
+                break;
+            case 2:
+                a.setInterpolator(AnimationUtils.loadInterpolator(this,
+                        android.R.anim.accelerate_decelerate_interpolator));
+                break;
+            case 3:
+                a.setInterpolator(AnimationUtils.loadInterpolator(this,
+                        android.R.anim.anticipate_interpolator));
+                break;
+            case 4:
+                a.setInterpolator(AnimationUtils.loadInterpolator(this,
+                        android.R.anim.overshoot_interpolator));
+                break;
+            case 5:
+                a.setInterpolator(AnimationUtils.loadInterpolator(this,
+                        android.R.anim.anticipate_overshoot_interpolator));
+                break;
+            case 6:
+                a.setInterpolator(AnimationUtils.loadInterpolator(this,
+                        android.R.anim.bounce_interpolator));
+                break;
+        }
+
+        target.startAnimation(a);
+    }
+
+    public void onNothingSelected(AdapterView parent) {
+    }
+}
\ No newline at end of file
diff --git a/testrunner/run_command.py b/testrunner/run_command.py
index 6b72b77..5336f33 100755
--- a/testrunner/run_command.py
+++ b/testrunner/run_command.py
@@ -3,37 +3,37 @@
 #
 # Copyright 2007, 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 
+# 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 
+#     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 
+# 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.
 
 # System imports
 import os
 import signal
 import subprocess
-import time
 import threading
+import time
 
 # local imports
-import logger
 import errors
+import logger
 
 _abort_on_error = False
 
 def SetAbortOnError(abort=True):
-  """Sets behavior of RunCommand to throw AbortError if command process returns 
+  """Sets behavior of RunCommand to throw AbortError if command process returns
   a negative error code"""
   global _abort_on_error
   _abort_on_error = abort
-  
+
 def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True):
   """Spawns a subprocess to run the given shell command, and checks for
   timeout_time. If return_output is True, the output of the command is returned
@@ -42,7 +42,7 @@
   result = None
   while True:
     try:
-      result = RunOnce(cmd, timeout_time=timeout_time, 
+      result = RunOnce(cmd, timeout_time=timeout_time,
                        return_output=return_output)
     except errors.WaitForResponseTimedOutError:
       if retry_count == 0:
@@ -59,13 +59,13 @@
   pid = []
   global _abort_on_error
   error_occurred = False
-  
+
   def Run():
     if return_output:
       output_dest = subprocess.PIPE
     else:
       # None means direct to stdout
-      output_dest = None  
+      output_dest = None
     pipe = subprocess.Popen(
         cmd,
         executable='/bin/bash',
@@ -83,9 +83,9 @@
       so.append("ERROR")
       error_occurred = True
     if pipe.returncode < 0:
-      logger.SilentLog("Error: %s was terminated by signal %d" %(cmd, 
+      logger.SilentLog("Error: %s was terminated by signal %d" %(cmd,
           pipe.returncode))
-      error_occurred = True  
+      error_occurred = True
 
   t = threading.Thread(target=Run)
   t.start()
@@ -113,5 +113,26 @@
 
   if _abort_on_error and error_occurred:
     raise errors.AbortError
-  
+
   return "".join(so)
+
+
+def RunHostCommand(binary, valgrind=False):
+  """Run a command on the host (opt using valgrind).
+
+  Runs the host binary. Does not capture any output but it
+  returns the exit code. The command can be run under valgrind.
+
+  Args:
+    binary: basename of the file to be run. It is expected to be under
+            out/host/linux-x86/bin.
+    valgrind: If True the command will be run under valgrind.
+
+  Returns:
+    The command exit code (int)
+  """
+  full_path = os.path.join("out", "host", "linux-x86", "bin", binary)
+  if not valgrind:
+    return subprocess.call(full_path)
+  else:
+    return subprocess.call(["/usr/bin/valgrind", "-q", full_path])
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index 243da77..f87d451 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -23,6 +23,7 @@
 import glob
 import optparse
 import os
+import re
 from sets import Set
 import sys
 
@@ -43,7 +44,7 @@
 
   # file path to android core platform tests, relative to android build root
   # TODO move these test data files to another directory
-  _CORE_TEST_PATH = os.path.join("development", "testrunner", 
+  _CORE_TEST_PATH = os.path.join("development", "testrunner",
                                  _TEST_FILE_NAME)
 
   # vendor glob file path patterns to tests, relative to android
@@ -58,7 +59,8 @@
 
   def __init__(self):
     # disable logging of timestamp
-    logger.SetTimestampLogging(False)  
+    self._root_path = android_build.GetTop()
+    logger.SetTimestampLogging(False)
 
   def _ProcessOptions(self):
     """Processes command-line options."""
@@ -137,8 +139,6 @@
     if self._options.verbose:
       logger.SetVerbose(True)
 
-    self._root_path = android_build.GetTop()
-
     self._known_tests = self._ReadTests()
 
     self._coverage_gen = coverage.CoverageGenerator(
@@ -172,22 +172,30 @@
     """Prints out set of defined tests."""
     print "The following tests are currently defined:"
     for test in self._known_tests:
-      print test.GetName()
+      print "%-15s %s" % (test.GetName(), test.GetDescription())
 
   def _DoBuild(self):
     logger.SilentLog("Building tests...")
     target_set = Set()
+    extra_args_set = Set()
     for test_suite in self._GetTestsToRun():
-      self._AddBuildTarget(test_suite.GetBuildPath(), target_set)
+      self._AddBuildTarget(test_suite, target_set, extra_args_set)
 
     if target_set:
       if self._options.coverage:
         self._coverage_gen.EnableCoverageBuild()
-        self._AddBuildTarget(self._coverage_gen.GetEmmaBuildPath(), target_set)
+        self._AddBuildTargetPath(self._coverage_gen.GetEmmaBuildPath(),
+                                 target_set)
       target_build_string = " ".join(list(target_set))
-      logger.Log("mmm %s" % target_build_string)
-      cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files' %  (target_build_string,
-                                                            self._root_path)
+      extra_args_string = " ".join(list(extra_args_set))
+      # log the user-friendly equivalent make command, so developers can
+      # replicate this step
+      logger.Log("mmm %s %s" % (target_build_string, extra_args_string))
+      # mmm cannot be used from python, so perform a similiar operation using
+      # ONE_SHOT_MAKEFILE
+      cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files %s' % (
+          target_build_string, self._root_path, extra_args_string)
+
       if self._options.preview:
         # in preview mode, just display to the user what command would have been
         # run
@@ -197,11 +205,18 @@
         logger.Log("Syncing to device...")
         self._adb.Sync()
 
-  def _AddBuildTarget(self, build_dir, target_set):
+  def _AddBuildTarget(self, test_suite, target_set, extra_args_set):
+    build_dir = test_suite.GetBuildPath()
+    if self._AddBuildTargetPath(build_dir, target_set):
+      extra_args_set.add(test_suite.GetExtraMakeArgs())
+
+  def _AddBuildTargetPath(self, build_dir, target_set):
     if build_dir is not None:
       build_file_path = os.path.join(build_dir, "Android.mk")
       if os.path.isfile(os.path.join(self._root_path, build_file_path)):
         target_set.add(build_file_path)
+        return True
+    return False
 
   def _GetTestsToRun(self):
     """Get a list of TestSuite objects to run, based on command line args."""
@@ -261,6 +276,52 @@
         if coverage_file is not None:
           logger.Log("Coverage report generated at %s" % coverage_file)
 
+  def _RunNativeTest(self, test_suite):
+    """Run the provided *native* test suite.
+
+    The test_suite must contain a build path where the native test files are.
+    Each test's name must start with 'test_' and have a .cc or .cpp extension.
+    A successful test must return 0. Any other value will be considered
+    as an error.
+
+    Args:
+      test_suite: TestSuite to run
+    """
+    # find all test files, convert unicode names to ascii, take the basename
+    # and drop the .cc/.cpp  extension.
+    file_pattern = os.path.join(test_suite.GetBuildPath(), "test_*")
+    logger.SilentLog("Scanning %s" % test_suite.GetBuildPath())
+    file_list = []
+    for f in map(str, glob.glob(file_pattern)):
+      f = os.path.basename(f)
+      f = re.split(".[cp]+$", f)[0]
+      logger.SilentLog("Found %s" % f)
+      file_list.append(f)
+
+    # Run on the host
+    logger.Log("\nRunning on host")
+    for f in file_list:
+      if run_command.RunHostCommand(f) != 0:
+        logger.Log("%s... failed" % f)
+      else:
+        if run_command.RunHostCommand(f, valgrind=True) == 0:
+          logger.Log("%s... ok\t\t[valgrind: ok]" % f)
+        else:
+          logger.Log("%s... ok\t\t[valgrind: failed]" % f)
+
+    # Run on the device
+    logger.Log("\nRunning on target")
+    for f in file_list:
+      full_path = "/system/bin/%s" % f
+
+      # Single quotes are needed to prevent the shell splitting it.
+      status = self._adb.SendShellCommand("'%s >/dev/null 2>&1;echo -n $?'" %
+                                          full_path)
+      logger.Log("%s... %s" % (f, status == "0" and "ok" or "failed"))
+
+      # Cleanup
+      self._adb.SendShellCommand("rm %s" % full_path)
+
   def RunTests(self):
     """Main entry method - executes the tests according to command line args."""
     try:
@@ -278,7 +339,10 @@
         self._DoBuild()
 
       for test_suite in self._GetTestsToRun():
-        self._RunTest(test_suite)
+        if test_suite.IsNative():
+          self._RunNativeTest(test_suite)
+        else:
+          self._RunTest(test_suite)
     except KeyboardInterrupt:
       logger.Log("Exiting...")
     except errors.AbortError:
diff --git a/testrunner/test_defs.py b/testrunner/test_defs.py
index 949ad6e..2cdcfa8 100644
--- a/testrunner/test_defs.py
+++ b/testrunner/test_defs.py
@@ -38,7 +38,14 @@
        [class=""]
        [coverage_target=""]
        [build_path=""]
-       [continuous]
+       [continuous=false]
+       [description=""]
+      />
+     <test-native
+       name=""
+       build_path=""
+       [continuous=false]
+       [description=""]
       />
      <test  ...
    </test-definitions>
@@ -48,13 +55,17 @@
 
   # tag/attribute constants
   _TEST_TAG_NAME = "test"
+  _TEST_NATIVE_TAG_NAME = "test-native"
 
   def __init__(self):
     # dictionary of test name to tests
     self._testname_map = {}
 
   def __iter__(self):
-    return iter(self._testname_map.values())
+    ordered_list = []
+    for k in sorted(self._testname_map):
+      ordered_list.append(self._testname_map[k])
+    return iter(ordered_list)
 
   def Parse(self, file_path):
     """Parse the test suite data from from given file path.
@@ -87,6 +98,12 @@
       test = self._ParseTestSuite(suite_element)
       self._AddTest(test)
 
+    suite_elements = doc.getElementsByTagName(self._TEST_NATIVE_TAG_NAME)
+
+    for suite_element in suite_elements:
+      test = self._ParseNativeTestSuite(suite_element)
+      self._AddTest(test)
+
   def _ParseTestSuite(self, suite_element):
     """Parse the suite element.
     
@@ -96,6 +113,17 @@
     test = TestSuite(suite_element)
     return test
 
+  def _ParseNativeTestSuite(self, suite_element):
+    """Parse the native test element.
+
+    Returns:
+      a TestSuite object, populated with parsed data
+    Raises:
+      ParseError if some required attribute is missing.
+    """
+    test = TestSuite(suite_element, native=True)
+    return test
+
   def _AddTest(self, test):
     """Adds a test to this TestManifest.
     
@@ -129,13 +157,28 @@
   _TARGET_ATTR = "coverage_target"
   _BUILD_ATTR = "build_path"
   _CONTINUOUS_ATTR = "continuous"
+  _DESCRIPTION_ATTR = "description"
+  _EXTRA_MAKE_ARGS_ATTR = "extra_make_args"
 
   _DEFAULT_RUNNER = "android.test.InstrumentationTestRunner"
 
-  def __init__(self, suite_element):
-    """Populates this instance's data from given suite xml element."""
+  def __init__(self, suite_element, native=False):
+    """Populates this instance's data from given suite xml element.
+    Raises:
+      ParseError if some required attribute is missing.
+    """
+    self._native = native
     self._name = suite_element.getAttribute(self._NAME_ATTR)
-    self._package = suite_element.getAttribute(self._PKG_ATTR)
+
+    if self._native:
+      # For native runs, _BUILD_ATTR is required
+      if not suite_element.hasAttribute(self._BUILD_ATTR):
+        logger.Log("Error: %s is missing required build_path attribute" %
+                   self._name)
+        raise errors.ParseError
+    else:
+      self._package = suite_element.getAttribute(self._PKG_ATTR)
+
     if suite_element.hasAttribute(self._RUNNER_ATTR):
       self._runner = suite_element.getAttribute(self._RUNNER_ATTR)
     else:
@@ -156,6 +199,15 @@
       self._continuous = suite_element.getAttribute(self._CONTINUOUS_ATTR)
     else:
       self._continuous = False
+    if suite_element.hasAttribute(self._DESCRIPTION_ATTR):
+      self._description = suite_element.getAttribute(self._DESCRIPTION_ATTR)
+    else:
+      self._description = ""
+    if suite_element.hasAttribute(self._EXTRA_MAKE_ARGS_ATTR):
+      self._extra_make_args = suite_element.getAttribute(
+          self._EXTRA_MAKE_ARGS_ATTR)
+    else:
+      self._extra_make_args = ""
 
   def GetName(self):
     return self._name
@@ -184,6 +236,18 @@
     """Returns true if test is flagged as being part of the continuous tests"""  
     return self._continuous
 
+  def IsNative(self):
+    """Returns true if test is a native one."""
+    return self._native
+
+  def GetDescription(self):
+    """Returns a description if available, an empty string otherwise."""
+    return self._description
+
+  def GetExtraMakeArgs(self):
+    """Returns the extra make args if available, an empty string otherwise."""
+    return self._extra_make_args
+
 def Parse(file_path):
   """Parses out a TestDefinitions from given path to xml file.
 
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index 87159fd..dd56db1 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -17,32 +17,67 @@
 <!-- 
 This file contains standard test definitions for the Android platform
           
-Tests are defined by <test> tags with the following attributes
+Java tests are defined by <test> tags and native ones (C/C++) are defined by
+<test-native> tags.
 
-name package [class runner build_path coverage_target continuous]
+JAVA/application tests:
+=======================
+  The java <test> element has the following attributes
 
-Where:
-name: Self-descriptive name used to uniquely identify the test
-build_path: File system path, relative to Android build root, to this package's
-   Android.mk file. If omitted, build/sync step for this test will be skipped
-package: Android application package that contains the tests
-class: Optional. Fully qualified Java test class to run. 
-runner: Fully qualified InstrumentationTestRunner to execute. If omitted, 
-   will default to android.test.InstrumentationTestRunner
-coverage_target: Build name of Android package this test targets - these targets
-   are defined in the coverage_targets.xml file.  Used as basis for code
-   coverage metrics. If omitted, code coverage will not be supported for this
-   test
-continuous: Optional boolean. Default is false. Set to true if tests are known
-   to be reliable, and should be included in a continuous test system. false if
-   they are under development.
+  name package [class runner build_path coverage_target continuous description]
 
-These attributes map to the following commands:  
-(if class is defined)
-    adb shell am instrument -w <package>/<runner>
-(else)
-    adb shell am instrument -w -e class <class> <package>/<runner>
+  Where:
+  name: Self-descriptive name used to uniquely identify the test
+  build_path: File system path, relative to Android build root, to this
+    package's Android.mk file. If omitted, build/sync step for this test will
+    be skipped.
+  package: Android application package that contains the tests
+  class: Optional. Fully qualified Java test class to run. 
+  runner: Fully qualified InstrumentationTestRunner to execute. If omitted, 
+     will default to android.test.InstrumentationTestRunner.
+  coverage_target: Build name of Android package this test targets - these
+    targets are defined in the coverage_targets.xml file.  Used as basis for
+    code coverage metrics. If omitted, code coverage will not be supported for
+    this test.
+  continuous: Optional boolean. Default is false. Set to true if tests are known
+    to be reliable, and should be included in a continuous test system. false if
+    they are under development.
 
+  description: Optional string. Default is empty. Short description (typically 
+     less than 60 characters) about this test.
+
+  These attributes map to the following commands:  
+  (if class is defined)
+      adb shell am instrument -w <package>/<runner>
+  (else)
+      adb shell am instrument -w -e class <class> <package>/<runner>
+
+Native tests:
+=============
+  The <test-native> element has the following attributes
+
+  name build_path [continuous description]
+
+  Where:
+  name: Self-descriptive name used to uniquely identify the test
+  build_path: File system path, relative to Android build root, to this
+     package's Android.mk file. By convention the name of a test starts with
+     'test_'.
+  continuous: Optional boolean. Default is false. Set to true if tests are known
+     to be reliable, and should be included in a continuous test system.
+     false if they are under development.
+  description: Optional string. Default is empty. Short description (typically
+     less than 60 characters) about this test.
+  extra_make_args: Optional string. Default is empty. Some test module require
+     extra make arguments to build. This string is append to the make command.
+
+  These attributes map to the following commands:
+    make <build_path>/Android.mk <extra_make_args>
+    adb sync
+    for test_prog in <tests built>; do
+      adb shell "/system/bin/${test_prog} >/dev/null 2>&1;echo \$?"
+      adb shell "rm /system/bin/${test_prog}"
+    done
 -->
 
 <test-definitions version="1">
@@ -222,4 +257,11 @@
     coverage_target="Settings" />
 -->
 
+<!--  native tests  -->
+<test-native name="libstdcpp"
+    build_path="system/extras/tests/bionic/libstdc++"
+    description="Bionic libstdc++."
+    extra_make_args="BIONIC_TESTS=1" />
+
+
 </test-definitions>
diff --git a/tools/androidprefs/.gitignore b/tools/androidprefs/.gitignore
new file mode 100644
index 0000000..fe99505
--- /dev/null
+++ b/tools/androidprefs/.gitignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/tools/anttasks/.gitignore b/tools/anttasks/.gitignore
new file mode 100644
index 0000000..fe99505
--- /dev/null
+++ b/tools/anttasks/.gitignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/tools/apkbuilder/.gitignore b/tools/apkbuilder/.gitignore
new file mode 100644
index 0000000..fe99505
--- /dev/null
+++ b/tools/apkbuilder/.gitignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/tools/ddms/.gitignore b/tools/ddms/.gitignore
new file mode 100644
index 0000000..6d833a0
--- /dev/null
+++ b/tools/ddms/.gitignore
@@ -0,0 +1,4 @@
+app/bin
+libs/ddmlib/bin
+libs/ddmuilib/bin
+
diff --git a/tools/ddms/app/src/com/android/ddms/Main.java b/tools/ddms/app/src/com/android/ddms/Main.java
index d63b884..d545ed9 100644
--- a/tools/ddms/app/src/com/android/ddms/Main.java
+++ b/tools/ddms/app/src/com/android/ddms/Main.java
@@ -78,7 +78,7 @@
         // the "ping" argument means to check in with the server and exit
         // the application name and version number must also be supplied
         if (args.length >= 3 && args[0].equals("ping")) {
-            SdkStatsService.ping(args[1], args[2]);
+            SdkStatsService.ping(args[1], args[2], null);
             return;
         } else if (args.length > 0) {
             Log.e("ddms", "Unknown argument: " + args[0]);
@@ -86,7 +86,7 @@
         }
 
         // ddms itself is wanted: send a ping for ourselves
-        SdkStatsService.ping("ddms", VERSION);  //$NON-NLS-1$
+        SdkStatsService.ping("ddms", VERSION, null);  //$NON-NLS-1$
 
         DebugPortManager.setProvider(DebugPortProvider.getInstance());
 
diff --git a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java
index 795bf88..0957171 100644
--- a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java
+++ b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java
@@ -194,6 +194,7 @@
         HandleThread.register(monitorThread);
         HandleHeap.register(monitorThread);
         HandleWait.register(monitorThread);
+        HandleProfiling.register(monitorThread);
     }
 
     /**
diff --git a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java
index 5752b86..5111638 100644
--- a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java
+++ b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHeap.java
@@ -32,6 +32,7 @@
     public static final int CHUNK_HPEN = type("HPEN");
     public static final int CHUNK_HPSG = type("HPSG");
     public static final int CHUNK_HPGC = type("HPGC");
+    public static final int CHUNK_HPDU = type("HPDU");
     public static final int CHUNK_REAE = type("REAE");
     public static final int CHUNK_REAQ = type("REAQ");
     public static final int CHUNK_REAL = type("REAL");
@@ -98,6 +99,8 @@
             client.update(Client.CHANGE_HEAP_DATA);
         } else if (type == CHUNK_HPSG) {
             handleHPSG(client, data);
+        } else if (type == CHUNK_HPDU) {
+            handleHPDU(client, data);
         } else if (type == CHUNK_REAQ) {
             handleREAQ(client, data);
             client.update(Client.CHANGE_HEAP_ALLOCATION_STATUS);
@@ -221,6 +224,44 @@
     }
 
     /**
+     * Sends an HPDU request to the client.
+     *
+     * We will get an HPDU response when the heap dump has completed.  On
+     * failure we get a generic failure response.
+     *
+     * @param fileName name of output file (on device)
+     */
+    public static void sendHPDU(Client client, String fileName)
+        throws IOException {
+        ByteBuffer rawBuf = allocBuffer(4 + fileName.length() * 2);
+        JdwpPacket packet = new JdwpPacket(rawBuf);
+        ByteBuffer buf = getChunkDataBuf(rawBuf);
+
+        buf.putInt(fileName.length());
+        putString(buf, fileName);
+
+        finishChunkPacket(packet, CHUNK_HPDU, buf.position());
+        Log.d("ddm-heap", "Sending " + name(CHUNK_HPDU) + " '" + fileName +"'");
+        client.sendAndConsume(packet, mInst);
+    }
+
+    /*
+     * Handle notification of completion of a HeaP DUmp.
+     */
+    private void handleHPDU(Client client, ByteBuffer data) {
+        byte result;
+
+        result = data.get();
+
+        if (result == 0) {
+            Log.i("ddm-heap", "Heap dump request has finished");
+            // TODO: stuff
+        } else {
+            Log.w("ddm-heap", "Heap dump request failed (check device log)");
+        }
+    }
+
+    /**
      * Sends a REAE (REcent Allocation Enable) request to the client.
      */
     public static void sendREAE(Client client, boolean enable)
diff --git a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHello.java b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHello.java
index 5ba5aeb..fb9697c 100644
--- a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHello.java
+++ b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleHello.java
@@ -20,11 +20,12 @@
 import java.nio.ByteBuffer;
 
 /**
- * Handle the "hello" chunk (HELO).
+ * Handle the "hello" chunk (HELO) and feature discovery.
  */
 final class HandleHello extends ChunkHandler {
 
     public static final int CHUNK_HELO = ChunkHandler.type("HELO");
+    public static final int CHUNK_FEAT = ChunkHandler.type("FEAT");
 
     private static final HandleHello mInst = new HandleHello();
 
@@ -65,6 +66,8 @@
         if (type == CHUNK_HELO) {
             assert isReply;
             handleHELO(client, data);
+        } else if (type == CHUNK_FEAT) {
+            handleFEAT(client, data);
         } else {
             handleUnknownChunk(client, type, data, isReply, msgId);
         }
@@ -126,5 +129,37 @@
             + " ID=0x" + Integer.toHexString(packet.getId()));
         client.sendAndConsume(packet, mInst);
     }
+
+    /**
+     * Handle a reply to our FEAT request.
+     */
+    private static void handleFEAT(Client client, ByteBuffer data) {
+        int featureCount;
+        int i;
+
+        featureCount = data.getInt();
+        for (i = 0; i < featureCount; i++) {
+            int len = data.getInt();
+            String feature = getString(data, len);
+
+            Log.d("ddm-hello", "Feature: " + feature);
+        }
+    }
+
+    /**
+     * Send a FEAT request to the client.
+     */
+    public static void sendFEAT(Client client) throws IOException {
+        ByteBuffer rawBuf = allocBuffer(0);
+        JdwpPacket packet = new JdwpPacket(rawBuf);
+        ByteBuffer buf = getChunkDataBuf(rawBuf);
+
+        // no data
+
+        finishChunkPacket(packet, CHUNK_FEAT, buf.position());
+        Log.d("ddm-heap", "Sending " + name(CHUNK_FEAT));
+        client.sendAndConsume(packet, mInst);
+    }
+
 }
 
diff --git a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java
new file mode 100644
index 0000000..e8e8103
--- /dev/null
+++ b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2009 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.ddmlib;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Handle heap status updates.
+ */
+final class HandleProfiling extends ChunkHandler {
+
+    public static final int CHUNK_MPRS = type("MPRS");
+    public static final int CHUNK_MPRE = type("MPRE");
+    public static final int CHUNK_MPRQ = type("MPRQ");
+
+    private static final HandleProfiling mInst = new HandleProfiling();
+
+    private HandleProfiling() {}
+
+    /**
+     * Register for the packets we expect to get from the client.
+     */
+    public static void register(MonitorThread mt) {
+        mt.registerChunkHandler(CHUNK_MPRE, mInst);
+        mt.registerChunkHandler(CHUNK_MPRQ, mInst);
+    }
+
+    /**
+     * Client is ready.
+     */
+    @Override
+    public void clientReady(Client client) throws IOException {}
+
+    /**
+     * Client went away.
+     */
+    @Override
+    public void clientDisconnected(Client client) {}
+
+    /**
+     * Chunk handler entry point.
+     */
+    @Override
+    public void handleChunk(Client client, int type, ByteBuffer data,
+        boolean isReply, int msgId) {
+
+        Log.d("ddm-prof", "handling " + ChunkHandler.name(type));
+
+        if (type == CHUNK_MPRE) {
+            handleMPRE(client, data);
+        } else if (type == CHUNK_MPRQ) {
+            handleMPRQ(client, data);
+        } else {
+            handleUnknownChunk(client, type, data, isReply, msgId);
+        }
+    }
+
+    /**
+     * Send a MPRS (Method PRofiling Start) request to the client.
+     *
+     * @param fileName is the name of the file to which profiling data
+     *          will be written (on the device); it will have ".trace"
+     *          appended if necessary
+     * @param bufferSize is the desired buffer size in bytes (8MB is good)
+     * @param flags should be zero
+     */
+    public static void sendMPRS(Client client, String fileName, int bufferSize,
+        int flags) throws IOException {
+
+        ByteBuffer rawBuf = allocBuffer(3*4 + fileName.length() * 2);
+        JdwpPacket packet = new JdwpPacket(rawBuf);
+        ByteBuffer buf = getChunkDataBuf(rawBuf);
+
+        buf.putInt(bufferSize);
+        buf.putInt(flags);
+        buf.putInt(fileName.length());
+        putString(buf, fileName);
+
+        finishChunkPacket(packet, CHUNK_MPRS, buf.position());
+        Log.d("ddm-prof", "Sending " + name(CHUNK_MPRS) + " '" + fileName
+            + "', size=" + bufferSize + ", flags=" + flags);
+        client.sendAndConsume(packet, mInst);
+    }
+
+    /**
+     * Send a MPRE (Method PRofiling End) request to the client.
+     */
+    public static void sendMPRE(Client client) throws IOException {
+        ByteBuffer rawBuf = allocBuffer(0);
+        JdwpPacket packet = new JdwpPacket(rawBuf);
+        ByteBuffer buf = getChunkDataBuf(rawBuf);
+
+        // no data
+
+        finishChunkPacket(packet, CHUNK_MPRE, buf.position());
+        Log.d("ddm-prof", "Sending " + name(CHUNK_MPRE));
+        client.sendAndConsume(packet, mInst);
+    }
+
+    /**
+     * Handle notification that method profiling has finished writing
+     * data to disk.
+     */
+    private void handleMPRE(Client client, ByteBuffer data) {
+        byte result;
+
+        result = data.get();
+
+        if (result == 0) {
+            Log.i("ddm-prof", "Method profiling has finished");
+        } else {
+            Log.w("ddm-prof", "Method profiling has failed (check device log)");
+        }
+
+        // TODO: stuff
+    }
+
+    /**
+     * Send a MPRQ (Method PRofiling Query) request to the client.
+     */
+    public static void sendMPRQ(Client client) throws IOException {
+        ByteBuffer rawBuf = allocBuffer(0);
+        JdwpPacket packet = new JdwpPacket(rawBuf);
+        ByteBuffer buf = getChunkDataBuf(rawBuf);
+
+        // no data
+
+        finishChunkPacket(packet, CHUNK_MPRQ, buf.position());
+        Log.d("ddm-prof", "Sending " + name(CHUNK_MPRQ));
+        client.sendAndConsume(packet, mInst);
+    }
+
+    /**
+     * Receive response to query.
+     */
+    private void handleMPRQ(Client client, ByteBuffer data) {
+        byte result;
+
+        result = data.get();
+
+        if (result == 0) {
+            Log.i("ddm-prof", "Method profiling is not running");
+        } else {
+            Log.i("ddm-prof", "Method profiling is running");
+        }
+    }
+}
+
diff --git a/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml
index e7cffea..1c4a043 100644
--- a/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml
+++ b/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="com.android.ide.eclipse.adt"
       label="Android Development Tools"
-      version="0.9.0.qualifier"
+      version="0.9.1.qualifier"
       provider-name="The Android Open Source Project"
       plugin="com.android.ide.eclipse.adt">
 
diff --git a/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml
index 00805e4..ae3944b 100644
--- a/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml
+++ b/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="com.android.ide.eclipse.ddms"
       label="Android DDMS"
-      version="0.9.0.qualifier"
+      version="0.9.1.qualifier"
       provider-name="The Android Open Source Project">
 
    <description>
diff --git a/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml
index 2a3a74f..b88f071 100644
--- a/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml
+++ b/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="com.android.ide.eclipse.tests"
       label="ADT Tests"
-      version="0.9.0.qualifier"
+      version="0.9.1.qualifier"
       provider-name="The Android Open Source Project">
 
    <copyright>
diff --git a/tools/eclipse/plugins/.gitignore b/tools/eclipse/plugins/.gitignore
new file mode 100644
index 0000000..2842bb1
--- /dev/null
+++ b/tools/eclipse/plugins/.gitignore
@@ -0,0 +1,52 @@
+com.android.ide.eclipse.adt/bin
+com.android.ide.eclipse.ddms/bin
+com.android.ide.eclipse.tests/bin
+
+com.android.ide.eclipse.adt/androidprefs.jar
+com.android.ide.eclipse.adt/jarutils.jar
+com.android.ide.eclipse.adt/kxml2-2.3.0.jar
+com.android.ide.eclipse.adt/layoutlib_api.jar
+com.android.ide.eclipse.adt/layoutlib_utils.jar
+com.android.ide.eclipse.adt/ninepatch.jar
+com.android.ide.eclipse.adt/sdklib.jar
+com.android.ide.eclipse.adt/sdkstats.jar
+com.android.ide.eclipse.adt/sdkuilib.jar
+com.android.ide.eclipse.ddms/icons/add.png
+com.android.ide.eclipse.ddms/icons/backward.png
+com.android.ide.eclipse.ddms/icons/clear.png
+com.android.ide.eclipse.ddms/icons/d.png
+com.android.ide.eclipse.ddms/icons/debug-attach.png
+com.android.ide.eclipse.ddms/icons/debug-error.png
+com.android.ide.eclipse.ddms/icons/debug-wait.png
+com.android.ide.eclipse.ddms/icons/delete.png
+com.android.ide.eclipse.ddms/icons/device.png
+com.android.ide.eclipse.ddms/icons/down.png
+com.android.ide.eclipse.ddms/icons/e.png
+com.android.ide.eclipse.ddms/icons/edit.png
+com.android.ide.eclipse.ddms/icons/empty.png
+com.android.ide.eclipse.ddms/icons/emulator.png
+com.android.ide.eclipse.ddms/icons/forward.png
+com.android.ide.eclipse.ddms/icons/gc.png
+com.android.ide.eclipse.ddms/icons/halt.png
+com.android.ide.eclipse.ddms/icons/heap.png
+com.android.ide.eclipse.ddms/icons/i.png
+com.android.ide.eclipse.ddms/icons/importBug.png
+com.android.ide.eclipse.ddms/icons/load.png
+com.android.ide.eclipse.ddms/icons/pause.png
+com.android.ide.eclipse.ddms/icons/play.png
+com.android.ide.eclipse.ddms/icons/pull.png
+com.android.ide.eclipse.ddms/icons/push.png
+com.android.ide.eclipse.ddms/icons/save.png
+com.android.ide.eclipse.ddms/icons/thread.png
+com.android.ide.eclipse.ddms/icons/up.png
+com.android.ide.eclipse.ddms/icons/v.png
+com.android.ide.eclipse.ddms/icons/w.png
+com.android.ide.eclipse.ddms/icons/warning.png
+com.android.ide.eclipse.ddms/libs/jcommon-1.0.12.jar
+com.android.ide.eclipse.ddms/libs/jfreechart-1.0.9-swt.jar
+com.android.ide.eclipse.ddms/libs/jfreechart-1.0.9.jar
+com.android.ide.eclipse.ddms/src/com/android/ddmlib
+com.android.ide.eclipse.ddms/src/com/android/ddmuilib
+com.android.ide.eclipse.tests/kxml2-2.3.0.jar
+com.android.ide.eclipse.tests/unittests/com/android/ddmlib
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath b/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
index a24fc87..9898b97 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
@@ -5,7 +5,7 @@
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="lib" path="jarutils.jar"/>
 	<classpathentry kind="lib" path="androidprefs.jar"/>
-	<classpathentry kind="lib" path="sdkstats.jar"/>
+	<classpathentry kind="lib" path="sdkstats.jar" sourcepath="/SdkStatsService"/>
 	<classpathentry kind="lib" path="kxml2-2.3.0.jar"/>
 	<classpathentry kind="lib" path="layoutlib_api.jar"/>
 	<classpathentry kind="lib" path="layoutlib_utils.jar"/>
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
index 8092f3a..7d52bb6 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: Android Development Toolkit
 Bundle-SymbolicName: com.android.ide.eclipse.adt;singleton:=true
-Bundle-Version: 0.9.0.qualifier
+Bundle-Version: 0.9.1.qualifier
 Bundle-ClassPath: .,
  jarutils.jar,
  androidprefs.jar,
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index 19cd509..6022a20 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -98,7 +98,7 @@
       <wizard
             canFinishEarly="false"
             category="com.android.ide.eclipse.wizards.category"
-            class="com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileWizard"
+            class="com.android.ide.eclipse.editors.wizards.NewXmlFileWizard"
             finalPerspective="org.eclipse.jdt.ui.JavaPerspective"
             hasPages="true"
             icon="icons/android.png"
@@ -220,7 +220,7 @@
                value="com.android.ide.eclipse.adt.AndroidNature">
          </filter>
          <action
-               class="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileWizardAction"
+               class="com.android.ide.eclipse.adt.project.NewXmlFileWizardAction"
                enablesFor="1"
                id="com.android.ide.eclipse.adt.project.NewXmlFileWizardAction"
                label="New Resource File..."
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index b5cee81..8ef0f2c 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -31,7 +31,6 @@
 import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
 import com.android.ide.eclipse.adt.ui.EclipseUiHelper;
 import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.common.SdkStatsHelper;
 import com.android.ide.eclipse.common.StreamHelper;
 import com.android.ide.eclipse.common.project.BaseProjectHelper;
 import com.android.ide.eclipse.common.project.ExportHelper;
@@ -51,6 +50,7 @@
 import com.android.ide.eclipse.editors.xml.XmlEditor;
 import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.SdkConstants;
+import com.android.sdkstats.SdkStatsService;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
@@ -983,13 +983,7 @@
             @Override
             protected IStatus run(IProgressMonitor monitor) {
                 try {
-
-                    // get the version of the plugin
-                    String versionString = (String) getBundle().getHeaders().get(
-                            Constants.BUNDLE_VERSION);
-                    Version version = new Version(versionString);
-                    
-                    SdkStatsHelper.pingUsageServer("adt", version); //$NON-NLS-1$
+                    pingUsageServer(); //$NON-NLS-1$
                     
                     return Status.OK_STATUS;
                 } catch (Throwable t) {
@@ -1389,4 +1383,22 @@
     public static synchronized OutputStream getErrorStream() {
         return sPlugin.mAndroidConsoleErrorStream;
     }
+
+    /**
+     * Pings the usage start server.
+     * @param pluginName the name of the plugin to appear in the stats
+     * @param pluginVersion the {@link Version} of the plugin.
+     */
+    private void pingUsageServer() {
+        // get the version of the plugin
+        String versionString = (String) getBundle().getHeaders().get(
+                Constants.BUNDLE_VERSION);
+        Version version = new Version(versionString);
+
+        versionString = String.format("%1$d.%2$d.%3$d", version.getMajor(), //$NON-NLS-1$
+                version.getMinor(), version.getMicro());
+
+        SdkStatsService.ping("adt", versionString, getDisplay()); //$NON-NLS-1$
+    }
+
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
index 47ea3e7..2121fa6 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
@@ -907,6 +907,21 @@
             AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
             markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
             return false;
+        } catch (Exception e) {
+            // try to catch other exception to actually display an error. This will be useful
+            // if we get an NPE or something so that we can at least notify the user that something
+            // went wrong (otherwise the build appears to succeed but the zip archive is not closed
+            // and therefore invalid.
+            String msg = e.getMessage();
+            if (msg == null) {
+                msg = e.getClass().getCanonicalName();
+            }
+            
+            msg = String.format("Unknown error: %1$s", msg);
+            AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
+            markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
+            return false;
+            
         } finally {
             if (fos != null) {
                 try {
@@ -943,7 +958,8 @@
             IPath path = resource.getFullPath();
 
             // check the extension.
-            if (path.getFileExtension().equalsIgnoreCase(AndroidConstants.EXT_NATIVE_LIB)) {
+            String ext = path.getFileExtension();
+            if (ext != null && ext.equalsIgnoreCase(AndroidConstants.EXT_NATIVE_LIB)) {
                 // remove the first segment to build the path inside the archive.
                 path = path.removeFirstSegments(rootSegmentCount);
                 
@@ -954,7 +970,8 @@
                 // writes the file in the apk.
                 jarBuilder.writeFile(resource.getLocation().toFile(), apkPath.toString());
             }
-        } else if (resource.getType() == IResource.FOLDER) {
+        } else if (resource.getType() == IResource.FOLDER &&
+                checkFolderForPackaging((IFolder)resource)) {
             IResource[] members = ((IFolder)resource).members();
             for (IResource member : members) {
                 writeNativeLibraries(rootSegmentCount, jarBuilder, member);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
index df023b8..e56f27e 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
@@ -271,8 +271,7 @@
             // if there was some XML errors, we just return w/o doing
             // anything since we've put some markers in the files anyway.
             if (dv != null && dv.mXmlError) {
-                AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
-                        Messages.Xml_Error);
+                AdtPlugin.printErrorToConsole(project, Messages.Xml_Error);
     
                 // This interrupts the build. The next builders will not run.
                 stopBuild(Messages.Xml_Error);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/SdkStatsHelper.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/SdkStatsHelper.java
deleted file mode 100644
index 345c663..0000000
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/SdkStatsHelper.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
- *
- * 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.ide.eclipse.common;
-
-import com.android.sdkstats.SdkStatsService;
-
-import org.osgi.framework.Version;
-
-/**
- * Helper class to access the ping usage stat server.
- */
-public class SdkStatsHelper {
-
-    /**
-     * Pings the usage start server.
-     * @param pluginName the name of the plugin to appear in the stats
-     * @param pluginVersion the {@link Version} of the plugin.
-     */
-    public static void pingUsageServer(String pluginName, Version pluginVersion) {
-        String versionString = String.format("%1$d.%2$d.%3$d", pluginVersion.getMajor(),
-                pluginVersion.getMinor(), pluginVersion.getMicro());
-
-        SdkStatsService.ping(pluginName, versionString);
-    }
-}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
index 3b5c823..cd02e27 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
@@ -334,10 +334,12 @@
                                 value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION,
                                         true /* hasNamespace */);
                                 
-                                try {
-                                    mApiLevelRequirement = Integer.parseInt(value);
-                                } catch (NumberFormatException e) {
-                                    handleError(e, -1 /* lineNumber */);
+                                if (value != null) {
+                                    try {
+                                        mApiLevelRequirement = Integer.parseInt(value);
+                                    } catch (NumberFormatException e) {
+                                        handleError(e, -1 /* lineNumber */);
+                                    }
                                 }
                             } else if (NODE_INSTRUMENTATION.equals(localName)) {
                                 processInstrumentationNode(attributes);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java
index 1810ad2..589e70b 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java
@@ -109,17 +109,22 @@
             mErrorListener.errorFound();
         }
         
+        String message = exception.getMessage();
+        if (message == null) {
+            message = "Unknown error " + exception.getClass().getCanonicalName();
+        }
+        
         if (mFile != null) {
             if (lineNumber != -1) {
                 BaseProjectHelper.addMarker(mFile,
                         AndroidConstants.MARKER_XML,
-                        exception.getMessage(),
+                        message,
                         lineNumber,
                         IMarker.SEVERITY_ERROR);
             } else {
                 BaseProjectHelper.addMarker(mFile,
                         AndroidConstants.MARKER_XML,
-                        exception.getMessage(),
+                        message,
                         IMarker.SEVERITY_ERROR);
             }
         }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF
index 09b8085..2488fd1 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: Dalvik Debug Monitor Service
 Bundle-SymbolicName: com.android.ide.eclipse.ddms;singleton:=true
-Bundle-Version: 0.9.0.qualifier
+Bundle-Version: 0.9.1.qualifier
 Bundle-Activator: com.android.ide.eclipse.ddms.DdmsPlugin
 Bundle-Vendor: The Android Open Source Project
 Bundle-Localization: plugin
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF
index c7f5ba8..22cda71 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: Android Plugin Tests
 Bundle-SymbolicName: com.android.ide.eclipse.tests
-Bundle-Version: 0.9.0.qualifier
+Bundle-Version: 0.9.1.qualifier
 Bundle-Activator: com.android.ide.eclipse.tests.AndroidTestPlugin
 Require-Bundle: org.eclipse.ui,
  org.eclipse.core.runtime,
diff --git a/tools/eclipse/sites/external/site.xml b/tools/eclipse/sites/external/site.xml
index 9fca8d2..404abe5 100644
--- a/tools/eclipse/sites/external/site.xml
+++ b/tools/eclipse/sites/external/site.xml
@@ -3,10 +3,10 @@
    <description url="https://dl-ssl.google.com/android/eclipse/">
       Update Site for Android Development Toolkit
    </description>
-   <feature url="features/com.android.ide.eclipse.adt_0.9.0.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.0.qualifier">
+   <feature url="features/com.android.ide.eclipse.adt_0.9.1.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.1.qualifier">
       <category name="developer"/>
    </feature>
-   <feature url="features/com.android.ide.eclipse.ddms_0.9.0.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.0.qualifier">
+   <feature url="features/com.android.ide.eclipse.ddms_0.9.1.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.1.qualifier">
       <category name="developer"/>
    </feature>
    <category-def name="developer" label="Developer Tools">
diff --git a/tools/eclipse/sites/internal/site.xml b/tools/eclipse/sites/internal/site.xml
index 9f2642f..b53af92 100644
--- a/tools/eclipse/sites/internal/site.xml
+++ b/tools/eclipse/sites/internal/site.xml
@@ -3,13 +3,13 @@
    <description url="https://android.corp.google.com/adt/">
       Update Site for Android Development Toolkit
    </description>
-   <feature url="features/com.android.ide.eclipse.adt_0.9.0.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.0.qualifier">
+   <feature url="features/com.android.ide.eclipse.adt_0.9.1.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.1.qualifier">
       <category name="developer"/>
    </feature>
-   <feature url="features/com.android.ide.eclipse.ddms_0.9.0.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.0.qualifier">
+   <feature url="features/com.android.ide.eclipse.ddms_0.9.1.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.1.qualifier">
       <category name="developer"/>
    </feature>
-   <feature url="features/com.android.ide.eclipse.tests_0.9.0.qualifier.jar" id="com.android.ide.eclipse.tests" version="0.9.0.qualifier">
+   <feature url="features/com.android.ide.eclipse.tests_0.9.1.qualifier.jar" id="com.android.ide.eclipse.tests" version="0.9.1.qualifier">
       <category name="test"/>
    </feature>
    <category-def name="developer" label="Application Developer Tools">
diff --git a/tools/jarutils/.gitignore b/tools/jarutils/.gitignore
new file mode 100644
index 0000000..fe99505
--- /dev/null
+++ b/tools/jarutils/.gitignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/tools/layoutlib_utils/.gitignore b/tools/layoutlib_utils/.gitignore
new file mode 100644
index 0000000..fe99505
--- /dev/null
+++ b/tools/layoutlib_utils/.gitignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java
index 8a8a677..77a6401 100755
--- a/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java
+++ b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java
@@ -96,6 +96,7 @@
             parser.parse(new File(filename), new DefaultHandler() {
                 boolean inWord;
                 int freq;
+                StringBuilder wordBuilder = new StringBuilder(48);
 
                 @Override
                 public void startElement(String uri, String localName,
@@ -103,6 +104,7 @@
                     if (qName.equals("w")) {
                         inWord = true;
                         freq = Integer.parseInt(attributes.getValue(0));
+                        wordBuilder.setLength(0);
                     }
                 }
 
@@ -110,18 +112,19 @@
                 public void characters(char[] data, int offset, int length) {
                     // Ignore other whitespace
                     if (!inWord) return;
-                    
-                    // Ignore one letter words
-                    if (length < 2) return;
-                    mWordCount++;
-                    String word = new String(data, offset, length);
-                    addWordTop(word, freq);
+                    wordBuilder.append(data, offset, length);
                 }
 
                 @Override
                 public void endElement(String uri, String localName,
                         String qName) {
-                    if (qName.equals("w")) inWord = false;
+                    if (qName.equals("w")) {
+                        if (wordBuilder.length() > 1) {
+                            addWordTop(wordBuilder.toString(), freq);
+                            mWordCount++;
+                        }
+                        inWord = false;
+                    }
                 }
             });
         } catch (Exception ioe) {
@@ -145,7 +148,6 @@
 
     private void addWordTop(String word, int occur) {
         if (occur > 255) occur = 255;
-
         char firstChar = word.charAt(0);
         int index = indexOf(roots, firstChar);
         if (index == -1) {
diff --git a/tools/mkstubs/.classpath b/tools/mkstubs/.classpath
index a6b4c47..49a6d6c 100644
--- a/tools/mkstubs/.classpath
+++ b/tools/mkstubs/.classpath
@@ -1,9 +1,9 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="src" path="tests"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/asm3"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>

+<classpath>

+	<classpathentry kind="src" path="src"/>

+	<classpathentry kind="src" path="tests"/>

+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>

+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>

+	<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/asm/asm-3.1.jar"/>

+	<classpathentry kind="output" path="bin"/>

+</classpath>

diff --git a/tools/mkstubs/.gitignore b/tools/mkstubs/.gitignore
new file mode 100644
index 0000000..fe99505
--- /dev/null
+++ b/tools/mkstubs/.gitignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/tools/mkstubs/.project b/tools/mkstubs/.project
index bef013e..12944f4 100644
--- a/tools/mkstubs/.project
+++ b/tools/mkstubs/.project
@@ -1,18 +1,17 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>MkStubs</name>
-	<comment></comment>
-	<projects>
-		<project>asm3</project>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-</projectDescription>
+<?xml version="1.0" encoding="UTF-8"?>

+<projectDescription>

+	<name>MkStubs</name>

+	<comment></comment>

+	<projects>

+	</projects>

+	<buildSpec>

+		<buildCommand>

+			<name>org.eclipse.jdt.core.javabuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+	</buildSpec>

+	<natures>

+		<nature>org.eclipse.jdt.core.javanature</nature>

+	</natures>

+</projectDescription>

diff --git a/tools/sdkmanager/.gitignore b/tools/sdkmanager/.gitignore
new file mode 100644
index 0000000..48f206a
--- /dev/null
+++ b/tools/sdkmanager/.gitignore
@@ -0,0 +1,4 @@
+app/bin
+libs/sdklib/bin
+libs/sdkuilib/bin
+
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
index fc9a2be..35d9bb1 100644
--- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -454,16 +454,18 @@
                 
                 // display some extra values.
                 Map<String, String> properties = info.getProperties();
-                String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME);
-                if (skin != null) {
-                    mSdkLog.printf("    Skin: %s\n", skin);
-                }
-                String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE);
-                if (sdcard == null) {
-                    sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH);
-                }
-                if (sdcard != null) {
-                    mSdkLog.printf("  Sdcard: %s\n", sdcard);
+                if (properties != null) {
+                    String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME);
+                    if (skin != null) {
+                        mSdkLog.printf("    Skin: %s\n", skin);
+                    }
+                    String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE);
+                    if (sdcard == null) {
+                        sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH);
+                    }
+                    if (sdcard != null) {
+                        mSdkLog.printf("  Sdcard: %s\n", sdcard);
+                    }
                 }
             }
 
@@ -508,7 +510,7 @@
         }
 
         try {
-            boolean removePrevious = false;
+            boolean removePrevious = mSdkCommandLine.getFlagForce();
             AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
 
             String avdName = mSdkCommandLine.getParamName();
@@ -522,8 +524,7 @@
             
             AvdInfo info = avdManager.getAvd(avdName, false /*validAvdOnly*/);
             if (info != null) {
-                if (mSdkCommandLine.getFlagForce()) {
-                    removePrevious = true;
+                if (removePrevious) {
                     mSdkLog.warning(
                             "Android Virtual Device '%s' already exists and will be replaced.",
                             avdName);
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
index 1936f8a..23b2f26 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
@@ -185,7 +185,7 @@
          * @param targetHash the target hash
          * @param target The target. Can be null, if the target was not resolved.
          * @param properties The property map. Can be null.
-         * @param error The error describing why this AVD is invalid. Cannot be null.
+         * @param status The {@link AvdStatus} of this AVD. Cannot be null.
          */
         public AvdInfo(String name, String path, String targetHash, IAndroidTarget target,
                 Map<String, String> properties, AvdStatus status) {
@@ -193,7 +193,7 @@
             mPath = path;
             mTargetHash = targetHash;
             mTarget = target;
-            mProperties = Collections.unmodifiableMap(properties);
+            mProperties = properties == null ? null : Collections.unmodifiableMap(properties);
             mStatus = status;
         }
 
@@ -214,7 +214,7 @@
             return mTargetHash;
         }
 
-        /** Returns the target of the AVD, or <code>null</code> if it has not been resolved */
+        /** Returns the target of the AVD, or <code>null</code> if it has not been resolved. */
         public IAndroidTarget getTarget() {
             return mTarget;
         }
@@ -257,7 +257,7 @@
         }
 
         /**
-         * Returns a map of properties for the AVD.
+         * Returns an unmodifiable map of properties for the AVD. This can be null.
          */
         public Map<String, String> getProperties() {
             return mProperties;
@@ -1173,7 +1173,9 @@
 
         // create a new map
         Map<String, String> properties = new HashMap<String, String>();
-        properties.putAll(oldProperties);
+        if (oldProperties != null) {
+            properties.putAll(oldProperties);
+        }
         
         AvdStatus status;
         
diff --git a/tools/sdkstats/.gitignore b/tools/sdkstats/.gitignore
new file mode 100644
index 0000000..fe99505
--- /dev/null
+++ b/tools/sdkstats/.gitignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/tools/sdkstats/src/com/android/sdkstats/SdkStatsService.java b/tools/sdkstats/src/com/android/sdkstats/SdkStatsService.java
index 0b3d41b..688474e 100644
--- a/tools/sdkstats/src/com/android/sdkstats/SdkStatsService.java
+++ b/tools/sdkstats/src/com/android/sdkstats/SdkStatsService.java
@@ -110,8 +110,10 @@
      *
      * @param app name to report in the ping
      * @param version to report in the ping
+     * @param display an optional {@link Display} object to use, or null, if a new one should be
+     * created.
      */
-    public static void ping(final String app, final String version) {
+    public static void ping(final String app, final String version, final Display display) {
         // Validate the application and version input.
         final String normalVersion = normalizeVersion(app, version);
 
@@ -123,7 +125,7 @@
                 prefs.setValue(PING_ID, new Random().nextLong());
     
                 // Also give them a chance to opt out.
-                prefs.setValue(PING_OPT_IN, getUserPermission());
+                prefs.setValue(PING_OPT_IN, getUserPermission(display));
                 try {
                     prefs.save();
                 }
@@ -273,77 +275,90 @@
      * Prompt the user for whether they want to opt out of reporting.
      * @return whether the user allows reporting (they do not opt out).
      */
-    private static boolean getUserPermission() {
-        // Use dialog trim for the shell, but without a close button.
-        final Display display = new Display();
-        final Shell shell = new Shell(display, SWT.TITLE | SWT.BORDER);
-        shell.setText(WINDOW_TITLE_TEXT);
-        shell.setLayout(new GridLayout(1, false));  // 1 column
-
-        // Take the default font and scale it up for the title.
-        final Label title = new Label(shell, SWT.CENTER | SWT.WRAP);
-        final FontData[] fontdata = title.getFont().getFontData();
-        for (int i = 0; i < fontdata.length; i++) {
-            fontdata[i].setHeight(fontdata[i].getHeight() * 4 / 3);
-        }
-        title.setFont(new Font(display, fontdata));
-        title.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-        title.setText(HEADER_TEXT);
-
-        final Label notice = new Label(shell, SWT.WRAP);
-        notice.setFont(title.getFont());
-        notice.setForeground(new Color(display, 255, 0, 0));
-        notice.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-        notice.setText(NOTICE_TEXT);
-
-        final Link text = new Link(shell, SWT.WRAP);
-        text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-        text.setText(BODY_TEXT);
-        text.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent event) {
-                openUrl(event.text);
-            }
-        });
-
-        final Button checkbox = new Button(shell, SWT.CHECK);
-        checkbox.setSelection(true);  // Opt-in by default.
-        checkbox.setText(CHECKBOX_TEXT);
-
-        final Link footer = new Link(shell, SWT.WRAP);
-        footer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-        footer.setText(FOOTER_TEXT);
-
+    private static boolean getUserPermission(Display display) {
         // Whether the user gave permission (size-1 array for writing to).
         // Initialize to false, set when the user clicks the button.
         final boolean[] permission = new boolean[] { false };
 
-        final Button button = new Button(shell, SWT.PUSH);
-        button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
-        button.setText(BUTTON_TEXT);
-        button.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent event) {
-                permission[0] = checkbox.getSelection();
-                shell.close();
+        boolean dispose = false;
+        if (display == null) {
+            display = new Display();
+            dispose = true;
+        }
+
+        final Display currentDisplay = display;
+        final boolean disposeDisplay = dispose;
+
+        display.syncExec(new Runnable() {
+            public void run() {
+                final Shell shell = new Shell(currentDisplay, SWT.TITLE | SWT.BORDER);
+                shell.setText(WINDOW_TITLE_TEXT);
+                shell.setLayout(new GridLayout(1, false)); // 1 column
+
+                // Take the default font and scale it up for the title.
+                final Label title = new Label(shell, SWT.CENTER | SWT.WRAP);
+                final FontData[] fontdata = title.getFont().getFontData();
+                for (int i = 0; i < fontdata.length; i++) {
+                    fontdata[i].setHeight(fontdata[i].getHeight() * 4 / 3);
+                }
+                title.setFont(new Font(currentDisplay, fontdata));
+                title.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+                title.setText(HEADER_TEXT);
+
+                final Label notice = new Label(shell, SWT.WRAP);
+                notice.setFont(title.getFont());
+                notice.setForeground(new Color(currentDisplay, 255, 0, 0));
+                notice.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+                notice.setText(NOTICE_TEXT);
+
+                final Link text = new Link(shell, SWT.WRAP);
+                text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+                text.setText(BODY_TEXT);
+                text.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent event) {
+                        openUrl(event.text);
+                    }
+                });
+
+                final Button checkbox = new Button(shell, SWT.CHECK);
+                checkbox.setSelection(true); // Opt-in by default.
+                checkbox.setText(CHECKBOX_TEXT);
+
+                final Link footer = new Link(shell, SWT.WRAP);
+                footer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+                footer.setText(FOOTER_TEXT);
+
+                final Button button = new Button(shell, SWT.PUSH);
+                button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
+                button.setText(BUTTON_TEXT);
+                button.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent event) {
+                        permission[0] = checkbox.getSelection();
+                        shell.close();
+                    }
+                });
+
+                // Size the window to a fixed width, as high as necessary,
+                // centered.
+                final Point size = shell.computeSize(450, SWT.DEFAULT, true);
+                final Rectangle screen = currentDisplay.getClientArea();
+                shell.setBounds(screen.x + screen.width / 2 - size.x / 2, screen.y + screen.height
+                        / 2 - size.y / 2, size.x, size.y);
+
+                shell.open();
+                while (!shell.isDisposed()) {
+                    if (!currentDisplay.readAndDispatch())
+                        currentDisplay.sleep();
+                }
+
+                if (disposeDisplay) {
+                    currentDisplay.dispose();
+                }
             }
         });
 
-        // Size the window to a fixed width, as high as necessary, centered.
-        final Point size = shell.computeSize(450, SWT.DEFAULT, true);
-        final Rectangle screen = display.getClientArea();
-        shell.setBounds(
-            screen.x + screen.width / 2 - size.x / 2,
-            screen.y + screen.height / 2 - size.y / 2,
-            size.x, size.y);
-
-        shell.open();
-        while (!shell.isDisposed()) {
-            if (!display.readAndDispatch())
-                display.sleep();
-        }
-
-        display.dispose();  // Otherwise ddms' own Display can't be created
         return permission[0];
     }
 
diff --git a/tools/traceview/.gitignore b/tools/traceview/.gitignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/tools/traceview/.gitignore
@@ -0,0 +1 @@
+bin
diff --git a/tools/traceview/src/com/android/traceview/MainWindow.java b/tools/traceview/src/com/android/traceview/MainWindow.java
index b0c24e9..5800f81 100644
--- a/tools/traceview/src/com/android/traceview/MainWindow.java
+++ b/tools/traceview/src/com/android/traceview/MainWindow.java
@@ -133,7 +133,7 @@
         boolean regression = false;
         
         // ping the usage server
-        SdkStatsService.ping(PING_NAME, PING_VERSION);
+        SdkStatsService.ping(PING_NAME, PING_VERSION, null);
 
         // Process command line arguments
         int argc = 0;
diff --git a/tools/yuv420sp2rgb/Android.mk b/tools/yuv420sp2rgb/Android.mk
new file mode 100644
index 0000000..b7e7802
--- /dev/null
+++ b/tools/yuv420sp2rgb/Android.mk
@@ -0,0 +1,16 @@
+# Copyright 2005 Google Inc. All Rights Reserved.
+#
+# Android.mk for yuv420sp2rgb 
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifeq ($(TARGET_ARCH),arm)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := yuv420sp2rgb.c cmdline.c debug.c
+
+LOCAL_MODULE := yuv420sp2rgb
+
+include $(BUILD_HOST_EXECUTABLE)
+endif
diff --git a/tools/yuv420sp2rgb/cmdline.c b/tools/yuv420sp2rgb/cmdline.c
new file mode 100644
index 0000000..eb870b5
--- /dev/null
+++ b/tools/yuv420sp2rgb/cmdline.c
@@ -0,0 +1,147 @@
+#include <debug.h>
+#include <cmdline.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static struct option long_options[] = {
+    {"output",  required_argument, 0, 'o'},
+    {"height",  required_argument, 0, 'h'},
+    {"width",   required_argument, 0, 'w'},
+    {"gray",    no_argument,       0, 'g'},
+    {"type",    required_argument, 0, 't'},
+    {"rotate",  required_argument, 0, 'r'},
+    {"verbose", no_argument,       0, 'V'},
+    {"help",    no_argument,       0, 1},
+    {0, 0, 0, 0},
+};
+
+/* This array must parallel long_options[] */
+static const char *descriptions[] = {
+    "output file",
+    "image height in pixels",
+    "image width in pixels",
+    "process the luma plane only",
+    "encode as one of { 'ppm', 'rgb', or 'argb' }",
+    "rotate (90, -90, 180 degrees)",
+    "print verbose output",
+    "print this help screen",
+};
+
+void print_help(const char *name) {
+    fprintf(stdout,
+            "Converts yuv 4:2:0 to rgb24 and generates a PPM file.\n"
+            "invokation:\n"
+            "\t%s infile --height <height> --width <width> --output <outfile> -t <ppm|grb|argb> [ --gray ] [ --rotate <degrees> ] [ --verbose ]\n"
+            "\t%s infile --help\n",
+            name, name);
+    fprintf(stdout, "options:\n");
+    struct option *opt = long_options;
+    const char **desc = descriptions;
+    while (opt->name) {
+        fprintf(stdout, "\t-%c/--%s%s: %s\n",
+                isprint(opt->val) ? opt->val : ' ',
+                opt->name,
+                (opt->has_arg ? " (argument)" : ""),
+                *desc);
+        opt++;
+        desc++;
+    }
+}
+
+int get_options(int argc, char **argv,
+                char **outfile,
+                int *height,
+                int *width,
+                int *gray,
+                char **type,
+                int *rotate,
+                int *verbose) {
+    int c;
+
+    ASSERT(outfile); *outfile = NULL;
+    ASSERT(height); *height = -1;
+    ASSERT(width); *width = -1;
+    ASSERT(gray); *gray = 0;
+    ASSERT(rotate); *rotate = 0;
+    ASSERT(verbose); *verbose = 0;
+    ASSERT(type); *type = NULL;
+
+    while (1) {
+        /* getopt_long stores the option index here. */
+        int option_index = 0;
+
+        c = getopt_long (argc, argv,
+                         "Vgo:h:w:r:t:",
+                         long_options,
+                         &option_index);
+        /* Detect the end of the options. */
+        if (c == -1) break;
+
+        if (isgraph(c)) {
+            INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
+        }
+
+#define SET_STRING_OPTION(name) do {                                   \
+    ASSERT(optarg);                                                    \
+    (*name) = strdup(optarg);                                          \
+} while(0)
+
+#define SET_INT_OPTION(val) do {                                       \
+    ASSERT(optarg);                                                    \
+	if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \
+			FAILIF(1 != sscanf(optarg+2, "%x", val),                   \
+				   "Expecting a hexadecimal argument!\n");             \
+	} else {                                                           \
+		FAILIF(1 != sscanf(optarg, "%d", val),                         \
+			   "Expecting a decimal argument!\n");                     \
+	}                                                                  \
+} while(0)
+
+        switch (c) {
+        case 0:
+            /* If this option set a flag, do nothing else now. */
+            if (long_options[option_index].flag != 0)
+                break;
+            INFO ("option %s", long_options[option_index].name);
+            if (optarg)
+                INFO (" with arg %s", optarg);
+            INFO ("\n");
+            break;
+        case 1: print_help(argv[0]); exit(1); break;
+		case 'o':
+			SET_STRING_OPTION(outfile);
+			break;
+		case 't':
+			SET_STRING_OPTION(type);
+			break;
+        case 'h':
+            SET_INT_OPTION(height);
+            break;
+        case 'w':
+            SET_INT_OPTION(width);
+            break;
+        case 'r':
+            SET_INT_OPTION(rotate);
+            break;
+        case 'g': *gray = 1; break;
+        case 'V': *verbose = 1; break;
+        case '?':
+            /* getopt_long already printed an error message. */
+            break;
+
+#undef SET_STRING_OPTION
+#undef SET_INT_OPTION
+
+        default:
+            FAILIF(1, "Unknown option");
+        }
+    }
+
+    return optind;
+}
diff --git a/tools/yuv420sp2rgb/cmdline.h b/tools/yuv420sp2rgb/cmdline.h
new file mode 100644
index 0000000..49760ad
--- /dev/null
+++ b/tools/yuv420sp2rgb/cmdline.h
@@ -0,0 +1,15 @@
+#ifndef CMDLINE_H
+#define CMDLINE_H
+
+void print_help(const char *executable_name);
+
+extern int get_options(int argc, char **argv,
+                       char **outfile,
+                       int *height,
+                       int *width,
+                       int *gray,
+                       char **type,
+                       int *rotate,
+                       int *verbose);
+
+#endif/*CMDLINE_H*/
diff --git a/tools/yuv420sp2rgb/debug.c b/tools/yuv420sp2rgb/debug.c
new file mode 100644
index 0000000..263e09f
--- /dev/null
+++ b/tools/yuv420sp2rgb/debug.c
@@ -0,0 +1,38 @@
+#include <debug.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define NUM_COLS  (32)
+
+int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize) {
+    int num_nonprintable = 0;
+    int i, last;
+    char *pchr = (char *)b;
+    fputc('\n', s);
+    fprintf(s, "%p: ", b);
+    for (i = last = 0; i < len; i++) {
+        if (!elsize) {
+            if (i && !(i % 4)) fprintf(s, " ");
+            if (i && !(i % 8)) fprintf(s, " ");
+        } else {
+            if (i && !(i % elsize)) fprintf(s, " ");
+        }
+
+        if (i && !(i % NUM_COLS)) {
+            while (last < i) {
+                if (isprint(pchr[last]))
+                    fputc(pchr[last], s);
+                else {
+                    fputc('.', s); 
+                    num_nonprintable++;
+                }
+                last++;
+            }
+            fprintf(s, " (%d)\n%p: ", i, b);
+        }
+        fprintf(s, "%02x", (unsigned char)pchr[i]);
+    }
+    if (i && (i % NUM_COLS)) fputs("\n", s);
+    return num_nonprintable;
+}
+
diff --git a/tools/yuv420sp2rgb/debug.h b/tools/yuv420sp2rgb/debug.h
new file mode 100644
index 0000000..9bbf47f
--- /dev/null
+++ b/tools/yuv420sp2rgb/debug.h
@@ -0,0 +1,90 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define unlikely(expr) __builtin_expect (expr, 0)
+#define likely(expr)   __builtin_expect (expr, 1)
+
+#ifdef DEBUG
+
+    #define FAILIF(cond, msg...) do {                        \
+	if (unlikely(cond)) {                                \
+        fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \
+		fprintf(stderr, ##msg);                          \
+		exit(1);                                         \
+	}                                                    \
+} while(0)
+
+/* Debug enabled */
+    #define ASSERT(x) do {                                \
+	if (unlikely(!(x))) {                             \
+		fprintf(stderr,                               \
+				"ASSERTION FAILURE %s:%d: [%s]\n",    \
+				__FILE__, __LINE__, #x);              \
+		exit(1);                                      \
+	}                                                 \
+} while(0)
+
+#else
+
+    #define FAILIF(cond, msg...) do { \
+	if (unlikely(cond)) {         \
+		fprintf(stderr, ##msg);   \
+		exit(1);                  \
+	}                             \
+} while(0)
+
+/* No debug */
+    #define ASSERT(x)   do { } while(0)
+
+#endif/* DEBUG */
+
+#define FAILIF_LIBELF(cond, function) \
+    FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno()));
+
+static inline void *MALLOC(unsigned int size) {
+    void *m = malloc(size);
+    FAILIF(NULL == m, "malloc(%d) failed!\n", size);
+    return m;
+}
+
+static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) {
+    void *m = calloc(num_entries, entry_size);
+    FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size);
+    return m;
+}
+
+static inline void *REALLOC(void *ptr, unsigned int size) {
+    void *m = realloc(ptr, size);
+    FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size);
+    return m;
+}
+
+static inline void FREE(void *ptr) {
+    free(ptr);
+}
+
+static inline void FREEIF(void *ptr) {
+    if (ptr) FREE(ptr);
+}
+
+#define PRINT(x...)  do {                             \
+    extern int quiet_flag;                            \
+    if(likely(!quiet_flag))                           \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+#define ERROR PRINT
+
+#define INFO(x...)  do {                              \
+    extern int verbose_flag;                          \
+    if(unlikely(verbose_flag))                        \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */
+int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize);
+
+#endif/*DEBUG_H*/
diff --git a/tools/yuv420sp2rgb/yuv420sp2rgb.c b/tools/yuv420sp2rgb/yuv420sp2rgb.c
new file mode 100644
index 0000000..6fe82e5
--- /dev/null
+++ b/tools/yuv420sp2rgb/yuv420sp2rgb.c
@@ -0,0 +1,339 @@
+#include <stdio.h>
+#include <debug.h>
+#include <cmdline.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifndef max
+#define max(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; })
+#define min(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
+#endif
+
+#define CONVERT_TYPE_PPM 0
+#define CONVERT_TYPE_RGB 1
+#define CONVERT_TYPE_ARGB 2
+
+/*
+   YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved
+   U/V plane containing 8 bit 2x2 subsampled chroma samples.
+   except the interleave order of U and V is reversed.
+
+                        H V
+   Y Sample Period      1 1
+   U (Cb) Sample Period 2 2
+   V (Cr) Sample Period 2 2
+ */
+
+typedef struct rgb_context {
+    unsigned char *buffer;
+    int width;
+    int height;
+    int rotate;
+    int i;
+    int j;
+    int size; /* for debugging */
+} rgb_context;
+
+typedef void (*rgb_cb)(
+    unsigned char r,
+    unsigned char g,
+    unsigned char b,
+    rgb_context *ctx);
+
+const int bytes_per_pixel = 2;
+
+static void color_convert_common(
+    unsigned char *pY, unsigned char *pUV,
+    int width, int height,
+    unsigned char *buffer,
+    int size, /* buffer size in bytes */
+    int gray,
+    int rotate,
+    rgb_cb cb) 
+{
+	int i, j;
+	int nR, nG, nB;
+	int nY, nU, nV;
+    rgb_context ctx;
+
+    ctx.buffer = buffer;
+    ctx.size = size; /* debug */
+    ctx.width = width;
+    ctx.height = height;
+    ctx.rotate = rotate;
+
+    if (gray) {
+        for (i = 0; i < height; i++) {
+            for (j = 0; j < width; j++) {
+                nB = *(pY + i * width + j);
+                ctx.i = i;
+                ctx.j = j;
+                cb(nB, nB, nB, &ctx);
+            }
+        }	
+    } else {
+        // YUV 4:2:0
+        for (i = 0; i < height; i++) {
+            for (j = 0; j < width; j++) {
+                nY = *(pY + i * width + j);
+                nV = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
+                nU = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
+            
+                // Yuv Convert
+                nY -= 16;
+                nU -= 128;
+                nV -= 128;
+            
+                if (nY < 0)
+                    nY = 0;
+            
+                // nR = (int)(1.164 * nY + 2.018 * nU);
+                // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
+                // nB = (int)(1.164 * nY + 1.596 * nV);
+            
+                nB = (int)(1192 * nY + 2066 * nU);
+                nG = (int)(1192 * nY - 833 * nV - 400 * nU);
+                nR = (int)(1192 * nY + 1634 * nV);
+            
+                nR = min(262143, max(0, nR));
+                nG = min(262143, max(0, nG));
+                nB = min(262143, max(0, nB));
+            
+                nR >>= 10; nR &= 0xff;
+                nG >>= 10; nG &= 0xff;
+                nB >>= 10; nB &= 0xff;
+
+                ctx.i = i;
+                ctx.j = j;
+                cb(nR, nG, nB, &ctx);
+            }
+        }
+    }
+}   
+
+static void rgb16_cb(
+    unsigned char r,
+    unsigned char g,
+    unsigned char b,
+    rgb_context *ctx)
+{
+    unsigned short *rgb16 = (unsigned short *)ctx->buffer;
+    *(rgb16 + ctx->i * ctx->width + ctx->j) = b | (g << 5) | (r << 11);
+}
+
+static void common_rgb_cb(
+    unsigned char r,
+    unsigned char g,
+    unsigned char b,
+    rgb_context *ctx,
+    int alpha)
+{
+    unsigned char *out = ctx->buffer;
+    int offset = 0;
+    int bpp;
+    int i = 0;
+    switch(ctx->rotate) {
+    case 0: /* no rotation */
+        offset = ctx->i * ctx->width + ctx->j;
+        break;
+    case 1: /* 90 degrees */
+        offset = ctx->height * (ctx->j + 1) - ctx->i;
+        break;
+    case 2: /* 180 degrees */
+        offset = (ctx->height - 1 - ctx->i) * ctx->width + ctx->j;
+        break;
+    case 3: /* 270 degrees */
+        offset = (ctx->width - 1 - ctx->j) * ctx->height + ctx->i;
+        break;
+    default:
+        FAILIF(1, "Unexpected roation value %d!\n", ctx->rotate);
+    }
+
+    bpp = 3 + !!alpha;
+    offset *= bpp;
+    FAILIF(offset < 0, "point (%d, %d) generates a negative offset.\n", ctx->i, ctx->j);
+    FAILIF(offset + bpp > ctx->size, "point (%d, %d) at offset %d exceeds the size %d of the buffer.\n",
+           ctx->i, ctx->j,
+           offset,
+           ctx->size);
+
+    out += offset;
+
+    if (alpha) out[i++] = 0xff;
+    out[i++] = r;
+    out[i++] = g;
+    out[i] = b;
+}
+
+static void rgb24_cb(
+    unsigned char r,
+    unsigned char g,
+    unsigned char b,
+    rgb_context *ctx)
+{
+    return common_rgb_cb(r,g,b,ctx,0);
+}
+
+static void argb_cb(
+    unsigned char r,
+    unsigned char g,
+    unsigned char b,
+    rgb_context *ctx)
+{
+    return common_rgb_cb(r,g,b,ctx,1);
+}
+
+static void convert(const char *infile,
+                    const char *outfile,
+                    int height,
+                    int width,
+                    int gray,
+                    int type,
+                    int rotate)
+{
+    void *in, *out;
+    int ifd, ofd, rc;
+    int psz = getpagesize();
+    static char header[1024];
+    int header_size;
+    size_t outsize;
+
+    int bpp = 3;
+    switch (type) {
+    case CONVERT_TYPE_PPM:
+        PRINT("encoding PPM\n");
+        if (rotate & 1)
+            header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", height, width);
+        else
+            header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", width, height);
+	break;
+    case CONVERT_TYPE_RGB:
+        PRINT("encoding raw RGB24\n");
+        header_size = 0;
+        break;
+    case CONVERT_TYPE_ARGB:
+        PRINT("encoding raw ARGB\n");
+        header_size = 0;
+        bpp = 4;
+        break;
+    }
+        
+    outsize = header_size + width * height * bpp;
+    outsize = (outsize + psz - 1) & ~(psz - 1);
+
+    INFO("Opening input file %s\n", infile);
+    ifd = open(infile, O_RDONLY);
+    FAILIF(ifd < 0, "open(%s) failed: %s (%d)\n",
+           infile, strerror(errno), errno);
+
+    INFO("Opening output file %s\n", outfile);
+    ofd = open(outfile, O_RDWR | O_CREAT, 0664);
+    FAILIF(ofd < 0, "open(%s) failed: %s (%d)\n",
+           outfile, strerror(errno), errno);
+    
+    INFO("Memory-mapping input file %s\n", infile);
+    in = mmap(0, width * height * 3 / 2, PROT_READ, MAP_PRIVATE, ifd, 0);
+    FAILIF(in == MAP_FAILED, "could not mmap input file: %s (%d)\n",
+           strerror(errno), errno);
+
+    INFO("Truncating output file %s to %d bytes\n", outfile, outsize);
+    FAILIF(ftruncate(ofd, outsize) < 0,
+           "Could not truncate output file to required size: %s (%d)\n",
+           strerror(errno), errno);
+
+    INFO("Memory mapping output file %s\n", outfile);
+    out = mmap(0, outsize, PROT_WRITE, MAP_SHARED, ofd, 0);
+    FAILIF(out == MAP_FAILED, "could not mmap output file: %s (%d)\n",
+           strerror(errno), errno);
+
+    INFO("PPM header (%d) bytes:\n%s\n", header_size, header);
+    FAILIF(write(ofd, header, header_size) != header_size,
+           "Error wrinting PPM header: %s (%d)\n",
+           strerror(errno), errno);
+
+    INFO("Converting %dx%d YUV 4:2:0 to RGB24...\n", width, height);
+    color_convert_common(in, in + width * height,
+                         width, height, 
+                         out + header_size, outsize - header_size,
+                         gray, rotate,
+                         type == CONVERT_TYPE_ARGB ? argb_cb : rgb24_cb);
+}
+
+int verbose_flag;
+int quiet_flag;
+
+int main(int argc, char **argv) {
+
+    char *infile, *outfile, *type;
+    int height, width, gray, rotate;
+    int cmdline_error = 0;
+
+    /* Parse command-line arguments. */
+    
+    int first = get_options(argc, argv,
+                            &outfile,
+                            &height,
+                            &width,
+                            &gray,
+                            &type,
+                            &rotate,
+                            &verbose_flag);
+
+    if (first == argc) {
+        ERROR("You must specify an input file!\n");
+        cmdline_error++;
+    }
+    if (!outfile) {
+        ERROR("You must specify an output file!\n");
+        cmdline_error++;
+    }
+    if (height < 0 || width < 0) {
+        ERROR("You must specify both image height and width!\n");
+        cmdline_error++;
+    }
+
+    FAILIF(rotate % 90, "Rotation angle must be a multiple of 90 degrees!\n");
+
+    rotate /= 90;
+    rotate %= 4;
+    if (rotate < 0) rotate += 4;
+
+    if (cmdline_error) {
+        print_help(argv[0]);
+        exit(1);
+    }
+
+    infile = argv[first];
+
+    INFO("input file: [%s]\n", infile);
+    INFO("output file: [%s]\n", outfile);
+    INFO("height: %d\n", height);
+    INFO("width: %d\n", width);
+    INFO("gray only: %d\n", gray);
+    INFO("encode as: %s\n", type);
+    INFO("rotation: %d\n", rotate);
+    
+    /* Convert the image */
+
+    int conv_type;
+    if (!type || !strcmp(type, "ppm"))
+        conv_type = CONVERT_TYPE_PPM;
+    else if (!strcmp(type, "rgb"))
+        conv_type = CONVERT_TYPE_RGB;
+    else if (!strcmp(type, "argb"))
+        conv_type = CONVERT_TYPE_ARGB;
+    else FAILIF(1, "Unknown encoding type %s.\n", type);
+    
+    convert(infile, outfile,
+            height, width, gray,
+            conv_type,
+            rotate);
+        
+    free(outfile);
+    return 0;
+}