Merge "Fix issue 2667796: [Audio Effect Framework] Effect factory and libraries." into kraken
diff --git a/api/current.xml b/api/current.xml
index 54cd3fb..923a7b6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -81605,6 +81605,28 @@
  visibility="public"
 >
 </method>
+<method name="getBearingAccuracy"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getHorizontalAccuracy"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPowerRequirement"
  return="int"
  abstract="false"
@@ -81616,6 +81638,39 @@
  visibility="public"
 >
 </method>
+<method name="getPriority"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpeedAccuracy"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVerticalAccuracy"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isAltitudeRequired"
  return="boolean"
  abstract="false"
@@ -81686,6 +81741,19 @@
 <parameter name="altitudeRequired" type="boolean">
 </parameter>
 </method>
+<method name="setBearingAccuracy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accuracy" type="int">
+</parameter>
+</method>
 <method name="setBearingRequired"
  return="void"
  abstract="false"
@@ -81712,6 +81780,19 @@
 <parameter name="costAllowed" type="boolean">
 </parameter>
 </method>
+<method name="setHorizontalAccuracy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accuracy" type="int">
+</parameter>
+</method>
 <method name="setPowerRequirement"
  return="void"
  abstract="false"
@@ -81725,6 +81806,32 @@
 <parameter name="level" type="int">
 </parameter>
 </method>
+<method name="setPreferredPriority"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="priority" type="int">
+</parameter>
+</method>
+<method name="setSpeedAccuracy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accuracy" type="int">
+</parameter>
+</method>
 <method name="setSpeedRequired"
  return="void"
  abstract="false"
@@ -81738,6 +81845,19 @@
 <parameter name="speedRequired" type="boolean">
 </parameter>
 </method>
+<method name="setVerticalAccuracy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accuracy" type="int">
+</parameter>
+</method>
 <method name="writeToParcel"
  return="void"
  abstract="false"
@@ -81753,6 +81873,17 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<field name="ACCURACY_BEST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACCURACY_COARSE"
  type="int"
  transient="false"
@@ -81775,6 +81906,50 @@
  visibility="public"
 >
 </field>
+<field name="ACCURACY_HIGH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCURACY_LOW"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCURACY_MEDIUM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BEARING_ACCURACY_PRIORITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CREATOR"
  type="android.os.Parcelable.Creator"
  transient="false"
@@ -81785,6 +81960,17 @@
  visibility="public"
 >
 </field>
+<field name="HORIZONTAL_ACCURACY_PRIORITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="NO_REQUIREMENT"
  type="int"
  transient="false"
@@ -81829,6 +82015,39 @@
  visibility="public"
 >
 </field>
+<field name="POWER_REQUIREMENT_PRIORITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SPEED_ACCURACY_PRIORITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="VERTICAL_ACCURACY_PRIORITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Geocoder"
  extends="java.lang.Object"
@@ -81921,6 +82140,86 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="isImplemented"
+ return="java.lang.Boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="GeocoderParams"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getClientPackage"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLocale"
+ return="java.util.Locale"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parcel" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="GpsSatellite"
  extends="java.lang.Object"
@@ -83079,6 +83378,27 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="minTime" type="long">
+</parameter>
+<parameter name="minDistance" type="float">
+</parameter>
+<parameter name="criteria" type="android.location.Criteria">
+</parameter>
+<parameter name="listener" type="android.location.LocationListener">
+</parameter>
+<parameter name="looper" type="android.os.Looper">
+</parameter>
+</method>
+<method name="requestLocationUpdates"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 <parameter name="provider" type="java.lang.String">
 </parameter>
 <parameter name="minTime" type="long">
@@ -83088,6 +83408,89 @@
 <parameter name="intent" type="android.app.PendingIntent">
 </parameter>
 </method>
+<method name="requestLocationUpdates"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="minTime" type="long">
+</parameter>
+<parameter name="minDistance" type="float">
+</parameter>
+<parameter name="criteria" type="android.location.Criteria">
+</parameter>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="requestSingleUpdate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="java.lang.String">
+</parameter>
+<parameter name="listener" type="android.location.LocationListener">
+</parameter>
+<parameter name="looper" type="android.os.Looper">
+</parameter>
+</method>
+<method name="requestSingleUpdate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="criteria" type="android.location.Criteria">
+</parameter>
+<parameter name="listener" type="android.location.LocationListener">
+</parameter>
+<parameter name="looper" type="android.os.Looper">
+</parameter>
+</method>
+<method name="requestSingleUpdate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="java.lang.String">
+</parameter>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="requestSingleUpdate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="criteria" type="android.location.Criteria">
+</parameter>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+</method>
 <method name="sendExtraCommand"
  return="boolean"
  abstract="false"
@@ -83398,6 +83801,390 @@
 </field>
 </class>
 </package>
+<package name="android.location.provider"
+>
+<class name="GeocodeProvider"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="GeocodeProvider"
+ type="android.location.provider.GeocodeProvider"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onGetFromLocation"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="latitude" type="double">
+</parameter>
+<parameter name="longitude" type="double">
+</parameter>
+<parameter name="maxResults" type="int">
+</parameter>
+<parameter name="params" type="android.location.GeocoderParams">
+</parameter>
+<parameter name="addrs" type="java.util.List&lt;android.location.Address&gt;">
+</parameter>
+</method>
+<method name="onGetFromLocationName"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="locationName" type="java.lang.String">
+</parameter>
+<parameter name="lowerLeftLatitude" type="double">
+</parameter>
+<parameter name="lowerLeftLongitude" type="double">
+</parameter>
+<parameter name="upperRightLatitude" type="double">
+</parameter>
+<parameter name="upperRightLongitude" type="double">
+</parameter>
+<parameter name="maxResults" type="int">
+</parameter>
+<parameter name="params" type="android.location.GeocoderParams">
+</parameter>
+<parameter name="addrs" type="java.util.List&lt;android.location.Address&gt;">
+</parameter>
+</method>
+</class>
+<class name="LocationProvider"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="LocationProvider"
+ type="android.location.provider.LocationProvider"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onAddListener"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="onDisable"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onEnable"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onEnableLocationTracking"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enable" type="boolean">
+</parameter>
+</method>
+<method name="onGetAccuracy"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onGetInternalState"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onGetPowerRequirement"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onGetStatus"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="extras" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onGetStatusUpdateTime"
+ return="long"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onHasMonetaryCost"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onMeetsCriteria"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="criteria" type="android.location.Criteria">
+</parameter>
+</method>
+<method name="onRemoveListener"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid" type="int">
+</parameter>
+</method>
+<method name="onRequiresCell"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onRequiresNetwork"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onRequiresSatellite"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onSendExtraCommand"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="command" type="java.lang.String">
+</parameter>
+<parameter name="extras" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onSetMinTime"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="minTime" type="long">
+</parameter>
+</method>
+<method name="onSupportsAltitude"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onSupportsBearing"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onSupportsSpeed"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onUpdateLocation"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="location" type="android.location.Location">
+</parameter>
+</method>
+<method name="onUpdateNetworkState"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="state" type="int">
+</parameter>
+<parameter name="info" type="android.net.NetworkInfo">
+</parameter>
+</method>
+<method name="reportLocation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="location" type="android.location.Location">
+</parameter>
+</method>
+</class>
+</package>
 <package name="android.media"
 >
 <class name="AsyncPlayer"
diff --git a/camera/tests/CameraServiceTest/Android.mk b/camera/tests/CameraServiceTest/Android.mk
index 9bb190a..cf4e42f 100644
--- a/camera/tests/CameraServiceTest/Android.mk
+++ b/camera/tests/CameraServiceTest/Android.mk
@@ -21,4 +21,6 @@
                 libcamera_client \
                 libsurfaceflinger_client
 
-include $(BUILD_EXECUTABLE)
+# Disable it because the ISurface interface may change, and before we have a
+# chance to fix this test, we don't want to break normal builds.
+#include $(BUILD_EXECUTABLE)
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2a3f032..cc30d71 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -140,7 +140,10 @@
     boolean mViewVisibility = false;
     int mRequestedWidth = -1;
     int mRequestedHeight = -1;
-    int mRequestedFormat = PixelFormat.OPAQUE;
+    /* Set SurfaceView's format to 565 by default to maintain backward
+     * compatibility with applications assuming this format.
+     */
+    int mRequestedFormat = PixelFormat.RGB_565;
     int mRequestedType = -1;
 
     boolean mHaveFrame = false;
@@ -163,16 +166,20 @@
     
     public SurfaceView(Context context) {
         super(context);
-        setWillNotDraw(true);
+        init();
     }
     
     public SurfaceView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        setWillNotDraw(true);
+        init();
     }
 
     public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        init();
+    }
+
+    private void init() {
         setWillNotDraw(true);
     }
     
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 48e7f79..fcfecb3 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2645,7 +2645,7 @@
                         mScrollDuration);
 
                 mLastSeenPos = lastPos;
-                if (lastPos != mTargetPos) {
+                if (lastPos < mTargetPos) {
                     post(this);
                 }
                 break;
@@ -2671,7 +2671,7 @@
                 final int nextViewHeight = nextView.getHeight();
                 final int nextViewTop = nextView.getTop();
                 final int extraScroll = mExtraScroll;
-                if (nextPos != mBoundPos) {
+                if (nextPos < mBoundPos) {
                     smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll),
                             mScrollDuration);
 
@@ -2704,7 +2704,7 @@
 
                 mLastSeenPos = firstPos;
 
-                if (firstPos != mTargetPos) {
+                if (firstPos > mTargetPos) {
                     post(this);
                 }
                 break;
@@ -2728,7 +2728,7 @@
                 final int lastViewTop = lastView.getTop();
                 final int lastViewPixelsShowing = listHeight - lastViewTop;
                 mLastSeenPos = lastPos;
-                if (lastPos != mBoundPos) {
+                if (lastPos > mBoundPos) {
                     smoothScrollBy(-(lastViewPixelsShowing - mExtraScroll), mScrollDuration);
                     post(this);
                 } else {
diff --git a/core/res/res/drawable-hdpi/status_bar_background.png b/core/res/res/drawable-hdpi/status_bar_background.png
index e6a865a..3d00cd0 100644
--- a/core/res/res/drawable-hdpi/status_bar_background.png
+++ b/core/res/res/drawable-hdpi/status_bar_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_close_on.9.png b/core/res/res/drawable-hdpi/status_bar_close_on.9.png
index 5acf638..f313ffb 100644
--- a/core/res/res/drawable-hdpi/status_bar_close_on.9.png
+++ b/core/res/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_header_background.9.png b/core/res/res/drawable-hdpi/status_bar_header_background.9.png
index be36ff2..37b5fef 100644
--- a/core/res/res/drawable-hdpi/status_bar_header_background.9.png
+++ b/core/res/res/drawable-hdpi/status_bar_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/statusbar_background.9.png b/core/res/res/drawable-hdpi/statusbar_background.9.png
index dcca695..a4be298 100644
--- a/core/res/res/drawable-hdpi/statusbar_background.9.png
+++ b/core/res/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/core/res/res/layout/status_bar.xml b/core/res/res/layout/status_bar.xml
index e8d8866..2237ee4 100644
--- a/core/res/res/layout/status_bar.xml
+++ b/core/res/res/layout/status_bar.xml
@@ -76,28 +76,28 @@
             android:paddingTop="2dip"
             android:paddingRight="10dip">
             <TextView
+                android:textAppearance="@style/TextAppearance.StatusBar.Ticker"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
-                android:textColor="#ff000000" />
+                />
             <TextView
+                android:textAppearance="@style/TextAppearance.StatusBar.Ticker"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
-                android:textColor="#ff000000" />
+                />
         </com.android.server.status.TickerView>
     </LinearLayout>
 
     <com.android.server.status.DateView android:id="@+id/date"
+        android:textAppearance="@style/TextAppearance.StatusBar.Icon"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:singleLine="true"
-        android:textSize="16sp"
-        android:textStyle="bold"
         android:gravity="center_vertical|left"
         android:paddingLeft="6px"
         android:paddingRight="6px"
-        android:textColor="?android:attr/textColorPrimaryInverse"
         android:background="@drawable/statusbar_background"
         />
 </com.android.server.status.StatusBarView>
diff --git a/core/res/res/layout/status_bar_expanded.xml b/core/res/res/layout/status_bar_expanded.xml
index 30138a7..68eb922 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/core/res/res/layout/status_bar_expanded.xml
@@ -48,7 +48,7 @@
                     android:layout_height="wrap_content"
                     android:layout_gravity="center_vertical"
                     android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:textColor="?android:attr/textColorSecondaryInverse"
+                    android:textColor="?android:attr/textColorSecondary"
                     android:paddingLeft="4dp"
                     />
                 <TextView android:id="@+id/spnLabel"
@@ -56,7 +56,7 @@
                     android:layout_height="wrap_content"
                     android:layout_gravity="center_vertical"
                     android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:textColor="?android:attr/textColorSecondaryInverse"
+                    android:textColor="?android:attr/textColorSecondary"
                     android:paddingLeft="4dp"
                     />
         </LinearLayout>
@@ -67,7 +67,7 @@
             android:layout_marginTop="4dp"
             android:layout_marginBottom="1dp"
             android:textSize="14sp"
-            android:textColor="#ff000000"
+            android:textColor="?android:attr/textColorPrimaryInverse"
             android:text="@string/status_bar_clear_all_button"
             style="?android:attr/buttonStyle"
             android:paddingLeft="15dp"
@@ -99,7 +99,7 @@
                     android:layout_height="wrap_content"
                     android:background="@drawable/title_bar_portrait"
                     android:paddingLeft="5dp"
-                    android:textAppearance="@style/TextAppearance.StatusBarTitle"
+                    android:textAppearance="@style/TextAppearance.StatusBar.Title"
                     android:text="@string/status_bar_no_notifications_title"
                     />
 
@@ -108,7 +108,7 @@
                     android:layout_height="wrap_content"
                     android:background="@drawable/title_bar_portrait"
                     android:paddingLeft="5dp"
-                    android:textAppearance="@style/TextAppearance.StatusBarTitle"
+                    android:textAppearance="@style/TextAppearance.StatusBar.Title"
                     android:text="@string/status_bar_ongoing_events_title"
                     />
                 <LinearLayout android:id="@+id/ongoingItems"
@@ -122,7 +122,7 @@
                     android:layout_height="wrap_content"
                     android:background="@drawable/title_bar_portrait"
                     android:paddingLeft="5dp"
-                    android:textAppearance="@style/TextAppearance.StatusBarTitle"
+                    android:textAppearance="@style/TextAppearance.StatusBar.Title"
                     android:text="@string/status_bar_latest_events_title"
                     />
                 <LinearLayout android:id="@+id/latestItems"
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index c3aa041..ea6200a 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -18,16 +18,15 @@
             android:scaleType="fitCenter"
             android:src="@drawable/arrow_down_float"/>
         <TextView android:id="@+id/title"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
-            android:textStyle="bold"
-            android:textSize="18sp"
             android:paddingLeft="4dp"
-            android:textColor="#ff000000" />
+            />
     </LinearLayout>
     <LinearLayout
         android:layout_width="match_parent"
@@ -35,23 +34,22 @@
         android:orientation="horizontal"
         >
         <TextView android:id="@+id/text"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:textColor="#ff000000"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
-            android:textSize="14sp"
             android:paddingLeft="4dp"
             />
         <android.widget.DateTimeView android:id="@+id/time"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
             android:layout_marginLeft="4dp"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textSize="14sp"
             android:paddingRight="5dp"
-            android:textColor="#ff000000" />
+            />
     </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index b5fff96..af04117 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -187,11 +187,26 @@
 
     <!-- Status Bar Styles -->
 
-    <style name="TextAppearance.StatusBarTitle">
+    <style name="TextAppearance.StatusBar">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
-        <item name="android:textStyle">bold</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
+    <style name="TextAppearance.StatusBar.Ticker">
+    </style>
+    <style name="TextAppearance.StatusBar.Title">
+        <item name="android:textStyle">bold</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Icon">
+        <item name="android:textStyle">bold</item>
+    </style>
+    <style name="TextAppearance.StatusBar.EventContent">
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+    </style>
+    <style name="TextAppearance.StatusBar.EventContent.Title">
+        <item name="android:textSize">18sp</item>
+        <item name="android:textStyle">bold</item>
+    </style>
 
     <!-- Widget Styles -->
 
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 0ba5e08..01940e8 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -14,9 +14,8 @@
                                   <img src="{@docRoot}images/home/io-logo.png" alt="Google IO
 2010" width="200" height="41" style="padding:22px 12px;"/>
                                   <div id="announcement" style="width:295px">
-<p>Google I/O is happening now! To those of you with us, welcome! If you couldn't make it to the
-event, stay tuned for videos and slides from the Android sessions, which will be posted at the
-Google I/O web site.</p><p><a
+<p>Thanks to everyone who visited us at Google I/O in San Francisco! Stay tuned for
+videos and slides from the Android sessions, which will be posted at the Google I/O web site.</p><p><a
 href="http://code.google.com/events/io/2010/sessions.html#Android">Learn more &raquo;</a></p>
                                 </div> <!-- end annoucement -->
                             </div> <!-- end annoucement-block -->
diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd
index 7bad054..77ffc6f 100644
--- a/docs/html/resources/tutorials/hello-world.jd
+++ b/docs/html/resources/tutorials/hello-world.jd
@@ -299,7 +299,7 @@
 
 <pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
 &lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
-  android:id=&quot;@id+/textview&quot;
+  android:id=&quot;@+id/textview&quot;
   android:layout_width=&quot;fill_parent&quot;
   android:layout_height=&quot;fill_parent&quot;
   android:text=&quot;@string/hello&quot;/&gt;</pre>
@@ -410,7 +410,7 @@
 
 <pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
 &lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
-  android:id=&quot;@id+/textview&quot;
+  android:id=&quot;@+id/textview&quot;
   android:layout_width=&quot;fill_parent&quot;
   android:layout_height=&quot;fill_parent&quot;
   android:text=&quot;@string/hello&quot;/&gt;</pre>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 57eac1f..f5558ab 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -95,7 +95,7 @@
 <div class="toggleable opened">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
-ADT 0.9.6</a> <em>(March 2010)</em>
+ADT 0.9.7</a> <em>(May 2010)</em>
   <div class="toggleme">
 
 <dl>
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 20eef72..faf6155 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -119,14 +119,17 @@
     // should not set default value for this parameter.
     // Example value: "0" or "90" or "180" or "270". Write only.
     static const char KEY_ROTATION[];
-    // GPS latitude coordinate. This will be stored in JPEG EXIF header.
-    // Example value: "25.032146". Write only.
+    // GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
+    // JPEG EXIF header.
+    // Example value: "25.032146" or "-33.462809". Write only.
     static const char KEY_GPS_LATITUDE[];
-    // GPS longitude coordinate. This will be stored in JPEG EXIF header.
-    // Example value: "121.564448". Write only.
+    // GPS longitude coordinate. GPSLongitude and GPSLongitudeRef will be stored
+    // in JPEG EXIF header.
+    // Example value: "121.564448" or "-70.660286". Write only.
     static const char KEY_GPS_LONGITUDE[];
-    // GPS altitude. This will be stored in JPEG EXIF header.
-    // Example value: "21.0". Write only.
+    // GPS altitude. GPSAltitude and GPSAltitudeRef will be stored in JPEG EXIF
+    // header.
+    // Example value: "21.0" or "-5". Write only.
     static const char KEY_GPS_ALTITUDE[];
     // GPS timestamp (UTC in seconds since January 1, 1970). This should be
     // stored in JPEG EXIF header.
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 207195a..a9a0d55 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -22,6 +22,7 @@
 
 extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
 
+extern const char *MEDIA_MIMETYPE_VIDEO_VPX;
 extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
 extern const char *MEDIA_MIMETYPE_VIDEO_H263;
@@ -38,6 +39,7 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
 extern const char *MEDIA_MIMETYPE_CONTAINER_OGG;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA;
 
 }  // namespace android
 
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index a1a02e0..ea8391d 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -55,12 +55,6 @@
  * 
  */
 
-// When changing these values, the COMPILE_TIME_ASSERT at the end of this
-// file need to be updated.
-const unsigned int NUM_LAYERS_MAX  = 31;
-const unsigned int NUM_BUFFER_MAX  = 16;
-const unsigned int NUM_DISPLAY_MAX = 4;
-
 // ----------------------------------------------------------------------------
 
 class Region;
@@ -82,6 +76,13 @@
     friend class SharedBufferServer;
 
 public:
+    // When changing these values, the COMPILE_TIME_ASSERT at the end of this
+    // file need to be updated.
+    static const unsigned int NUM_LAYERS_MAX  = 31;
+    static const unsigned int NUM_BUFFER_MAX  = 16;
+    static const unsigned int NUM_BUFFER_MIN  = 2;
+    static const unsigned int NUM_DISPLAY_MAX = 4;
+
     struct Statistics { // 4 longs
         typedef int32_t usecs_t;
         usecs_t  totalTime;
@@ -147,7 +148,7 @@
     // FIXME: this should be replaced by a lock-less primitive
     Mutex lock;
     Condition cv;
-    SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
+    SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];
 };
 
 // ============================================================================
@@ -155,7 +156,7 @@
 class SharedBufferBase
 {
 public:
-    SharedBufferBase(SharedClient* sharedClient, int surface, int num,
+    SharedBufferBase(SharedClient* sharedClient, int surface,
             int32_t identity);
     ~SharedBufferBase();
     uint32_t getIdentity();
@@ -166,9 +167,7 @@
 protected:
     SharedClient* const mSharedClient;
     SharedBufferStack* const mSharedStack;
-    int mNumBuffers;
     const int mIdentity;
-    int32_t computeTail() const;
 
     friend struct Update;
     friend struct QueueUpdate;
@@ -217,8 +216,16 @@
     bool needNewBuffer(int buffer) const;
     status_t setDirtyRegion(int buffer, const Region& reg);
     status_t setCrop(int buffer, const Rect& reg);
-    status_t setBufferCount(int bufferCount);
     
+
+    class SetBufferCountCallback {
+        friend class SharedBufferClient;
+        virtual status_t operator()(int bufferCount) const = 0;
+    protected:
+        virtual ~SetBufferCountCallback() { }
+    };
+    status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc);
+
 private:
     friend struct Condition;
     friend struct DequeueCondition;
@@ -249,11 +256,16 @@
         inline const char* name() const { return "LockCondition"; }
     };
 
+    int32_t computeTail() const;
+
+    mutable RWLock mLock;
+    int mNumBuffers;
+
     int32_t tail;
     int32_t undoDequeueTail;
     int32_t queued_head;
     // statistics...
-    nsecs_t mDequeueTime[NUM_BUFFER_MAX];
+    nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX];
 };
 
 // ----------------------------------------------------------------------------
@@ -267,7 +279,8 @@
     ssize_t retireAndLock();
     status_t unlock(int buffer);
     void setStatus(status_t status);
-    status_t reallocate();
+    status_t reallocateAll();
+    status_t reallocateAllExcept(int buffer);
     status_t assertReallocate(int buffer);
     int32_t getQueuedCount() const;
     Region getDirtyRegion(int buffer) const;
@@ -287,9 +300,11 @@
         size_t mCapacity;
         uint32_t mList;
     public:
-        BufferList(size_t c = NUM_BUFFER_MAX) : mCapacity(c), mList(0) { }
+        BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX)
+            : mCapacity(c), mList(0) { }
         status_t add(int value);
         status_t remove(int value);
+        uint32_t getMask() const { return mList; }
 
         class const_iterator {
             friend class BufferList;
@@ -324,6 +339,9 @@
         }
     };
 
+    // this protects mNumBuffers and mBufferList
+    mutable RWLock mLock;
+    int mNumBuffers;
     BufferList mBufferList;
 
     struct UnlockUpdate : public UpdateBase {
@@ -373,7 +391,7 @@
     uint8_t         connected;
     uint8_t         reserved[3];
     uint32_t        pad[7];
-    display_cblk_t  displays[NUM_DISPLAY_MAX];
+    display_cblk_t  displays[SharedBufferStack::NUM_DISPLAY_MAX];
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index 9476686..18e7950 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -53,7 +53,8 @@
 public: 
     DECLARE_META_INTERFACE(Surface);
 
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0; 
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
     virtual status_t setBufferCount(int bufferCount) = 0;
     
     class BufferHeap {
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 973780f..77e4a61 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -36,6 +36,7 @@
 
 // ---------------------------------------------------------------------------
 
+class GraphicBuffer;
 class GraphicBufferMapper;
 class IOMX;
 class Rect;
@@ -212,12 +213,15 @@
     int  dispatch_connect(va_list args);
     int  dispatch_disconnect(va_list args);
     int  dispatch_crop(va_list args);
+    int  dispatch_set_buffer_count(va_list args);
+    int  dispatch_set_buffers_geometry(va_list args);
     
     void setUsage(uint32_t reqUsage);
     int  connect(int api);
     int  disconnect(int api);
     int  crop(Rect const* rect);
     int  setBufferCount(int bufferCount);
+    int  setBuffersGeometry(int w, int h, int format);
 
     /*
      *  private stuff...
@@ -230,12 +234,34 @@
     inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
     inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
 
-    status_t getBufferLocked(int index, int usage);
+    status_t getBufferLocked(int index,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
     int getBufferIndex(const sp<GraphicBuffer>& buffer) const;
 
-    uint32_t getUsage() const;
-    int      getConnectedApi() const;
+    int getConnectedApi() const;
     
+    bool needNewBuffer(int bufIdx,
+            uint32_t *pWidth, uint32_t *pHeight,
+            uint32_t *pFormat, uint32_t *pUsage) const;
+
+    class BufferInfo {
+        uint32_t mWidth;
+        uint32_t mHeight;
+        uint32_t mFormat;
+        uint32_t mUsage;
+        mutable uint32_t mDirty;
+        enum {
+            GEOMETRY = 0x01
+        };
+    public:
+        BufferInfo();
+        void set(uint32_t w, uint32_t h, uint32_t format);
+        void set(uint32_t usage);
+        void get(uint32_t *pWidth, uint32_t *pHeight,
+                uint32_t *pFormat, uint32_t *pUsage) const;
+        bool validateBuffer(const sp<GraphicBuffer>& buffer) const;
+    };
+
     // constants
     sp<SurfaceComposerClient>   mClient;
     sp<ISurface>                mSurface;
@@ -248,13 +274,12 @@
 
     // protected by mSurfaceLock
     Rect                        mSwapRectangle;
-    uint32_t                    mUsage;
     int                         mConnected;
     Rect                        mNextBufferCrop;
+    BufferInfo                  mBufferInfo;
     
     // protected by mSurfaceLock. These are also used from lock/unlock
     // but in that case, they must be called form the same thread.
-    sp<GraphicBuffer>           mBuffers[2];
     mutable Region              mDirtyRegion;
 
     // must be used from the lock/unlock thread
@@ -263,6 +288,9 @@
     mutable Region              mOldDirtyRegion;
     bool                        mReserved;
 
+    // only used from dequeueBuffer()
+    Vector< sp<GraphicBuffer> > mBuffers;
+
     // query() must be called from dequeueBuffer() thread
     uint32_t                    mWidth;
     uint32_t                    mHeight;
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 49bfa2b..171f3df 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -81,6 +81,8 @@
     NATIVE_WINDOW_CONNECT,
     NATIVE_WINDOW_DISCONNECT,
     NATIVE_WINDOW_SET_CROP,
+    NATIVE_WINDOW_SET_BUFFER_COUNT,
+    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
 };
 
 /* parameter for NATIVE_WINDOW_[DIS]CONNECT */
@@ -190,6 +192,8 @@
      *     NATIVE_WINDOW_CONNECT
      *     NATIVE_WINDOW_DISCONNECT
      *     NATIVE_WINDOW_SET_CROP
+     *     NATIVE_WINDOW_SET_BUFFER_COUNT
+     *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
      *  
      */
     
@@ -201,8 +205,9 @@
 
 
 /*
- *  native_window_set_usage() sets the intended usage flags for the next
- *  buffers acquired with (*lockBuffer)() and on.
+ *  native_window_set_usage(..., usage)
+ *  Sets the intended usage flags for the next buffers
+ *  acquired with (*lockBuffer)() and on.
  *  By default (if this function is never called), a usage of
  *      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
  *  is assumed.
@@ -217,8 +222,8 @@
 }
 
 /*
- * native_window_connect(..., NATIVE_WINDOW_API_EGL) must be called
- * by EGL when the window is made current.
+ * native_window_connect(..., NATIVE_WINDOW_API_EGL)
+ * Must be called by EGL when the window is made current.
  * Returns -EINVAL if for some reason the window cannot be connected, which
  * can happen if it's connected to some other API.
  */
@@ -229,8 +234,8 @@
 }
 
 /*
- * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) must be called
- * by EGL when the window is made not current.
+ * native_window_disconnect(..., NATIVE_WINDOW_API_EGL)
+ * Must be called by EGL when the window is made not current.
  * An error is returned if for instance the window wasn't connected in the
  * first place.
  */
@@ -241,8 +246,8 @@
 }
 
 /*
- * native_window_set_crop(..., crop) sets which region of the next queued
- * buffers needs to be considered.
+ * native_window_set_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
  * A buffer's crop region is scaled to match the surface's size.
  *
  * The specified crop region applies to all buffers queued after it is called.
@@ -259,6 +264,36 @@
     return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
 }
 
+/*
+ * native_window_set_buffer_count(..., count)
+ * Sets the number of buffers associated with this native window.
+ */
+static inline int native_window_set_buffer_count(
+        android_native_window_t* window,
+        size_t bufferCount)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
+}
+
+/*
+ * native_window_set_buffers_geometry(..., int w, int h, int format)
+ * All buffers dequeued after this call will have the geometry specified.
+ * In particular, all buffers will have a fixed-size, independent form the
+ * native-window size. They will be appropriately scaled to the window-size
+ * upon composition.
+ *
+ * If all parameters are 0, the normal behavior is restored. That is,
+ * dequeued buffers following this call will be sized to the window's size.
+ *
+ */
+static inline int native_window_set_buffers_geometry(
+        android_native_window_t* window,
+        int w, int h, int format)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+            w, h, format);
+}
+
 // ---------------------------------------------------------------------------
 
 /* FIXME: this is legacy for pixmaps */
diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h
index e2bcf6a..6f8507e 100644
--- a/libs/surfaceflinger/Barrier.h
+++ b/libs/surfaceflinger/Barrier.h
@@ -29,10 +29,6 @@
     inline Barrier() : state(CLOSED) { }
     inline ~Barrier() { }
     void open() {
-        // gcc memory barrier, this makes sure all memory writes
-        // have been issued by gcc. On an SMP system we'd need a real
-        // h/w barrier.
-        asm volatile ("":::"memory");
         Mutex::Autolock _l(lock);
         state = OPENED;
         cv.broadcast();
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 1fe997d..84584aa 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -55,12 +55,13 @@
         mNeedsBlending(true),
         mNeedsDithering(false),
         mTextureManager(mFlags),
-        mBufferManager(mTextureManager)
+        mBufferManager(mTextureManager),
+        mWidth(0), mHeight(0), mFixedSize(false)
 {
     // no OpenGL operation is possible here, since we might not be
     // in the OpenGL thread.
     lcblk = new SharedBufferServer(
-            client->ctrlblk, i, mBufferManager.getBufferCount(),
+            client->ctrlblk, i, mBufferManager.getDefaultBufferCount(),
             getIdentity());
 
    mBufferManager.setActiveBufferIndex( lcblk->getFrontBuffer() );
@@ -68,7 +69,10 @@
 
 Layer::~Layer()
 {
-    destroy();
+    // FIXME: must be called from the main UI thread
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+    mBufferManager.destroy(dpy);
+
     // the actual buffers will be destroyed here
     delete lcblk;
 }
@@ -81,17 +85,6 @@
     lcblk->setStatus(NO_INIT);
 }
 
-void Layer::destroy()
-{
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-    mBufferManager.destroy(dpy);
-
-    mSurface.clear();
-
-    Mutex::Autolock _l(mLock);
-    mWidth = mHeight = 0;
-}
-
 sp<LayerBaseClient::Surface> Layer::createSurface() const
 {
     return mSurface;
@@ -99,9 +92,17 @@
 
 status_t Layer::ditch()
 {
+    // NOTE: Called from the main UI thread
+
     // the layer is not on screen anymore. free as much resources as possible
     mFreezeLock.clear();
-    destroy();
+
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+    mBufferManager.destroy(dpy);
+    mSurface.clear();
+
+    Mutex::Autolock _l(mLock);
+    mWidth = mHeight = 0;
     return NO_ERROR;
 }
 
@@ -211,7 +212,7 @@
 
 status_t Layer::setBufferCount(int bufferCount)
 {
-    // this ensures our client doesn't go away while we're accessing
+    // Ensures our client doesn't go away while we're accessing
     // the shared area.
     sp<Client> ourClient(client.promote());
     if (ourClient == 0) {
@@ -219,23 +220,26 @@
         return DEAD_OBJECT;
     }
 
-    status_t err;
-
-    // FIXME: resize() below is NOT thread-safe, we need to synchronize
-    // the users of lcblk in our process (ie: retire), and we assume the
-    // client is not mucking with the SharedStack, which is only enforced
-    // by construction, therefore we need to protect ourselves against
-    // buggy and malicious client (as always)
-
-    err = lcblk->resize(bufferCount);
+    // NOTE: lcblk->resize() is protected by an internal lock
+    status_t err = lcblk->resize(bufferCount);
+    if (err == NO_ERROR)
+        mBufferManager.resize(bufferCount);
 
     return err;
 }
 
-sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)
+sp<GraphicBuffer> Layer::requestBuffer(int index,
+        uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat,
+        uint32_t usage)
 {
     sp<GraphicBuffer> buffer;
 
+    if ((reqWidth | reqHeight | reqFormat) < 0)
+        return buffer;
+
+    if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
+        return buffer;
+
     // this ensures our client doesn't go away while we're accessing
     // the shared area.
     sp<Client> ourClient(client.promote());
@@ -248,7 +252,7 @@
      * This is called from the client's Surface::dequeue(). This can happen
      * at any time, especially while we're in the middle of using the
      * buffer 'index' as our front buffer.
-     * 
+     *
      * Make sure the buffer we're resizing is not the front buffer and has been
      * dequeued. Once this condition is asserted, we are guaranteed that this
      * buffer cannot become the front buffer under our feet, since we're called
@@ -261,23 +265,33 @@
         return buffer;
     }
 
-    uint32_t w, h;
+    uint32_t w, h, f;
     { // scope for the lock
         Mutex::Autolock _l(mLock);
-        w = mWidth;
-        h = mHeight;
+        const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight);
+        const bool formatChanged    = mReqFormat != reqFormat;
+        mReqWidth  = reqWidth;
+        mReqHeight = reqHeight;
+        mReqFormat = reqFormat;
+        mFixedSize = reqWidth && reqHeight;
+        w = reqWidth  ? reqWidth  : mWidth;
+        h = reqHeight ? reqHeight : mHeight;
+        f = reqFormat ? reqFormat : mFormat;
         buffer = mBufferManager.detachBuffer(index);
+        if (fixedSizeChanged || formatChanged) {
+            lcblk->reallocateAllExcept(index);
+        }
     }
 
     const uint32_t effectiveUsage = getEffectiveUsage(usage);
     if (buffer!=0 && buffer->getStrongCount() == 1) {
-        err = buffer->reallocate(w, h, mFormat, effectiveUsage);
+        err = buffer->reallocate(w, h, f, effectiveUsage);
     } else {
         // here we have to reallocate a new buffer because we could have a
         // client in our process with a reference to it (eg: status bar),
         // and we can't release the handle under its feet.
         buffer.clear();
-        buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage);
+        buffer = new GraphicBuffer(w, h, f, effectiveUsage);
         err = buffer->initCheck();
     }
 
@@ -293,12 +307,7 @@
 
     if (err == NO_ERROR && buffer->handle != 0) {
         Mutex::Autolock _l(mLock);
-        if (mWidth && mHeight) {
-            mBufferManager.attachBuffer(index, buffer);
-        } else {
-            // oops we got killed while we were allocating the buffer
-            buffer.clear();
-        }
+        mBufferManager.attachBuffer(index, buffer);
     }
     return buffer;
 }
@@ -335,39 +344,46 @@
     const Layer::State& front(drawingState());
     const Layer::State& temp(currentState());
 
-    if ((front.requested_w != temp.requested_w) || 
-        (front.requested_h != temp.requested_h)) {
+    const bool sizeChanged = (front.requested_w != temp.requested_w) ||
+            (front.requested_h != temp.requested_h);
+
+    if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
-                    "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
-                    this, 
-                    int(temp.requested_w), int(temp.requested_h),
-                    int(front.requested_w), int(front.requested_h));
+                "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
+                this,
+                int(temp.requested_w), int(temp.requested_h),
+                int(front.requested_w), int(front.requested_h));
 
-        // we're being resized and there is a freeze display request,
-        // acquire a freeze lock, so that the screen stays put
-        // until we've redrawn at the new size; this is to avoid
-        // glitches upon orientation changes.
-        if (mFlinger->hasFreezeRequest()) {
-            // if the surface is hidden, don't try to acquire the
-            // freeze lock, since hidden surfaces may never redraw
-            if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
-                mFreezeLock = mFlinger->getFreezeLock();
+        if (!isFixedSize()) {
+            // we're being resized and there is a freeze display request,
+            // acquire a freeze lock, so that the screen stays put
+            // until we've redrawn at the new size; this is to avoid
+            // glitches upon orientation changes.
+            if (mFlinger->hasFreezeRequest()) {
+                // if the surface is hidden, don't try to acquire the
+                // freeze lock, since hidden surfaces may never redraw
+                if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
+                    mFreezeLock = mFlinger->getFreezeLock();
+                }
             }
+
+            // this will make sure LayerBase::doTransaction doesn't update
+            // the drawing state's size
+            Layer::State& editDraw(mDrawingState);
+            editDraw.requested_w = temp.requested_w;
+            editDraw.requested_h = temp.requested_h;
+
+            // record the new size, form this point on, when the client request
+            // a buffer, it'll get the new size.
+            setBufferSize(temp.requested_w, temp.requested_h);
+
+            // all buffers need reallocation
+            lcblk->reallocateAll();
+        } else {
+            // record the new size
+            setBufferSize(temp.requested_w, temp.requested_h);
         }
-
-        // this will make sure LayerBase::doTransaction doesn't update
-        // the drawing state's size
-        Layer::State& editDraw(mDrawingState);
-        editDraw.requested_w = temp.requested_w;
-        editDraw.requested_h = temp.requested_h;
-
-        // record the new size, form this point on, when the client request a
-        // buffer, it'll get the new size.
-        setDrawingSize(temp.requested_w, temp.requested_h);
-
-        // all buffers need reallocation
-        lcblk->reallocate();
     }
 
     if (temp.sequence != front.sequence) {
@@ -381,12 +397,17 @@
     return LayerBase::doTransaction(flags);
 }
 
-void Layer::setDrawingSize(uint32_t w, uint32_t h) {
+void Layer::setBufferSize(uint32_t w, uint32_t h) {
     Mutex::Autolock _l(mLock);
     mWidth = w;
     mHeight = h;
 }
 
+bool Layer::isFixedSize() const {
+    Mutex::Autolock _l(mLock);
+    return mFixedSize;
+}
+
 // ----------------------------------------------------------------------------
 // pageflip handling...
 // ----------------------------------------------------------------------------
@@ -544,12 +565,20 @@
 // ---------------------------------------------------------------------------
 
 Layer::BufferManager::BufferManager(TextureManager& tm)
-    : mTextureManager(tm), mActiveBuffer(0), mFailover(false)
+    : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
+      mActiveBuffer(0), mFailover(false)
 {
 }
 
-size_t Layer::BufferManager::getBufferCount() const {
-    return NUM_BUFFERS;
+Layer::BufferManager::~BufferManager()
+{
+}
+
+status_t Layer::BufferManager::resize(size_t size)
+{
+    Mutex::Autolock _l(mLock);
+    mNumBuffers = size;
+    return NO_ERROR;
 }
 
 // only for debugging
@@ -568,51 +597,55 @@
 }
 
 Texture Layer::BufferManager::getActiveTexture() const {
-    return mFailover ? mFailoverTexture : mBufferData[mActiveBuffer].texture;
+    Texture res;
+    if (mFailover) {
+        res = mFailoverTexture;
+    } else {
+        static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture;
+    }
+    return res;
 }
 
 sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
+    const size_t activeBuffer = mActiveBuffer;
+    BufferData const * const buffers = mBufferData;
     Mutex::Autolock _l(mLock);
-    return mBufferData[mActiveBuffer].buffer;
+    return buffers[activeBuffer].buffer;
 }
 
 sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
 {
+    BufferData* const buffers = mBufferData;
     sp<GraphicBuffer> buffer;
     Mutex::Autolock _l(mLock);
-    buffer = mBufferData[index].buffer;
-    mBufferData[index].buffer = 0;
+    buffer = buffers[index].buffer;
+    buffers[index].buffer = 0;
     return buffer;
 }
 
 status_t Layer::BufferManager::attachBuffer(size_t index,
         const sp<GraphicBuffer>& buffer)
 {
+    BufferData* const buffers = mBufferData;
     Mutex::Autolock _l(mLock);
-    mBufferData[index].buffer = buffer;
-    mBufferData[index].texture.dirty = true;
-    return NO_ERROR;
-}
-
-status_t Layer::BufferManager::destroyTexture(Texture* tex, EGLDisplay dpy)
-{
-    if (tex->name != -1U) {
-        glDeleteTextures(1, &tex->name);
-        tex->name = -1U;
-    }
-    if (tex->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, tex->image);
-        tex->image = EGL_NO_IMAGE_KHR;
-    }
+    buffers[index].buffer = buffer;
+    buffers[index].texture.dirty = true;
     return NO_ERROR;
 }
 
 status_t Layer::BufferManager::destroy(EGLDisplay dpy)
 {
-    Mutex::Autolock _l(mLock);
-    for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-        destroyTexture(&mBufferData[i].texture, dpy);
-        mBufferData[i].buffer = 0;
+    BufferData* const buffers = mBufferData;
+    size_t num;
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        num = mNumBuffers;
+        for (size_t i=0 ; i<num ; i++) {
+            buffers[i].buffer = 0;
+        }
+    }
+    for (size_t i=0 ; i<num ; i++) {
+        destroyTexture(&buffers[i].texture, dpy);
     }
     destroyTexture(&mFailoverTexture, dpy);
     return NO_ERROR;
@@ -622,7 +655,7 @@
         const sp<GraphicBuffer>& buffer)
 {
     size_t index = mActiveBuffer;
-    Texture& texture(mBufferData[index].texture);
+    Image& texture(mBufferData[index].texture);
     status_t err = mTextureManager.initEglImage(&texture, dpy, buffer);
     // if EGLImage fails, we switch to regular texture mode, and we
     // free all resources associated with using EGLImages.
@@ -631,7 +664,8 @@
         destroyTexture(&mFailoverTexture, dpy);
     } else {
         mFailover = true;
-        for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
+        const size_t num = mNumBuffers;
+        for (size_t i=0 ; i<num ; i++) {
             destroyTexture(&mBufferData[i].texture, dpy);
         }
     }
@@ -644,6 +678,19 @@
     return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
 }
 
+status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy)
+{
+    if (tex->name != -1U) {
+        glDeleteTextures(1, &tex->name);
+        tex->name = -1U;
+    }
+    if (tex->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, tex->image);
+        tex->image = EGL_NO_IMAGE_KHR;
+    }
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 
 Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
@@ -656,12 +703,18 @@
 {
 }
 
-sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage)
+sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
 {
     sp<GraphicBuffer> buffer;
     sp<Layer> owner(getOwner());
     if (owner != 0) {
-        buffer = owner->requestBuffer(index, usage);
+        /*
+         * requestBuffer() cannot be called from the main thread
+         * as it could cause a dead-lock, since it may have to wait
+         * on conditions updated my the main thread.
+         */
+        buffer = owner->requestBuffer(index, w, h, format, usage);
     }
     return buffer;
 }
@@ -671,6 +724,11 @@
     status_t err = DEAD_OBJECT;
     sp<Layer> owner(getOwner());
     if (owner != 0) {
+        /*
+         * setBufferCount() cannot be called from the main thread
+         * as it could cause a dead-lock, since it may have to wait
+         * on conditions updated my the main thread.
+         */
         err = owner->setBufferCount(bufferCount);
     }
     return err;
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 80fbd6a..10b5910 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -57,7 +57,8 @@
     status_t setBuffers(uint32_t w, uint32_t h, 
             PixelFormat format, uint32_t flags=0);
 
-    void setDrawingSize(uint32_t w, uint32_t h);
+    void setBufferSize(uint32_t w, uint32_t h);
+    bool isFixedSize() const;
 
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
@@ -88,9 +89,9 @@
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
-    sp<GraphicBuffer> requestBuffer(int index, int usage);
+    sp<GraphicBuffer> requestBuffer(int bufferIdx,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
     status_t setBufferCount(int bufferCount);
-    void destroy();
 
     class SurfaceLayer : public LayerBaseClient::Surface {
     public:
@@ -98,7 +99,8 @@
                 SurfaceID id, const sp<Layer>& owner);
         ~SurfaceLayer();
     private:
-        virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
+        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
         virtual status_t setBufferCount(int bufferCount);
         sp<Layer> getOwner() const {
             return static_cast<Layer*>(Surface::getOwner().get());
@@ -120,25 +122,32 @@
                 static const size_t NUM_BUFFERS = 2;
                 struct BufferData {
                     sp<GraphicBuffer>   buffer;
-                    Texture             texture;
+                    Image               texture;
                 };
+                // this lock protect mBufferData[].buffer but since there
+                // is very little contention, we have only one like for
+                // the whole array, we also use it to protect mNumBuffers.
                 mutable Mutex mLock;
-                BufferData          mBufferData[NUM_BUFFERS];
+                BufferData          mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
+                size_t              mNumBuffers;
                 Texture             mFailoverTexture;
                 TextureManager&     mTextureManager;
                 ssize_t             mActiveBuffer;
                 bool                mFailover;
-                static status_t destroyTexture(Texture* tex, EGLDisplay dpy);
+                static status_t destroyTexture(Image* tex, EGLDisplay dpy);
 
             public:
+                static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
                 BufferManager(TextureManager& tm);
-
-                size_t getBufferCount() const;
+                ~BufferManager();
 
                 // detach/attach buffer from/to given index
                 sp<GraphicBuffer> detachBuffer(size_t index);
                 status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
 
+                // resize the number of active buffers
+                status_t resize(size_t size);
+
                 // ----------------------------------------------
                 // must be called from GL thread
 
@@ -170,9 +179,15 @@
             TextureManager mTextureManager;
             BufferManager mBufferManager;
 
+            // this lock protects mWidth and mHeight which are accessed from
+            // the main thread and requestBuffer's binder transaction thread.
             mutable Mutex mLock;
             uint32_t    mWidth;
             uint32_t    mHeight;
+            uint32_t    mReqWidth;
+            uint32_t    mReqHeight;
+            uint32_t    mReqFormat;
+            bool        mFixedSize;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 63b9520..51673ff 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -616,7 +616,8 @@
     return BnSurface::onTransact(code, data, reply, flags);
 }
 
-sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage) 
+sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
 {
     return NULL; 
 }
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 53b848f..569b0ff 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -301,7 +301,8 @@
         sp<LayerBaseClient> getOwner() const;
 
     private:
-        virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
+        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
         virtual status_t setBufferCount(int bufferCount);
 
         virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); 
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 2d77876..09c90e8 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -95,7 +95,9 @@
                     mCacheDirty = false;
                 } else {
                     if (!mAutoRefreshPending) {
-                        mFlinger->signalDelayedEvent(ms2ns(500));
+                        mFlinger->postMessageAsync(
+                                new MessageBase(MessageQueue::INVALIDATE),
+                                ms2ns(500));
                         mAutoRefreshPending = true;
                     }
                 }
diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp
index b43d801..d668e88 100644
--- a/libs/surfaceflinger/MessageQueue.cpp
+++ b/libs/surfaceflinger/MessageQueue.cpp
@@ -60,9 +60,9 @@
 {
 }
 
-MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)
+sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout)
 {
-    MessageList::value_type result;
+    sp<MessageBase> result;
 
     bool again;
     do {
@@ -132,6 +132,7 @@
         if (again) {
             // the message has been processed. release our reference to it
             // without holding the lock.
+            result->notify();
             result = 0;
         }
         
@@ -141,7 +142,7 @@
 }
 
 status_t MessageQueue::postMessage(
-        const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+        const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
 {
     return queueMessage(message, relTime, flags);
 }
@@ -154,7 +155,7 @@
 }
 
 status_t MessageQueue::queueMessage(
-        const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+        const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
 {
     Mutex::Autolock _l(mLock);
     message->when = systemTime() + relTime;
@@ -167,13 +168,13 @@
     return NO_ERROR;
 }
 
-void MessageQueue::dump(const MessageList::value_type& message)
+void MessageQueue::dump(const sp<MessageBase>& message)
 {
     Mutex::Autolock _l(mLock);
     dumpLocked(message);
 }
 
-void MessageQueue::dumpLocked(const MessageList::value_type& message)
+void MessageQueue::dumpLocked(const sp<MessageBase>& message)
 {
     LIST::const_iterator cur(mMessages.begin());
     LIST::const_iterator end(mMessages.end());
diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h
index dc8138d..890f809 100644
--- a/libs/surfaceflinger/MessageQueue.h
+++ b/libs/surfaceflinger/MessageQueue.h
@@ -25,6 +25,7 @@
 #include <utils/Timers.h>
 #include <utils/List.h>
 
+#include "Barrier.h"
 
 namespace android {
 
@@ -37,7 +38,6 @@
     List< sp<MessageBase> > mList;
     typedef List< sp<MessageBase> > LIST;
 public:
-    typedef sp<MessageBase> value_type;
     inline LIST::iterator begin()                { return mList.begin(); }
     inline LIST::const_iterator begin() const    { return mList.begin(); }
     inline LIST::iterator end()                  { return mList.end(); }
@@ -63,11 +63,19 @@
     
     // return true if message has a handler
     virtual bool handler() { return false; }
+
+    // waits for the handler to be processed
+    void wait() const { barrier.wait(); }
     
+    // releases all waiters. this is done automatically if
+    // handler returns true
+    void notify() const { barrier.open(); }
+
 protected:
     virtual ~MessageBase() { }
 
 private:
+    mutable Barrier barrier;
     friend class LightRefBase<MessageBase>;
 };
 
@@ -82,42 +90,33 @@
     typedef List< sp<MessageBase> > LIST;
 public:
 
-    // this is a work-around the multichar constant warning. A macro would
-    // work too, but would pollute the namespace.
-    template <int a, int b, int c, int d>
-    struct WHAT {
-        static const uint32_t Value = 
-            (uint32_t(a&0xff)<<24)|(uint32_t(b&0xff)<<16)|
-            (uint32_t(c&0xff)<<8)|uint32_t(d&0xff);
-    };
-    
     MessageQueue();
     ~MessageQueue();
 
     // pre-defined messages
     enum {
-        INVALIDATE = WHAT<'_','p','d','t'>::Value
+        INVALIDATE = '_upd'
     };
 
-    MessageList::value_type waitMessage(nsecs_t timeout = -1);
+    sp<MessageBase> waitMessage(nsecs_t timeout = -1);
     
-    status_t postMessage(const MessageList::value_type& message, 
+    status_t postMessage(const sp<MessageBase>& message,
             nsecs_t reltime=0, uint32_t flags = 0);
-        
+
     status_t invalidate();
     
-    void dump(const MessageList::value_type& message);
+    void dump(const sp<MessageBase>& message);
 
 private:
-    status_t queueMessage(const MessageList::value_type& message,
+    status_t queueMessage(const sp<MessageBase>& message,
             nsecs_t reltime, uint32_t flags);
-    void dumpLocked(const MessageList::value_type& message);
+    void dumpLocked(const sp<MessageBase>& message);
     
     Mutex           mLock;
     Condition       mCondition;
     MessageList     mMessages;
     bool            mInvalidate;
-    MessageList::value_type mInvalidateMessage;
+    sp<MessageBase> mInvalidateMessage;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 62d829b..5a6893f 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -426,7 +426,7 @@
             timeout = waitTime>0 ? waitTime : 0;
         }
 
-        MessageList::value_type msg = mEventQueue.waitMessage(timeout);
+        sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
 
         // see if we timed out
         if (isFrozen()) {
@@ -461,9 +461,20 @@
     const_cast<SurfaceFlinger*>(this)->signalEvent();
 }
 
-void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags)
 {
-    mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay);
+    return mEventQueue.postMessage(msg, reltime, flags);
+}
+
+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags)
+{
+    status_t res = mEventQueue.postMessage(msg, reltime, flags);
+    if (res == NO_ERROR) {
+        msg->wait();
+    }
+    return res;
 }
 
 // ----------------------------------------------------------------------------
@@ -1135,15 +1146,11 @@
     return android_atomic_and(~flags, &mTransactionFlags) & flags;
 }
 
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay)
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
 {
     uint32_t old = android_atomic_or(flags, &mTransactionFlags);
     if ((old & flags)==0) { // wake the server up
-        if (delay > 0) {
-            signalDelayedEvent(delay);
-        } else {
-            signalEvent();
-        }
+        signalEvent();
     }
     return old;
 }
@@ -1245,7 +1252,7 @@
 
     //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
     int32_t id = client->generateId(pid);
-    if (uint32_t(id) >= NUM_LAYERS_MAX) {
+    if (uint32_t(id) >= SharedBufferStack::NUM_LAYERS_MAX) {
         LOGE("createSurface() failed, generateId = %d", id);
         return surfaceHandle;
     }
@@ -1399,7 +1406,7 @@
         }
     };
 
-    mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
+    postMessageAsync( new MessageDestroySurface(this, layer) );
     return NO_ERROR;
 }
 
@@ -1672,7 +1679,7 @@
 int32_t Client::generateId(int pid)
 {
     const uint32_t i = clz( ~mBitmap );
-    if (i >= NUM_LAYERS_MAX) {
+    if (i >= SharedBufferStack::NUM_LAYERS_MAX) {
         return NO_MEMORY;
     }
     mPid = pid;
@@ -1699,7 +1706,8 @@
 }
 
 bool Client::isValid(int32_t i) const {
-    return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
+    return (uint32_t(i)<SharedBufferStack::NUM_LAYERS_MAX) &&
+            (mBitmap & (1<<(31-i)));
 }
 
 sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 9c8de51..2558324 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -255,8 +255,6 @@
 public:     // hack to work around gcc 4.0.3 bug
             void        signalEvent();
 private:
-            void        signalDelayedEvent(nsecs_t delay);
-
             void        handleConsoleEvents();
             void        handleTransaction(uint32_t transactionFlags);
             void        handleTransactionLocked(
@@ -286,7 +284,7 @@
             void        free_resources_l();
 
             uint32_t    getTransactionFlags(uint32_t flags);
-            uint32_t    setTransactionFlags(uint32_t flags, nsecs_t delay = 0);
+            uint32_t    setTransactionFlags(uint32_t flags);
             void        commitTransaction();
 
 
@@ -310,7 +308,12 @@
            
 
     mutable     MessageQueue    mEventQueue;
-    
+
+    status_t postMessageAsync(const sp<MessageBase>& msg,
+            nsecs_t reltime=0, uint32_t flags = 0);
+
+    status_t postMessageSync(const sp<MessageBase>& msg,
+            nsecs_t reltime=0, uint32_t flags = 0);
                 
                 
                 // access must be protected by mStateLock
diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp
index e5d5302..ee2159b 100644
--- a/libs/surfaceflinger/TextureManager.cpp
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -68,7 +68,7 @@
     return false;
 }
 
-status_t TextureManager::initEglImage(Texture* texture,
+status_t TextureManager::initEglImage(Image* texture,
         EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
 {
     status_t err = NO_ERROR;
@@ -108,7 +108,6 @@
             err = INVALID_OPERATION;
         } else {
             // Everything went okay!
-            texture->NPOTAdjust = false;
             texture->dirty  = false;
             texture->width  = clientBuf->width;
             texture->height = clientBuf->height;
diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h
index 90cb62b..d0acfe9 100644
--- a/libs/surfaceflinger/TextureManager.h
+++ b/libs/surfaceflinger/TextureManager.h
@@ -36,21 +36,24 @@
 
 // ---------------------------------------------------------------------------
 
-struct Texture {
-    Texture() : name(-1U), width(0), height(0),
-        image(EGL_NO_IMAGE_KHR), transform(0),
-        NPOTAdjust(false), dirty(true) { }
+struct Image {
+    Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
+        transform(0), dirty(true) { }
     GLuint        name;
+    EGLImageKHR   image;
     GLuint        width;
     GLuint        height;
+    uint32_t      transform;
+    bool          dirty;
+};
+
+struct Texture : public Image {
+    Texture() : Image(), NPOTAdjust(false)  { }
     GLuint        potWidth;
     GLuint        potHeight;
     GLfloat       wScale;
     GLfloat       hScale;
-    EGLImageKHR   image;
-    uint32_t      transform;
     bool          NPOTAdjust;
-    bool          dirty;
 };
 
 // ---------------------------------------------------------------------------
@@ -68,7 +71,7 @@
             const Region& dirty, const GGLSurface& t);
 
     // make active buffer an EGLImage if needed
-    status_t initEglImage(Texture* texture,
+    status_t initEglImage(Image* texture,
             EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
 };
 
diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp
index c5d0c0e..7049d9e 100644
--- a/libs/surfaceflinger_client/ISurface.cpp
+++ b/libs/surfaceflinger_client/ISurface.cpp
@@ -71,11 +71,15 @@
     {
     }
 
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage)
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
         data.writeInt32(bufferIdx);
+        data.writeInt32(w);
+        data.writeInt32(h);
+        data.writeInt32(format);
         data.writeInt32(usage);
         remote()->transact(REQUEST_BUFFER, data, &reply);
         sp<GraphicBuffer> buffer = new GraphicBuffer();
@@ -150,8 +154,11 @@
         case REQUEST_BUFFER: {
             CHECK_INTERFACE(ISurface, data, reply);
             int bufferIdx = data.readInt32();
-            int usage = data.readInt32();
-            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
+            uint32_t w = data.readInt32();
+            uint32_t h = data.readInt32();
+            uint32_t format = data.readInt32();
+            uint32_t usage = data.readInt32();
+            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));
             if (buffer == NULL)
                 return BAD_VALUE;
             return reply->write(*buffer);
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index dab8ed8..b4522598 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -44,7 +44,7 @@
 
 // these functions are used by the clients
 status_t SharedClient::validate(size_t i) const {
-    if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX))
+    if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))
         return BAD_INDEX;
     return surfaces[i].status;
 }
@@ -144,10 +144,10 @@
 // ----------------------------------------------------------------------------
 
 SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
-        int surface, int num, int32_t identity)
+        int surface, int32_t identity)
     : mSharedClient(sharedClient), 
       mSharedStack(sharedClient->surfaces + surface),
-      mNumBuffers(num), mIdentity(identity)
+      mIdentity(identity)
 {
 }
 
@@ -179,34 +179,16 @@
     char buffer[SIZE];
     String8 result;
     SharedBufferStack& stack( *mSharedStack );
-    int tail = computeTail();
     snprintf(buffer, SIZE, 
-            "%s[ head=%2d, available=%2d, queued=%2d, tail=%2d ] "
+            "%s[ head=%2d, available=%2d, queued=%2d ] "
             "reallocMask=%08x, inUse=%2d, identity=%d, status=%d",
-            prefix, stack.head, stack.available, stack.queued, tail,
+            prefix, stack.head, stack.available, stack.queued,
             stack.reallocMask, stack.inUse, stack.identity, stack.status);
     result.append(buffer);
-
-    snprintf(buffer, SIZE, " { ");
-    result.append(buffer);
-
-    for (int i=0 ; i<mNumBuffers ; i++) {
-        snprintf(buffer, SIZE, "%d ", stack.index[i]);
-        result.append(buffer);
-    }
-
-    snprintf(buffer, SIZE, " }\n");
-    result.append(buffer);
-
+    result.append("\n");
     return result;
 }
 
-int32_t SharedBufferBase::computeTail() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
-}
-
 status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
 {
     const SharedBufferStack& stack( *mSharedStack );
@@ -270,7 +252,7 @@
 }
 bool SharedBufferServer::ReallocateCondition::operator()() const {
     int32_t head = stack.head;
-    if (uint32_t(head) >= NUM_BUFFER_MAX) {
+    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) {
         // if stack.head is messed up, we cannot allow the server to
         // crash (since stack.head is mapped on the client side)
         stack.status = BAD_VALUE;
@@ -318,7 +300,7 @@
 }
 ssize_t SharedBufferServer::RetireUpdate::operator()() {
     int32_t head = stack.head;
-    if (uint32_t(head) >= NUM_BUFFER_MAX)
+    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
 
     // Preventively lock the current buffer before updating queued.
@@ -361,14 +343,20 @@
 
 SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
         int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, num, identity),
-      tail(0), undoDequeueTail(0)
+    : SharedBufferBase(sharedClient, surface, identity),
+      mNumBuffers(num), tail(0), undoDequeueTail(0)
 {
     SharedBufferStack& stack( *mSharedStack );
     tail = computeTail();
     queued_head = stack.head;
 }
 
+int32_t SharedBufferClient::computeTail() const
+{
+    SharedBufferStack& stack( *mSharedStack );
+    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
+}
+
 ssize_t SharedBufferClient::dequeue()
 {
     SharedBufferStack& stack( *mSharedStack );
@@ -377,7 +365,9 @@
         LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
                 tail, stack.head, stack.available, stack.queued);
     }
-        
+
+    RWLock::AutoRLock _rd(mLock);
+
     const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
 
     //LOGD("[%d] about to dequeue a buffer",
@@ -407,6 +397,8 @@
 
 status_t SharedBufferClient::undoDequeue(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
     // TODO: we can only undo the previous dequeue, we should
     // enforce that in the api
     UndoDequeueUpdate update(this);
@@ -419,6 +411,8 @@
 
 status_t SharedBufferClient::lock(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
     SharedBufferStack& stack( *mSharedStack );
     LockCondition condition(this, buf);
     status_t err = waitForCondition(condition);
@@ -427,6 +421,8 @@
 
 status_t SharedBufferClient::queue(int buf)
 {
+    RWLock::AutoRLock _rd(mLock);
+
     SharedBufferStack& stack( *mSharedStack );
 
     queued_head = (queued_head + 1) % mNumBuffers;
@@ -444,7 +440,7 @@
 bool SharedBufferClient::needNewBuffer(int buf) const
 {
     SharedBufferStack& stack( *mSharedStack );
-    const uint32_t mask = 1<<buf;
+    const uint32_t mask = 1<<(31-buf);
     return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
 }
 
@@ -460,21 +456,32 @@
     return stack.setDirtyRegion(buf, reg);
 }
 
-status_t SharedBufferClient::setBufferCount(int bufferCount)
+status_t SharedBufferClient::setBufferCount(
+        int bufferCount, const SetBufferCountCallback& ipc)
 {
     SharedBufferStack& stack( *mSharedStack );
-    if (uint32_t(bufferCount) >= NUM_BUFFER_MAX)
+    if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
-    mNumBuffers = bufferCount;
-    queued_head = (stack.head + stack.queued) % mNumBuffers;
-    return NO_ERROR;
+
+    if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN)
+        return BAD_VALUE;
+
+    RWLock::AutoWLock _wr(mLock);
+
+    status_t err = ipc(bufferCount);
+    if (err == NO_ERROR) {
+        mNumBuffers = bufferCount;
+        queued_head = (stack.head + stack.queued) % mNumBuffers;
+    }
+    return err;
 }
 
 // ----------------------------------------------------------------------------
 
 SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
         int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, num, identity)
+    : SharedBufferBase(sharedClient, surface, identity),
+      mNumBuffers(num)
 {
     mSharedStack->init(identity);
     mSharedStack->head = num-1;
@@ -490,10 +497,12 @@
 
 ssize_t SharedBufferServer::retireAndLock()
 {
+    RWLock::AutoRLock _l(mLock);
+
     RetireUpdate update(this, mNumBuffers);
     ssize_t buf = updateCondition( update );
     if (buf >= 0) {
-        if (uint32_t(buf) >= NUM_BUFFER_MAX)
+        if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
             return BAD_VALUE;
         SharedBufferStack& stack( *mSharedStack );
         buf = stack.index[buf];
@@ -518,11 +527,25 @@
     }
 }
 
-status_t SharedBufferServer::reallocate()
+status_t SharedBufferServer::reallocateAll()
 {
+    RWLock::AutoRLock _l(mLock);
+
     SharedBufferStack& stack( *mSharedStack );
-    uint32_t mask = (1<<mNumBuffers)-1;
-    android_atomic_or(mask, &stack.reallocMask); 
+    uint32_t mask = mBufferList.getMask();
+    android_atomic_or(mask, &stack.reallocMask);
+    return NO_ERROR;
+}
+
+status_t SharedBufferServer::reallocateAllExcept(int buffer)
+{
+    RWLock::AutoRLock _l(mLock);
+
+    SharedBufferStack& stack( *mSharedStack );
+    BufferList temp(mBufferList);
+    temp.remove(buffer);
+    uint32_t mask = temp.getMask();
+    android_atomic_or(mask, &stack.reallocMask);
     return NO_ERROR;
 }
 
@@ -534,6 +557,13 @@
 
 status_t SharedBufferServer::assertReallocate(int buf)
 {
+    /*
+     * NOTE: it's safe to hold mLock for read while waiting for
+     * the ReallocateCondition because that condition is not updated
+     * by the thread that holds mLock for write.
+     */
+    RWLock::AutoRLock _l(mLock);
+
     // TODO: need to validate "buf"
     ReallocateCondition condition(this, buf);
     status_t err = waitForCondition(condition);
@@ -546,9 +576,7 @@
     return stack.getDirtyRegion(buf);
 }
 
-
 /*
- *
  * NOTE: this is not thread-safe on the server-side, meaning
  * 'head' cannot move during this operation. The client-side
  * can safely operate an usual.
@@ -556,9 +584,11 @@
  */
 status_t SharedBufferServer::resize(int newNumBuffers)
 {
-    if (uint32_t(newNumBuffers) >= NUM_BUFFER_MAX)
+    if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
 
+    RWLock::AutoWLock _l(mLock);
+
     // for now we're not supporting shrinking
     const int numBuffers = mNumBuffers;
     if (newNumBuffers < numBuffers)
@@ -569,7 +599,7 @@
 
     // read the head, make sure it's valid
     int32_t head = stack.head;
-    if (uint32_t(head) >= NUM_BUFFER_MAX)
+    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
         return BAD_VALUE;
 
     int base = numBuffers;
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index afbeafb..71504fa 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -349,15 +349,18 @@
     const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
     const_cast<uint32_t&>(android_native_window_t::flags) = 0;
     // be default we request a hardware surface
-    mUsage = GRALLOC_USAGE_HW_RENDER;
     mConnected = 0;
+    // two buffers by default
+    mBuffers.setCapacity(2);
+    mBuffers.insertAt(0, 2);
 }
 
 Surface::~Surface()
 {
     // this is a client-side operation, the surface is destroyed, unmap
     // its buffers in this process.
-    for (int i=0 ; i<2 ; i++) {
+    size_t size = mBuffers.size();
+    for (size_t i=0 ; i<size ; i++) {
         if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
             getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
         }
@@ -365,6 +368,7 @@
 
     // clear all references and trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
+    mBuffers.clear();
     mClient.clear();
     mSurface.clear();
     delete mSharedBufferClient;
@@ -463,6 +467,22 @@
 
 // ----------------------------------------------------------------------------
 
+bool Surface::needNewBuffer(int bufIdx,
+        uint32_t *pWidth, uint32_t *pHeight,
+        uint32_t *pFormat, uint32_t *pUsage) const
+{
+    Mutex::Autolock _l(mSurfaceLock);
+
+    // Always call needNewBuffer(), since it clears the needed buffers flags
+    bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
+    bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
+    bool newNeewBuffer = needNewBuffer || !validBuffer;
+    if (newNeewBuffer) {
+        mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
+    }
+    return newNeewBuffer;
+}
+
 int Surface::dequeueBuffer(android_native_buffer_t** buffer)
 {
     sp<SurfaceComposerClient> client(getClient());
@@ -476,27 +496,28 @@
         return bufIdx;
     }
 
-    // below we make sure we AT LEAST have the usage flags we want
-    const uint32_t usage(getUsage());
-    const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
+    // grow the buffer array if needed
+    const size_t size = mBuffers.size();
+    const size_t needed = bufIdx+1;
+    if (size < needed) {
+        mBuffers.insertAt(size, needed-size);
+    }
 
-    // Always call needNewBuffer(), since it clears the needed buffers flags
-    bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
-    if (backBuffer == 0 || 
-        ((uint32_t(backBuffer->usage) & usage) != usage) ||
-        needNewBuffer)
-    {
-        err = getBufferLocked(bufIdx, usage);
-        LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)",
-                bufIdx, usage, strerror(-err));
+    uint32_t w, h, format, usage;
+    if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
+        err = getBufferLocked(bufIdx, w, h, format, usage);
+        LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)",
+                bufIdx, w, h, format, usage, strerror(-err));
         if (err == NO_ERROR) {
             // reset the width/height with the what we get from the buffer
+            const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
             mWidth  = uint32_t(backBuffer->width);
             mHeight = uint32_t(backBuffer->height);
         }
     }
 
     // if we still don't have a buffer here, we probably ran out of memory
+    const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
     if (!err && backBuffer==0) {
         err = NO_MEMORY;
     }
@@ -584,6 +605,9 @@
     case NATIVE_WINDOW_SET_CROP:
         res = dispatch_crop( args );
         break;
+    case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        res = dispatch_set_buffer_count( args );
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -607,12 +631,21 @@
     android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
     return crop( reinterpret_cast<Rect const*>(rect) );
 }
-
+int Surface::dispatch_set_buffer_count(va_list args) {
+    size_t bufferCount = va_arg(args, size_t);
+    return setBufferCount(bufferCount);
+}
+int Surface::dispatch_set_buffers_geometry(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    int f = va_arg(args, int);
+    return setBuffersGeometry(w, h, f);
+}
 
 void Surface::setUsage(uint32_t reqUsage)
 {
     Mutex::Autolock _l(mSurfaceLock);
-    mUsage = reqUsage;
+    mBufferInfo.set(reqUsage);
 }
 
 int Surface::connect(int api)
@@ -653,18 +686,6 @@
     return err;
 }
 
-uint32_t Surface::getUsage() const
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    return mUsage;
-}
-
-int Surface::getConnectedApi() const
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    return mConnected;
-}
-
 int Surface::crop(Rect const* rect)
 {
     Mutex::Autolock _l(mSurfaceLock);
@@ -678,22 +699,41 @@
     sp<ISurface> s(mSurface);
     if (s == 0) return NO_INIT;
 
-    // FIXME: this needs to be synchronized dequeue/queue
+    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
+        sp<ISurface> surface;
+        virtual status_t operator()(int bufferCount) const {
+            return surface->setBufferCount(bufferCount);
+        }
+    public:
+        SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { }
+    } ipc(s);
 
-    status_t err = s->setBufferCount(bufferCount);
+    status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
     LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
             bufferCount, strerror(-err));
-    if (err == NO_ERROR) {
-        err = mSharedBufferClient->getStatus();
-        LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);
-        if (!err) {
-            // update our local copy of the buffer count
-            mSharedBufferClient->setBufferCount(bufferCount);
-        }
-    }
     return err;
 }
 
+int Surface::setBuffersGeometry(int w, int h, int format)
+{
+    if (w<0 || h<0 || format<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    Mutex::Autolock _l(mSurfaceLock);
+    mBufferInfo.set(w, h, format);
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::getConnectedApi() const
+{
+    Mutex::Autolock _l(mSurfaceLock);
+    return mConnected;
+}
 
 // ----------------------------------------------------------------------------
 
@@ -824,7 +864,8 @@
     return buffer->getIndex();
 }
 
-status_t Surface::getBufferLocked(int index, int usage)
+status_t Surface::getBufferLocked(int index,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
 {
     sp<ISurface> s(mSurface);
     if (s == 0) return NO_INIT;
@@ -832,20 +873,21 @@
     status_t err = NO_MEMORY;
 
     // free the current buffer
-    sp<GraphicBuffer>& currentBuffer(mBuffers[index]);
+    sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
     if (currentBuffer != 0) {
         getBufferMapper().unregisterBuffer(currentBuffer->handle);
         currentBuffer.clear();
     }
 
-    sp<GraphicBuffer> buffer = s->requestBuffer(index, usage);
+    sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
     LOGE_IF(buffer==0,
             "ISurface::getBuffer(%d, %08x) returned NULL",
             index, usage);
     if (buffer != 0) { // this should never happen by construction
         LOGE_IF(buffer->handle == NULL, 
-                "Surface (identity=%d) requestBuffer(%d, %08x) returned"
-                "a buffer with a null handle", mIdentity, index, usage);
+                "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
+                "returned a buffer with a null handle",
+                mIdentity, index, w, h, format, usage);
         err = mSharedBufferClient->getStatus();
         LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);
         if (!err && buffer->handle != NULL) {
@@ -857,11 +899,50 @@
                 currentBuffer->setIndex(index);
             }
         } else {
-            err = err<0 ? err : NO_MEMORY;
+            err = err<0 ? err : status_t(NO_MEMORY);
         }
     }
     return err; 
 }
 
+// ----------------------------------------------------------------------------
+Surface::BufferInfo::BufferInfo()
+    : mWidth(0), mHeight(0), mFormat(0),
+      mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0)
+{
+}
+
+void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) {
+    if ((mWidth != w) || (mHeight != h) || (mFormat != format)) {
+        mWidth = w;
+        mHeight = h;
+        mFormat = format;
+        mDirty |= GEOMETRY;
+    }
+}
+
+void Surface::BufferInfo::set(uint32_t usage) {
+    mUsage = usage;
+}
+
+void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight,
+        uint32_t *pFormat, uint32_t *pUsage) const {
+    *pWidth  = mWidth;
+    *pHeight = mHeight;
+    *pFormat = mFormat;
+    *pUsage  = mUsage;
+}
+
+bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
+    // make sure we AT LEAST have the usage flags we want
+    if (mDirty || buffer==0 ||
+            ((buffer->usage & mUsage) != mUsage)) {
+        mDirty = 0;
+        return false;
+    }
+    return true;
+}
+
+// ----------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 85167da..9ac73d2 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -250,7 +250,7 @@
 status_t SurfaceComposerClient::getDisplayInfo(
         DisplayID dpy, DisplayInfo* info)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
 
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
@@ -268,7 +268,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -277,7 +277,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -286,7 +286,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -345,7 +345,7 @@
         sp<ISurface> surface = mClient->createSurface(&data, pid, name,
                 display, w, h, format, flags);
         if (surface != 0) {
-            if (uint32_t(data.token) < NUM_LAYERS_MAX) {
+            if (uint32_t(data.token) < SharedBufferStack::NUM_LAYERS_MAX) {
                 result = new SurfaceControl(this, surface, data, w, h, format, flags);
             }
         }
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
index f490a65..f409f48 100644
--- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
+++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
@@ -54,8 +54,16 @@
 
 
     printf("resize test\n");
-    s.resize(6);
-    c.setBufferCount(6);
+    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
+        SharedBufferServer& s;
+        virtual status_t operator()(int bufferCount) const {
+            return s.resize(bufferCount);
+        }
+    public:
+        SetBufferCountIPC(SharedBufferServer& s) : s(s) { }
+    } resize(s);
+
+    c.setBufferCount(6, resize);
     int list3[6] = {3, 2, 1, 4, 5, 0};
     test0(s, c, 6, list3);
 
diff --git a/location/java/android/location/Criteria.java b/location/java/android/location/Criteria.java
index 9d258d0..647a9df 100644
--- a/location/java/android/location/Criteria.java
+++ b/location/java/android/location/Criteria.java
@@ -57,9 +57,72 @@
      */
     public static final int ACCURACY_COARSE = 2;
 
-    private int mAccuracy              = NO_REQUIREMENT;
+    /**
+     * A constant indicating a low location accuracy requirement
+     * - may be used for horizontal, altitude, speed or bearing accuracy.
+     * For horizontal and vertical position this corresponds to an accuracy
+     * greater than 500 meters.  For speed and bearing, this corresponds
+     * to greater than 5 meters/second velocity and 10 degrees for bearing.
+     */
+    public static final int ACCURACY_LOW = 1;
+
+    /**
+     * A constant indicating a medium accuracy requirement
+     * - may be used for horizontal, altitude, speed or bearing accuracy.
+     * For horizontal position this corresponds to an accuracy of between
+     * 100 and 500 meters, and between 200 and 500 meters for vertical accuracy.
+     * For speed and bearing, this corresponds to 1 meter/second to 5 meters/second
+     * velocity and and between 5 and 10 degrees for bearing.
+     */
+    public static final int ACCURACY_MEDIUM = 2;
+
+    /**
+     * a constant indicating a high accuracy requirement
+     * - may be used for horizontal, altitude, speed or bearing accuracy.
+     * For horizontal and vertical position this corresponds to an accuracy
+     * less than 100 meters.  For speed and bearing, this corresponds
+     * to less 1 meter/second velocity less than 5 degrees for bearing.
+     */
+    public static final int ACCURACY_HIGH = 3;
+
+    /**
+     * a constant indicating the best accuracy that is available for any
+     * location provider available
+     * - may be used for horizontal, altitude, speed or bearing accuracy.
+     */
+    public static final int ACCURACY_BEST = 4;
+
+    /**
+     * A constant indicating horizontal accuracy has the top priority
+     */
+    public static final int HORIZONTAL_ACCURACY_PRIORITY = 1;
+
+    /**
+     * A constant indicating altitude accuracy has the top priority
+     */
+    public static final int VERTICAL_ACCURACY_PRIORITY = 2;
+
+    /**
+     * A constant indicating speed accuracy has the top priority
+     */
+    public static final int SPEED_ACCURACY_PRIORITY = 3;
+
+    /**
+     * A constant indicating bearing accuracy has the top priority
+     */
+    public static final int BEARING_ACCURACY_PRIORITY = 4;
+
+    /**
+     * A constant indicating power requirement has the top priority
+     */
+    public static final int POWER_REQUIREMENT_PRIORITY = 5;
+
+    private int mHorizontalAccuracy    = NO_REQUIREMENT;
+    private int mVerticalAccuracy      = NO_REQUIREMENT;
+    private int mSpeedAccuracy         = NO_REQUIREMENT;
+    private int mBearingAccuracy       = NO_REQUIREMENT;
+    private int mPriority              = HORIZONTAL_ACCURACY_PRIORITY;
     private int mPowerRequirement      = NO_REQUIREMENT;
-//    private int mPreferredResponseTime = NO_REQUIREMENT;
     private boolean mAltitudeRequired  = false;
     private boolean mBearingRequired   = false;
     private boolean mSpeedRequired     = false;
@@ -77,9 +140,12 @@
      * Constructs a new Criteria object that is a copy of the given criteria.
      */
     public Criteria(Criteria criteria) {
-        mAccuracy = criteria.mAccuracy;
+        mHorizontalAccuracy = criteria.mHorizontalAccuracy;
+        mVerticalAccuracy = criteria.mVerticalAccuracy;
+        mSpeedAccuracy = criteria.mSpeedAccuracy;
+        mBearingAccuracy = criteria.mBearingAccuracy;
+        mPriority = criteria.mPriority;
         mPowerRequirement = criteria.mPowerRequirement;
-//        mPreferredResponseTime = criteria.mPreferredResponseTime;
         mAltitudeRequired = criteria.mAltitudeRequired;
         mBearingRequired = criteria.mBearingRequired;
         mSpeedRequired = criteria.mSpeedRequired;
@@ -87,19 +153,149 @@
     }
 
     /**
+     * Indicates the desired horizontal accuracy (latitude and longitude).
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     * More accurate location may consume more power and may take longer.
+     *
+     * @throws IllegalArgumentException if accuracy is not one of the supported constants
+     */
+    public void setHorizontalAccuracy(int accuracy) {
+        if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) {
+            throw new IllegalArgumentException("accuracy=" + accuracy);
+        }
+        mHorizontalAccuracy = accuracy;
+    }
+
+    /**
+     * Returns a constant indicating the desired horizontal accuracy (latitude and longitude).
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     */
+    public int getHorizontalAccuracy() {
+        return mHorizontalAccuracy;
+    }
+
+    /**
+     * Indicates the desired vertical accuracy (altitude).
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     * More accurate location may consume more power and may take longer.
+     *
+     * @throws IllegalArgumentException if accuracy is not one of the supported constants
+     */
+    public void setVerticalAccuracy(int accuracy) {
+        if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) {
+            throw new IllegalArgumentException("accuracy=" + accuracy);
+        }
+        mVerticalAccuracy = accuracy;
+    }
+
+    /**
+     * Returns a constant indicating the desired vertical accuracy (altitude).
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     */
+    public int getVerticalAccuracy() {
+        return mVerticalAccuracy;
+    }
+
+    /**
+     * Indicates the desired speed accuracy.
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     * More accurate location may consume more power and may take longer.
+     *
+     * @throws IllegalArgumentException if accuracy is not one of the supported constants
+     */
+    public void setSpeedAccuracy(int accuracy) {
+        if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) {
+            throw new IllegalArgumentException("accuracy=" + accuracy);
+        }
+        mSpeedAccuracy = accuracy;
+    }
+
+    /**
+     * Returns a constant indicating the desired speed accuracy
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     */
+    public int getSpeedAccuracy() {
+        return mSpeedAccuracy;
+    }
+
+    /**
+     * Indicates the desired bearing accuracy.
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     * More accurate location may consume more power and may take longer.
+     *
+     * @throws IllegalArgumentException if accuracy is not one of the supported constants
+     */
+    public void setBearingAccuracy(int accuracy) {
+        if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) {
+            throw new IllegalArgumentException("accuracy=" + accuracy);
+        }
+        mBearingAccuracy = accuracy;
+    }
+
+    /**
+     * Returns a constant indicating the desired bearing accuracy.
+     * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
+     * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST},
+     */
+    public int getBearingAccuracy() {
+        return mBearingAccuracy;
+    }
+
+    /**
+     * Indicates the top priority to optimize for if the criteria parameters are
+     * found to be in conflict.
+     * Since a location provider might only be able to optimize for one requirement,
+     * the other requirements are considered good to have, but not guaranteed.
+     * This parameter does not override the priorities communicated through the
+     * preferred accuracy and power consumption parameters.
+     * If this parameter is not specified and conflicts occur, the location manager
+     * will use thefollowing default priority (high priority to low priority):
+     * {@link #HORIZONTAL_ACCURACY_PRIORITY}, {@link #POWER_REQUIREMENT_PRIORITY},
+     * {@link #VERTICAL_ACCURACY_PRIORITY}, {@link #SPEED_ACCURACY_PRIORITY},
+     * {@link #BEARING_ACCURACY_PRIORITY}.
+     */
+    public void setPreferredPriority(int priority) {
+        if (priority < HORIZONTAL_ACCURACY_PRIORITY || priority > POWER_REQUIREMENT_PRIORITY) {
+            throw new IllegalArgumentException("priority=" + priority);
+        }
+        mPriority = priority;
+    }
+
+    /**
+     * Returns a constant indicating the top priority to optimize for if the
+     * criteria parameters are found to be in conflict.
+     * The value can be {@link #HORIZONTAL_ACCURACY_PRIORITY},
+     * {@link #VERTICAL_ACCURACY_PRIORITY}, {@link #SPEED_ACCURACY_PRIORITY},
+     * {@link #BEARING_ACCURACY_PRIORITY} or {@link #POWER_REQUIREMENT_PRIORITY}.
+     */
+    public int getPriority() {
+        return mPriority;
+    }
+
+    /**
      * Indicates the desired accuracy for latitude and longitude. Accuracy
      * may be {@link #ACCURACY_FINE} if desired location
      * is fine, else it can be {@link #ACCURACY_COARSE}.
-     * More accurate location usually consumes more power and may take
-     * longer.
+     * More accurate location may consume more power and may take longer.
      *
-     * @throws IllegalArgumentException if accuracy is negative
+     * @throws IllegalArgumentException if accuracy is not one of the supported constants
      */
     public void setAccuracy(int accuracy) {
-        if (accuracy < NO_REQUIREMENT && accuracy > ACCURACY_COARSE) {
+        if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_COARSE) {
             throw new IllegalArgumentException("accuracy=" + accuracy);
         }
-        mAccuracy = accuracy;
+        if (accuracy == ACCURACY_FINE) {
+            mHorizontalAccuracy = ACCURACY_BEST;
+        } else {
+            mHorizontalAccuracy = ACCURACY_LOW;
+        }
     }
 
     /**
@@ -108,7 +304,11 @@
      * is fine, else it can be {@link #ACCURACY_COARSE}.
      */
     public int getAccuracy() {
-        return mAccuracy;
+        if (mHorizontalAccuracy >= ACCURACY_HIGH) {
+            return ACCURACY_FINE;
+        } else {
+            return ACCURACY_COARSE;
+        }
     }
 
     /**
@@ -131,20 +331,6 @@
         return mPowerRequirement;
     }
 
-//    /**
-//     * Indicates the preferred response time of the provider, in milliseconds.
-//     */
-//    public void setPreferredResponseTime(int time) {
-//        mPreferredResponseTime = time;
-//    }
-//
-//    /**
-//     * Returns the preferred response time of the provider, in milliseconds.
-//     */
-//    public int getPreferredResponseTime() {
-//        return mPreferredResponseTime;
-//    }
-
     /**
      * Indicates whether the provider is allowed to incur monetary cost.
      */
@@ -211,9 +397,12 @@
         new Parcelable.Creator<Criteria>() {
         public Criteria createFromParcel(Parcel in) {
             Criteria c = new Criteria();
-            c.mAccuracy = in.readInt();
+            c.mHorizontalAccuracy = in.readInt();
+            c.mVerticalAccuracy = in.readInt();
+            c.mSpeedAccuracy = in.readInt();
+            c.mBearingAccuracy = in.readInt();
+            c.mPriority = in.readInt();
             c.mPowerRequirement = in.readInt();
-//            c.mPreferredResponseTime = in.readInt();
             c.mAltitudeRequired = in.readInt() != 0;
             c.mBearingRequired = in.readInt() != 0;
             c.mSpeedRequired = in.readInt() != 0;
@@ -231,9 +420,12 @@
     }
 
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mAccuracy);
+        parcel.writeInt(mHorizontalAccuracy);
+        parcel.writeInt(mVerticalAccuracy);
+        parcel.writeInt(mSpeedAccuracy);
+        parcel.writeInt(mBearingAccuracy);
+        parcel.writeInt(mPriority);
         parcel.writeInt(mPowerRequirement);
-//        parcel.writeInt(mPreferredResponseTime);
         parcel.writeInt(mAltitudeRequired ? 1 : 0);
         parcel.writeInt(mBearingRequired ? 1 : 0);
         parcel.writeInt(mSpeedRequired ? 1 : 0);
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index c325b1b..546bb9d 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -40,7 +40,9 @@
  *
  * The Geocoder class requires a backend service that is not included in
  * the core android framework.  The Geocoder query methods will return an
- * empty list if there no backend service in the platform.
+ * empty list if there no backend service in the platform.  Use the
+ * isImplemented() method to determine whether a Geocoder implementation
+ * exists.
  */
 public final class Geocoder {
     private static final String TAG = "Geocoder";
@@ -49,6 +51,23 @@
     private ILocationManager mService;
 
     /**
+     * Returns true if the Geocoder methods getFromLocation and
+     * getFromLocationName are implemented.  Lack of network
+     * connectivity may still cause these methods to return null or
+     * empty lists.
+     */
+    public static Boolean isImplemented() {
+        IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
+        ILocationManager lm = ILocationManager.Stub.asInterface(b);
+        try {
+            return lm.geocoderIsImplemented();
+        } catch (RemoteException e) {
+            Log.e(TAG, "isImplemented: got RemoteException", e);
+            return false;
+        }
+    }
+
+    /**
      * Constructs a Geocoder whose responses will be localized for the
      * given Locale.
      *
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index 174fe3e..8b8e63b 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -29,8 +29,6 @@
  * as well as the Geocoder client's package name for geocoder server
  * logging.  This information is kept in a separate class to allow for
  * future expansion of the IGeocodeProvider interface.
- *
- * @hide
  */
 public class GeocoderParams implements Parcelable {
     private Locale mLocale;
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 2c0399e..32d4b27 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.location.Address;
+import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.IGeocodeProvider;
 import android.location.IGpsStatusListener;
@@ -32,13 +33,15 @@
  */
 interface ILocationManager
 {
-    List getAllProviders();
-    List getProviders(boolean enabledOnly);
+    List<String> getAllProviders();
+    List<String> getProviders(in Criteria criteria, boolean enabledOnly);
+    String getBestProvider(in Criteria criteria, boolean enabledOnly);
+    boolean providerMeetsCriteria(String provider, in Criteria criteria);
 
-    void requestLocationUpdates(String provider, long minTime, float minDistance,
-        in ILocationListener listener);
-    void requestLocationUpdatesPI(String provider, long minTime, float minDistance,
-        in PendingIntent intent);
+    void requestLocationUpdates(String provider, in Criteria criteria, long minTime, float minDistance,
+        boolean singleShot, in ILocationListener listener);
+    void requestLocationUpdatesPI(String provider, in Criteria criteria, long minTime, float minDistance,
+        boolean singleShot, in PendingIntent intent);
     void removeUpdates(in ILocationListener listener);
     void removeUpdatesPI(in PendingIntent intent);
 
@@ -64,6 +67,7 @@
     // it need not be shared with other providers.
     void reportLocation(in Location location, boolean passive);
 
+    boolean geocoderIsImplemented();
     String getFromLocation(double latitude, double longitude, int maxResults,
         in GeocoderParams params, out List<Address> addrs);
     String getFromLocationName(String locationName,
diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl
index 97b283c..2b9782a 100644
--- a/location/java/android/location/ILocationProvider.aidl
+++ b/location/java/android/location/ILocationProvider.aidl
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.location.Criteria;
 import android.location.Location;
 import android.net.NetworkInfo;
 import android.os.Bundle;
@@ -34,6 +35,7 @@
     boolean supportsSpeed();
     boolean supportsBearing();
     int getPowerRequirement();
+    boolean meetsCriteria(in Criteria criteria);
     int getAccuracy();
     void enable();
     void disable();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 28bc599..7d07e4b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -28,8 +28,6 @@
 import com.android.internal.location.DummyLocationProvider;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 
@@ -249,15 +247,12 @@
      * factory Context.getSystemService.
      */
     public LocationManager(ILocationManager service) {
-        if (false) {
-            Log.d(TAG, "Constructor: service = " + service);
-        }
         mService = service;
     }
 
     private LocationProvider createProvider(String name, Bundle info) {
         DummyLocationProvider provider =
-            new DummyLocationProvider(name);
+            new DummyLocationProvider(name, mService);
         provider.setRequiresNetwork(info.getBoolean("network"));
         provider.setRequiresSatellite(info.getBoolean("satellite"));
         provider.setRequiresCell(info.getBoolean("cell"));
@@ -299,7 +294,7 @@
      */
     public List<String> getProviders(boolean enabledOnly) {
         try {
-            return mService.getProviders(enabledOnly);
+            return mService.getProviders(null, enabledOnly);
         } catch (RemoteException ex) {
             Log.e(TAG, "getProviders: RemoteException", ex);
         }
@@ -344,173 +339,15 @@
      * @return list of Strings containing names of the providers
      */
     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
-        List<String> goodProviders = Collections.emptyList();
-        List<String> providers = getProviders(enabledOnly);
-        for (String providerName : providers) {
-            LocationProvider provider = getProvider(providerName);
-            if (provider != null && provider.meetsCriteria(criteria)) {
-                if (goodProviders.isEmpty()) {
-                    goodProviders = new ArrayList<String>();
-                }
-                goodProviders.add(providerName);
-            }
+        if (criteria == null) {
+            throw new IllegalArgumentException("criteria==null");
         }
-        return goodProviders;
-    }
-
-    /**
-     * Returns the next looser power requirement, in the sequence:
-     *
-     * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
-     */
-    private int nextPower(int power) {
-        switch (power) {
-        case Criteria.POWER_LOW:
-            return Criteria.POWER_MEDIUM;
-        case Criteria.POWER_MEDIUM:
-            return Criteria.POWER_HIGH;
-        case Criteria.POWER_HIGH:
-            return Criteria.NO_REQUIREMENT;
-        case Criteria.NO_REQUIREMENT:
-        default:
-            return Criteria.NO_REQUIREMENT;
+        try {
+            return mService.getProviders(criteria, enabledOnly);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "getProviders: RemoteException", ex);
         }
-    }
-
-    /**
-     * Returns the next looser accuracy requirement, in the sequence:
-     *
-     * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
-     */
-    private int nextAccuracy(int accuracy) {
-        if (accuracy == Criteria.ACCURACY_FINE) {
-            return Criteria.ACCURACY_COARSE;
-        } else {
-            return Criteria.NO_REQUIREMENT;
-        }
-    }
-
-    private abstract class LpComparator implements Comparator<LocationProvider> {
-
-        public int compare(int a1, int a2) {
-            if (a1 < a2) {
-                return -1;
-            } else if (a1 > a2) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
-
-        public int compare(float a1, float a2) {
-            if (a1 < a2) {
-                return -1;
-            } else if (a1 > a2) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
-    }
-
-    private class LpPowerComparator extends LpComparator {
-        public int compare(LocationProvider l1, LocationProvider l2) {
-            int a1 = l1.getPowerRequirement();
-            int a2 = l2.getPowerRequirement();
-            return compare(a1, a2); // Smaller is better
-         }
-
-         public boolean equals(LocationProvider l1, LocationProvider l2) {
-             int a1 = l1.getPowerRequirement();
-             int a2 = l2.getPowerRequirement();
-             return a1 == a2;
-         }
-    }
-
-    private class LpAccuracyComparator extends LpComparator {
-        public int compare(LocationProvider l1, LocationProvider l2) {
-            int a1 = l1.getAccuracy();
-            int a2 = l2.getAccuracy();
-            return compare(a1, a2); // Smaller is better
-         }
-
-         public boolean equals(LocationProvider l1, LocationProvider l2) {
-             int a1 = l1.getAccuracy();
-             int a2 = l2.getAccuracy();
-             return a1 == a2;
-         }
-    }
-
-    private class LpCapabilityComparator extends LpComparator {
-
-        private static final int ALTITUDE_SCORE = 4;
-        private static final int BEARING_SCORE = 4;
-        private static final int SPEED_SCORE = 4;
-
-        private int score(LocationProvider p) {
-            return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
-                (p.supportsBearing() ? BEARING_SCORE : 0) +
-                (p.supportsSpeed() ? SPEED_SCORE : 0);
-        }
-
-        public int compare(LocationProvider l1, LocationProvider l2) {
-            int a1 = score(l1);
-            int a2 = score(l2);
-            return compare(-a1, -a2); // Bigger is better
-         }
-
-         public boolean equals(LocationProvider l1, LocationProvider l2) {
-             int a1 = score(l1);
-             int a2 = score(l2);
-             return a1 == a2;
-         }
-    }
-
-    private LocationProvider best(List<String> providerNames) {
-        List<LocationProvider> providers = new ArrayList<LocationProvider>(providerNames.size());
-        for (String name : providerNames) {
-            providers.add(getProvider(name));
-        }
-
-        if (providers.size() < 2) {
-            return providers.get(0);
-        }
-
-        // First, sort by power requirement
-        Collections.sort(providers, new LpPowerComparator());
-        int power = providers.get(0).getPowerRequirement();
-        if (power < providers.get(1).getPowerRequirement()) {
-            return providers.get(0);
-        }
-
-        int idx, size;
-
-        List<LocationProvider> tmp = new ArrayList<LocationProvider>();
-        idx = 0;
-        size = providers.size();
-        while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
-            tmp.add(providers.get(idx));
-            idx++;
-        }
-
-        // Next, sort by accuracy
-        Collections.sort(tmp, new LpAccuracyComparator());
-        int acc = tmp.get(0).getAccuracy();
-        if (acc < tmp.get(1).getAccuracy()) {
-            return tmp.get(0);
-        }
-
-        List<LocationProvider> tmp2 = new ArrayList<LocationProvider>();
-        idx = 0;
-        size = tmp.size();
-        while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
-            tmp2.add(tmp.get(idx));
-            idx++;
-        }
-
-        // Finally, sort by capability "score"
-        Collections.sort(tmp2, new LpCapabilityComparator());
-        return tmp2.get(0);
+        return null;
     }
 
     /**
@@ -536,72 +373,14 @@
      * @return name of the provider that best matches the requirements
      */
     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
-        List<String> goodProviders = getProviders(criteria, enabledOnly);
-        if (!goodProviders.isEmpty()) {
-            return best(goodProviders).getName();
+        if (criteria == null) {
+            throw new IllegalArgumentException("criteria==null");
         }
-
-        // Make a copy of the criteria that we can modify
-        criteria = new Criteria(criteria);
-
-        // Loosen power requirement
-        int power = criteria.getPowerRequirement();
-        while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
-            power = nextPower(power);
-            criteria.setPowerRequirement(power);
-            goodProviders = getProviders(criteria, enabledOnly);
+        try {
+            return mService.getBestProvider(criteria, enabledOnly);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "getBestProvider: RemoteException", ex);
         }
-        if (!goodProviders.isEmpty()) {
-            return best(goodProviders).getName();
-        }
-
-//        // Loosen response time requirement
-//        int responseTime = criteria.getPreferredResponseTime();
-//        while (goodProviders.isEmpty() &&
-//            (responseTime != Criteria.NO_REQUIREMENT)) {
-//            responseTime += 1000;
-//            if (responseTime > 60000) {
-//                responseTime = Criteria.NO_REQUIREMENT;
-//            }
-//            criteria.setPreferredResponseTime(responseTime);
-//            goodProviders = getProviders(criteria);
-//        }
-//        if (!goodProviders.isEmpty()) {
-//            return best(goodProviders);
-//        }
-
-        // Loosen accuracy requirement
-        int accuracy = criteria.getAccuracy();
-        while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
-            accuracy = nextAccuracy(accuracy);
-            criteria.setAccuracy(accuracy);
-            goodProviders = getProviders(criteria, enabledOnly);
-        }
-        if (!goodProviders.isEmpty()) {
-            return best(goodProviders).getName();
-        }
-
-        // Remove bearing requirement
-        criteria.setBearingRequired(false);
-        goodProviders = getProviders(criteria, enabledOnly);
-        if (!goodProviders.isEmpty()) {
-            return best(goodProviders).getName();
-        }
-
-        // Remove speed requirement
-        criteria.setSpeedRequired(false);
-        goodProviders = getProviders(criteria, enabledOnly);
-        if (!goodProviders.isEmpty()) {
-            return best(goodProviders).getName();
-        }
-
-        // Remove altitude requirement
-        criteria.setAltitudeRequired(false);
-        goodProviders = getProviders(criteria, enabledOnly);
-        if (!goodProviders.isEmpty()) {
-            return best(goodProviders).getName();
-        }
-
         return null;
     }
 
@@ -658,7 +437,7 @@
         if (listener == null) {
             throw new IllegalArgumentException("listener==null");
         }
-        _requestLocationUpdates(provider, minTime, minDistance, listener, null);
+        _requestLocationUpdates(provider, null, minTime, minDistance, false, listener, null);
     }
 
     /**
@@ -701,10 +480,10 @@
      * each location update
      * @param looper a Looper object whose message queue will be used to
      * implement the callback mechanism.
+     * If looper is null then the callbacks will be called on the main thread.
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
-     * @throws IllegalArgumentException if looper is null
      * @throws SecurityException if no suitable permission is present for the provider.
      */
     public void requestLocationUpdates(String provider,
@@ -716,15 +495,70 @@
         if (listener == null) {
             throw new IllegalArgumentException("listener==null");
         }
-        if (looper == null) {
-            throw new IllegalArgumentException("looper==null");
-        }
-        _requestLocationUpdates(provider, minTime, minDistance, listener, looper);
+        _requestLocationUpdates(provider, null, minTime, minDistance, false, listener, looper);
     }
 
-    private void _requestLocationUpdates(String provider,
-        long minTime, float minDistance, LocationListener listener,
-        Looper looper) {
+    /**
+     * Registers the current activity to be notified periodically based on
+     * the specified criteria.  Periodically, the supplied LocationListener will
+     * be called with the current Location or with status updates.
+     *
+     * <p> It may take a while to receive the most recent location. If
+     * an immediate location is required, applications may use the
+     * {@link #getLastKnownLocation(String)} method.
+     *
+     * <p> In case the provider is disabled by the user, updates will stop,
+     * and the {@link LocationListener#onProviderDisabled(String)}
+     * method will be called. As soon as the provider is enabled again,
+     * the {@link LocationListener#onProviderEnabled(String)} method will
+     * be called and location updates will start again.
+     *
+     * <p> The frequency of notification may be controlled using the
+     * minTime and minDistance parameters. If minTime is greater than 0,
+     * the LocationManager could potentially rest for minTime milliseconds
+     * between location updates to conserve power. If minDistance is greater than 0,
+     * a location will only be broadcasted if the device moves by minDistance meters.
+     * To obtain notifications as frequently as possible, set both parameters to 0.
+     *
+     * <p> Background services should be careful about setting a sufficiently high
+     * minTime so that the device doesn't consume too much power by keeping the
+     * GPS or wireless radios on all the time. In particular, values under 60000ms
+     * are not recommended.
+     *
+     * <p> The supplied Looper is used to implement the callback mechanism.
+     *
+     * @param minTime the minimum time interval for notifications, in
+     * milliseconds. This field is only used as a hint to conserve power, and actual
+     * time between location updates may be greater or lesser than this value.
+     * @param minDistance the minimum distance interval for notifications,
+     * in meters
+     * @param criteria contains parameters for the location manager to choose the
+     * appropriate provider and parameters to compute the location
+     * @param listener a {#link LocationListener} whose
+     * {@link LocationListener#onLocationChanged} method will be called for
+     * each location update
+     * @param looper a Looper object whose message queue will be used to
+     * implement the callback mechanism.
+     * If looper is null then the callbacks will be called on the main thread.
+     *
+     * @throws IllegalArgumentException if criteria is null
+     * @throws IllegalArgumentException if listener is null
+     * @throws SecurityException if no suitable permission is present to access
+     * the location services.
+     */
+    public void requestLocationUpdates(long minTime, float minDistance,
+            Criteria criteria, LocationListener listener, Looper looper) {
+        if (criteria == null) {
+            throw new IllegalArgumentException("criteria==null");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("listener==null");
+        }
+        _requestLocationUpdates(null, criteria, minTime, minDistance, false, listener, looper);
+    }
+
+    private void _requestLocationUpdates(String provider, Criteria criteria, long minTime,
+            float minDistance, boolean singleShot, LocationListener listener, Looper looper) {
         if (minTime < 0L) {
             minTime = 0L;
         }
@@ -739,7 +573,7 @@
                     transport = new ListenerTransport(listener, looper);
                 }
                 mListeners.put(listener, transport);
-                mService.requestLocationUpdates(provider, minTime, minDistance, transport);
+                mService.requestLocationUpdates(provider, criteria, minTime, minDistance, singleShot, transport);
             }
         } catch (RemoteException ex) {
             Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex);
@@ -785,7 +619,7 @@
      * time between location updates may be greater or lesser than this value.
      * @param minDistance the minimum distance interval for notifications,
      * in meters
-     * @param intent a {#link PendingIntet} to be sent for each location update
+     * @param intent a {#link PendingIntent} to be sent for each location update
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if intent is null
@@ -799,11 +633,67 @@
         if (intent == null) {
             throw new IllegalArgumentException("intent==null");
         }
-        _requestLocationUpdates(provider, minTime, minDistance, intent);
+        _requestLocationUpdates(provider, null, minTime, minDistance, false, intent);
     }
 
-    private void _requestLocationUpdates(String provider,
-            long minTime, float minDistance, PendingIntent intent) {
+    /**
+     * Registers the current activity to be notified periodically based on
+     * the specified criteria.  Periodically, the supplied PendingIntent will
+     * be broadcast with the current Location or with status updates.
+     *
+     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+     *
+     * <p> It may take a while to receive the most recent location. If
+     * an immediate location is required, applications may use the
+     * {@link #getLastKnownLocation(String)} method.
+     *
+     * <p> The frequency of notification or new locations may be controlled using the
+     * minTime and minDistance parameters. If minTime is greater than 0,
+     * the LocationManager could potentially rest for minTime milliseconds
+     * between location updates to conserve power. If minDistance is greater than 0,
+     * a location will only be broadcast if the device moves by minDistance meters.
+     * To obtain notifications as frequently as possible, set both parameters to 0.
+     *
+     * <p> Background services should be careful about setting a sufficiently high
+     * minTime so that the device doesn't consume too much power by keeping the
+     * GPS or wireless radios on all the time. In particular, values under 60000ms
+     * are not recommended.
+     *
+     * <p> In case the provider is disabled by the user, updates will stop,
+     * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value
+     * of false.  If the provider is re-enabled, an intent will be sent with an
+     * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will
+     * start again.
+     *
+     * <p> If the provider's status changes, an intent will be sent with an extra with key
+     * KEY_STATUS_CHANGED and an integer value indicating the new status.  Any extras associated
+     * with the status update will be sent as well.
+     *
+     * @param minTime the minimum time interval for notifications, in
+     * milliseconds. This field is only used as a hint to conserve power, and actual
+     * time between location updates may be greater or lesser than this value.
+     * @param minDistance the minimum distance interval for notifications,
+     * in meters
+     * @param criteria contains parameters for the location manager to choose the
+     * appropriate provider and parameters to compute the location
+     * @param intent a {#link PendingIntent} to be sent for each location update
+     *
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present for the provider.
+     */
+    public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent intent) {
+        if (criteria == null) {
+            throw new IllegalArgumentException("criteria==null");
+        }
+        if (intent == null) {
+            throw new IllegalArgumentException("intent==null");
+        }
+        _requestLocationUpdates(null, criteria, minTime, minDistance, false, intent);
+    }
+
+    private void _requestLocationUpdates(String provider, Criteria criteria,
+            long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
         if (minTime < 0L) {
             minTime = 0L;
         }
@@ -812,13 +702,150 @@
         }
 
         try {
-            mService.requestLocationUpdatesPI(provider, minTime, minDistance, intent);
+            mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot, intent);
         } catch (RemoteException ex) {
             Log.e(TAG, "requestLocationUpdates: RemoteException", ex);
         }
     }
 
     /**
+     * Registers the current activity to be notified periodically by
+     * the named provider.  Periodically, the supplied LocationListener will
+     * be called with the current Location or with status updates.
+     *
+     * <p> It may take a while to receive the most recent location. If
+     * an immediate location is required, applications may use the
+     * {@link #getLastKnownLocation(String)} method.
+     *
+     * <p> In case the provider is disabled by the user, updates will stop,
+     * and the {@link LocationListener#onProviderDisabled(String)}
+     * method will be called. As soon as the provider is enabled again,
+     * the {@link LocationListener#onProviderEnabled(String)} method will
+     * be called and location updates will start again.
+     *
+     * <p> The supplied Looper is used to implement the callback mechanism.
+     *
+     * @param provider the name of the provider with which to register
+     * @param listener a {#link LocationListener} whose
+     * {@link LocationListener#onLocationChanged} method will be called for
+     * each location update
+     * @param looper a Looper object whose message queue will be used to
+     * implement the callback mechanism.
+     * If looper is null then the callbacks will be called on the main thread.
+     *
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if listener is null
+     * @throws SecurityException if no suitable permission is present for the provider.
+     */
+    public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
+        if (provider == null) {
+            throw new IllegalArgumentException("provider==null");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("listener==null");
+        }
+        _requestLocationUpdates(provider, null, 0L, 0.0f, true, listener, looper);
+    }
+
+    /**
+     * Registers the current activity to be notified periodically based on
+     * the specified criteria.  Periodically, the supplied LocationListener will
+     * be called with the current Location or with status updates.
+     *
+     * <p> It may take a while to receive the most recent location. If
+     * an immediate location is required, applications may use the
+     * {@link #getLastKnownLocation(String)} method.
+     *
+     * <p> In case the provider is disabled by the user, updates will stop,
+     * and the {@link LocationListener#onProviderDisabled(String)}
+     * method will be called. As soon as the provider is enabled again,
+     * the {@link LocationListener#onProviderEnabled(String)} method will
+     * be called and location updates will start again.
+     *
+     * <p> The supplied Looper is used to implement the callback mechanism.
+     *
+     * @param criteria contains parameters for the location manager to choose the
+     * appropriate provider and parameters to compute the location
+     * @param listener a {#link LocationListener} whose
+     * {@link LocationListener#onLocationChanged} method will be called for
+     * each location update
+     * @param looper a Looper object whose message queue will be used to
+     * implement the callback mechanism.
+     * If looper is null then the callbacks will be called on the current thread.
+     *
+     * @throws IllegalArgumentException if criteria is null
+     * @throws IllegalArgumentException if listener is null
+     * @throws SecurityException if no suitable permission is present to access
+     * the location services.
+     */
+    public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {
+        if (criteria == null) {
+            throw new IllegalArgumentException("criteria==null");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("listener==null");
+        }
+        _requestLocationUpdates(null, criteria, 0L, 0.0f, true, listener, looper);
+    }
+
+    /**
+     * Registers the current activity to be notified periodically by
+     * the named provider.  Periodically, the supplied PendingIntent will
+     * be broadcast with the current Location or with status updates.
+     *
+     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+     *
+     * <p> It may take a while to receive the most recent location. If
+     * an immediate location is required, applications may use the
+     * {@link #getLastKnownLocation(String)} method.
+     *
+     * @param provider the name of the provider with which to register
+     * @param intent a {#link PendingIntent} to be sent for the location update
+     *
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present for the provider.
+     */
+    public void requestSingleUpdate(String provider, PendingIntent intent) {
+        if (provider == null) {
+            throw new IllegalArgumentException("provider==null");
+        }
+        if (intent == null) {
+            throw new IllegalArgumentException("intent==null");
+        }
+        _requestLocationUpdates(provider, null, 0L, 0.0f, true, intent);
+    }
+
+    /**
+     * Registers the current activity to be notified periodically based on
+     * the specified criteria.  Periodically, the supplied PendingIntent will
+     * be broadcast with the current Location or with status updates.
+     *
+     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+     *
+     * <p> It may take a while to receive the most recent location. If
+     * an immediate location is required, applications may use the
+     * {@link #getLastKnownLocation(String)} method.
+     *
+     * @param criteria contains parameters for the location manager to choose the
+     * appropriate provider and parameters to compute the location
+     * @param intent a {#link PendingIntent} to be sent for the location update
+     *
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present for the provider.
+     */
+    public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
+        if (criteria == null) {
+            throw new IllegalArgumentException("criteria==null");
+        }
+        if (intent == null) {
+            throw new IllegalArgumentException("intent==null");
+        }
+        _requestLocationUpdates(null, criteria, 0L, 0.0f, true, intent);
+    }
+
+    /**
      * Removes any current registration for location updates of the current activity
      * with the given LocationListener.  Following this call, updates will no longer
      * occur for this listener.
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index bb3e2a5..8c16580 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -16,6 +16,9 @@
 
 package android.location;
 
+import android.os.RemoteException;
+import android.util.Log;
+
 /**
  * An abstract superclass for location providers.  A location provider
  * provides periodic reports on the geographical location of the
@@ -36,7 +39,8 @@
     // in the name of a LocationProvider.
     static final String BAD_CHARS_REGEX = "[^a-zA-Z0-9]";
 
-    private String mName;
+    private final String mName;
+    private final ILocationManager mService;
 
     public static final int OUT_OF_SERVICE = 0;
     public static final int TEMPORARILY_UNAVAILABLE = 1;
@@ -50,13 +54,13 @@
      *
      * {@hide}
      */
-    public LocationProvider(String name) {
+    public LocationProvider(String name, ILocationManager service) {
         if (name.matches(BAD_CHARS_REGEX)) {
             throw new IllegalArgumentException("name " + name +
                 " contains an illegal character");
         }
-        // Log.d(TAG, "Constructor: name = " + name);
         mName = name;
+        mService = service;
     }
 
     /**
@@ -71,29 +75,12 @@
      * false otherwise.
      */
     public boolean meetsCriteria(Criteria criteria) {
-        // We do not want to match the special passive provider based on criteria.
-        if (LocationManager.PASSIVE_PROVIDER.equals(mName)) {
+        try {
+            return mService.providerMeetsCriteria(mName, criteria);
+        } catch (RemoteException e) {
+            Log.e(TAG, "meetsCriteria: RemoteException", e);
             return false;
         }
-        if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) && 
-            (criteria.getAccuracy() < getAccuracy())) {
-            return false;
-        }
-        int criteriaPower = criteria.getPowerRequirement();
-        if ((criteriaPower != Criteria.NO_REQUIREMENT) &&
-            (criteriaPower < getPowerRequirement())) {
-            return false;
-        }
-        if (criteria.isAltitudeRequired() && !supportsAltitude()) {
-            return false;
-        }
-        if (criteria.isSpeedRequired() && !supportsSpeed()) {
-            return false;
-        }
-        if (criteria.isBearingRequired() && !supportsBearing()) {
-            return false;
-        }
-        return true;
     }
 
     /**
diff --git a/location/java/android/location/provider/GeocodeProvider.java b/location/java/android/location/provider/GeocodeProvider.java
index 86376a7..9a587631 100644
--- a/location/java/android/location/provider/GeocodeProvider.java
+++ b/location/java/android/location/provider/GeocodeProvider.java
@@ -29,8 +29,6 @@
  * outside of the core android platform.
  * Geocode providers can be implemented as services and return the result of
  * {@link GeocodeProvider#getBinder()} in its getBinder() method.
- *
- * @hide
  */
 public abstract class GeocodeProvider {
 
@@ -53,7 +51,7 @@
 
     /**
      * This method is overridden to implement the
-     * {@link Geocoder#getFromLocation(double, double, int)} method.
+     * {@link android.location.Geocoder#getFromLocation(double, double, int)} method.
      * Classes implementing this method should not hold a reference to the params parameter.
      */
     public abstract String onGetFromLocation(double latitude, double longitude, int maxResults,
@@ -61,7 +59,7 @@
 
     /**
      * This method is overridden to implement the
-     * {@link Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
+     * {@link android.location.Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
      * Classes implementing this method should not hold a reference to the params parameter.
      */
     public abstract String onGetFromLocationName(String locationName,
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java
index 56cfb33..cf939de 100644
--- a/location/java/android/location/provider/LocationProvider.java
+++ b/location/java/android/location/provider/LocationProvider.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.net.NetworkInfo;
+import android.location.Criteria;
 import android.location.ILocationManager;
 import android.location.ILocationProvider;
 import android.location.Location;
@@ -32,8 +33,6 @@
  * outside of the core android platform.
  * Location providers can be implemented as services and return the result of
  * {@link LocationProvider#getBinder()} in its getBinder() method.
- *
- * @hide
  */
 public abstract class LocationProvider {
 
@@ -75,6 +74,10 @@
             return LocationProvider.this.onGetPowerRequirement();
         }
 
+        public boolean meetsCriteria(Criteria criteria) {
+            return LocationProvider.this.onMeetsCriteria(criteria);
+        }
+
         public int getAccuracy() {
             return LocationProvider.this.onGetAccuracy();
         }
@@ -226,6 +229,12 @@
     public abstract int onGetPowerRequirement();
 
     /**
+     * Returns true if this provider meets the given criteria,
+     * false otherwise.
+     */
+    public abstract boolean onMeetsCriteria(Criteria criteria);
+
+    /**
      * Returns a constant describing horizontal accuracy of this provider.
      * If the provider returns finer grain or exact location,
      * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the
@@ -246,11 +255,11 @@
 
     /**
      * Returns a information on the status of this provider.
-     * {@link #OUT_OF_SERVICE} is returned if the provider is
+     * {@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is
      * out of service, and this is not expected to change in the near
-     * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if
+     * future; {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} is returned if
      * the provider is temporarily unavailable but is expected to be
-     * available shortly; and {@link #AVAILABLE} is returned
+     * available shortly; and {@link android.location.LocationProvider#AVAILABLE} is returned
      * if the provider is currently available.
      *
      * <p> If extras is non-null, additional status information may be
@@ -299,9 +308,9 @@
 
     /**
      * Updates the network state for the given provider. This function must
-     * be overwritten if {@link #requiresNetwork} returns true. The state is
-     * {@link #TEMPORARILY_UNAVAILABLE} (disconnected), OR {@link #AVAILABLE}
-     * (connected or connecting).
+     * be overwritten if {@link android.location.LocationProvider#requiresNetwork} returns true.
+     * The state is {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} (disconnected)
+     * OR {@link android.location.LocationProvider#AVAILABLE} (connected or connecting).
      *
      * @param state data state
      */
diff --git a/location/java/com/android/internal/location/DummyLocationProvider.java b/location/java/com/android/internal/location/DummyLocationProvider.java
index ff5e27b..e7b5143 100644
--- a/location/java/com/android/internal/location/DummyLocationProvider.java
+++ b/location/java/com/android/internal/location/DummyLocationProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.location;
 
+import android.location.ILocationManager;
 import android.location.LocationProvider;
 
 /**
@@ -41,8 +42,8 @@
     int mPowerRequirement;
     int mAccuracy;
 
-    public DummyLocationProvider(String name) {
-        super(name);
+    public DummyLocationProvider(String name, ILocationManager service) {
+        super(name, service);
     }
 
     public void setRequiresNetwork(boolean requiresNetwork) {
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 9d1d420..f1da72f 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -46,8 +46,9 @@
     public static final int FILE_TYPE_WMA     = 6;
     public static final int FILE_TYPE_OGG     = 7;
     public static final int FILE_TYPE_AAC     = 8;
+    public static final int FILE_TYPE_MKA     = 9;
     private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3;
-    private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_AAC;
+    private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_MKA;
 
     // MIDI file types
     public static final int FILE_TYPE_MID     = 11;
@@ -63,8 +64,9 @@
     public static final int FILE_TYPE_3GPP2   = 24;
     public static final int FILE_TYPE_WMV     = 25;
     public static final int FILE_TYPE_ASF     = 26;
+    public static final int FILE_TYPE_MKV     = 27;
     private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
-    private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_ASF;
+    private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_MKV;
     
     // Image file types
     public static final int FILE_TYPE_JPEG    = 31;
@@ -134,6 +136,7 @@
         addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
         addFileType("OGA", FILE_TYPE_OGG, "application/ogg");
         addFileType("AAC", FILE_TYPE_AAC, "audio/aac");
+        addFileType("MKA", FILE_TYPE_MKA, "audio/x-matroska");
  
         addFileType("MID", FILE_TYPE_MID, "audio/midi");
         addFileType("MIDI", FILE_TYPE_MID, "audio/midi");
@@ -151,6 +154,8 @@
         addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp");
         addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
         addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
+        addFileType("MKV", FILE_TYPE_MKV, "video/x-matroska");
+        addFileType("WEBM", FILE_TYPE_MKV, "video/x-matroska");
         if (isWMVEnabled()) {
             addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
             addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index de64714..572389f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -701,6 +701,7 @@
     mSampleRate    = 8000;
     mAudioChannels = 1;
     mAudioBitRate  = 12200;
+    mInterleaveDurationUs = 0;
 
     mOutputFd = -1;
     mFlags = 0;
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e54fb67..681943f 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -75,7 +75,8 @@
         libstagefright_avcdec \
         libstagefright_m4vh263dec \
         libstagefright_mp3dec \
-        libstagefright_vorbisdec
+        libstagefright_vorbisdec \
+        libstagefright_matroska \
 
 LOCAL_SHARED_LIBRARIES += \
         libstagefright_amrnb_common \
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index a66f86b..475422d 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -20,6 +20,8 @@
 #include "include/WAVExtractor.h"
 #include "include/OggExtractor.h"
 
+#include "matroska/MatroskaExtractor.h"
+
 #include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
@@ -94,6 +96,7 @@
     RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffWAV);
     RegisterSniffer(SniffOgg);
+    RegisterSniffer(SniffMatroska);
 }
 
 // static
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index b6f1af2..dd2579b 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -45,6 +45,10 @@
 }
 
 ssize_t FileSource::readAt(off_t offset, void *data, size_t size) {
+    if (mFile == NULL) {
+        return NO_INIT;
+    }
+
     Mutex::Autolock autoLock(mLock);
 
     if (mLength >= 0) {
@@ -67,6 +71,10 @@
 }
 
 status_t FileSource::getSize(off_t *size) {
+    if (mFile == NULL) {
+        return NO_INIT;
+    }
+
     if (mLength >= 0) {
         *size = mLength;
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 094059d..e0f8f9e 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -334,8 +334,6 @@
 }
 
 off_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
-    StripStartcode(buffer);
-
     off_t old_offset = mOffset;
 
     size_t length = buffer->range_length();
@@ -827,6 +825,8 @@
             continue;
         }
 
+        if (is_avc) StripStartcode(buffer);
+
         SampleInfo info;
         info.size = is_avc
 #if USE_NALLEN_FOUR
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 4b3813b..327a0ce 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -20,6 +20,7 @@
 
 const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
 
+const char *MEDIA_MIMETYPE_VIDEO_VPX = "video/x-vnd.on2.vp8";
 const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
 const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
 const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
@@ -36,5 +37,6 @@
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
 const char *MEDIA_MIMETYPE_CONTAINER_OGG = "application/ogg";
+const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 513f49c..376d715 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -24,6 +24,8 @@
 #include "include/WAVExtractor.h"
 #include "include/OggExtractor.h"
 
+#include "matroska/MatroskaExtractor.h"
+
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
@@ -69,6 +71,8 @@
         return new WAVExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
         return new OggExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
+        return new MatroskaExtractor(source);
     }
 
     return NULL;
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 03287dd1..ab17b04 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -42,7 +42,8 @@
     static const char *kValidExtensions[] = {
         ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
-        ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota"
+        ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
+        ".mkv", ".mka", ".webm"
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 258be74..9d89c20 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -378,6 +378,24 @@
     // The duration value is a string representing the duration in ms.
     sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
     mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
+
+    if (numTracks == 1) {
+        const char *fileMIME;
+        CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
+
+        if (!strcasecmp(fileMIME, "video/x-matroska")) {
+            sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
+            const char *trackMIME;
+            CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
+
+            if (!strncasecmp("audio/", trackMIME, 6)) {
+                // The matroska file only contains a single audio track,
+                // rewrite its mime type.
+                mMetaData.add(
+                        METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
+            }
+        }
+    }
 }
 
 
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
new file mode 100644
index 0000000..0e72198
--- /dev/null
+++ b/media/libstagefright/matroska/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=                 \
+        MatroskaExtractor.cpp     \
+        mkvparser.cpp             \
+
+LOCAL_C_INCLUDES:= \
+	$(JNI_H_INCLUDE) \
+        $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= libstagefright_matroska
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
new file mode 100644
index 0000000..197ccf8
--- /dev/null
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MatroskaExtractor"
+#include <utils/Log.h>
+
+#include "MatroskaExtractor.h"
+
+#include "mkvparser.hpp"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct DataSourceReader : public mkvparser::IMkvReader {
+    DataSourceReader(const sp<DataSource> &source)
+        : mSource(source) {
+    }
+
+    virtual int Read(long long position, long length, unsigned char* buffer) {
+        CHECK(position >= 0);
+        CHECK(length >= 0);
+
+        if (length == 0) {
+            return 0;
+        }
+
+        ssize_t n = mSource->readAt(position, buffer, length);
+
+        if (n <= 0) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    virtual int Length(long long* total, long long* available) {
+        off_t size;
+        if (mSource->getSize(&size) != OK) {
+            return -1;
+        }
+
+        if (total) {
+            *total = size;
+        }
+
+        if (available) {
+            *available = size;
+        }
+
+        return 0;
+    }
+
+private:
+    sp<DataSource> mSource;
+
+    DataSourceReader(const DataSourceReader &);
+    DataSourceReader &operator=(const DataSourceReader &);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include <ctype.h>
+static void hexdump(const void *_data, size_t size) {
+    const uint8_t *data = (const uint8_t *)_data;
+    size_t offset = 0;
+    while (offset < size) {
+        printf("0x%04x  ", offset);
+
+        size_t n = size - offset;
+        if (n > 16) {
+            n = 16;
+        }
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (i == 8) {
+                printf(" ");
+            }
+
+            if (offset + i < size) {
+                printf("%02x ", data[offset + i]);
+            } else {
+                printf("   ");
+            }
+        }
+
+        printf(" ");
+
+        for (size_t i = 0; i < n; ++i) {
+            if (isprint(data[offset + i])) {
+                printf("%c", data[offset + i]);
+            } else {
+                printf(".");
+            }
+        }
+
+        printf("\n");
+
+        offset += 16;
+    }
+}
+
+struct MatroskaSource : public MediaSource {
+    MatroskaSource(
+            const sp<MatroskaExtractor> &extractor, size_t index);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+private:
+    enum Type {
+        AVC,
+        AAC,
+        OTHER
+    };
+
+    sp<MatroskaExtractor> mExtractor;
+    size_t mTrackIndex;
+    unsigned long mTrackNum;
+    Type mType;
+    mkvparser::Cluster *mCluster;
+    const mkvparser::BlockEntry *mBlockEntry;
+
+    status_t advance();
+
+    MatroskaSource(const MatroskaSource &);
+    MatroskaSource &operator=(const MatroskaSource &);
+};
+
+MatroskaSource::MatroskaSource(
+        const sp<MatroskaExtractor> &extractor, size_t index)
+    : mExtractor(extractor),
+      mTrackIndex(index),
+      mType(OTHER),
+      mCluster(NULL),
+      mBlockEntry(NULL) {
+    mTrackNum = mExtractor->mTracks.itemAt(index).mTrackNum;
+
+    const char *mime;
+    CHECK(mExtractor->mTracks.itemAt(index).mMeta->
+            findCString(kKeyMIMEType, &mime));
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+        mType = AVC;
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+        mType = AAC;
+    }
+}
+
+status_t MatroskaSource::start(MetaData *params) {
+    mCluster = NULL;
+    mBlockEntry = NULL;
+
+    return OK;
+}
+
+status_t MatroskaSource::stop() {
+    return OK;
+}
+
+sp<MetaData> MatroskaSource::getFormat() {
+    return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
+}
+
+status_t MatroskaSource::advance() {
+    for (;;) {
+        if (mBlockEntry == NULL || mBlockEntry->EOS()) {
+            if (mCluster == NULL) {
+                mCluster = mExtractor->mSegment->GetFirst();
+            } else {
+                mCluster = mExtractor->mSegment->GetNext(mCluster);
+            }
+            if (mCluster == NULL || mCluster->EOS()) {
+                return ERROR_END_OF_STREAM;
+            }
+            mBlockEntry = mCluster->GetFirst();
+        }
+
+        if (mBlockEntry->GetBlock()->GetTrackNumber() != mTrackNum) {
+            mBlockEntry = mCluster->GetNext(mBlockEntry);
+            continue;
+        }
+
+        break;
+    }
+
+    return OK;
+}
+
+status_t MatroskaSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        mBlockEntry = NULL;
+        mCluster = mExtractor->mSegment->GetCluster(seekTimeUs * 1000ll);
+
+        status_t err;
+        while ((err = advance()) == OK && !mBlockEntry->GetBlock()->IsKey()) {
+            mBlockEntry = mCluster->GetNext(mBlockEntry);
+        }
+
+        if (err != OK) {
+            return ERROR_END_OF_STREAM;
+        }
+    }
+
+    if (advance() != OK) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    const mkvparser::Block *block = mBlockEntry->GetBlock();
+    size_t size = block->GetSize();
+    long long timeNs = block->GetTime(mCluster);
+
+    MediaBuffer *buffer = new MediaBuffer(size + 2);
+    buffer->meta_data()->setInt64(kKeyTime, (timeNs + 500) / 1000);
+
+    long res = block->Read(
+            mExtractor->mReader, (unsigned char *)buffer->data() + 2);
+
+    if (res != 0) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    buffer->set_range(2, size);
+
+    if (mType == AVC) {
+        CHECK(size >= 2);
+
+        uint8_t *data = (uint8_t *)buffer->data();
+
+        unsigned NALsize = data[2] << 8 | data[3];
+        CHECK_EQ(size, NALsize + 2);
+
+        memcpy(data, "\x00\x00\x00\x01", 4);
+        buffer->set_range(0, size + 2);
+    } else if (mType == AAC) {
+        // There's strange junk at the beginning...
+
+        const uint8_t *data = (const uint8_t *)buffer->data() + 2;
+        size_t offset = 0;
+        while (offset < size && data[offset] != 0x21) {
+            ++offset;
+        }
+        buffer->set_range(2 + offset, size - offset);
+    }
+
+    *out = buffer;
+
+#if 0
+    hexdump((const uint8_t *)buffer->data() + buffer->range_offset(),
+            buffer->range_length());
+#endif
+
+    mBlockEntry = mCluster->GetNext(mBlockEntry);
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mReader(new DataSourceReader(mDataSource)),
+      mSegment(NULL) {
+    mkvparser::EBMLHeader ebmlHeader;
+    long long pos;
+    if (ebmlHeader.Parse(mReader, pos) < 0) {
+        return;
+    }
+
+    long long ret =
+        mkvparser::Segment::CreateInstance(mReader, pos, mSegment);
+
+    if (ret) {
+        CHECK(mSegment == NULL);
+        return;
+    }
+
+    ret = mSegment->Load();
+
+    if (ret < 0) {
+        delete mSegment;
+        mSegment = NULL;
+        return;
+    }
+
+    addTracks();
+}
+
+MatroskaExtractor::~MatroskaExtractor() {
+    delete mSegment;
+    mSegment = NULL;
+
+    delete mReader;
+    mReader = NULL;
+}
+
+size_t MatroskaExtractor::countTracks() {
+    return mTracks.size();
+}
+
+sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
+    if (index >= mTracks.size()) {
+        return NULL;
+    }
+
+    return new MatroskaSource(this, index);
+}
+
+sp<MetaData> MatroskaExtractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
+    if (index >= mTracks.size()) {
+        return NULL;
+    }
+
+    return mTracks.itemAt(index).mMeta;
+}
+
+static void addESDSFromAudioSpecificInfo(
+        const sp<MetaData> &meta, const void *asi, size_t asiSize) {
+    static const uint8_t kStaticESDS[] = {
+        0x03, 22,
+        0x00, 0x00,     // ES_ID
+        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+        0x04, 17,
+        0x40,                       // Audio ISO/IEC 14496-3
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x05,
+        // AudioSpecificInfo (with size prefix) follows
+    };
+
+    CHECK(asiSize < 128);
+    size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
+    uint8_t *esds = new uint8_t[esdsSize];
+    memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
+    uint8_t *ptr = esds + sizeof(kStaticESDS);
+    *ptr++ = asiSize;
+    memcpy(ptr, asi, asiSize);
+
+    meta->setData(kKeyESDS, 0, esds, esdsSize);
+
+    delete[] esds;
+    esds = NULL;
+}
+
+void addVorbisCodecInfo(
+        const sp<MetaData> &meta,
+        const void *_codecPrivate, size_t codecPrivateSize) {
+    // printf("vorbis private data follows:\n");
+    // hexdump(_codecPrivate, codecPrivateSize);
+
+    CHECK(codecPrivateSize >= 3);
+
+    const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate;
+    CHECK(codecPrivate[0] == 0x02);
+
+    size_t len1 = codecPrivate[1];
+    size_t len2 = codecPrivate[2];
+
+    CHECK(codecPrivateSize > 3 + len1 + len2);
+
+    CHECK(codecPrivate[3] == 0x01);
+    meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1);
+
+    CHECK(codecPrivate[len1 + 3] == 0x03);
+
+    CHECK(codecPrivate[len1 + len2 + 3] == 0x05);
+    meta->setData(
+            kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3],
+            codecPrivateSize - len1 - len2 - 3);
+}
+
+void MatroskaExtractor::addTracks() {
+    const mkvparser::Tracks *tracks = mSegment->GetTracks();
+
+    for (size_t index = 0; index < tracks->GetTracksCount(); ++index) {
+        const mkvparser::Track *track = tracks->GetTrackByIndex(index);
+
+        const char *const codecID = track->GetCodecId();
+        LOGV("codec id = %s", codecID);
+        LOGV("codec name = %s", track->GetCodecNameAsUTF8());
+
+        size_t codecPrivateSize;
+        const unsigned char *codecPrivate =
+            track->GetCodecPrivate(&codecPrivateSize);
+
+        enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
+
+        sp<MetaData> meta = new MetaData;
+
+        switch (track->GetType()) {
+            case VIDEO_TRACK:
+            {
+                const mkvparser::VideoTrack *vtrack =
+                    static_cast<const mkvparser::VideoTrack *>(track);
+
+                if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+                    meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("V_VP8", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX);
+                } else {
+                    continue;
+                }
+
+                meta->setInt32(kKeyWidth, vtrack->GetWidth());
+                meta->setInt32(kKeyHeight, vtrack->GetHeight());
+                break;
+            }
+
+            case AUDIO_TRACK:
+            {
+                const mkvparser::AudioTrack *atrack =
+                    static_cast<const mkvparser::AudioTrack *>(track);
+
+                if (!strcmp("A_AAC", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+                    CHECK(codecPrivateSize >= 2);
+
+                    addESDSFromAudioSpecificInfo(
+                            meta, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("A_VORBIS", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
+
+                    addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize);
+                } else {
+                    continue;
+                }
+
+                meta->setInt32(kKeySampleRate, atrack->GetSamplingRate());
+                meta->setInt32(kKeyChannelCount, atrack->GetChannels());
+                break;
+            }
+
+            default:
+                continue;
+        }
+
+        long long durationNs = mSegment->GetDuration();
+        meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
+
+        mTracks.push();
+        TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
+        trackInfo->mTrackNum = track->GetNumber();
+        trackInfo->mMeta = meta;
+    }
+}
+
+sp<MetaData> MatroskaExtractor::getMetaData() {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA);
+
+    return meta;
+}
+
+bool SniffMatroska(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+    DataSourceReader reader(source);
+    mkvparser::EBMLHeader ebmlHeader;
+    long long pos;
+    if (ebmlHeader.Parse(&reader, pos) < 0) {
+        return false;
+    }
+
+    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA);
+    *confidence = 0.6;
+
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
new file mode 100644
index 0000000..7bf41a9
--- /dev/null
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MATROSKA_EXTRACTOR_H_
+
+#define MATROSKA_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/Vector.h>
+
+namespace mkvparser {
+struct Segment;
+};
+
+namespace android {
+
+class String8;
+
+struct DataSourceReader;
+struct MatroskaSource;
+
+struct MatroskaExtractor : public MediaExtractor {
+    MatroskaExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+
+    virtual sp<MediaSource> getTrack(size_t index);
+
+    virtual sp<MetaData> getTrackMetaData(
+            size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+protected:
+    virtual ~MatroskaExtractor();
+
+private:
+    friend struct MatroskaSource;
+
+    struct TrackInfo {
+        unsigned long mTrackNum;
+        sp<MetaData> mMeta;
+    };
+    Vector<TrackInfo> mTracks;
+
+    sp<DataSource> mDataSource;
+    DataSourceReader *mReader;
+    mkvparser::Segment *mSegment;
+
+    void addTracks();
+
+    MatroskaExtractor(const MatroskaExtractor &);
+    MatroskaExtractor &operator=(const MatroskaExtractor &);
+};
+
+bool SniffMatroska(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+}  // namespace android
+
+#endif  // MATROSKA_EXTRACTOR_H_
diff --git a/media/libstagefright/matroska/mkvparser.cpp b/media/libstagefright/matroska/mkvparser.cpp
new file mode 100644
index 0000000..4e51004
--- /dev/null
+++ b/media/libstagefright/matroska/mkvparser.cpp
@@ -0,0 +1,3103 @@
+#include "mkvparser.hpp"
+#include <cassert>
+#include <cstring>
+
+mkvparser::IMkvReader::~IMkvReader()
+{
+}
+
+long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(pos < available);
+    assert((available - pos) >= 1);  //assume here max u-int len is 8
+    
+    unsigned char b;
+
+    hr = pReader->Read(pos, 1, &b);
+    if (hr < 0)
+        return hr;
+        
+    assert(hr == 0L);
+    
+    if (b & 0x80)       //1000 0000
+    {
+        len = 1;
+        b &= 0x7F;      //0111 1111
+    }        
+    else if (b & 0x40)  //0100 0000
+    {
+        len = 2;
+        b &= 0x3F;      //0011 1111
+    }
+    else if (b & 0x20)  //0010 0000
+    {
+        len = 3;
+        b &= 0x1F;      //0001 1111
+    }
+    else if (b & 0x10)  //0001 0000
+    {
+        len = 4;
+        b &= 0x0F;      //0000 1111
+    }
+    else if (b & 0x08)  //0000 1000
+    {
+        len = 5;
+        b &= 0x07;      //0000 0111
+    }
+    else if (b & 0x04)  //0000 0100
+    {
+        len = 6;
+        b &= 0x03;      //0000 0011
+    }
+    else if (b & 0x02)  //0000 0010
+    {
+        len = 7;
+        b &= 0x01;      //0000 0001
+    }
+    else 
+    {
+        assert(b & 0x01);  //0000 0001
+        len = 8;
+        b = 0;             //0000 0000
+    }
+    
+    assert((available - pos) >= len);
+    
+    long long result = b;
+    ++pos;
+    for (long i = 1; i < len; ++i)
+    {
+        hr = pReader->Read(pos, 1, &b);
+        
+        if (hr < 0)
+            return hr;
+            
+        assert(hr == 0L);
+        
+        result <<= 8;
+        result |= b;
+        
+        ++pos;
+    }
+    
+    return result;
+}
+    
+    
+long long mkvparser::GetUIntLength(
+    IMkvReader* pReader,
+    long long pos, 
+    long& len)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    
+    if (pos >= available)
+        return pos;  //too few bytes available
+    
+    unsigned char b;
+    
+    hr = pReader->Read(pos, 1, &b);
+    
+    if (hr < 0)
+        return hr;
+
+    assert(hr == 0L);
+    
+    if (b == 0)  //we can't handle u-int values larger than 8 bytes
+        return E_FILE_FORMAT_INVALID;
+    
+    unsigned char m = 0x80;
+    len = 1;
+    
+    while (!(b & m))
+    {
+        m >>= 1;
+        ++len;
+    }
+    
+    return 0;  //success
+}
+
+
+long long mkvparser::SyncReadUInt(
+    IMkvReader* pReader,
+    long long pos, 
+    long long stop,
+    long& len)
+{
+    assert(pReader);
+
+    if (pos >= stop)
+        return E_FILE_FORMAT_INVALID;
+    
+    unsigned char b;
+    
+    long hr = pReader->Read(pos, 1, &b);
+    
+    if (hr < 0)
+        return hr;
+        
+    if (hr != 0L)
+        return E_BUFFER_NOT_FULL;
+
+    if (b == 0)  //we can't handle u-int values larger than 8 bytes
+        return E_FILE_FORMAT_INVALID;
+    
+    unsigned char m = 0x80;
+    len = 1;
+        
+    while (!(b & m))
+    {
+        m >>= 1;
+        ++len;
+    }
+    
+    if ((pos + len) > stop)
+        return E_FILE_FORMAT_INVALID;
+        
+    long long result = b & (~m);
+    ++pos;
+    
+    for (int i = 1; i < len; ++i)
+    {
+        hr = pReader->Read(pos, 1, &b);
+        
+        if (hr < 0)
+            return hr;
+           
+        if (hr != 0L)
+            return E_BUFFER_NOT_FULL;
+            
+        result <<= 8;
+        result |= b;
+        
+        ++pos;
+    }
+    
+    return result;
+}
+
+
+long long mkvparser::UnserializeUInt(
+    IMkvReader* pReader, 
+    long long pos,
+    long long size)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    assert(size > 0);
+    assert(size <= 8);
+    
+    long long result = 0;
+    
+    for (long long i = 0; i < size; ++i)
+    {
+        unsigned char b;
+        
+        const long hr = pReader->Read(pos, 1, &b);
+        
+        if (hr < 0)      
+            return hr;
+        result <<= 8;
+        result |= b;
+        
+        ++pos;
+    }
+    
+    return result;
+}
+
+
+float mkvparser::Unserialize4Float(
+    IMkvReader* pReader, 
+    long long pos)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+    
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    assert((pos + 4) <= available);
+    
+    float result;
+    
+    unsigned char* const p = (unsigned char*)&result;
+    unsigned char* q = p + 4;
+    
+    for (;;)
+    {
+        hr = pReader->Read(pos, 1, --q);
+        assert(hr == 0L);
+        
+        if (q == p)
+            break;
+            
+        ++pos;
+    }
+    
+    return result;
+}
+
+
+double mkvparser::Unserialize8Double(
+    IMkvReader* pReader, 
+    long long pos)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    double result;
+    
+    unsigned char* const p = (unsigned char*)&result;
+    unsigned char* q = p + 8;
+    
+    for (;;)
+    {
+        const long hr = pReader->Read(pos, 1, --q);
+        assert(hr == 0L);
+        
+        if (q == p)
+            break;
+            
+        ++pos;
+    }
+    
+    return result;
+}
+
+signed char mkvparser::Unserialize1SInt(
+    IMkvReader* pReader,
+    long long pos)
+{
+    assert(pReader);
+    assert(pos >= 0);
+ 
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr == 0);   
+    assert(available <= total);
+    assert(pos < available);
+
+    signed char result;
+
+    hr = pReader->Read(pos, 1, (unsigned char*)&result);
+    assert(hr == 0);
+
+    return result;
+}
+
+short mkvparser::Unserialize2SInt(
+    IMkvReader* pReader, 
+    long long pos)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+    
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    assert((pos + 2) <= available);
+    
+    short result;
+    
+    unsigned char* const p = (unsigned char*)&result;
+    unsigned char* q = p + 2;
+    
+    for (;;)
+    {
+        hr = pReader->Read(pos, 1, --q);
+        assert(hr == 0L);
+        
+        if (q == p)
+            break;
+            
+        ++pos;
+    }
+    
+    return result;
+}
+
+
+bool mkvparser::Match(
+    IMkvReader* pReader,
+    long long& pos,
+    unsigned long id_,
+    long long& val)
+
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    
+    long len;
+
+    const long long id = ReadUInt(pReader, pos, len);
+    assert(id >= 0);
+    assert(len > 0);
+    assert(len <= 8);
+    assert((pos + len) <= available);
+    
+    if ((unsigned long)id != id_)
+        return false;
+        
+    pos += len;  //consume id
+    
+    const long long size = ReadUInt(pReader, pos, len);
+    assert(size >= 0);
+    assert(size <= 8);
+    assert(len > 0);
+    assert(len <= 8);
+    assert((pos + len) <= available);
+    
+    pos += len;  //consume length of size of payload
+    
+    val = UnserializeUInt(pReader, pos, size);
+    assert(val >= 0);
+    
+    pos += size;  //consume size of payload
+    
+    return true;
+}
+
+bool mkvparser::Match(
+    IMkvReader* pReader,
+    long long& pos,
+    unsigned long id_,
+    char*& val)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    
+    long len;
+
+    const long long id = ReadUInt(pReader, pos, len);
+    assert(id >= 0);
+    assert(len > 0);
+    assert(len <= 8);
+    assert((pos + len) <= available);
+    
+    if ((unsigned long)id != id_)
+        return false;
+    
+    pos += len;  //consume id
+    
+    const long long size_ = ReadUInt(pReader, pos, len);
+    assert(size_ >= 0);
+    assert(len > 0);
+    assert(len <= 8);
+    assert((pos + len) <= available);
+    
+    pos += len;  //consume length of size of payload
+    assert((pos + size_) <= available);
+
+    const size_t size = static_cast<size_t>(size_);    
+    val = new char[size+1];
+
+    for (size_t i = 0; i < size; ++i)
+    {
+        char c;
+
+        hr = pReader->Read(pos + i, 1, (unsigned char*)&c);
+        assert(hr == 0L);
+            
+        val[i] = c;
+   
+        if (c == '\0')
+            break;     
+   
+    }
+
+    val[size] = '\0';
+    pos += size_;  //consume size of payload
+    
+    return true;
+}
+
+#if 0
+bool mkvparser::Match(
+    IMkvReader* pReader,
+    long long& pos,
+    unsigned long id,
+    wchar_t*& val)
+{
+    char* str;
+    
+    if (!Match(pReader, pos, id, str))
+        return false;
+
+    const size_t size = mbstowcs(NULL, str, 0);
+       
+    if (size == 0) 
+        val = NULL;
+    else 
+    { 
+        val = new wchar_t[size+1];
+        mbstowcs(val, str, size);
+        val[size] = L'\0';
+    }
+
+    delete[] str;
+    return true;    
+}
+#endif
+
+
+bool mkvparser::Match(
+    IMkvReader* pReader,
+    long long& pos,
+    unsigned long id_,
+    unsigned char*& val,
+    size_t *optionalSize)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    
+    long len;
+    const long long id = ReadUInt(pReader, pos, len);
+    assert(id >= 0);
+    assert(len > 0);
+    assert(len <= 8);
+    assert((pos + len) <= available);
+    
+    if ((unsigned long)id != id_)
+        return false;
+        
+    pos += len;  //consume id
+    
+    const long long size_ = ReadUInt(pReader, pos, len);
+    assert(size_ >= 0);
+    assert(len > 0);
+    assert(len <= 8);
+    assert((pos + len) <= available);
+    
+    pos += len;  //consume length of size of payload
+    assert((pos + size_) <= available);
+
+    const size_t size = static_cast<size_t>(size_);    
+    val = new unsigned char[size];
+ 
+    if (optionalSize) {
+        *optionalSize = size;
+    }
+
+    for (size_t i = 0; i < size; ++i)
+    {
+        unsigned char b;
+
+        hr = pReader->Read(pos + i, 1, &b);
+        assert(hr == 0L);
+
+        val[i] = b; 
+    }
+    
+    pos += size_;  //consume size of payload    
+    return true;
+}
+
+
+bool mkvparser::Match(
+    IMkvReader* pReader,
+    long long& pos,
+    unsigned long id_,
+    double& val)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    long idlen;
+    const long long id = ReadUInt(pReader, pos, idlen);
+    assert(id >= 0);  //TODO
+    
+    if ((unsigned long)id != id_)
+        return false;
+
+    long sizelen;
+    const long long size = ReadUInt(pReader, pos + idlen, sizelen);
+
+    switch (size)
+    {	
+        case 4:
+        case 8:
+            break;
+        default:
+            return false;
+    }
+
+    pos += idlen + sizelen;  //consume id and size fields
+    assert((pos + size) <= available);
+
+    if (size == 4)
+        val = Unserialize4Float(pReader, pos);
+    else
+    {
+        assert(size == 8);
+        val = Unserialize8Double(pReader, pos);
+    }
+    
+    pos += size;  //consume size of payload
+    
+    return true;
+}
+
+
+bool mkvparser::Match(
+    IMkvReader* pReader,
+    long long& pos,
+    unsigned long id_,
+    short& val)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    long long total, available;
+
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    
+    long len;
+    const long long id = ReadUInt(pReader, pos, len);
+    assert(id >= 0);
+    assert((pos + len) <= available);
+    
+    if ((unsigned long)id != id_)
+        return false;
+        
+    pos += len;  //consume id
+    
+    const long long size = ReadUInt(pReader, pos, len);
+    assert(size <= 2);
+    assert((pos + len) <= available);
+   
+    pos += len;  //consume length of size of payload
+    assert((pos + size) <= available);
+
+    //TODO:
+    // Generalize this to work for any size signed int
+    if (size == 1)
+        val = Unserialize1SInt(pReader, pos);
+    else 
+        val = Unserialize2SInt(pReader, pos);
+        
+    pos += size;  //consume size of payload
+    
+    return true;
+}
+
+
+namespace mkvparser
+{
+
+EBMLHeader::EBMLHeader():
+    m_docType(NULL)
+{
+}
+
+EBMLHeader::~EBMLHeader()
+{
+    delete[] m_docType;
+}
+
+long long EBMLHeader::Parse(
+    IMkvReader* pReader,
+    long long& pos)
+{
+    assert(pReader);
+    
+    long long total, available;
+    
+    long hr = pReader->Length(&total, &available);
+    
+    if (hr < 0) 
+        return hr;
+    
+    pos = 0;    
+    long long end = (1024 < available)? 1024: available;    
+
+    for (;;)
+    {    
+        unsigned char b = 0;
+    
+        while (pos < end)
+        {
+            hr = pReader->Read(pos, 1, &b);
+           
+            if (hr < 0)
+                return hr;
+            
+            if (b == 0x1A)
+                break;
+                
+            ++pos;
+        }
+    
+        if (b != 0x1A)
+        {
+            if ((pos >= 1024) ||
+                (available >= total) || 
+                ((total - available) < 5))
+                  return -1;
+                
+            return available + 5;  //5 = 4-byte ID + 1st byte of size
+        }
+    
+        if ((total - pos) < 5)
+            return E_FILE_FORMAT_INVALID;
+            
+        if ((available - pos) < 5)
+            return pos + 5;  //try again later
+
+        long len;            
+
+        const long long result = ReadUInt(pReader, pos, len);
+        
+        if (result < 0)  //error
+            return result;
+            
+        if (result == 0x0A45DFA3)  //ReadId masks-off length indicator bits
+        {
+            assert(len == 4);
+            pos += len;
+            break;
+        }
+
+        ++pos;  //throw away just the 0x1A byte, and try again
+    }
+        
+    long len;
+    long long result = GetUIntLength(pReader, pos, len);
+    
+    if (result < 0)  //error
+        return result;
+        
+    if (result > 0)  //need more data
+        return result;
+        
+    assert(len > 0);
+    assert(len <= 8);
+    
+    if ((total -  pos) < len)
+        return E_FILE_FORMAT_INVALID;
+    if ((available - pos) < len)
+        return pos + len;  //try again later
+        
+    result = ReadUInt(pReader, pos, len);
+    
+    if (result < 0)  //error
+        return result;
+        
+    pos += len;  //consume u-int
+    
+    if ((total - pos) < result)
+        return E_FILE_FORMAT_INVALID;
+
+    if ((available - pos) < result)
+        return pos + result;
+        
+    end = pos + result;
+    
+    m_version = 1;
+    m_readVersion = 1;
+    m_maxIdLength = 4;
+    m_maxSizeLength = 8;
+    m_docTypeVersion = 1;
+    m_docTypeReadVersion = 1;
+
+    while (pos < end)
+    {
+        if (Match(pReader, pos, 0x0286, m_version))   
+            ;
+        else if (Match(pReader, pos, 0x02F7, m_readVersion))        
+            ;
+        else if (Match(pReader, pos, 0x02F2, m_maxIdLength))        
+            ;
+        else if (Match(pReader, pos, 0x02F3, m_maxSizeLength))      
+            ;
+        else if (Match(pReader, pos, 0x0282, m_docType))            
+            ; 
+        else if (Match(pReader, pos, 0x0287, m_docTypeVersion))     
+            ;
+        else if (Match(pReader, pos, 0x0285, m_docTypeReadVersion)) 
+            ;
+        else
+        {
+            result = ReadUInt(pReader, pos, len);
+            assert(result > 0);
+            assert(len > 0);
+            assert(len <= 8);
+        
+            pos += len;
+            assert(pos < end);
+            
+            result = ReadUInt(pReader, pos, len);
+            assert(result >= 0);
+            assert(len > 0);
+            assert(len <= 8);
+            
+            pos += len + result;
+            assert(pos <= end);
+        }
+    }
+    
+    assert(pos == end);
+        
+    return 0;    
+}
+
+
+Segment::Segment(
+    IMkvReader* pReader,
+    long long start,
+    long long size) :
+    m_pReader(pReader),
+    m_start(start),
+    m_size(size),
+    m_pos(start),
+    m_pInfo(NULL),
+    m_pTracks(NULL),
+    m_clusterCount(0)
+    //m_clusterNumber(0)
+{
+}
+
+
+Segment::~Segment()
+{
+    Cluster** i = m_clusters;
+    Cluster** j = m_clusters + m_clusterCount;
+
+    while (i != j)
+    {
+        Cluster* p = *i++;
+        assert(p);		
+        delete p;
+    } 
+    
+    delete[] m_clusters;
+       
+    delete m_pTracks;
+    delete m_pInfo;
+}
+
+
+long long Segment::CreateInstance(
+    IMkvReader* pReader,
+    long long pos,
+    Segment*& pSegment)
+{
+    assert(pReader);
+    assert(pos >= 0);
+    
+    pSegment = NULL;
+    
+    long long total, available;
+    
+    long hr = pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    
+    //I would assume that in practice this loop would execute
+    //exactly once, but we allow for other elements (e.g. Void)
+    //to immediately follow the EBML header.  This is fine for
+    //the source filter case (since the entire file is available),
+    //but in the splitter case over a network we should probably
+    //just give up early.  We could for example decide only to
+    //execute this loop a maximum of, say, 10 times.
+    
+    while (pos < total)
+    {    
+        //Read ID
+        
+        long len;
+        long long result = GetUIntLength(pReader, pos, len);
+        
+        if (result)  //error, or too few available bytes
+            return result;
+            
+        if ((pos + len) > total)
+            return E_FILE_FORMAT_INVALID;
+            
+        if ((pos + len) > available)
+            return pos + len;
+
+        //TODO: if we liberalize the behavior of ReadUInt, we can
+        //probably eliminate having to use GetUIntLength here.
+        const long long id = ReadUInt(pReader, pos, len);
+        
+        if (id < 0)  //error
+            return id;
+            
+        pos += len;  //consume ID
+        
+        //Read Size
+        
+        result = GetUIntLength(pReader, pos, len);
+        
+        if (result)  //error, or too few available bytes
+            return result;
+            
+        if ((pos + len) > total)
+            return E_FILE_FORMAT_INVALID;
+            
+        if ((pos + len) > available)
+            return pos + len;
+
+        //TODO: if we liberalize the behavior of ReadUInt, we can
+        //probably eliminate having to use GetUIntLength here.
+        const long long size = ReadUInt(pReader, pos, len);
+        
+        if (size < 0)
+            return size;
+            
+        pos += len;  //consume length of size of element
+        
+        //Pos now points to start of payload
+        
+        if ((pos + size) > total)
+            return E_FILE_FORMAT_INVALID;
+        
+        if (id == 0x08538067)  //Segment ID
+        {
+            pSegment = new  Segment(pReader, pos, size); 
+            assert(pSegment);  //TODO   
+
+            return 0;    //success
+        }
+        
+        pos += size;  //consume payload
+    }
+    
+    assert(pos == total);
+    
+    pSegment = new Segment(pReader, pos, 0); 
+    assert(pSegment);  //TODO   
+
+    return 0;  //success (sort of)
+}
+
+
+long long Segment::ParseHeaders()
+{
+    //Outermost (level 0) segment object has been constructed, 
+    //and pos designates start of payload.  We need to find the
+    //inner (level 1) elements.
+    long long total, available;
+    
+    long hr = m_pReader->Length(&total, &available);
+    assert(hr >= 0);
+    assert(available <= total);
+    
+    const long long stop = m_start + m_size;
+    assert(stop <= total);
+    assert(m_pos <= stop);
+    
+    bool bQuit = false;
+    while ((m_pos < stop) && !bQuit)
+    {
+        long long pos = m_pos;
+        
+        long len;
+        long long result = GetUIntLength(m_pReader, pos, len);
+        
+        if (result)  //error, or too few available bytes
+            return result;
+            
+        if ((pos + len) > stop)
+            return E_FILE_FORMAT_INVALID;
+            
+        if ((pos + len) > available)
+            return pos + len;
+            
+        const long long idpos = pos;
+        const long long id = ReadUInt(m_pReader, idpos, len);
+        
+        if (id < 0)  //error
+            return id;
+            
+        pos += len;  //consume ID
+        
+        //Read Size
+        result = GetUIntLength(m_pReader, pos, len);
+        
+        if (result)  //error, or too few available bytes
+            return result;
+            
+        if ((pos + len) > stop)
+            return E_FILE_FORMAT_INVALID;
+            
+        if ((pos + len) > available)
+            return pos + len;
+
+        const long long size = ReadUInt(m_pReader, pos, len);
+        
+        if (size < 0)
+            return size;
+            
+        pos += len;  //consume length of size of element
+        
+        //Pos now points to start of payload
+        
+        if ((pos + size) > stop)
+            return E_FILE_FORMAT_INVALID;
+            
+        //We read EBML elements either in total or nothing at all.
+            
+        if ((pos + size) > available)
+            return pos + size;
+        
+        if (id == 0x0549A966)  //Segment Info ID
+        {
+            assert(m_pInfo == NULL);
+            m_pInfo = new  SegmentInfo(this, pos, size);
+            assert(m_pInfo);  //TODO
+            
+            if (m_pTracks)
+                bQuit = true;
+        }
+        else if (id == 0x0654AE6B)  //Tracks ID
+        {
+            assert(m_pTracks == NULL);
+            m_pTracks = new  Tracks(this, pos, size);
+            assert(m_pTracks);  //TODO
+            
+            if (m_pInfo)
+                bQuit = true;
+        }
+        else if (id == 0x0F43B675)  //Cluster ID
+        {
+#if 0
+            if (m_pInfo == NULL)  //TODO: liberalize
+                ;  
+            else if (m_pTracks == NULL)
+                ;
+            else
+                //ParseCluster(idpos, pos, size);            
+                Cluster::Parse(this, m_clusters, pos, size);
+#endif
+            bQuit = true;
+        }
+        
+        m_pos = pos + size;  //consume payload
+    }
+    
+    assert(m_pos <= stop);
+    
+    return 0;  //success
+}
+
+
+long Segment::ParseCluster(Cluster*& pCluster, long long& pos_) const
+{
+    pCluster = NULL;
+    pos_ = -1;
+    
+    const long long stop = m_start + m_size;
+    assert(m_pos <= stop);
+    
+    long long pos = m_pos;
+    long long off = -1;
+   
+ 
+    while (pos < stop)
+    {
+        long len;
+        const long long idpos = pos;
+        
+        const long long id = SyncReadUInt(m_pReader, pos, stop, len);
+        
+        if (id < 0)  //error
+            return static_cast<long>(id);
+            
+        if (id == 0)
+            return E_FILE_FORMAT_INVALID;
+            
+        pos += len;  //consume id        
+        assert(pos < stop);
+
+        const long long size = SyncReadUInt(m_pReader, pos, stop, len);
+        
+        if (size < 0)  //error
+            return static_cast<long>(size);
+            
+        pos += len;  //consume size
+        assert(pos <= stop);
+            
+        if (size == 0)  //weird
+            continue;
+            
+        //pos now points to start of payload
+            
+        pos += size;  //consume payload
+        assert(pos <= stop);
+
+        if (off >= 0)
+        {
+            pos_ = idpos;
+            break;
+        }
+
+        if (id == 0x0F43B675)  //Cluster ID
+            off = idpos - m_start;
+    }
+    
+    Segment* const this_ = const_cast<Segment*>(this);
+    const size_t idx = m_clusterCount;
+    
+    if (pos >= stop)
+    {
+        pos_ = stop;
+        
+#if 0        
+        if (off < 0)
+        {
+            pCluster = Cluster::CreateEndOfStream(this_, idx);
+            return 1L;
+        }
+#else
+        if (off < 0)
+            return 1L;
+#endif
+                
+        //Reading 0 bytes at pos might work too -- it would depend 
+        //on how the reader is implemented.
+        
+        unsigned char b;
+
+        const long hr = m_pReader->Read(pos - 1, 1, &b);
+        
+        if (hr < 0)
+            return hr;
+            
+        if (hr != 0L)
+            return E_BUFFER_NOT_FULL;
+    }
+    
+    assert(off >= 0);
+    assert(pos_ >= m_start);
+    assert(pos_ <= stop);
+
+    pCluster = Cluster::Parse(this_, idx, off);
+    return 0L;
+}
+
+
+bool Segment::AddCluster(Cluster* pCluster, long long pos)
+{
+    assert(pos >= m_start);
+    
+    const long long stop = m_start + m_size;
+    assert(pos <= stop);
+
+    if (pCluster)    
+        m_clusters[pos] = pCluster;
+        
+    m_pos = pos;  //m_pos >= stop is now we know we have all clusters
+    
+    return (pos >= stop);
+}
+
+
+long Segment::Load()
+{
+    //Outermost (level 0) segment object has been constructed, 
+    //and pos designates start of payload.  We need to find the
+    //inner (level 1) elements.
+    const long long stop = m_start + m_size;
+#ifdef _DEBUG
+    {
+        long long total, available;
+        
+        long hr = m_pReader->Length(&total, &available);
+        assert(hr >= 0);
+        assert(available >= total);
+        assert(stop <= total);
+    }
+#endif
+    long long index = m_pos;
+    
+    m_clusterCount = 0;
+
+    while (index < stop)
+    {
+        long len = 0;
+
+        long long result = GetUIntLength(m_pReader, index, len);
+       
+        if (result < 0)  //error
+            return static_cast<long>(result);
+            
+        if ((index + len) > stop)
+            return E_FILE_FORMAT_INVALID;
+            
+        const long long idpos = index;
+        const long long id = ReadUInt(m_pReader, idpos, len);
+        
+        if (id < 0)  //error
+            return static_cast<long>(id);
+            
+        index += len;  //consume ID
+        
+        //Read Size
+        result = GetUIntLength(m_pReader, index, len);
+        
+        if (result < 0)  //error
+            return static_cast<long>(result);
+            
+        if ((index + len) > stop)
+            return E_FILE_FORMAT_INVALID;
+            
+        const long long size = ReadUInt(m_pReader, index, len);
+        
+        if (size < 0)  //error
+            return static_cast<long>(size);
+            
+        index += len;  //consume length of size of element
+ 
+        if (id == 0x0F43B675) // Cluster ID 
+            break;
+	
+        if (id == 0x014D9B74) // SeekHead ID 
+        {
+            ParseSeekHead(index, size, NULL); 
+            break;
+        }
+        index += size;
+    }
+        
+    if (m_clusterCount == 0)
+        return -1L;
+
+    while (m_pos < stop)
+    {
+        long long pos = m_pos;
+        
+        long len;
+
+        long long result = GetUIntLength(m_pReader, pos, len);
+        
+        if (result < 0)  //error
+            return static_cast<long>(result);
+            
+        if ((pos + len) > stop)
+            return E_FILE_FORMAT_INVALID;
+            
+        const long long idpos = pos;
+        const long long id = ReadUInt(m_pReader, idpos, len);
+        
+        if (id < 0)  //error
+            return static_cast<long>(id);
+            
+        pos += len;  //consume ID
+        
+        //Read Size
+        result = GetUIntLength(m_pReader, pos, len);
+        
+        if (result < 0)  //error
+            return static_cast<long>(result);
+            
+        if ((pos + len) > stop)
+	        return E_FILE_FORMAT_INVALID;
+            
+        const long long size = ReadUInt(m_pReader, pos, len);
+       
+        if (size < 0)  //error
+            return static_cast<long>(size);
+            
+        pos += len;  //consume length of size of element
+        
+        //Pos now points to start of payload
+        
+        if ((pos + size) > stop)
+            return E_FILE_FORMAT_INVALID;
+            
+        if (id == 0x0F43B675)  //Cluster ID
+            break;
+
+        if (id == 0x014D9B74)  //SeekHead ID
+        {
+            m_clusters = new Cluster*[m_clusterCount];   
+            size_t index = 0;
+            
+            ParseSeekHead(pos, size, &index);            
+            assert(index == m_clusterCount);
+        }            
+        else if (id == 0x0549A966)  //Segment Info ID
+        {
+            assert(m_pInfo == NULL);
+            m_pInfo = new  SegmentInfo(this, pos, size);
+            assert(m_pInfo);  //TODO
+        }
+        else if (id == 0x0654AE6B)  //Tracks ID
+        {
+            assert(m_pTracks == NULL);
+            m_pTracks = new Tracks(this, pos, size);
+            assert(m_pTracks);  //TODO
+        }
+
+        m_pos = pos + size;  //consume payload
+    }
+    
+    assert(m_clusters);
+    
+    //TODO: see notes above.  This check is here (temporarily) to ensure
+    //that the first seekhead has entries for the clusters (because that's
+    //when they're loaded).  In case we are given a file that lists the
+    //clusters in a second seekhead, the worst thing that happens is that
+    //we treat this as an invalid file (which is better then simply
+    //asserting somewhere).  But that's only a work-around.  What we need
+    //to do is be able to handle having multiple seekheads, and having
+    //clusters listed somewhere besides the first seekhead.
+    //    
+    //if (m_clusters == NULL)
+    //    return E_FILE_FORMAT_INVALID;
+        
+    //NOTE: we stop parsing when we reach the first cluster, under the
+    //assumption all clusters are named in some SeekHead.  Clusters
+    //will have been (pre)loaded, so we indicate that we have all clusters
+    //by adjusting the parse position:
+    m_pos = stop;  //means "we have all clusters"
+
+    return 0L;
+}
+
+
+void Segment::ParseSeekHead(long long start, long long size_, size_t* pIndex)
+{
+    long long pos = start;
+    const long long stop = start + size_;
+    while (pos < stop)
+    {
+        long len;
+        
+        const long long id = ReadUInt(m_pReader, pos, len);
+        assert(id >= 0);  //TODO
+        assert((pos + len) <= stop);
+        
+        pos += len;  //consume ID
+        
+        const long long size = ReadUInt(m_pReader, pos, len);
+        assert(size >= 0);
+        assert((pos + len) <= stop);
+        
+        pos += len;  //consume Size field
+        assert((pos + size) <= stop);
+
+        if (id == 0x0DBB)  //SeekEntry ID
+            ParseSeekEntry(pos, size, pIndex);
+        
+        pos += size;  //consume payload
+        assert(pos <= stop);
+    }
+    
+    assert(pos == stop);
+}
+
+
+void Segment::ParseSecondarySeekHead(long long off, size_t* pIndex)
+{
+    assert(off >= 0);
+    assert(off < m_size);
+
+    long long pos = m_start + off;
+    const long long stop = m_start + m_size;
+    
+    long len;
+
+    long long result = GetUIntLength(m_pReader, pos, len);
+    assert(result == 0);
+    assert((pos + len) <= stop);
+    
+    const long long idpos = pos;
+
+    const long long id = ReadUInt(m_pReader, idpos, len);
+    assert(id == 0x014D9B74);  //SeekHead ID
+    
+    pos += len;  //consume ID
+    assert(pos < stop);
+    
+    //Read Size
+    
+    result = GetUIntLength(m_pReader, pos, len);
+    assert(result == 0);
+    assert((pos + len) <= stop);
+    
+    const long long size = ReadUInt(m_pReader, pos, len);
+    assert(size >= 0);
+    
+    pos += len;  //consume length of size of element
+    assert((pos + size) <= stop);
+    
+    //Pos now points to start of payload
+    
+    ParseSeekHead(pos, size, pIndex);
+}
+
+
+void Segment::ParseSeekEntry(long long start, long long size_, size_t* pIndex)
+{
+    long long pos = start;
+
+    const long long stop = start + size_;
+    
+    long len;
+    
+    const long long seekIdId = ReadUInt(m_pReader, pos, len);
+    //seekIdId;
+    assert(seekIdId == 0x13AB);  //SeekID ID
+    assert((pos + len) <= stop);
+    
+    pos += len;  //consume id
+
+    const long long seekIdSize = ReadUInt(m_pReader, pos, len);
+    assert(seekIdSize >= 0);
+    assert((pos + len) <= stop);
+    
+    pos += len;  //consume size
+    
+    const long long seekId = ReadUInt(m_pReader, pos, len);  //payload
+    assert(seekId >= 0);
+    assert(len == seekIdSize);
+    assert((pos + len) <= stop);
+    
+    pos += seekIdSize;  //consume payload
+    
+    const long long seekPosId = ReadUInt(m_pReader, pos, len);
+    //seekPosId;
+    assert(seekPosId == 0x13AC);  //SeekPos ID
+    assert((pos + len) <= stop);
+    
+    pos += len;  //consume id
+    
+    const long long seekPosSize = ReadUInt(m_pReader, pos, len);
+    assert(seekPosSize >= 0);
+    assert((pos + len) <= stop);
+
+    pos += len;  //consume size
+    assert((pos + seekPosSize) <= stop);
+        
+    const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize);
+    assert(seekOff >= 0);
+    assert(seekOff < m_size);
+    
+    pos += seekPosSize;  //consume payload
+    assert(pos == stop);
+    
+    const long long seekPos = m_start + seekOff;
+    assert(seekPos < (m_start + m_size));
+   
+    if (seekId == 0x0F43B675)  //cluster id
+    {       
+        if (pIndex == NULL)
+            ++m_clusterCount; 
+        else
+        {
+            assert(m_clusters);
+            assert(m_clusterCount > 0);
+            
+            size_t& index = *pIndex;
+            assert(index < m_clusterCount);
+            
+            Cluster*& pCluster = m_clusters[index];
+            
+            pCluster = Cluster::Parse(this, index, seekOff);
+            assert(pCluster);  //TODO
+            
+            ++index;
+        }
+    }
+    else if (seekId == 0x014D9B74)  //SeekHead ID
+    {
+        ParseSecondarySeekHead(seekOff, pIndex);
+    }
+}
+
+
+long long Segment::Unparsed() const
+{
+    const long long stop = m_start + m_size;
+
+    const long long result = stop - m_pos;
+    assert(result >= 0);
+    
+    return result;
+}
+
+
+#if 0  //NOTE: too inefficient
+long long Segment::Load(long long time_ns)
+{
+    if (Unparsed() <= 0)
+        return 0;
+    
+    while (m_clusters.empty())
+    {
+        const long long result = Parse();
+        
+        if (result)  //error, or not enough bytes available
+            return result;
+            
+        if (Unparsed() <= 0)
+            return 0;
+    }
+    
+    while (m_clusters.back()->GetTime() < time_ns)
+    {
+        const long long result = Parse();
+        
+        if (result)  //error, or not enough bytes available
+            return result;
+            
+        if (Unparsed() <= 0)
+            return 0;
+    }        
+
+    return 0;        
+}
+#endif
+
+
+Cluster* Segment::GetFirst()
+{
+    if ((m_clusters == NULL) || (m_clusterCount <= 0))
+       return &m_eos;
+
+    Cluster* const pCluster = m_clusters[0];
+    assert(pCluster);
+        
+    return pCluster;
+}
+
+
+Cluster* Segment::GetLast()
+{
+    if ((m_clusters == NULL) || (m_clusterCount <= 0))
+        return &m_eos;
+
+    const size_t idx = m_clusterCount - 1;    
+    Cluster* const pCluster = m_clusters[idx];
+    assert(pCluster);
+        
+    return pCluster;
+}
+
+
+unsigned long Segment::GetCount() const
+{
+    //TODO: m_clusterCount should not be long long.
+    return static_cast<unsigned long>(m_clusterCount);
+}
+
+
+Cluster* Segment::GetNext(const Cluster* pCurr)
+{
+    assert(pCurr);
+    assert(pCurr != &m_eos);
+    assert(m_clusters);
+    assert(m_clusterCount > 0);
+
+    size_t idx =  pCurr->m_index;
+    assert(idx < m_clusterCount);
+    assert(pCurr == m_clusters[idx]);
+    
+    idx++;
+    
+    if (idx >= m_clusterCount) 
+        return &m_eos;
+        
+    Cluster* const pNext = m_clusters[idx];
+    assert(pNext);
+    
+    return pNext;
+}
+
+
+Cluster* Segment::GetCluster(long long time_ns)
+{
+    if ((m_clusters == NULL) || (m_clusterCount <= 0))
+        return &m_eos;
+        
+    {
+        Cluster* const pCluster = m_clusters[0];
+        assert(pCluster);
+        assert(pCluster->m_index == 0);
+        
+        if (time_ns <= pCluster->GetTime())
+            return pCluster;
+    }
+    
+    //Binary search of cluster array
+       
+    size_t i = 0;
+    size_t j = m_clusterCount;
+    
+    while (i < j)
+    {
+        //INVARIANT:
+        //[0, i) <= time_ns
+        //[i, j) ?
+        //[j, m_clusterCount)  > time_ns
+        
+        const size_t k = i + (j - i) / 2;
+        assert(k < m_clusterCount);
+
+        Cluster* const pCluster = m_clusters[k];
+        assert(pCluster);
+        assert(pCluster->m_index == k);
+        
+        const long long t = pCluster->GetTime();
+        
+        if (t <= time_ns)
+            i = k + 1;
+        else
+            j = k;
+            
+        assert(i <= j);
+    }
+    
+    assert(i == j);
+    assert(i > 0);
+    assert(i <= m_clusterCount);
+    
+    const size_t k = i - 1;
+    
+    Cluster* const pCluster = m_clusters[k];
+    assert(pCluster);
+    assert(pCluster->m_index == k);
+    assert(pCluster->GetTime() <= time_ns);
+    
+    return pCluster;
+}
+
+
+Tracks* Segment::GetTracks() const
+{
+    return m_pTracks;
+}
+
+
+const SegmentInfo* const Segment::GetInfo() const
+{
+    return m_pInfo;
+}
+
+
+long long Segment::GetDuration() const
+{
+    assert(m_pInfo);
+    return m_pInfo->GetDuration();
+}
+
+
+SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_) :
+    m_pSegment(pSegment),
+    m_start(start),
+    m_size(size_),
+    m_pMuxingAppAsUTF8(NULL),
+    m_pWritingAppAsUTF8(NULL),
+    m_pTitleAsUTF8(NULL)
+{
+    IMkvReader* const pReader = m_pSegment->m_pReader;
+   
+    long long pos = start;
+    const long long stop = start + size_;
+    
+    m_timecodeScale = 1000000;
+    m_duration = 0;
+    
+    
+    while (pos < stop)
+    {
+        if (Match(pReader, pos, 0x0AD7B1, m_timecodeScale))
+            assert(m_timecodeScale > 0);
+
+        else if (Match(pReader, pos, 0x0489, m_duration))
+            assert(m_duration >= 0);
+
+        else if (Match(pReader, pos, 0x0D80, m_pMuxingAppAsUTF8))   //[4D][80] 
+            assert(m_pMuxingAppAsUTF8);
+
+        else if (Match(pReader, pos, 0x1741, m_pWritingAppAsUTF8))  //[57][41]
+            assert(m_pWritingAppAsUTF8);
+            
+        else if (Match(pReader, pos, 0x3BA9, m_pTitleAsUTF8))        //[7B][A9]
+            assert(m_pTitleAsUTF8);
+
+        else
+        {
+            long len;
+            
+            const long long id = ReadUInt(pReader, pos, len);
+            //id;
+            assert(id >= 0);
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume id
+            assert((stop - pos) > 0);
+            
+            const long long size = ReadUInt(pReader, pos, len);
+            assert(size >= 0);
+            assert((pos + len) <= stop);
+            
+            pos += len + size;  //consume size and payload
+            assert(pos <= stop);
+        }
+    }
+    
+    assert(pos == stop);
+}
+
+SegmentInfo::~SegmentInfo()
+{
+    if (m_pMuxingAppAsUTF8)
+    {
+        delete[] m_pMuxingAppAsUTF8;
+        m_pMuxingAppAsUTF8 = NULL;
+    }
+
+    if (m_pWritingAppAsUTF8)
+    {
+        delete[] m_pWritingAppAsUTF8;
+        m_pWritingAppAsUTF8 = NULL;
+    }
+   
+    if (m_pTitleAsUTF8)
+    {
+        delete[] m_pTitleAsUTF8;
+        m_pTitleAsUTF8 = NULL;
+    }
+}
+
+long long SegmentInfo::GetTimeCodeScale() const
+{
+    return m_timecodeScale;
+}
+
+
+long long SegmentInfo::GetDuration() const
+{
+    assert(m_duration >= 0);    
+    assert(m_timecodeScale >= 1);
+    
+    const double dd = double(m_duration) * double(m_timecodeScale);
+    const long long d = static_cast<long long>(dd);
+    
+    return d;
+}
+
+const char* SegmentInfo::GetMuxingAppAsUTF8() const
+{
+    return m_pMuxingAppAsUTF8;
+}
+
+const char* SegmentInfo::GetWritingAppAsUTF8() const
+{
+    return m_pWritingAppAsUTF8;
+}
+
+const char* SegmentInfo::GetTitleAsUTF8() const
+{
+    return m_pTitleAsUTF8;
+}
+
+Track::Track(Segment* pSegment, const Info& i) :
+    m_pSegment(pSegment),
+    m_info(i)
+{
+}
+
+Track::~Track()
+{
+    Info& info = const_cast<Info&>(m_info);
+    info.Clear();
+}
+
+Track::Info::Info():
+    type(-1),
+    number(-1),
+    uid(-1),
+    nameAsUTF8(NULL),
+    codecId(NULL),
+    codecPrivate(NULL),
+    codecPrivateSize(0),
+    codecNameAsUTF8(NULL)
+{
+}
+
+void Track::Info::Clear() 
+{
+    delete[] nameAsUTF8;
+    nameAsUTF8 = NULL;
+
+    delete[] codecId;
+    codecId = NULL;
+
+    delete[] codecPrivate;
+    codecPrivate = NULL;
+
+    delete[] codecNameAsUTF8;
+    codecNameAsUTF8 = NULL;
+}
+
+const BlockEntry* Track::GetEOS() const
+{
+    return &m_eos;
+}
+
+long long Track::GetType() const
+{
+    const unsigned long result = static_cast<unsigned long>(m_info.type);
+    return result;
+}
+
+unsigned long Track::GetNumber() const
+{
+    assert(m_info.number >= 0);
+    const unsigned long result = static_cast<unsigned long>(m_info.number);
+    return result;
+}
+
+const char* Track::GetNameAsUTF8() const
+{
+    return m_info.nameAsUTF8;
+}
+
+const char* Track::GetCodecNameAsUTF8() const
+{  
+    return m_info.codecNameAsUTF8;
+}
+
+
+const char* Track::GetCodecId() const
+{
+    return m_info.codecId;
+}
+
+
+const unsigned char* Track::GetCodecPrivate(size_t *optionalSize) const
+{
+    if (optionalSize) {
+        *optionalSize = m_info.codecPrivateSize;
+    }
+    return m_info.codecPrivate;
+}
+
+
+long Track::GetFirst(const BlockEntry*& pBlockEntry) const
+{
+    Cluster* const pCluster = m_pSegment->GetFirst();
+    
+    //If Segment::GetFirst returns NULL, then this must be a network 
+    //download, and we haven't loaded any clusters yet.  In this case,
+    //returning NULL from Track::GetFirst means the same thing.
+
+    if ((pCluster == NULL) || pCluster->EOS())
+    {
+        pBlockEntry = NULL;
+        return E_BUFFER_NOT_FULL;  //return 1L instead?
+    }
+        
+    pBlockEntry = pCluster->GetFirst();
+    
+    while (pBlockEntry)
+    {
+        const Block* const pBlock = pBlockEntry->GetBlock();
+        assert(pBlock);
+        
+        if (pBlock->GetTrackNumber() == (unsigned long)m_info.number)
+            return 0L;
+            
+        pBlockEntry = pCluster->GetNext(pBlockEntry);
+    }
+    
+    //NOTE: if we get here, it means that we didn't find a block with
+    //a matching track number.  We interpret that as an error (which
+    //might be too conservative).
+
+    pBlockEntry = GetEOS();  //so we can return a non-NULL value
+    return 1L;
+}
+
+
+long Track::GetNext(const BlockEntry* pCurrEntry, const BlockEntry*& pNextEntry) const
+{
+    assert(pCurrEntry);
+    assert(!pCurrEntry->EOS());  //?
+    assert(pCurrEntry->GetBlock()->GetTrackNumber() == (unsigned long)m_info.number);    
+    
+    const Cluster* const pCurrCluster = pCurrEntry->GetCluster();
+    assert(pCurrCluster);
+    assert(!pCurrCluster->EOS());
+    
+    pNextEntry = pCurrCluster->GetNext(pCurrEntry);
+            
+    while (pNextEntry)
+    {    
+        const Block* const pNextBlock = pNextEntry->GetBlock();
+        assert(pNextBlock);
+    
+        if (pNextBlock->GetTrackNumber() == (unsigned long)m_info.number)
+            return 0L;
+            
+        pNextEntry = pCurrCluster->GetNext(pNextEntry);
+    }
+
+    Segment* pSegment = pCurrCluster->m_pSegment;    
+    Cluster* const pNextCluster = pSegment->GetNext(pCurrCluster);
+    
+    if ((pNextCluster == NULL) || pNextCluster->EOS())
+    {
+        if (pSegment->Unparsed() <= 0)   //all clusters have been loaded
+        {
+            pNextEntry = GetEOS();
+            return 1L;
+        }
+        
+        pNextEntry = NULL;
+        return E_BUFFER_NOT_FULL;
+    }
+        
+    pNextEntry = pNextCluster->GetFirst();
+    
+    while (pNextEntry)
+    {
+        const Block* const pNextBlock = pNextEntry->GetBlock();
+        assert(pNextBlock);
+        
+        if (pNextBlock->GetTrackNumber() == (unsigned long)m_info.number)
+            return 0L;
+            
+        pNextEntry = pNextCluster->GetNext(pNextEntry);
+    }
+    
+    //TODO: what has happened here is that we did not find a block
+    //with a matching track number on the next cluster.  It might
+    //be the case that some cluster beyond the next cluster 
+    //contains a block having a matching track number, but for
+    //now we terminate the search immediately.  We do this so that
+    //we don't end up searching the entire file looking for the
+    //next block.  Another possibility is to try searching for the next
+    //block in a small, fixed number of clusters (intead searching
+    //just the next one), or to terminate the search when when the
+    //there is a large gap in time, or large gap in file position.  It
+    //might very well be the case that the approach we use here is
+    //unnecessarily conservative.
+    
+    //TODO: again, here's a case where we need to return the special
+    //EOS block.  Or something.  It's OK if pNext is NULL, because
+    //we only need it to set the stop time of the media sample.
+    //(The start time is determined from pCurr, which is non-NULL
+    //and non-EOS.)  The problem is when we set pCurr=pNext; when
+    //pCurr has the value NULL we interpret that to mean that we
+    //haven't fully initialized pCurr and we attempt to set it to
+    //point to the first block for this track.  But that's not what
+    //we want at all; we want the next call to PopulateSample to
+    //return end-of-stream, not (re)start from the beginning.
+    //
+    //One work-around is to send EOS immediately.  We would send 
+    //the EOS the next pass anyway, so maybe it's no great loss.  The 
+    //only problem is that if this the stream really does end one
+    //cluster early (relative to other tracks), or the last frame
+    //happens to be a keyframe ("CanSeekToEnd").
+    //
+    //The problem is that we need a way to mark as stream as
+    //"at end of stream" without actually being at end of stream.
+    //We need to give pCurr some value that means "you've reached EOS".
+    //We can't synthesize the special EOS Cluster immediately
+    //(when we first open the file, say), because we use the existance
+    //of that special cluster value to mean that we've read all of 
+    //the clusters (this is a network download, so we can't know apriori
+    //how many we have).
+    //
+    //Or, we could return E_FAIL, and set another bit in the stream
+    //object itself, to indicate that it should send EOS earlier
+    //than when (pCurr=pStop).
+    //
+    //Or, probably the best solution, when we actually load the 
+    //blocks into a cluster: if we notice that there's no block
+    //for a track, we synthesize a nonce EOS block for that track.
+    //That way we always have something to return.  But that will
+    //only work for sequential scan???
+
+    //pNext = NULL;    
+    //return E_FAIL;
+    pNextEntry = GetEOS();
+    return 1L;
+}
+
+
+Track::EOSBlock::EOSBlock()
+{
+}
+
+
+bool Track::EOSBlock::EOS() const
+{
+    return true;
+}
+
+
+Cluster* Track::EOSBlock::GetCluster() const
+{
+    return NULL;
+}
+
+
+size_t Track::EOSBlock::GetIndex() const
+{
+    return 0;
+}
+
+
+const Block* Track::EOSBlock::GetBlock() const
+{
+    return NULL;
+}
+
+
+bool Track::EOSBlock::IsBFrame() const
+{
+    return false;
+}
+
+
+VideoTrack::VideoTrack(Segment* pSegment, const Info& i) :
+    Track(pSegment, i),
+    m_width(-1),
+    m_height(-1),
+    m_rate(-1)
+{
+    assert(i.type == 1);
+    assert(i.number > 0);
+    
+    IMkvReader* const pReader = pSegment->m_pReader;
+    
+    const Settings& s = i.settings;
+    assert(s.start >= 0);
+    assert(s.size >= 0);
+    
+    long long pos = s.start;
+    assert(pos >= 0);
+    
+    const long long stop = pos + s.size;
+    
+    while (pos < stop)
+    {
+#ifdef _DEBUG
+        long len;
+        const long long id = ReadUInt(pReader, pos, len);
+        assert(id >= 0);  //TODO: handle error case
+        assert((pos + len) <= stop);
+#endif
+        if (Match(pReader, pos, 0x30, m_width))         
+            ;
+        else if (Match(pReader, pos, 0x3A, m_height))   
+            ;
+        else if (Match(pReader, pos, 0x0383E3, m_rate)) 
+            ;
+        else
+        {
+            long len;
+            const long long id = ReadUInt(pReader, pos, len);
+            assert(id >= 0);  //TODO: handle error case
+            assert((pos + len) <= stop);
+        
+            pos += len;  //consume id
+            
+            const long long size = ReadUInt(pReader, pos, len);
+            assert(size >= 0);  //TODO: handle error case
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume length of size
+            assert((pos + size) <= stop);
+            
+            //pos now designates start of payload
+            
+            pos += size;  //consume payload
+            assert(pos <= stop);
+        }
+    }
+    
+    return;
+}
+
+
+bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const
+{
+    assert(pBlockEntry);
+    
+    const Block* const pBlock = pBlockEntry->GetBlock();
+    assert(pBlock);    
+    assert(pBlock->GetTrackNumber() == (unsigned long)m_info.number);
+    
+    return pBlock->IsKey();
+}
+
+
+
+long long VideoTrack::GetWidth() const
+{
+    return m_width;
+}
+
+
+long long VideoTrack::GetHeight() const
+{
+    return m_height;
+}
+
+
+double VideoTrack::GetFrameRate() const
+{
+    return m_rate;
+}
+
+
+AudioTrack::AudioTrack(Segment* pSegment, const Info& i) :
+    Track(pSegment, i)
+{
+    assert(i.type == 2);
+    assert(i.number > 0);
+
+    IMkvReader* const pReader = pSegment->m_pReader;
+    
+    const Settings& s = i.settings;
+    assert(s.start >= 0);
+    assert(s.size >= 0);
+    
+    long long pos = s.start;
+    assert(pos >= 0);
+    
+    const long long stop = pos + s.size;
+    
+    while (pos < stop)
+    {
+#ifdef _DEBUG
+        long len;
+        const long long id = ReadUInt(pReader, pos, len);
+        assert(id >= 0);  //TODO: handle error case
+        assert((pos + len) <= stop);
+#endif
+        if (Match(pReader, pos, 0x35, m_rate))            
+            ;
+        else if (Match(pReader, pos, 0x1F, m_channels))   
+            ;
+        else if (Match(pReader, pos, 0x2264, m_bitDepth))  
+            ;            
+        else
+        {
+            long len;
+            const long long id = ReadUInt(pReader, pos, len);
+            assert(id >= 0);  //TODO: handle error case
+            assert((pos + len) <= stop);
+        
+            pos += len;  //consume id
+            
+            const long long size = ReadUInt(pReader, pos, len);
+            assert(size >= 0);  //TODO: handle error case
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume length of size
+            assert((pos + size) <= stop);
+            
+            //pos now designates start of payload
+            
+            pos += size;  //consume payload
+            assert(pos <= stop);
+        }
+    }
+
+    return;
+}
+
+bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const
+{
+    assert(pBlockEntry);
+    
+    const Block* const pBlock = pBlockEntry->GetBlock();
+    assert(pBlock);
+    assert(pBlock->GetTrackNumber() == (unsigned long)m_info.number);
+
+    return true;
+}
+
+
+double AudioTrack::GetSamplingRate() const
+{
+    return m_rate;
+}
+
+
+long long AudioTrack::GetChannels() const
+{
+    return m_channels;
+}
+
+long long AudioTrack::GetBitDepth() const
+{
+    return m_bitDepth;
+}
+
+Tracks::Tracks(Segment* pSegment, long long start, long long size_) :
+    m_pSegment(pSegment),
+    m_start(start),
+    m_size(size_),
+    m_trackEntries(NULL),
+    m_trackEntriesEnd(NULL)
+{
+    long long stop = m_start + m_size;
+    IMkvReader* const pReader = m_pSegment->m_pReader;
+    
+    long long pos1 = m_start;
+    int count = 0;
+    
+    while (pos1 < stop)
+    {
+        long len;
+        const long long id = ReadUInt(pReader, pos1, len);
+        assert(id >= 0);
+        assert((pos1 + len) <= stop);
+        
+        pos1 += len;  //consume id
+        
+        const long long size = ReadUInt(pReader, pos1, len);
+        assert(size >= 0);
+        assert((pos1 + len) <= stop);
+        
+        pos1 += len;  //consume length of size
+        
+        //pos now desinates start of element
+        if (id == 0x2E)  //TrackEntry ID
+            ++count;
+            
+        pos1 += size;  //consume payload
+        assert(pos1 <= stop);
+    }    
+
+    if (count <= 0)
+        return;
+
+    m_trackEntries = new Track*[count];
+    m_trackEntriesEnd = m_trackEntries;
+
+    long long pos = m_start;
+
+    while (pos < stop)
+    {
+        long len;
+        const long long id = ReadUInt(pReader, pos, len);
+        assert(id >= 0);
+        assert((pos + len) <= stop);
+        
+        pos += len;  //consume id
+        
+        const long long size1 = ReadUInt(pReader, pos, len);
+        assert(size1 >= 0);
+        assert((pos + len) <= stop);
+        
+        pos += len;  //consume length of size
+        
+        //pos now desinates start of element
+        
+        if (id == 0x2E)  //TrackEntry ID
+            ParseTrackEntry(pos, size1, *m_trackEntriesEnd++);
+            
+        pos += size1;  //consume payload
+        assert(pos <= stop);
+    }    
+}
+
+unsigned long Tracks::GetTracksCount() const
+{
+    const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
+    assert(result >= 0);
+    
+    return static_cast<unsigned long>(result);
+}
+
+
+void Tracks::ParseTrackEntry(
+    long long start,
+    long long size,
+    Track*& pTrack)
+{
+    IMkvReader* const pReader = m_pSegment->m_pReader;
+    
+    long long pos = start;
+    const long long stop = start + size;
+
+    Track::Info i;
+    
+    Track::Settings videoSettings;
+    videoSettings.start = -1;
+    
+    Track::Settings audioSettings;
+    audioSettings.start = -1;
+    
+    while (pos < stop)
+    {
+#ifdef _DEBUG
+        long len;
+        const long long id = ReadUInt(pReader, pos, len);
+        len;
+        id;
+#endif
+        if (Match(pReader, pos, 0x57, i.number))
+            assert(i.number > 0);
+
+        else if (Match(pReader, pos, 0x33C5, i.uid))           
+            ;  
+
+        else if (Match(pReader, pos, 0x03, i.type))            
+            ;  
+
+        else if (Match(pReader, pos, 0x136E, i.nameAsUTF8))          
+            assert(i.nameAsUTF8);  
+
+        else if (Match(pReader, pos, 0x06, i.codecId))         
+            ;  
+
+        else if (Match(pReader, pos, 0x23A2, i.codecPrivate, &i.codecPrivateSize))  
+            ;  
+
+        else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8))   
+            assert(i.codecNameAsUTF8);  
+
+        else
+        {
+            long len;
+            
+            const long long id = ReadUInt(pReader, pos, len);
+            assert(id >= 0);  //TODO: handle error case
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume id
+            
+            const long long size = ReadUInt(pReader, pos, len);
+            assert(size >= 0);  //TODO: handle error case
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume length of size
+            const long long start = pos;
+            
+            pos += size;  //consume payload
+            assert(pos <= stop);
+            
+            if (id == 0x60)
+            {
+                videoSettings.start = start;
+                videoSettings.size = size;
+            }
+            else if (id == 0x61)
+            {
+                audioSettings.start = start;
+                audioSettings.size = size;
+            }
+        }
+    }
+    
+    assert(pos == stop);
+    //TODO: propertly vet info.number, to ensure both its existence,
+    //and that it is unique among all tracks.
+    assert(i.number > 0);
+
+    //TODO: vet settings, to ensure that video settings (0x60)
+    //were specified when type = 1, and that audio settings (0x61)
+    //were specified when type = 2.    
+    if (i.type == 1)  //video
+    {
+        assert(audioSettings.start < 0);
+        assert(videoSettings.start >= 0);
+        
+        i.settings = videoSettings;
+        
+        VideoTrack* const t = new VideoTrack(m_pSegment, i);
+        assert(t);  //TODO
+        pTrack = t;    
+    }
+    else if (i.type == 2)  //audio
+    {
+        assert(videoSettings.start < 0);
+        assert(audioSettings.start >= 0);
+        
+        i.settings = audioSettings;
+        
+        AudioTrack* const t = new  AudioTrack(m_pSegment, i);
+        assert(t);  //TODO
+        pTrack = t;  
+    }
+    else
+    {
+        // for now we do not support other track types yet.
+        // TODO: support other track types
+        i.Clear();
+  
+        pTrack = NULL;
+    }
+    
+    return;
+}
+
+
+Tracks::~Tracks()
+{
+    Track** i = m_trackEntries;
+    Track** const j = m_trackEntriesEnd;
+    
+    while (i != j)
+    {
+        Track* pTrack = *i++;
+        delete pTrack;
+        pTrack = NULL;    
+    }
+
+    delete[] m_trackEntries;
+}
+
+
+Track* Tracks::GetTrackByNumber(unsigned long tn) const
+{
+    Track** i = m_trackEntries;
+    Track** const j = m_trackEntriesEnd;
+
+    while (i != j)
+    {
+        Track* const pTrack = *i++;
+       
+        if (pTrack == NULL)
+            continue;
+
+        if (tn == pTrack->GetNumber())
+            return pTrack;
+    }
+
+    return NULL;  //not found
+}
+
+
+Track* Tracks::GetTrackByIndex(unsigned long idx) const
+{
+    const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
+       
+    if (idx >= static_cast<unsigned long>(count))
+         return NULL;
+
+    return m_trackEntries[idx];
+}
+
+
+void Cluster::Load()
+{
+    assert(m_pSegment);
+    
+    if (m_start > 0)
+    {
+        assert(m_size > 0);
+        assert(m_timecode >= 0);
+        return;
+    }
+    
+    assert(m_size == 0);
+    assert(m_timecode < 0);
+    
+    IMkvReader* const pReader = m_pSegment->m_pReader;
+
+    const long long off = -m_start;  //relative to segment
+    long long pos = m_pSegment->m_start + off;  //absolute
+    
+    long len;
+
+    const long long id_ = ReadUInt(pReader, pos, len);
+    assert(id_ >= 0);
+    assert(id_ == 0x0F43B675);  //Cluster ID
+    
+    pos += len;  //consume id
+    
+    const long long size_ = ReadUInt(pReader, pos, len);
+    assert(size_ >= 0);
+    
+    pos += len;  //consume size
+    
+    m_start = pos;
+    m_size = size_;
+    
+    const long long stop = m_start + size_;
+    
+    long long timecode = -1;
+    
+    while (pos < stop)
+    {
+        if (Match(pReader, pos, 0x67, timecode))
+            break;            
+        else
+        {
+            const long long id = ReadUInt(pReader, pos, len);
+            assert(id >= 0);  //TODO
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume id
+            
+            const long long size = ReadUInt(pReader, pos, len);
+            assert(size >= 0);  //TODO
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume size
+            
+            if (id == 0x20)  //BlockGroup ID
+                break;
+                
+            if (id == 0x23)  //SimpleBlock ID
+                break;
+
+            pos += size;  //consume payload
+            assert(pos <= stop);
+        }
+    }
+    
+    assert(pos <= stop);
+    assert(timecode >= 0);
+    
+    m_timecode = timecode;
+}
+
+
+Cluster* Cluster::Parse(
+    Segment* pSegment,
+    size_t idx,
+    long long off)
+{
+    assert(pSegment);
+    assert(off >= 0);
+    assert(off < pSegment->m_size);
+    Cluster* const pCluster = new Cluster(pSegment, idx, -off);
+    assert(pCluster);
+    
+    return pCluster;
+}
+
+
+Cluster::Cluster() :
+    m_pSegment(NULL),
+    m_index(0),
+    m_start(0),
+    m_size(0),
+    m_timecode(0),
+    m_pEntries(NULL),
+    m_entriesCount(0)
+{
+}
+
+Cluster::Cluster(
+    Segment* pSegment,
+    size_t idx,
+    long long off) :
+    m_pSegment(pSegment),
+    m_index(idx),
+    m_start(off),
+    m_size(0),
+    m_timecode(-1),
+    m_pEntries(NULL),
+    m_entriesCount(0)
+{
+}
+
+
+Cluster::~Cluster()
+{
+#if 0
+    while (!m_pEntries.empty())
+    {
+        BlockEntry* pBlockEntry = m_pEntries.front();
+        assert(pBlockEntry);
+        
+        m_pEntries.pop_front();
+        delete pBlockEntry;
+    }
+#else
+    BlockEntry** i = m_pEntries;
+    BlockEntry** const j = m_pEntries + m_entriesCount;
+    while (i != j)
+    {
+         BlockEntry* p = *i++;
+   
+         assert(p);
+         delete p;
+    }
+ 
+    delete[] m_pEntries;
+#endif
+
+}
+
+bool Cluster::EOS() const
+{
+    return (m_pSegment == 0);
+}
+
+
+void Cluster::LoadBlockEntries()
+{
+    if (m_pEntries)
+        return;
+
+    Load();    
+    assert(m_timecode >= 0);
+    assert(m_start > 0);
+    assert(m_size > 0);
+    
+    IMkvReader* const pReader = m_pSegment->m_pReader;
+    
+    long long pos = m_start;
+    const long long stop = m_start + m_size;
+    long long timecode = -1;
+   
+    long long idx = pos;
+
+    m_entriesCount = 0;
+    
+    while (idx < stop)
+    {
+        if (Match(pReader, idx, 0x67, timecode))
+            assert(timecode == m_timecode);
+        else 
+        {
+            long len;
+            
+            const long long id = ReadUInt(pReader, idx, len);
+            assert(id >= 0);  //TODO
+            assert((idx + len) <= stop);
+            
+            idx += len;  //consume id
+            
+            const long long size = ReadUInt(pReader, idx, len);
+            assert(size >= 0);  //TODO
+            assert((idx + len) <= stop);
+            
+            idx += len;  //consume size
+            
+            if (id == 0x20)  //BlockGroup ID
+                ++m_entriesCount;
+            else if (id == 0x23)  //SimpleBlock ID
+                ++m_entriesCount;
+
+            idx += size;  //consume payload
+
+            assert(idx <= stop);
+        }  
+    }
+
+    if (m_entriesCount == 0)
+        return;
+     
+    m_pEntries = new BlockEntry*[m_entriesCount];
+    size_t index = 0;
+    
+    while (pos < stop)
+    {
+        if (Match(pReader, pos, 0x67, timecode))
+            assert(timecode == m_timecode);
+        else
+        {
+            long len;
+            const long long id = ReadUInt(pReader, pos, len);
+            assert(id >= 0);  //TODO
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume id
+            
+            const long long size = ReadUInt(pReader, pos, len);
+            assert(size >= 0);  //TODO
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume size
+            
+            if (id == 0x20)  //BlockGroup ID
+                ParseBlockGroup(pos, size, index++);
+            else if (id == 0x23)  //SimpleBlock ID
+                ParseSimpleBlock(pos, size, index++);
+
+            pos += size;  //consume payload
+            assert(pos <= stop);
+        }
+    }
+    
+    assert(pos == stop);
+    assert(timecode >= 0);
+    assert(index == m_entriesCount);
+}
+
+
+
+long long Cluster::GetTimeCode()
+{
+    Load();
+    return m_timecode;
+}
+
+
+long long Cluster::GetTime()
+{
+    const long long tc = GetTimeCode();
+    assert(tc >= 0);
+    
+    const SegmentInfo* const pInfo = m_pSegment->GetInfo();
+    assert(pInfo);
+    
+    const long long scale = pInfo->GetTimeCodeScale();
+    assert(scale >= 1);
+    
+    const long long t = m_timecode * scale;
+
+    return t;
+}
+
+
+void Cluster::ParseBlockGroup(long long start, long long size, size_t index)
+{
+    assert(m_pEntries);
+    assert(m_entriesCount);
+    assert(index < m_entriesCount);
+    
+    BlockGroup* const pGroup = new BlockGroup(this, index, start, size);
+    assert(pGroup);  //TODO
+        
+    m_pEntries[index] = pGroup;
+}
+
+
+
+void Cluster::ParseSimpleBlock(long long start, long long size, size_t index)
+{
+    assert(m_pEntries);
+    assert(m_entriesCount);
+    assert(index < m_entriesCount);
+
+    SimpleBlock* const pSimpleBlock = new SimpleBlock(this, index, start, size);
+    assert(pSimpleBlock);  //TODO
+        
+    m_pEntries[index] = pSimpleBlock;
+}
+
+
+const BlockEntry* Cluster::GetFirst()
+{
+    LoadBlockEntries();
+    
+    return m_pEntries[0];
+}
+
+        
+const BlockEntry* Cluster::GetLast()
+{ 
+    if (m_entriesCount == 0)
+        return m_pEntries[0];
+    
+    return m_pEntries[m_entriesCount-1];
+}
+
+        
+const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
+{
+    assert(pEntry);
+    
+    size_t idx = pEntry->GetIndex();
+    
+    ++idx;
+
+    if (idx == m_entriesCount) 
+      return NULL;
+
+    return m_pEntries[idx];
+
+}
+
+
+const BlockEntry* Cluster::GetEntry(const Track* pTrack)
+{
+
+    assert(pTrack);
+    
+    if (m_pSegment == NULL)  //EOS
+        return pTrack->GetEOS();
+    
+    LoadBlockEntries();
+    
+    BlockEntry* i = *m_pEntries;
+    BlockEntry* j = *m_pEntries + m_entriesCount;
+    while (i != j)
+    {
+        BlockEntry* pEntry = i;
+        i++;
+        assert(pEntry);
+        assert(!pEntry->EOS());
+        
+        const Block* const pBlock = pEntry->GetBlock();
+        assert(pBlock);
+        
+        if (pBlock->GetTrackNumber() != pTrack->GetNumber())
+            continue;
+
+        if (pTrack->VetEntry(pEntry))
+            return pEntry;
+    }
+    
+    return pTrack->GetEOS();  //no satisfactory block found
+}
+
+
+BlockEntry::BlockEntry()
+{
+}
+
+
+BlockEntry::~BlockEntry()
+{
+}
+
+
+
+SimpleBlock::SimpleBlock(
+    Cluster* pCluster, 
+    size_t idx, 
+    long long start, 
+    long long size) :
+    m_pCluster(pCluster),
+    m_index(idx),
+    m_block(start, size, pCluster->m_pSegment->m_pReader)
+{
+}
+
+
+bool SimpleBlock::EOS() const
+{
+    return false;
+}
+
+
+Cluster* SimpleBlock::GetCluster() const
+{
+    return m_pCluster;
+}
+
+
+size_t SimpleBlock::GetIndex() const
+{
+    return m_index;
+}
+
+
+const Block* SimpleBlock::GetBlock() const
+{
+    return &m_block;
+}
+
+
+bool SimpleBlock::IsBFrame() const
+{
+    return false;
+}
+
+
+BlockGroup::BlockGroup(
+    Cluster* pCluster, 
+    size_t idx, 
+    long long start, 
+    long long size_) :
+    m_pCluster(pCluster),
+    m_index(idx),
+    m_prevTimeCode(0),
+    m_nextTimeCode(0),
+    m_pBlock(NULL)  //TODO: accept multiple blocks within a block group
+{
+    IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
+    
+    long long pos = start;
+    const long long stop = start + size_;
+ 
+    bool bSimpleBlock = false;
+    
+    while (pos < stop)
+    {
+        short t;
+    
+        if (Match(pReader, pos, 0x7B, t))
+        {    
+            if (t < 0)
+                m_prevTimeCode = t;
+            else if (t > 0)
+                m_nextTimeCode = t;
+            else
+                assert(false);
+        }
+        else
+        {
+            long len;
+            const long long id = ReadUInt(pReader, pos, len);
+            assert(id >= 0);  //TODO
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume ID
+            
+            const long long size = ReadUInt(pReader, pos, len);
+            assert(size >= 0);  //TODO
+            assert((pos + len) <= stop);
+            
+            pos += len;  //consume size
+            
+            switch (id)
+            {
+                case 0x23:  //SimpleBlock ID
+                    bSimpleBlock = true;
+                    //YES, FALL THROUGH TO NEXT CASE
+
+                case 0x21:  //Block ID
+                    ParseBlock(pos, size);                    
+                    break;
+                    
+                default:
+                    break;
+            }
+                
+            pos += size;  //consume payload
+            assert(pos <= stop);
+        }
+    }
+    
+    assert(pos == stop);
+    assert(m_pBlock);
+    
+    if (!bSimpleBlock)
+        m_pBlock->SetKey(m_prevTimeCode >= 0);
+}
+
+
+BlockGroup::~BlockGroup()
+{
+    delete m_pBlock;
+}
+
+
+void BlockGroup::ParseBlock(long long start, long long size)
+{   
+    IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
+    
+    Block* const pBlock = new Block(start, size, pReader);
+    assert(pBlock);  //TODO
+
+    //TODO: the Matroska spec says you have multiple blocks within the 
+    //same block group, with blocks ranked by priority (the flag bits).
+    //I haven't ever seen such a file (mkvmux certainly doesn't make
+    //one), so until then I'll just assume block groups contain a single
+    //block.
+#if 0    
+    m_blocks.push_back(pBlock);
+#else
+    assert(m_pBlock == NULL);
+    m_pBlock = pBlock;
+#endif
+
+#if 0
+    Track* const pTrack = pBlock->GetTrack();
+    assert(pTrack);
+    
+    pTrack->Insert(pBlock);
+#endif
+}
+
+
+bool BlockGroup::EOS() const
+{
+    return false;
+}
+
+
+Cluster* BlockGroup::GetCluster() const
+{
+    return m_pCluster;
+}
+
+
+size_t BlockGroup::GetIndex() const
+{
+    return m_index;
+}
+
+
+const Block* BlockGroup::GetBlock() const
+{
+    return m_pBlock;
+}
+
+
+short BlockGroup::GetPrevTimeCode() const
+{
+    return m_prevTimeCode;
+}
+
+
+short BlockGroup::GetNextTimeCode() const
+{
+    return m_nextTimeCode;
+}    
+
+
+bool BlockGroup::IsBFrame() const
+{
+    return (m_nextTimeCode > 0);
+}
+
+
+
+Block::Block(long long start, long long size_, IMkvReader* pReader) :
+    m_start(start),
+    m_size(size_)
+{
+    long long pos = start;
+    const long long stop = start + size_;
+
+    long len;
+    
+    m_track = ReadUInt(pReader, pos, len);
+    assert(m_track > 0);
+    assert((pos + len) <= stop);
+    
+    pos += len;  //consume track number
+    assert((stop - pos) >= 2);
+    
+    m_timecode = Unserialize2SInt(pReader, pos);
+
+    pos += 2;
+    assert((stop - pos) >= 1);
+    
+    const long hr = pReader->Read(pos, 1, &m_flags);
+    assert(hr == 0L);
+
+    ++pos;
+    assert(pos <= stop);
+    
+    m_frameOff = pos;
+    
+    const long long frame_size = stop - pos;
+
+    assert(frame_size <= 2147483647L);
+    
+    m_frameSize = static_cast<long>(frame_size);
+}
+
+
+long long Block::GetTimeCode(Cluster* pCluster) const
+{
+    assert(pCluster);
+    
+    const long long tc0 = pCluster->GetTimeCode();
+    assert(tc0 >= 0);
+    
+    const long long tc = tc0 + static_cast<long long>(m_timecode);
+    assert(tc >= 0);
+    
+    return tc;  //unscaled timecode units
+}
+
+
+long long Block::GetTime(Cluster* pCluster) const
+{
+    assert(pCluster);
+    
+    const long long tc = GetTimeCode(pCluster);
+    
+    const Segment* const pSegment = pCluster->m_pSegment;
+    const SegmentInfo* const pInfo = pSegment->GetInfo();
+    assert(pInfo);
+    
+    const long long scale = pInfo->GetTimeCodeScale();
+    assert(scale >= 1);
+    
+    const long long ns = tc * scale;
+
+    return ns;
+}
+
+
+unsigned long Block::GetTrackNumber() const
+{
+    assert(m_track > 0);
+    
+    return static_cast<unsigned long>(m_track);
+}
+
+
+bool Block::IsKey() const
+{
+    return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
+}
+
+
+void Block::SetKey(bool bKey)
+{
+    if (bKey)
+        m_flags |= static_cast<unsigned char>(1 << 7);
+    else
+        m_flags &= 0x7F;
+}
+
+
+long Block::GetSize() const
+{
+    return m_frameSize;
+}
+
+
+long Block::Read(IMkvReader* pReader, unsigned char* buf) const
+{
+
+    assert(pReader);
+    assert(buf);
+    
+    const long hr = pReader->Read(m_frameOff, m_frameSize, buf);
+    
+    return hr;
+}
+
+
+}  //end namespace mkvparser
diff --git a/media/libstagefright/matroska/mkvparser.hpp b/media/libstagefright/matroska/mkvparser.hpp
new file mode 100644
index 0000000..4d311b4
--- /dev/null
+++ b/media/libstagefright/matroska/mkvparser.hpp
@@ -0,0 +1,428 @@
+#ifndef MKVPARSER_HPP
+#define MKVPARSER_HPP
+
+#include <cstdlib>
+#include <cstdio>
+
+namespace mkvparser
+{
+
+const int E_FILE_FORMAT_INVALID = -2;
+const int E_BUFFER_NOT_FULL = -3;
+
+class IMkvReader
+{
+public:
+    virtual int Read(long long position, long length, unsigned char* buffer) = 0;
+    virtual int Length(long long* total, long long* available) = 0; 	
+protected:
+    virtual ~IMkvReader();
+};
+
+long long GetUIntLength(IMkvReader*, long long, long&);
+long long ReadUInt(IMkvReader*, long long, long&);
+long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&);
+long long UnserializeUInt(IMkvReader*, long long pos, long long size);
+float Unserialize4Float(IMkvReader*, long long);
+double Unserialize8Double(IMkvReader*, long long);
+short Unserialize2SInt(IMkvReader*, long long);
+signed char Unserialize1SInt(IMkvReader*, long long);
+bool Match(IMkvReader*, long long&, unsigned long, long long&);
+bool Match(IMkvReader*, long long&, unsigned long, char*&);
+bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&,
+           size_t *optionalSize = NULL);
+bool Match(IMkvReader*, long long&, unsigned long, double&);
+bool Match(IMkvReader*, long long&, unsigned long, short&);
+
+
+struct EBMLHeader
+{
+    EBMLHeader();
+    ~EBMLHeader();  
+    long long m_version;
+    long long m_readVersion;
+    long long m_maxIdLength;
+    long long m_maxSizeLength;
+    char* m_docType;
+    long long m_docTypeVersion;
+    long long m_docTypeReadVersion;
+    
+    long long Parse(IMkvReader*, long long&);
+};
+
+
+class Segment;
+class Track;
+class Cluster;
+
+class Block
+{
+    Block(const Block&);
+    Block& operator=(const Block&);
+
+public:
+    const long long m_start;
+    const long long m_size;
+    
+    Block(long long start, long long size, IMkvReader*);
+    
+    unsigned long GetTrackNumber() const;
+    
+    long long GetTimeCode(Cluster*) const;  //absolute, but not scaled
+    long long GetTime(Cluster*) const;      //absolute, and scaled (nanosecond units)
+    bool IsKey() const;
+    void SetKey(bool);
+
+    long GetSize() const;
+    long Read(IMkvReader*, unsigned char*) const;
+    
+private:
+    long long m_track;   //Track::Number()
+    short m_timecode;  //relative to cluster
+    unsigned char m_flags;
+    long long m_frameOff;
+    long m_frameSize;    
+
+};
+
+
+class BlockEntry
+{
+    BlockEntry(const BlockEntry&);
+    BlockEntry& operator=(const BlockEntry&);
+    
+public:
+    virtual ~BlockEntry();
+    virtual bool EOS() const = 0;
+    virtual Cluster* GetCluster() const = 0;
+    virtual size_t GetIndex() const = 0;
+    virtual const Block* GetBlock() const = 0;
+    virtual bool IsBFrame() const = 0;
+    
+protected:
+    BlockEntry();
+
+};
+
+
+class SimpleBlock : public BlockEntry
+{
+    SimpleBlock(const SimpleBlock&);
+    SimpleBlock& operator=(const SimpleBlock&);
+
+public:
+    SimpleBlock(Cluster*, size_t, long long start, long long size);
+
+    bool EOS() const;
+    Cluster* GetCluster() const; 
+    size_t GetIndex() const;
+    const Block* GetBlock() const;
+    bool IsBFrame() const;
+
+protected:
+    Cluster* const m_pCluster;
+    const size_t m_index;
+    Block m_block;
+    
+};
+
+
+class BlockGroup : public BlockEntry
+{
+    BlockGroup(const BlockGroup&);
+    BlockGroup& operator=(const BlockGroup&);
+
+public:
+    BlockGroup(Cluster*, size_t, long long, long long);
+    ~BlockGroup();
+    
+    bool EOS() const;
+    Cluster* GetCluster() const; 
+    size_t GetIndex() const;
+    const Block* GetBlock() const;
+    bool IsBFrame() const;
+    
+    short GetPrevTimeCode() const;  //relative to block's time
+    short GetNextTimeCode() const;  //as above
+    
+protected:
+    Cluster* const m_pCluster;
+    const size_t m_index;
+    
+private:
+    BlockGroup(Cluster*, size_t, unsigned long);
+    void ParseBlock(long long start, long long size);
+
+    short m_prevTimeCode;
+    short m_nextTimeCode;
+    
+    //TODO: the Matroska spec says you can have multiple blocks within the 
+    //same block group, with blocks ranked by priority (the flag bits).
+    //For now we just cache a single block.
+#if 0
+    typedef std::deque<Block*> blocks_t;
+    blocks_t m_blocks;  //In practice should contain only a single element.
+#else
+    Block* m_pBlock;
+#endif
+    
+};
+
+
+class Track
+{
+    Track(const Track&);
+    Track& operator=(const Track&);
+
+public:    
+    Segment* const m_pSegment;
+    virtual ~Track();
+    
+    long long GetType() const; 
+    unsigned long GetNumber() const;
+    const char* GetNameAsUTF8() const;
+    const char* GetCodecNameAsUTF8() const;
+    const char* GetCodecId() const;
+    const unsigned char* GetCodecPrivate(
+            size_t *optionalSize = NULL) const;
+    
+    const BlockEntry* GetEOS() const;
+    
+    struct Settings 
+    {
+        long long start;
+        long long size;
+    };
+    
+    struct Info
+    {
+        long long type;
+        long long number;
+        long long uid;
+        char* nameAsUTF8;
+        char* codecId;
+        unsigned char* codecPrivate;
+        size_t codecPrivateSize;
+        char* codecNameAsUTF8;
+        Settings settings;
+        Info();
+        void Clear();
+    };
+    
+    long GetFirst(const BlockEntry*&) const;
+    long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
+    virtual bool VetEntry(const BlockEntry*) const = 0;
+        
+protected:
+    Track(Segment*, const Info&);        
+    const Info m_info;
+
+    class EOSBlock : public BlockEntry
+    {
+    public:
+        EOSBlock();
+
+        bool EOS() const;    
+        Cluster* GetCluster() const;
+        size_t GetIndex() const;
+        const Block* GetBlock() const;
+        bool IsBFrame() const;
+    };
+    
+    EOSBlock m_eos;
+    
+};
+
+
+class VideoTrack : public Track
+{
+    VideoTrack(const VideoTrack&);
+    VideoTrack& operator=(const VideoTrack&);
+    
+public:
+    VideoTrack(Segment*, const Info&);    
+    long long GetWidth() const;
+    long long GetHeight() const;
+    double GetFrameRate() const;
+    
+    bool VetEntry(const BlockEntry*) const;
+
+private:
+    long long m_width;
+    long long m_height;
+    double m_rate;
+    
+};
+
+
+class AudioTrack : public Track
+{
+    AudioTrack(const AudioTrack&);
+    AudioTrack& operator=(const AudioTrack&);
+
+public:
+    AudioTrack(Segment*, const Info&);    
+    double GetSamplingRate() const;
+    long long GetChannels() const;
+    long long GetBitDepth() const;    
+    bool VetEntry(const BlockEntry*) const;
+
+private:
+    double m_rate;
+    long long m_channels;
+    long long m_bitDepth;
+};
+
+
+class Tracks
+{
+    Tracks(const Tracks&);
+    Tracks& operator=(const Tracks&);
+
+public:
+    Segment* const m_pSegment;
+    const long long m_start;
+    const long long m_size;
+    
+    Tracks(Segment*, long long start, long long size);
+    virtual ~Tracks();
+
+    Track* GetTrackByNumber(unsigned long tn) const;
+    Track* GetTrackByIndex(unsigned long idx) const;
+    
+private:
+    Track** m_trackEntries; 
+    Track** m_trackEntriesEnd;
+
+    void ParseTrackEntry(long long, long long, Track*&);
+    
+public:
+    unsigned long GetTracksCount() const;
+};
+
+
+class SegmentInfo
+{
+    SegmentInfo(const SegmentInfo&);
+    SegmentInfo& operator=(const SegmentInfo&);
+    
+public:
+    Segment* const m_pSegment;
+    const long long m_start;
+    const long long m_size;
+    
+    SegmentInfo(Segment*, long long start, long long size);
+    ~SegmentInfo();
+    long long GetTimeCodeScale() const;
+    long long GetDuration() const;  //scaled
+    const char* GetMuxingAppAsUTF8() const;
+    const char* GetWritingAppAsUTF8() const;
+    const char* GetTitleAsUTF8() const;
+    
+private:
+    long long m_timecodeScale;
+    double m_duration;
+    char* m_pMuxingAppAsUTF8;
+    char* m_pWritingAppAsUTF8;
+    char* m_pTitleAsUTF8;
+};
+
+
+class Cluster
+{
+    Cluster(const Cluster&);
+    Cluster& operator=(const Cluster&);
+
+public:
+    Segment* const m_pSegment;
+    const size_t m_index;
+    
+public:    
+    static Cluster* Parse(Segment*, size_t, long long off);
+
+    Cluster();  //EndOfStream
+    ~Cluster();
+    
+    bool EOS() const;
+    
+    long long GetTimeCode();  //absolute, but not scaled
+    long long GetTime();      //absolute, and scaled (nanosecond units)
+
+    const BlockEntry* GetFirst();
+    const BlockEntry* GetLast();
+    const BlockEntry* GetNext(const BlockEntry*) const;    
+    const BlockEntry* GetEntry(const Track*);
+protected:    
+    Cluster(Segment*, size_t, long long off);
+    
+private:
+    long long m_start;
+    long long m_size;    
+    long long m_timecode;
+    BlockEntry** m_pEntries;
+    size_t m_entriesCount;
+   
+    void Load();
+    void LoadBlockEntries();
+    void ParseBlockGroup(long long, long long, size_t);
+    void ParseSimpleBlock(long long, long long, size_t);
+    
+};
+
+
+class Segment
+{
+    Segment(const Segment&);
+    Segment& operator=(const Segment&);
+
+private:
+    Segment(IMkvReader*, long long pos, long long size);
+
+public:
+    IMkvReader* const m_pReader;
+    const long long m_start;  //posn of segment payload
+    const long long m_size;   //size of segment payload
+    Cluster m_eos;  //TODO: make private?
+    
+    static long long CreateInstance(IMkvReader*, long long, Segment*&);
+    ~Segment();
+
+    //for big-bang loading (source filter)
+    long Load();
+
+    //for incremental loading (splitter)    
+    long long Unparsed() const;
+    long long ParseHeaders();
+    long ParseCluster(Cluster*&, long long& newpos) const;
+    bool AddCluster(Cluster*, long long);
+
+    Tracks* GetTracks() const;    
+    const SegmentInfo* const GetInfo() const;
+    long long GetDuration() const;
+    
+    //NOTE: this turned out to be too inefficient.
+    //long long Load(long long time_nanoseconds);
+
+    Cluster* GetFirst();
+    Cluster* GetLast();
+    unsigned long GetCount() const;
+    
+    Cluster* GetNext(const Cluster*);
+    Cluster* GetCluster(long long time_nanoseconds);
+    
+private:
+    long long m_pos;  //absolute file posn; what has been consumed so far    
+    SegmentInfo* m_pInfo;
+    Tracks* m_pTracks;    
+    Cluster** m_clusters;
+    size_t m_clusterCount;
+
+    void ParseSeekHead(long long pos, long long size, size_t*);
+    void ParseSeekEntry(long long pos, long long size, size_t*);
+    void ParseSecondarySeekHead(long long off, size_t*);
+};
+
+
+}  //end namespace mkvparser
+
+#endif  //MKVPARSER_HPP
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index f904cdf..2ff231d 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -222,7 +222,6 @@
         // underlying surface is created and destroyed
         SurfaceHolder holder = getHolder();
         holder.addCallback(this);
-        holder.setFormat(PixelFormat.RGB_565);
         // setType is not needed for SDK 2.0 or newer. Uncomment this
         // statement if back-porting this code to older SDKs.
         // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 33b0e81..8519e2c 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.location.Address;
+import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
@@ -68,6 +69,8 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -610,10 +613,10 @@
         return out;
     }
 
-    public List<String> getProviders(boolean enabledOnly) {
+    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
         try {
             synchronized (mLock) {
-                return _getProvidersLocked(enabledOnly);
+                return _getProvidersLocked(criteria, enabledOnly);
             }
         } catch (SecurityException se) {
             throw se;
@@ -623,7 +626,7 @@
         }
     }
 
-    private List<String> _getProvidersLocked(boolean enabledOnly) {
+    private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) {
         if (LOCAL_LOGV) {
             Slog.v(TAG, "getProviders");
         }
@@ -635,12 +638,225 @@
                 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
                     continue;
                 }
+                if (criteria != null && !p.meetsCriteria(criteria)) {
+                    continue;
+                }
                 out.add(name);
             }
         }
         return out;
     }
 
+    /**
+     * Returns the next looser power requirement, in the sequence:
+     *
+     * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
+     */
+    private int nextPower(int power) {
+        switch (power) {
+        case Criteria.POWER_LOW:
+            return Criteria.POWER_MEDIUM;
+        case Criteria.POWER_MEDIUM:
+            return Criteria.POWER_HIGH;
+        case Criteria.POWER_HIGH:
+            return Criteria.NO_REQUIREMENT;
+        case Criteria.NO_REQUIREMENT:
+        default:
+            return Criteria.NO_REQUIREMENT;
+        }
+    }
+
+    /**
+     * Returns the next looser accuracy requirement, in the sequence:
+     *
+     * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
+     */
+    private int nextAccuracy(int accuracy) {
+        if (accuracy == Criteria.ACCURACY_FINE) {
+            return Criteria.ACCURACY_COARSE;
+        } else {
+            return Criteria.NO_REQUIREMENT;
+        }
+    }
+
+    private class LpPowerComparator implements Comparator<LocationProviderInterface> {
+        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
+            // Smaller is better
+            return (l1.getPowerRequirement() - l2.getPowerRequirement());
+         }
+
+         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
+             return (l1.getPowerRequirement() == l2.getPowerRequirement());
+         }
+    }
+
+    private class LpAccuracyComparator implements Comparator<LocationProviderInterface> {
+        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
+            // Smaller is better
+            return (l1.getAccuracy() - l2.getAccuracy());
+         }
+
+         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
+             return (l1.getAccuracy() == l2.getAccuracy());
+         }
+    }
+
+    private class LpCapabilityComparator implements Comparator<LocationProviderInterface> {
+
+        private static final int ALTITUDE_SCORE = 4;
+        private static final int BEARING_SCORE = 4;
+        private static final int SPEED_SCORE = 4;
+
+        private int score(LocationProviderInterface p) {
+            return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
+                (p.supportsBearing() ? BEARING_SCORE : 0) +
+                (p.supportsSpeed() ? SPEED_SCORE : 0);
+        }
+
+        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
+            return (score(l2) - score(l1)); // Bigger is better
+         }
+
+         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
+             return (score(l1) == score(l2));
+         }
+    }
+
+    private LocationProviderInterface best(List<String> providerNames) {
+        ArrayList<LocationProviderInterface> providers;
+        synchronized (mLock) {
+            providers = new ArrayList<LocationProviderInterface>(mProviders.size());
+            for (int i = mProviders.size() - 1; i >= 0; i--) {
+                providers.add(mProviders.get(i));
+            }
+        }
+
+        if (providers.size() < 2) {
+            return providers.get(0);
+        }
+
+        // First, sort by power requirement
+        Collections.sort(providers, new LpPowerComparator());
+        int power = providers.get(0).getPowerRequirement();
+        if (power < providers.get(1).getPowerRequirement()) {
+            return providers.get(0);
+        }
+
+        int idx, size;
+
+        ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>();
+        idx = 0;
+        size = providers.size();
+        while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
+            tmp.add(providers.get(idx));
+            idx++;
+        }
+
+        // Next, sort by accuracy
+        Collections.sort(tmp, new LpAccuracyComparator());
+        int acc = tmp.get(0).getAccuracy();
+        if (acc < tmp.get(1).getAccuracy()) {
+            return tmp.get(0);
+        }
+
+        ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>();
+        idx = 0;
+        size = tmp.size();
+        while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
+            tmp2.add(tmp.get(idx));
+            idx++;
+        }
+
+        // Finally, sort by capability "score"
+        Collections.sort(tmp2, new LpCapabilityComparator());
+        return tmp2.get(0);
+    }
+
+    /**
+     * Returns the name of the provider that best meets the given criteria. Only providers
+     * that are permitted to be accessed by the calling activity will be
+     * returned.  If several providers meet the criteria, the one with the best
+     * accuracy is returned.  If no provider meets the criteria,
+     * the criteria are loosened in the following sequence:
+     *
+     * <ul>
+     * <li> power requirement
+     * <li> accuracy
+     * <li> bearing
+     * <li> speed
+     * <li> altitude
+     * </ul>
+     *
+     * <p> Note that the requirement on monetary cost is not removed
+     * in this process.
+     *
+     * @param criteria the criteria that need to be matched
+     * @param enabledOnly if true then only a provider that is currently enabled is returned
+     * @return name of the provider that best matches the requirements
+     */
+    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
+        List<String> goodProviders = getProviders(criteria, enabledOnly);
+        if (!goodProviders.isEmpty()) {
+            return best(goodProviders).getName();
+        }
+
+        // Make a copy of the criteria that we can modify
+        criteria = new Criteria(criteria);
+
+        // Loosen power requirement
+        int power = criteria.getPowerRequirement();
+        while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
+            power = nextPower(power);
+            criteria.setPowerRequirement(power);
+            goodProviders = getProviders(criteria, enabledOnly);
+        }
+        if (!goodProviders.isEmpty()) {
+            return best(goodProviders).getName();
+        }
+
+        // Loosen accuracy requirement
+        int accuracy = criteria.getAccuracy();
+        while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
+            accuracy = nextAccuracy(accuracy);
+            criteria.setAccuracy(accuracy);
+            goodProviders = getProviders(criteria, enabledOnly);
+        }
+        if (!goodProviders.isEmpty()) {
+            return best(goodProviders).getName();
+        }
+
+        // Remove bearing requirement
+        criteria.setBearingRequired(false);
+        goodProviders = getProviders(criteria, enabledOnly);
+        if (!goodProviders.isEmpty()) {
+            return best(goodProviders).getName();
+        }
+
+        // Remove speed requirement
+        criteria.setSpeedRequired(false);
+        goodProviders = getProviders(criteria, enabledOnly);
+        if (!goodProviders.isEmpty()) {
+            return best(goodProviders).getName();
+        }
+
+        // Remove altitude requirement
+        criteria.setAltitudeRequired(false);
+        goodProviders = getProviders(criteria, enabledOnly);
+        if (!goodProviders.isEmpty()) {
+            return best(goodProviders).getName();
+        }
+
+        return null;
+    }
+
+    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
+        LocationProviderInterface p = mProvidersByName.get(provider);
+        if (p == null) {
+            throw new IllegalArgumentException("provider=" + provider);
+        }
+        return p.meetsCriteria(criteria);
+    }
+
     private void updateProvidersLocked() {
         for (int i = mProviders.size() - 1; i >= 0; i--) {
             LocationProviderInterface p = mProviders.get(i);
@@ -717,6 +933,7 @@
         final Receiver mReceiver;
         final long mMinTime;
         final float mMinDistance;
+        final boolean mSingleShot;
         final int mUid;
         Location mLastFixBroadcast;
         long mLastStatusBroadcast;
@@ -724,12 +941,13 @@
         /**
          * Note: must be constructed with lock held.
          */
-        UpdateRecord(String provider, long minTime, float minDistance,
+        UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot,
             Receiver receiver, int uid) {
             mProvider = provider;
             mReceiver = receiver;
             mMinTime = minTime;
             mMinDistance = minDistance;
+            mSingleShot = singleShot;
             mUid = uid;
 
             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
@@ -764,6 +982,7 @@
             pw.println(prefix + this);
             pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
             pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
+            pw.println(prefix + "mSingleShot=" + mSingleShot);
             pw.println(prefix + "mUid=" + mUid);
             pw.println(prefix + "mLastFixBroadcast:");
             if (mLastFixBroadcast != null) {
@@ -819,12 +1038,21 @@
         return false;
     }
 
-    public void requestLocationUpdates(String provider,
-        long minTime, float minDistance, ILocationListener listener) {
-
+    public void requestLocationUpdates(String provider, Criteria criteria,
+        long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
+        if (criteria != null) {
+            // FIXME - should we consider using multiple providers simultaneously
+            // rather than only the best one?
+            // Should we do anything different for single shot fixes?
+            provider = getBestProvider(criteria, true);
+            if (provider == null) {
+                throw new IllegalArgumentException("no providers found for criteria");
+            }
+        }
         try {
             synchronized (mLock) {
-                requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
+                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
+                        getReceiver(listener));
             }
         } catch (SecurityException se) {
             throw se;
@@ -835,11 +1063,21 @@
         }
     }
 
-    public void requestLocationUpdatesPI(String provider,
-            long minTime, float minDistance, PendingIntent intent) {
+    public void requestLocationUpdatesPI(String provider, Criteria criteria,
+            long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
+        if (criteria != null) {
+            // FIXME - should we consider using multiple providers simultaneously
+            // rather than only the best one?
+            // Should we do anything different for single shot fixes?
+            provider = getBestProvider(criteria, true);
+            if (provider == null) {
+                throw new IllegalArgumentException("no providers found for criteria");
+            }
+        }
         try {
             synchronized (mLock) {
-                requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
+                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
+                        getReceiver(intent));
             }
         } catch (SecurityException se) {
             throw se;
@@ -850,8 +1088,8 @@
         }
     }
 
-    private void requestLocationUpdatesLocked(String provider,
-            long minTime, float minDistance, Receiver receiver) {
+    private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance,
+            boolean singleShot, Receiver receiver) {
         if (LOCAL_LOGV) {
             Slog.v(TAG, "_requestLocationUpdates: listener = " + receiver);
         }
@@ -868,7 +1106,8 @@
         boolean newUid = !providerHasListener(provider, callingUid, null);
         long identity = Binder.clearCallingIdentity();
         try {
-            UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
+            UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot,
+                    receiver, callingUid);
             UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
             if (oldRecord != null) {
                 oldRecord.disposeLocked();
@@ -882,7 +1121,11 @@
             if (isProviderEnabled) {
                 long minTimeForProvider = getMinTimeLocked(provider);
                 p.setMinTime(minTimeForProvider);
-                p.enableLocationTracking(true);
+                // try requesting single shot if singleShot is true, and fall back to
+                // regular location tracking if requestSingleShotFix() is not supported
+                if (!singleShot || !p.requestSingleShotFix()) {
+                    p.enableLocationTracking(true);
+                }
             } else {
                 // Notify the listener that updates are currently disabled
                 receiver.callProviderEnabledLocked(provider, false);
@@ -1288,7 +1531,8 @@
 
             for (int i = mProviders.size() - 1; i >= 0; i--) {
                 LocationProviderInterface provider = mProviders.get(i);
-                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
+                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f,
+                        false, mProximityReceiver);
             }
         }
     }
@@ -1486,6 +1730,7 @@
         for (int i=0; i<N; i++) {
             UpdateRecord r = records.get(i);
             Receiver receiver = r.mReceiver;
+            boolean receiverDead = false;
 
             Location lastLoc = r.mLastFixBroadcast;
             if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
@@ -1497,10 +1742,7 @@
                 }
                 if (!receiver.callLocationChangedLocked(location)) {
                     Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
-                    if (deadReceivers == null) {
-                        deadReceivers = new ArrayList<Receiver>();
-                    }
-                    deadReceivers.add(receiver);
+                    receiverDead = true;
                 }
             }
 
@@ -1510,13 +1752,18 @@
 
                 r.mLastStatusBroadcast = newStatusUpdateTime;
                 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
+                    receiverDead = true;
                     Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
-                    if (deadReceivers == null) {
-                        deadReceivers = new ArrayList<Receiver>();
-                    }
-                    if (!deadReceivers.contains(receiver)) {
-                        deadReceivers.add(receiver);
-                    }
+                }
+            }
+
+            // remove receiver if it is dead or we just processed a single shot request
+            if (receiverDead || r.mSingleShot) {
+                if (deadReceivers == null) {
+                    deadReceivers = new ArrayList<Receiver>();
+                }
+                if (!deadReceivers.contains(receiver)) {
+                    deadReceivers.add(receiver);
                 }
             }
         }
@@ -1693,6 +1940,10 @@
 
     // Geocoder
 
+    public boolean geocoderIsImplemented() {
+        return mGeocodeProvider != null;
+    }
+
     public String getFromLocation(double latitude, double longitude, int maxResults,
             GeocoderParams params, List<Address> addrs) {
         if (mGeocodeProvider != null) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 19c9018..0cf67a3 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -150,6 +150,7 @@
     private static final int UPDATE_LOCATION = 7;
     private static final int ADD_LISTENER = 8;
     private static final int REMOVE_LISTENER = 9;
+    private static final int REQUEST_SINGLE_SHOT = 10;
 
     private static final String PROPERTIES_FILE = "/etc/gps.conf";
 
@@ -190,6 +191,9 @@
     // true if we started navigation
     private boolean mStarted;
 
+    // true if single shot request is in progress
+    private boolean mSingleShot;
+
     // capabilities of the GPS engine
     private int mEngineCapabilities;
 
@@ -318,7 +322,7 @@
 
             if (action.equals(ALARM_WAKEUP)) {
                 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
-                startNavigating();
+                startNavigating(false);
             } else if (action.equals(ALARM_TIMEOUT)) {
                 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
                 hibernate();
@@ -599,6 +603,14 @@
     }
 
     /**
+     * Returns true if this provider meets the given criteria,
+     * false otherwise.
+     */
+    public boolean meetsCriteria(Criteria criteria) {
+        return (criteria.getPowerRequirement() != Criteria.POWER_LOW);
+    }
+
+    /**
      * Returns the horizontal accuracy of this provider
      *
      * @return the accuracy of location from this provider, as one
@@ -707,6 +719,7 @@
     }
 
     public void enableLocationTracking(boolean enable) {
+        // FIXME - should set a flag here to avoid race conditions with single shot request
         synchronized (mHandler) {
             sendMessage(ENABLE_TRACKING, (enable ? 1 : 0), null);
         }
@@ -716,7 +729,7 @@
         if (enable) {
             mTTFF = 0;
             mLastFixTime = 0;
-            startNavigating();
+            startNavigating(false);
         } else {
             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
                 mAlarmManager.cancel(mWakeupIntent);
@@ -726,6 +739,25 @@
         }
     }
 
+    public boolean requestSingleShotFix() {
+        if (mStarted) {
+            // cannot do single shot if already navigating
+            return false;
+        }
+        synchronized (mHandler) {
+            mHandler.removeMessages(REQUEST_SINGLE_SHOT);
+            Message m = Message.obtain(mHandler, REQUEST_SINGLE_SHOT);
+            mHandler.sendMessage(m);
+        }
+        return true;
+    }
+
+    private void handleRequestSingleShot() {
+        mTTFF = 0;
+        mLastFixTime = 0;
+        startNavigating(true);
+    }
+
     public void setMinTime(long minTime) {
         if (DEBUG) Log.d(TAG, "setMinTime " + minTime);
         
@@ -875,16 +907,20 @@
         return false;
     }
 
-    private void startNavigating() {
+    private void startNavigating(boolean singleShot) {
         if (!mStarted) {
             if (DEBUG) Log.d(TAG, "startNavigating");
             mStarted = true;
-            if (hasCapability(GPS_CAPABILITY_MSB) &&
-                Settings.Secure.getInt(mContext.getContentResolver(),
+            mSingleShot = singleShot;
+            mPositionMode = GPS_POSITION_MODE_STANDALONE;
+
+             if (Settings.Secure.getInt(mContext.getContentResolver(),
                     Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
-                mPositionMode = GPS_POSITION_MODE_MS_BASED;
-            } else {
-                mPositionMode = GPS_POSITION_MODE_STANDALONE;
+                if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
+                    mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
+                } else if (hasCapability(GPS_CAPABILITY_MSA)) {
+                    mPositionMode = GPS_POSITION_MODE_MS_BASED;
+                }
             }
 
             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
@@ -918,6 +954,7 @@
         if (DEBUG) Log.d(TAG, "stopNavigating");
         if (mStarted) {
             mStarted = false;
+            mSingleShot = false;
             native_stop();
             mTTFF = 0;
             mLastFixTime = 0;
@@ -1008,6 +1045,9 @@
             }
         }
 
+        if (mSingleShot) {
+            stopNavigating();
+        }
         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
             // we want to time out if we do not receive a fix
             // within the time out and we are requesting infrequent fixes
@@ -1022,7 +1062,7 @@
             updateStatus(LocationProvider.AVAILABLE, mSvCount);
         }
 
-       if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval > 1000) {
+       if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && mFixInterval > 1000) {
             if (DEBUG) Log.d(TAG, "got fix, hibernating");
             hibernate();
         }
@@ -1133,7 +1173,8 @@
             }
         }
 
-        updateStatus(mStatus, svCount);
+        // return number of sets used in fix instead of total
+        updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
 
         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
             System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
@@ -1369,6 +1410,9 @@
                 case ENABLE_TRACKING:
                     handleEnableLocationTracking(msg.arg1 == 1);
                     break;
+                case REQUEST_SINGLE_SHOT:
+                    handleRequestSingleShot();
+                    break;
                 case UPDATE_NETWORK_STATE:
                     handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
                     break;
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java
index a472143..084ab81 100644
--- a/services/java/com/android/server/location/LocationProviderInterface.java
+++ b/services/java/com/android/server/location/LocationProviderInterface.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.location.Criteria;
 import android.location.Location;
 import android.net.NetworkInfo;
 import android.os.Bundle;
@@ -35,6 +36,7 @@
     boolean supportsSpeed();
     boolean supportsBearing();
     int getPowerRequirement();
+    boolean meetsCriteria(Criteria criteria);
     int getAccuracy();
     boolean isEnabled();
     void enable();
@@ -42,6 +44,8 @@
     int getStatus(Bundle extras);
     long getStatusUpdateTime();
     void enableLocationTracking(boolean enable);
+    /* returns false if single shot is not supported */
+    boolean requestSingleShotFix();
     String getInternalState();
     void setMinTime(long minTime);
     void updateNetworkState(int state, NetworkInfo info);
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 3e118f9..24d7737 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.location.Criteria;
 import android.location.ILocationProvider;
 import android.location.Location;
 import android.net.NetworkInfo;
@@ -97,7 +98,7 @@
 
             if (mCachedAttributes == null) {
                 try {
-                    mCachedAttributes = new DummyLocationProvider(mName);
+                    mCachedAttributes = new DummyLocationProvider(mName, null);
                     mCachedAttributes.setRequiresNetwork(provider.requiresNetwork());
                     mCachedAttributes.setRequiresSatellite(provider.requiresSatellite());
                     mCachedAttributes.setRequiresCell(provider.requiresCell());
@@ -199,6 +200,39 @@
         }
     }
 
+    public boolean meetsCriteria(Criteria criteria) {
+       ILocationProvider provider;
+        synchronized (mServiceConnection) {
+            provider = mProvider;
+        }
+        if (provider != null) {
+            try {
+                return provider.meetsCriteria(criteria);
+            } catch (RemoteException e) {
+            }
+        }
+        // default implementation if we lost connection to the provider
+        if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) &&
+            (criteria.getAccuracy() < getAccuracy())) {
+            return false;
+        }
+        int criteriaPower = criteria.getPowerRequirement();
+        if ((criteriaPower != Criteria.NO_REQUIREMENT) &&
+            (criteriaPower < getPowerRequirement())) {
+            return false;
+        }
+        if (criteria.isAltitudeRequired() && !supportsAltitude()) {
+            return false;
+        }
+        if (criteria.isSpeedRequired() && !supportsSpeed()) {
+            return false;
+        }
+        if (criteria.isBearingRequired() && !supportsBearing()) {
+            return false;
+        }
+        return true;
+    }
+
     public int getAccuracy() {
         if (mCachedAttributes != null) {
             return mCachedAttributes.getAccuracy();
@@ -297,6 +331,10 @@
         }
     }
 
+    public boolean requestSingleShotFix() {
+        return false;
+    }
+
     public long getMinTime() {
         return mMinTime;
     }
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java
index e3f33469..01b34b7 100644
--- a/services/java/com/android/server/location/MockProvider.java
+++ b/services/java/com/android/server/location/MockProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.location.Criteria;
 import android.location.ILocationManager;
 import android.location.Location;
 import android.location.LocationProvider;
@@ -138,6 +139,28 @@
         return mSupportsSpeed;
     }
 
+    public boolean meetsCriteria(Criteria criteria) {
+        if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) &&
+            (criteria.getAccuracy() < mAccuracy)) {
+            return false;
+        }
+        int criteriaPower = criteria.getPowerRequirement();
+        if ((criteriaPower != Criteria.NO_REQUIREMENT) &&
+            (criteriaPower < mPowerRequirement)) {
+            return false;
+        }
+        if (criteria.isAltitudeRequired() && !mSupportsAltitude) {
+            return false;
+        }
+        if (criteria.isSpeedRequired() && !mSupportsSpeed) {
+            return false;
+        }
+        if (criteria.isBearingRequired() && !mSupportsBearing) {
+            return false;
+        }
+        return true;
+    }
+
     public void setLocation(Location l) {
         mLocation.set(l);
         mHasLocation = true;
@@ -174,6 +197,10 @@
     public void enableLocationTracking(boolean enable) {
     }
 
+    public boolean requestSingleShotFix() {
+        return false;
+    }
+
     public void setMinTime(long minTime) {
     }
 
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
index 5ed1558..7fc93f8 100644
--- a/services/java/com/android/server/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.location.Criteria;
 import android.location.ILocationManager;
 import android.location.Location;
 import android.location.LocationManager;
@@ -79,6 +80,11 @@
         return -1;
     }
 
+    public boolean meetsCriteria(Criteria criteria) {
+        // We do not want to match the special passive provider based on criteria.
+        return false;
+    }
+
     public int getAccuracy() {
         return -1;
     }
@@ -113,6 +119,10 @@
         mTracking = enable;
     }
 
+    public boolean requestSingleShotFix() {
+        return false;
+    }
+
     public void setMinTime(long minTime) {
     }
 
diff --git a/services/java/com/android/server/status/StatusBarIcon.java b/services/java/com/android/server/status/StatusBarIcon.java
index 6f8b8a8..f77b550 100644
--- a/services/java/com/android/server/status/StatusBarIcon.java
+++ b/services/java/com/android/server/status/StatusBarIcon.java
@@ -51,14 +51,11 @@
         switch (data.type) {
             case IconData.TEXT: {
                 TextView t;
-                t = new TextView(context);
+                t = new TextView(context, null, com.android.internal.R.style.TextAppearance_StatusBar_Icon);
                 mTextView = t;
                 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                         LinearLayout.LayoutParams.WRAP_CONTENT,
                         LinearLayout.LayoutParams.MATCH_PARENT);
-                t.setTextSize(16);
-                t.setTextColor(0xff000000);
-                t.setTypeface(Typeface.DEFAULT_BOLD);
                 t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
                 t.setPadding(6, 0, 0, 0);
                 t.setLayoutParams(layoutParams);
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 35ccfe8..cab2662 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -29,6 +29,7 @@
 import android.content.IntentFilter;
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.location.LocationManager;
 import android.media.AudioManager;
@@ -49,7 +50,10 @@
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.text.format.DateFormat;
+import android.text.style.CharacterStyle;
 import android.text.style.RelativeSizeSpan;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.util.Slog;
@@ -86,6 +90,12 @@
     // message codes for the handler
     private static final int EVENT_BATTERY_CLOSE = 4;
 
+    private static final int AM_PM_STYLE_NORMAL  = 0;
+    private static final int AM_PM_STYLE_SMALL   = 1;
+    private static final int AM_PM_STYLE_GONE    = 2;
+
+    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
+
     private final Context mContext;
     private final StatusBarService mService;
     private final Handler mHandler = new StatusBarHandler();
@@ -576,31 +586,33 @@
              * add dummy characters around it to let us find it again after
              * formatting and change its size.
              */
-            int a = -1;
-            boolean quoted = false;
-            for (int i = 0; i < format.length(); i++) {
-                char c = format.charAt(i);
+            if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+                int a = -1;
+                boolean quoted = false;
+                for (int i = 0; i < format.length(); i++) {
+                    char c = format.charAt(i);
 
-                if (c == '\'') {
-                    quoted = !quoted;
+                    if (c == '\'') {
+                        quoted = !quoted;
+                    }
+
+                    if (!quoted && c == 'a') {
+                        a = i;
+                        break;
+                    }
                 }
 
-                if (!quoted && c == 'a') {
-                    a = i;
-                    break;
+                if (a >= 0) {
+                    // Move a back so any whitespace before the AM/PM is also in the alternate size.
+                    final int b = a;
+                    while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
+                        a--;
+                    }
+                    format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
+                            + "a" + MAGIC2 + format.substring(b + 1);
                 }
             }
 
-            if (a >= 0) {
-                // Move a back so any whitespace before the AM/PM is also in the alternate size.
-                final int b = a;
-                while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
-                    a--;
-                }
-                format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
-                        + "a" + MAGIC2 + format.substring(b + 1);
-            }
-
             mClockFormat = sdf = new SimpleDateFormat(format);
             mClockFormatString = format;
         } else {
@@ -608,22 +620,31 @@
         }
         String result = sdf.format(mCalendar.getTime());
 
-        int magic1 = result.indexOf(MAGIC1);
-        int magic2 = result.indexOf(MAGIC2);
+        if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+            int magic1 = result.indexOf(MAGIC1);
+            int magic2 = result.indexOf(MAGIC2);
 
-        if (magic1 >= 0 && magic2 > magic1) {
-            SpannableStringBuilder formatted = new SpannableStringBuilder(result);
+            if (magic1 >= 0 && magic2 > magic1) {
+                SpannableStringBuilder formatted = new SpannableStringBuilder(result);
 
-            formatted.setSpan(new RelativeSizeSpan(0.7f), magic1, magic2,
-                              Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+                if (AM_PM_STYLE == AM_PM_STYLE_GONE) {
+                    formatted.delete(magic1, magic2+1);
+                } else {
+                    if (AM_PM_STYLE == AM_PM_STYLE_SMALL) {
+                        CharacterStyle style = new RelativeSizeSpan(0.7f);
+                        formatted.setSpan(style, magic1, magic2,
+                                          Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+                    }
 
-            formatted.delete(magic2, magic2 + 1);
-            formatted.delete(magic1, magic1 + 1);
+                    formatted.delete(magic2, magic2 + 1);
+                    formatted.delete(magic1, magic1 + 1);
+                }
 
-            return formatted;
-        } else {
-            return result;
+                return formatted;
+            }
         }
+ 
+        return result;
     }
 
     private final void updateClock() {